|  | @@ -133,12 +133,12 @@ static uint16_t wire_buf_b[WIRE_BUFFER_SIZE];
 | 
											
												
													
														|  |  // tracking for audio playback
 |  |  // tracking for audio playback
 | 
											
												
													
														|  |  static uint8_t audio_owner; // SCSI ID or 0xFF when idle
 |  |  static uint8_t audio_owner; // SCSI ID or 0xFF when idle
 | 
											
												
													
														|  |  static volatile bool audio_paused = false;
 |  |  static volatile bool audio_paused = false;
 | 
											
												
													
														|  | -static FsFile audio_file;
 |  | 
 | 
											
												
													
														|  | 
 |  | +static ImageBackingStore audio_file;
 | 
											
												
													
														|  | 
 |  | +static uint64_t fpos;
 | 
											
												
													
														|  |  static uint32_t fleft;
 |  |  static uint32_t fleft;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  // historical playback status information
 |  |  // historical playback status information
 | 
											
												
													
														|  |  static audio_status_code audio_last_status[8] = {ASC_NO_STATUS};
 |  |  static audio_status_code audio_last_status[8] = {ASC_NO_STATUS};
 | 
											
												
													
														|  | -static uint32_t audio_bytes_read[8] = {0};
 |  | 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  // mechanism for cleanly stopping DMA units
 |  |  // mechanism for cleanly stopping DMA units
 | 
											
												
													
														|  |  static volatile bool audio_stopping = false;
 |  |  static volatile bool audio_stopping = false;
 | 
											
										
											
												
													
														|  | @@ -355,6 +355,11 @@ void audio_poll() {
 | 
											
												
													
														|  |      } else if (fleft == 0) {
 |  |      } else if (fleft == 0) {
 | 
											
												
													
														|  |          // out of data to read but still working on remainder
 |  |          // out of data to read but still working on remainder
 | 
											
												
													
														|  |          return;
 |  |          return;
 | 
											
												
													
														|  | 
 |  | +    } else if (!audio_file.isOpen()) {
 | 
											
												
													
														|  | 
 |  | +        // closed elsewhere, maybe disk ejected?
 | 
											
												
													
														|  | 
 |  | +        debuglog("------ Playback stop due to closed file");
 | 
											
												
													
														|  | 
 |  | +        audio_stop(audio_owner);
 | 
											
												
													
														|  | 
 |  | +        return;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      // are new audio samples needed from the memory card?
 |  |      // are new audio samples needed from the memory card?
 | 
											
										
											
												
													
														|  | @@ -373,11 +378,20 @@ void audio_poll() {
 | 
											
												
													
														|  |      platform_set_sd_callback(NULL, NULL);
 |  |      platform_set_sd_callback(NULL, NULL);
 | 
											
												
													
														|  |      uint16_t toRead = AUDIO_BUFFER_SIZE;
 |  |      uint16_t toRead = AUDIO_BUFFER_SIZE;
 | 
											
												
													
														|  |      if (fleft < toRead) toRead = fleft;
 |  |      if (fleft < toRead) toRead = fleft;
 | 
											
												
													
														|  | 
 |  | +    if (audio_file.position() != fpos) {
 | 
											
												
													
														|  | 
 |  | +        // should be uncommon due to SCSI command restrictions on devices
 | 
											
												
													
														|  | 
 |  | +        // playing audio; if this is showing up in logs a different approach
 | 
											
												
													
														|  | 
 |  | +        // will be needed to avoid seek performance issues on FAT32 vols
 | 
											
												
													
														|  | 
 |  | +        debuglog("------ Audio seek required on ", audio_owner);
 | 
											
												
													
														|  | 
 |  | +        if (!audio_file.seek(fpos)) {
 | 
											
												
													
														|  | 
 |  | +            log("Audio error, unable to seek to ", fpos, ", ID:", audio_owner);
 | 
											
												
													
														|  | 
 |  | +        }
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  |      if (audio_file.read(audiobuf, toRead) != toRead) {
 |  |      if (audio_file.read(audiobuf, toRead) != toRead) {
 | 
											
												
													
														|  |          log("Audio sample data underrun");
 |  |          log("Audio sample data underrun");
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  | 
 |  | +    fpos += toRead;
 | 
											
												
													
														|  |      fleft -= toRead;
 |  |      fleft -= toRead;
 | 
											
												
													
														|  | -    audio_bytes_read[audio_owner] += toRead;
 |  | 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      if (sbufst_a == FILLING) {
 |  |      if (sbufst_a == FILLING) {
 | 
											
												
													
														|  |          sbufst_a = READY;
 |  |          sbufst_a = READY;
 | 
											
										
											
												
													
														|  | @@ -386,7 +400,7 @@ void audio_poll() {
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -bool audio_play(uint8_t owner, const char* file, uint64_t start, uint64_t end, bool swap) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +bool audio_play(uint8_t owner, ImageBackingStore img, uint64_t start, uint64_t end, bool swap) {
 | 
											
												
													
														|  |      // stop any existing playback first
 |  |      // stop any existing playback first
 | 
											
												
													
														|  |      if (audio_is_active()) audio_stop(audio_owner);
 |  |      if (audio_is_active()) audio_stop(audio_owner);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -402,50 +416,44 @@ bool audio_play(uint8_t owner, const char* file, uint64_t start, uint64_t end, b
 | 
											
												
													
														|  |          return false;
 |  |          return false;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |      platform_set_sd_callback(NULL, NULL);
 |  |      platform_set_sd_callback(NULL, NULL);
 | 
											
												
													
														|  | -    audio_file = SD.open(file, O_RDONLY);
 |  | 
 | 
											
												
													
														|  | 
 |  | +    audio_file = img;
 | 
											
												
													
														|  |      if (!audio_file.isOpen()) {
 |  |      if (!audio_file.isOpen()) {
 | 
											
												
													
														|  | -        log("Unable to open file for audio playback: ", file);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        log("File not open for audio playback, ", owner);
 | 
											
												
													
														|  |          return false;
 |  |          return false;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |      uint64_t len = audio_file.size();
 |  |      uint64_t len = audio_file.size();
 | 
											
												
													
														|  |      if (start > len) {
 |  |      if (start > len) {
 | 
											
												
													
														|  | -        log("File '", file, "' playback request start (",
 |  | 
 | 
											
												
													
														|  | -                start, ":", len, ") outside file bounds");
 |  | 
 | 
											
												
													
														|  | -        audio_file.close();
 |  | 
 | 
											
												
													
														|  | 
 |  | +        log("File playback request start (", start, ":", len, ") outside file bounds");
 | 
											
												
													
														|  |          return false;
 |  |          return false;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |      // truncate playback end to end of file
 |  |      // truncate playback end to end of file
 | 
											
												
													
														|  |      // we will not consider this to be an error at the moment
 |  |      // we will not consider this to be an error at the moment
 | 
											
												
													
														|  |      if (end > len) {
 |  |      if (end > len) {
 | 
											
												
													
														|  | -        dbgmsg("------ Truncate audio play request end ", end, " to file size ", len);
 |  | 
 | 
											
												
													
														|  | 
 |  | +        debuglog("------ Truncate audio play request end ", end, " to file size ", len);
 | 
											
												
													
														|  |          end = len;
 |  |          end = len;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |      fleft = end - start;
 |  |      fleft = end - start;
 | 
											
												
													
														|  |      if (fleft <= 2 * AUDIO_BUFFER_SIZE) {
 |  |      if (fleft <= 2 * AUDIO_BUFFER_SIZE) {
 | 
											
												
													
														|  | -        log("File '", file, "' playback request (",
 |  | 
 | 
											
												
													
														|  | -                start, ":", end, ") too short");
 |  | 
 | 
											
												
													
														|  | -        audio_file.close();
 |  | 
 | 
											
												
													
														|  | 
 |  | +        log("File playback request (", start, ":", end, ") too short");
 | 
											
												
													
														|  |          return false;
 |  |          return false;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      // read in initial sample buffers
 |  |      // read in initial sample buffers
 | 
											
												
													
														|  |      if (!audio_file.seek(start)) {
 |  |      if (!audio_file.seek(start)) {
 | 
											
												
													
														|  | -        log("Sample file (", file, ") failed start seek to ", start);
 |  | 
 | 
											
												
													
														|  | -        audio_file.close();
 |  | 
 | 
											
												
													
														|  | 
 |  | +        log("Sample file failed start seek to ", start);
 | 
											
												
													
														|  |          return false;
 |  |          return false;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |      if (audio_file.read(sample_buf_a, AUDIO_BUFFER_SIZE) != AUDIO_BUFFER_SIZE) {
 |  |      if (audio_file.read(sample_buf_a, AUDIO_BUFFER_SIZE) != AUDIO_BUFFER_SIZE) {
 | 
											
												
													
														|  | -        log("File '", file, "' playback start returned fewer bytes than allowed");
 |  | 
 | 
											
												
													
														|  | -        audio_file.close();
 |  | 
 | 
											
												
													
														|  | 
 |  | +        log("File playback start returned fewer bytes than allowed");
 | 
											
												
													
														|  |          return false;
 |  |          return false;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |      if (audio_file.read(sample_buf_b, AUDIO_BUFFER_SIZE) != AUDIO_BUFFER_SIZE) {
 |  |      if (audio_file.read(sample_buf_b, AUDIO_BUFFER_SIZE) != AUDIO_BUFFER_SIZE) {
 | 
											
												
													
														|  | -        log("File '", file, "' playback start returned fewer bytes than allowed");
 |  | 
 | 
											
												
													
														|  | -        audio_file.close();
 |  | 
 | 
											
												
													
														|  | 
 |  | +        log("File playback start returned fewer bytes than allowed");
 | 
											
												
													
														|  |          return false;
 |  |          return false;
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      // prepare initial tracking state
 |  |      // prepare initial tracking state
 | 
											
												
													
														|  | 
 |  | +    fpos = audio_file.position();
 | 
											
												
													
														|  |      fleft -= AUDIO_BUFFER_SIZE * 2;
 |  |      fleft -= AUDIO_BUFFER_SIZE * 2;
 | 
											
												
													
														|  |      sbufsel = A;
 |  |      sbufsel = A;
 | 
											
												
													
														|  |      sbufpos = 0;
 |  |      sbufpos = 0;
 | 
											
										
											
												
													
														|  | @@ -453,7 +461,6 @@ bool audio_play(uint8_t owner, const char* file, uint64_t start, uint64_t end, b
 | 
											
												
													
														|  |      sbufst_a = READY;
 |  |      sbufst_a = READY;
 | 
											
												
													
														|  |      sbufst_b = READY;
 |  |      sbufst_b = READY;
 | 
											
												
													
														|  |      audio_owner = owner & 7;
 |  |      audio_owner = owner & 7;
 | 
											
												
													
														|  | -    audio_bytes_read[audio_owner] = AUDIO_BUFFER_SIZE * 2;
 |  | 
 | 
											
												
													
														|  |      audio_last_status[audio_owner] = ASC_PLAYING;
 |  |      audio_last_status[audio_owner] = ASC_PLAYING;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      // prepare the wire buffers
 |  |      // prepare the wire buffers
 | 
											
										
											
												
													
														|  | @@ -523,9 +530,6 @@ void audio_stop(uint8_t id) {
 | 
											
												
													
														|  |      audio_stopping = false;
 |  |      audio_stopping = false;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      // idle the subsystem
 |  |      // idle the subsystem
 | 
											
												
													
														|  | -    if (audio_file.isOpen()) {
 |  | 
 | 
											
												
													
														|  | -        audio_file.close();
 |  | 
 | 
											
												
													
														|  | -    }
 |  | 
 | 
											
												
													
														|  |      audio_last_status[audio_owner] = ASC_COMPLETED;
 |  |      audio_last_status[audio_owner] = ASC_COMPLETED;
 | 
											
												
													
														|  |      audio_owner = 0xFF;
 |  |      audio_owner = 0xFF;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
										
											
												
													
														|  | @@ -538,12 +542,4 @@ audio_status_code audio_get_status_code(uint8_t id) {
 | 
											
												
													
														|  |      return tmp;
 |  |      return tmp;
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -uint32_t audio_get_bytes_read(uint8_t id) {
 |  | 
 | 
											
												
													
														|  | -    return audio_bytes_read[id & 7];
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -void audio_clear_bytes_read(uint8_t id) {
 |  | 
 | 
											
												
													
														|  | -    audio_bytes_read[id & 7] = 0;
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  |  #endif // ENABLE_AUDIO_OUTPUT
 |  |  #endif // ENABLE_AUDIO_OUTPUT
 |