Parcourir la source

Use existing image store instead of new FsFile for audio data.

Also adds image position() call, for audio checking and removal of separate mechanism tracking system.
saybur il y a 2 ans
Parent
commit
33d6a27991

+ 27 - 31
lib/BlueSCSI_platform_RP2040/audio.cpp

@@ -133,12 +133,12 @@ static uint16_t wire_buf_b[WIRE_BUFFER_SIZE];
 // tracking for audio playback
 static uint8_t audio_owner; // SCSI ID or 0xFF when idle
 static volatile bool audio_paused = false;
-static FsFile audio_file;
+static ImageBackingStore audio_file;
+static uint64_t fpos;
 static uint32_t fleft;
 
 // historical playback status information
 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
 static volatile bool audio_stopping = false;
@@ -355,6 +355,11 @@ void audio_poll() {
     } else if (fleft == 0) {
         // out of data to read but still working on remainder
         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?
@@ -373,11 +378,20 @@ void audio_poll() {
     platform_set_sd_callback(NULL, NULL);
     uint16_t toRead = AUDIO_BUFFER_SIZE;
     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) {
         log("Audio sample data underrun");
     }
+    fpos += toRead;
     fleft -= toRead;
-    audio_bytes_read[audio_owner] += toRead;
 
     if (sbufst_a == FILLING) {
         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
     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;
     }
     platform_set_sd_callback(NULL, NULL);
-    audio_file = SD.open(file, O_RDONLY);
+    audio_file = img;
     if (!audio_file.isOpen()) {
-        log("Unable to open file for audio playback: ", file);
+        log("File not open for audio playback, ", owner);
         return false;
     }
     uint64_t len = audio_file.size();
     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;
     }
     // truncate playback end to end of file
     // we will not consider this to be an error at the moment
     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;
     }
     fleft = end - start;
     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;
     }
 
     // read in initial sample buffers
     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;
     }
     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;
     }
     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;
     }
 
     // prepare initial tracking state
+    fpos = audio_file.position();
     fleft -= AUDIO_BUFFER_SIZE * 2;
     sbufsel = A;
     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_b = READY;
     audio_owner = owner & 7;
-    audio_bytes_read[audio_owner] = AUDIO_BUFFER_SIZE * 2;
     audio_last_status[audio_owner] = ASC_PLAYING;
 
     // prepare the wire buffers
@@ -523,9 +530,6 @@ void audio_stop(uint8_t id) {
     audio_stopping = false;
 
     // idle the subsystem
-    if (audio_file.isOpen()) {
-        audio_file.close();
-    }
     audio_last_status[audio_owner] = ASC_COMPLETED;
     audio_owner = 0xFF;
 }
@@ -538,12 +542,4 @@ audio_status_code audio_get_status_code(uint8_t id) {
     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

+ 3 - 24
src/BlueSCSI_audio.h

@@ -22,6 +22,7 @@
 #pragma once
 
 #include <stdint.h>
+#include "ImageBackingStore.h"
 
 /*
  * Status codes for audio playback, matching the SCSI 'audio status codes'.
@@ -52,13 +53,13 @@ bool audio_is_playing(uint8_t id);
  * Begins audio playback for a file.
  *
  * \param owner  The SCSI ID that initiated this playback operation.
- * \param file   Path of a file containing PCM samples to play.
+ * \param img    Image containing PCM samples to play.
  * \param start  Byte offset within file where playback will begin, inclusive.
  * \param end    Byte offset within file where playback will end, exclusive.
  * \param swap   If false, little-endian sample order, otherwise big-endian.
  * \return       True if successful, false otherwise.
  */
-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);
 
 /**
  * Pauses audio playback. This may be delayed slightly to allow sample buffers
@@ -85,25 +86,3 @@ void audio_stop(uint8_t id);
  * \return      The matching audio status code.
  */
 audio_status_code audio_get_status_code(uint8_t id);
-
-/**
- * Provides the number of sample bytes read in during an individual audio
- * call. This can be combined with a separate starting offset to determine
- * virtual CD positioning information. This may only be an approximation due
- * to platform-specific behavior with sample reading.
- *
- * Data here should not be cleared when audio is stopped. Playback events
- * should reset this information.
- *
- * \param id    The SCSI ID target to return data for.
- * \return      The number of bytes read in during a playback.
- */
-uint32_t audio_get_bytes_read(uint8_t id);
-
-/**
- * Clears the byte counter in the above call. This should be supported even
- * during playback.
- *
- * \param id    The SCSI ID target to clear data for.
- */
-void audio_clear_bytes_read(uint8_t id);

+ 10 - 28
src/BlueSCSI_cdrom.cpp

@@ -42,15 +42,6 @@ extern "C" {
 #include <scsi.h>
 }
 
-/******************************************/
-/*   CDROM positioning information        */
-/******************************************/
-
-typedef struct {
-    uint32_t last_lba = 0;
-} mechanism_status_t;
-static mechanism_status_t mechanism_status[8];
-
 /******************************************/
 /* Basic TOC generation without cue sheet */
 /******************************************/
@@ -865,9 +856,7 @@ bool cdromSwitchNextImage(image_config_t &img)
     audio_stop(target_idx);
     // Reset position tracking for the new image
     audio_get_status_code(target_idx); // trash audio status code
-    audio_clear_bytes_read(target_idx);
 #endif
-    mechanism_status[target_idx].last_lba = 0;
 
     if (filename[0] != '\0')
     {
@@ -947,12 +936,17 @@ void cdromGetAudioPlaybackStatus(uint8_t *status, uint32_t *current_lba, bool cu
             *status = (uint8_t) audio_get_status_code(target);
         }
     }
-    if (current_lba) *current_lba = mechanism_status[target].last_lba
-            + audio_get_bytes_read(target) / 2352;
 #else
     if (status) *status = 0; // audio status code for 'unsupported/invalid' and not-playing indicator
-    if (current_lba) *current_lba = mechanism_status[target].last_lba;
 #endif
+    if (current_lba)
+    {
+        if (img.file.isOpen()) {
+            *current_lba = img.file.position() / 2352;
+        } else {
+            *current_lba = 0;
+        }
+    }
 }
 
 static void doPlayAudio(uint32_t lba, uint32_t length)
@@ -986,7 +980,7 @@ static void doPlayAudio(uint32_t lba, uint32_t length)
         if (lba == 0xFFFFFFFF)
         {
             // request to start playback from 'current position'
-            lba = mechanism_status[target_id].last_lba + audio_get_bytes_read(target_id) / 2352;
+            lba = img.file.position() / 2352;
         }
 
         // --- TODO --- determine proper track offset, software I tested with had a tendency
@@ -1007,18 +1001,7 @@ static void doPlayAudio(uint32_t lba, uint32_t length)
         }
 
         // playback request appears to be sane, so perform it
-        char filename[MAX_FILE_PATH];
-        if (!img.file.name(filename, sizeof(filename)))
-        {
-            // No underlying file available?
-            log("---- No filename for SCSI ID ", target_id);
-            scsiDev.status = CHECK_CONDITION;
-            scsiDev.target->sense.code = ILLEGAL_REQUEST;
-            scsiDev.target->sense.asc = 0x0000;
-            scsiDev.phase = STATUS;
-            return;
-        }
-        if (!audio_play(target_id, filename, offset, offset + length * 2352, false))
+        if (!audio_play(target_id, img.file, offset, offset + length * 2352, false))
         {
             // Underlying data/media error? Fake a disk scratch, which should
             // be a condition most CD-DA players are expecting
@@ -1028,7 +1011,6 @@ static void doPlayAudio(uint32_t lba, uint32_t length)
             scsiDev.phase = STATUS;
             return;
         }
-        mechanism_status[target_id].last_lba = lba;
         scsiDev.status = 0;
         scsiDev.phase = STATUS;
     }

+ 2 - 2
src/ImageBackingStore.cpp

@@ -300,11 +300,11 @@ void ImageBackingStore::flush()
     }
 }
 
-size_t ImageBackingStore::name(char* filename, size_t len)
+uint64_t ImageBackingStore::position()
 {
     if (!m_israw && !m_isrom)
     {
-        return m_fsfile.getName(filename, len);
+        return m_fsfile.curPosition();
     }
     else
     {

+ 3 - 2
src/ImageBackingStore.h

@@ -71,8 +71,9 @@ public:
     // Flush any pending changes to filesystem
     void flush();
 
-    // If available, read filename and return actual length.
-    size_t name(char* filename, size_t len);
+    // Gets current position for following read/write operations
+    // Result is only valid for regular files, not raw or flash access
+    uint64_t position();
 
 protected:
     bool m_israw;