ソースを参照

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 2 年 前
コミット
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;