ソースを参照

Merge pull request #541 from ZuluSCSI/feature/play-audio-track-index

Playback based on track/index. Reporting Party confirms this addresses their issue, so merging as-is.
Alex Perez 7 ヶ月 前
コミット
7b558ae9fd

+ 126 - 0
lib/ZuluSCSI_platform_RP2MCU/audio_i2s.cpp

@@ -530,7 +530,133 @@ void audio_poll() {
     }
 }
 
+bool  audio_play_track_index(uint8_t owner,      image_config_t* img, 
+                            uint8_t start_track, uint8_t start_index, 
+                            uint8_t end_track,   uint8_t end_index)
+{
+    if(!img->cuesheetfile && img->cuesheetfile.isOpen())
+    {
+        logmsg("Error attempting to play CD Audio with no cue/bin image(s)");
+        return false;
+    }
+    if (img->bin_container.isOpen() && img->bin_container.isDir())
+    {
+        audio_parent.close();
+        audio_file.close();
+        audio_parent = img->bin_container;
+        single_bin_file = false;
+    }
+    else if (img->bin_container.isOpen())
+    {
+        audio_parent.close();
+        audio_file.close();
+        audio_file = img->bin_container;
+        single_bin_file = true;
+    }
+    else
+        return false;
+
+    if (&img->cuesheetfile != cuesheet_file)
+    {
+        cuesheet_file = &img->cuesheetfile;
+        cuesheet_file->seek(0);
+        cuesheet_file->read(g_cuesheet, sizeof(g_cuesheet));
+        delete g_cue_parser;
+        g_cue_parser = new CUEParser(g_cuesheet);
+    }
+
+    // read in the first track and report errors
+    const CUETrackInfo *find_track_info;
+
+    // Init globals
+    within_gap = false;
+    last_track_reached = false;
+    gap_length = 0;
+    gap_read = 0;
+
+    uint64_t file_size = 0;
+    CUETrackInfo track_info = {0};
+    int file_index = -1;
+    uint32_t start_lba = 0;
+    uint32_t end_lba = 0;
+    bool found_start = false;
+    bool found_end = false;
+    bool searched_past_last_track = false;
+    uint64_t last_file_size_lba = 0;
+    g_cue_parser->restart();
+
+    while ((find_track_info = g_cue_parser->next_track(file_size)) != nullptr )
+    {
+
+        if (!single_bin_file)
+        {
+            // opening the file for getting file size
+            if (find_track_info->file_index != file_index)
+            {
+                if (!(audio_parent.isDir() && audio_file.open(&audio_parent, find_track_info->filename, O_RDONLY)))
+                {
+                    dbgmsg("------ Audio playback - could not open the next track's bin file: ", find_track_info->filename);
+                    audio_file.close();
+                    return false;
+                }
+                file_index = find_track_info->file_index;
+            }
+        }
+        file_size = audio_file.size();
+
+        if (!found_start && start_track == find_track_info->track_number)
+        {
+            // current we only handle index 0 and index 1 in CUEParser
+            // because index can only be 1 - 99, start_lba will always be data_start
+            start_lba = find_track_info->data_start;
+            end_lba = find_track_info->data_start;
+            last_file_size_lba = (file_size - find_track_info->file_offset) / find_track_info->sector_length;
+            found_start = true;
+            if (end_track == find_track_info->track_number)
+            {
+                found_end = true;
+            }
+        }
+        else if (found_start && !found_end)
+        {
+            last_file_size_lba = (file_size - find_track_info->file_offset) / find_track_info->sector_length;
+            end_lba = find_track_info->data_start;
+
+            if (end_track == find_track_info->track_number)
+            {
+                found_end = true;
+                if (!single_bin_file)
+                {
+                    end_lba += last_file_size_lba;
+                    break;
+                }
+            }
+        }
+        else if (found_end)
+        {
+            end_lba = find_track_info->track_start;
+            searched_past_last_track = true;
+            break;
+        }
+        track_info = *find_track_info;
+    }
+
+    if (!found_start)
+    {
+        dbgmsg("------ Audio playback - could not find starting track");
+        return false;
+    }
+    
+    if (single_bin_file && !searched_past_last_track)
+    {
+        end_lba += last_file_size_lba;
+    }
+
+    return audio_play(owner, img, start_lba, end_lba - start_lba, false);
+}
+
 bool audio_play(uint8_t owner, image_config_t* img, uint32_t start, uint32_t length, bool swap) {
+    dbgmsg("------ Audio playback lba start ", (int) start, ", length ", (int)(length));
     // Per Annex C terminate playback immediately if already in progress on
     // the current target. Non-current targets may also get their audio
     // interrupted later due to hardware limitations

+ 13 - 0
src/ZuluSCSI_audio.h

@@ -95,6 +95,19 @@ bool audio_play(uint8_t owner, image_config_t* img, uint64_t start, uint64_t end
  */
 bool audio_play(uint8_t owner, image_config_t* img, uint32_t start, uint32_t length, bool swap);
 
+/**
+ * Begins audio playback for a file using the track and index.
+ *
+ * \param owner         The SCSI ID that initiated this playback operation.
+ * \param img           Pointer to the image container that can load PCM samples to play.
+ * \param start_track   Starting track
+ * \param start_index   Starting index
+ * \param end_track     LBA offset within file where playback will begin, inclusive.
+ * \param end_index     LBA length of play .
+ * \return       True if successful, false otherwise.
+ */
+
+bool audio_play_track_index(uint8_t owner, image_config_t* img, uint8_t start_track, uint8_t start_index, uint8_t end_track, uint8_t end_index);
 #endif
 
 

+ 61 - 1
src/ZuluSCSI_cdrom.cpp

@@ -1445,7 +1445,7 @@ static void doPlayAudio(uint32_t lba, uint32_t length)
         scsiDev.phase = STATUS;
     }
 #elif defined(ENABLE_AUDIO_OUTPUT_I2S) && defined(ZULUSCSI_BLASTER)
-    dbgmsg("------ CD-ROM Play Audio request at ", lba, " for ", length, " sectors");
+    dbgmsg("------ CD-ROM Play Audio request at ", (int)lba, " for ", (int)length, " sectors");
     image_config_t &img = *(image_config_t*)scsiDev.target->cfg;
     uint8_t target_id = img.scsiId & 7;
 
@@ -1491,6 +1491,55 @@ static void doPlayAudio(uint32_t lba, uint32_t length)
 #endif
 }
 
+static void doPlayAudioTrackIndex(uint8_t start_track, uint8_t start_index, uint8_t end_track, uint8_t end_index)
+{
+#if defined(ENABLE_AUDIO_OUTPUT)
+# if defined(ZULUSCSI_BLASTER)
+    dbgmsg("------ CD-ROM Play Audio request at track:index ", (int)start_track, ":", (int)start_index, " until ", (int)end_track, ":", (int)end_index);
+    image_config_t &img = *(image_config_t*)scsiDev.target->cfg;
+    uint8_t target_id = img.scsiId & 7;
+    if (audio_play_track_index(target_id, &img, start_track, start_index, end_track, end_index))
+    {
+        scsiDev.status = 0;
+        scsiDev.phase = STATUS;
+    }
+    else
+    {
+        // // Underlying data/media error? Fake a disk scratch, which should
+        // // be a condition most CD-DA players are expecting
+        // scsiDev.status = CHECK_CONDITION;
+        // scsiDev.target->sense.code = MEDIUM_ERROR;
+        // scsiDev.target->sense.asc = 0x1106; // CIRC UNRECOVERED ERROR
+        // scsiDev.phase = STATUS;
+        // return;
+        
+        // virtual drive supports audio, just not with this disk image
+        dbgmsg("---- Request to play audio on non-audio image");
+        scsiDev.status = CHECK_CONDITION;
+        scsiDev.target->sense.code = ILLEGAL_REQUEST;
+        scsiDev.target->sense.asc = 0x6400; // ILLEGAL MODE FOR THIS TRACK
+        scsiDev.phase = STATUS;
+    }
+# else
+    logmsg("---- Request to play audio via track and index has not been implemented for this board");
+    scsiDev.status = CHECK_CONDITION;
+    scsiDev.target->sense.code = ILLEGAL_REQUEST;
+    scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
+    scsiDev.phase = STATUS;
+# endif
+
+#else
+    dbgmsg("---- Target does not support audio playback");
+    // per SCSI-2, targets not supporting audio respond to zero-length
+    // PLAY AUDIO commands with ILLEGAL REQUEST; this seems to be a check
+    // performed by at least some audio playback software
+    scsiDev.status = CHECK_CONDITION;
+    scsiDev.target->sense.code = ILLEGAL_REQUEST;
+    scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
+    scsiDev.phase = STATUS;
+#endif
+}
+
 static void doPauseResumeAudio(bool resume)
 {
 #ifdef ENABLE_AUDIO_OUTPUT
@@ -2212,6 +2261,17 @@ extern "C" int scsiCDRomCommand()
         uint32_t length = end - lba;
         doPlayAudio(lba, length);
     }
+    else if (command == 0x48)
+    {
+        // PLAY AUDIO (Track/Index)
+        uint8_t start_track = scsiDev.cdb[4];
+        uint8_t start_index = scsiDev.cdb[5];
+        uint8_t end_track   = scsiDev.cdb[7];
+        uint8_t end_index   = scsiDev.cdb[8];
+
+        doPlayAudioTrackIndex(start_track, start_index, end_track, end_index);
+
+    }
     else if (command == 0x4B)
     {
         // PAUSE/RESUME AUDIO

+ 1 - 1
src/ZuluSCSI_log_trace.cpp

@@ -89,7 +89,7 @@ static const char *getCommandName(uint8_t cmd)
         case 0x45: return "CDROM PlayAudio10";
         case 0xA5: return "CDROM PlayAudio12";
         case 0x47: return "CDROM PlayAudioMSF";
-        case 0x48: return "CDROM PauseResume";
+        case 0x48: return "CDROM PlayAudioTrackIndex";
         case 0x52: return "CDROM ReadTrackInformation";
         case 0xBB: return "CDROM SetCDSpeed";
         case 0xBD: return "CDROM MechanismStatus";