ソースを参照

Split common audio components out of platform-specific header.

saybur 2 年 前
コミット
317a22971e

+ 9 - 20
lib/BlueSCSI_platform_RP2040/audio.cpp

@@ -24,14 +24,11 @@
 #include <hardware/spi.h>
 #include <pico/multicore.h>
 #include "audio.h"
+#include "BlueSCSI_audio.h"
 #include "BlueSCSI_config.h"
 #include "BlueSCSI_log.h"
 #include "BlueSCSI_platform.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 extern SdFs SD;
 
 // Table with the number of '1' bits for each index.
@@ -328,12 +325,8 @@ bool audio_is_active() {
     return audio_owner != 0xFF;
 }
 
-bool audio_is_paused() {
-    return audio_paused;
-}
-
-uint8_t audio_get_owner() {
-    return audio_owner;
+bool audio_is_playing(uint8_t id) {
+    return audio_owner == (id & 7);
 }
 
 void audio_setup() {
@@ -357,7 +350,7 @@ void audio_poll() {
     if (audio_paused) return;
     if (fleft == 0 && sbufst_a == STALE && sbufst_b == STALE) {
         // out of data and ready to stop
-        audio_stop();
+        audio_stop(audio_owner);
         return;
     } else if (fleft == 0) {
         // out of data to read but still working on remainder
@@ -395,7 +388,7 @@ void audio_poll() {
 
 bool audio_play(uint8_t owner, const char* file, uint64_t start, uint64_t end, bool swap) {
     // stop any existing playback first
-    if (audio_is_active()) audio_stop();
+    if (audio_is_active()) audio_stop(audio_owner);
 
     // debuglog("Request to play ('", file, "':", start, ":", end, ")");
 
@@ -498,8 +491,8 @@ bool audio_play(uint8_t owner, const char* file, uint64_t start, uint64_t end, b
     return true;
 }
 
-bool audio_set_paused(bool paused) {
-    if (!audio_is_active()) return false;
+bool audio_set_paused(uint8_t id, bool paused) {
+    if (audio_owner != (id & 7)) return false;
     else if (audio_paused && paused) return false;
     else if (!audio_paused && !paused) return false;
 
@@ -512,8 +505,8 @@ bool audio_set_paused(bool paused) {
     return true;
 }
 
-void audio_stop() {
-    if (!audio_is_active()) return;
+void audio_stop(uint8_t id) {
+    if (audio_owner != (id & 7)) return;
 
     // to help mute external hardware, send a bunch of '0' samples prior to
     // halting the datastream; easiest way to do this is invalidating the
@@ -553,8 +546,4 @@ void audio_clear_bytes_read(uint8_t id) {
     audio_bytes_read[id & 7] = 0;
 }
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif // ENABLE_AUDIO_OUTPUT

+ 1 - 90
lib/BlueSCSI_platform_RP2040/audio.h

@@ -18,11 +18,7 @@
 #pragma once
 #ifdef ENABLE_AUDIO_OUTPUT
 
-#include <Arduino.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include <stdint.h>
 
 // audio subsystem DMA channels
 #define SOUND_DMA_CHA 6
@@ -32,20 +28,6 @@ extern "C" {
 // these must be divisible by 1024
 #define AUDIO_BUFFER_SIZE 8192 // ~46.44ms
 
-/*
- * Status codes for audio playback, matching the SCSI 'audio status codes'.
- *
- * The first two are for a live condition and will be returned repeatedly. The
- * following two reflect a historical condition and are only returned once.
- */
-enum audio_status_code {
-    ASC_PLAYING = 0x11,
-    ASC_PAUSED = 0x12,
-    ASC_COMPLETED = 0x13,
-    ASC_ERRORED = 0x14,
-    ASC_NO_STATUS = 0x15
-};
-
 /**
  * Handler for DMA interrupts
  *
@@ -66,16 +48,6 @@ void audio_dma_irq();
  */
 bool audio_is_active();
 
-/**
- * \return true if audio streaming is paused, false otherwise.
- */
-bool audio_is_paused();
-
-/**
- * \return the owner value passed to the _play() call, or 0xFF if no owner.
- */
-uint8_t audio_get_owner();
-
 /**
  * Initializes the audio subsystem. Should be called only once, toward the end
  * of platform_late_init().
@@ -87,65 +59,4 @@ void audio_setup();
  */
 void audio_poll();
 
-/**
- * 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 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);
-
-/**
- * Pauses audio playback. This may be delayed slightly to allow sample buffers
- * to purge.
- *
- * \param pause  If true, pause, otherwise resume.
- * \return       True if operation changed audio output, false if no change.
- */
-bool audio_set_paused(bool pause);
-
-/**
- * Stops audio playback.
- */
-void audio_stop();
-
-/**
- * Provides SCSI 'audio status code' for the given target. Depending on the
- * code this operation may produce side-effects, see the enum for details.
- *
- * \param id    The SCSI ID to provide status codes for.
- * \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 audio_play() call.
- * This can be combined with an (external) starting offset to determine
- * virtual CD positioning information. This is only an approximation since
- * this tracker is always at the end of the most recently read sample data.
- *
- * This is intentionally not cleared by audio_stop(): audio_play() events will
- * 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 is insensitive to whether
- * audio playback is occurring but is safe to call in any event.
- *
- * \param id    The SCSI ID target to return data for.
- */
-void audio_clear_bytes_read(uint8_t id);
-
-#ifdef __cplusplus
-}
-#endif
-
 #endif // ENABLE_AUDIO_OUTPUT

+ 109 - 0
src/BlueSCSI_audio.h

@@ -0,0 +1,109 @@
+/** 
+ * ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
+ * 
+ * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
+ * 
+ * https://www.gnu.org/licenses/gpl-3.0.html
+ * ----
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version. 
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details. 
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+**/
+
+#pragma once
+
+#include <stdint.h>
+
+/*
+ * Status codes for audio playback, matching the SCSI 'audio status codes'.
+ *
+ * The first two are for a live condition and will be returned repeatedly. The
+ * following two reflect a historical condition and are only returned once.
+ */
+enum audio_status_code {
+    ASC_PLAYING = 0x11,
+    ASC_PAUSED = 0x12,
+    ASC_COMPLETED = 0x13,
+    ASC_ERRORED = 0x14,
+    ASC_NO_STATUS = 0x15
+};
+
+/**
+ * Indicates whether there is an active playback event for a given target.
+ *
+ * Note: this does not consider pause/resume events: even if audio is paused
+ * this will indicate playback is in progress.
+ *
+ * \param owner  The SCSI ID to check.
+ * \return       True if playback in progress, false if playback idle.
+ */
+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 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);
+
+/**
+ * Pauses audio playback. This may be delayed slightly to allow sample buffers
+ * to purge.
+ *
+ * \param id     The SCSI ID to pause audio playback on.
+ * \param pause  If true, pause, otherwise resume.
+ * \return       True if operation changed audio output, false if no change.
+ */
+bool audio_set_paused(uint8_t id, bool pause);
+
+/**
+ * Stops audio playback.
+ *
+ * \param id     The SCSI ID to stop audio playback on.
+ */
+void audio_stop(uint8_t id);
+
+/**
+ * Provides SCSI 'audio status code' for the given target. Depending on the
+ * code this operation may produce side-effects, see the enum for details.
+ *
+ * \param id    The SCSI ID to provide status codes for.
+ * \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);

+ 9 - 19
src/BlueSCSI_cdrom.cpp

@@ -35,7 +35,7 @@
 #include <CUEParser.h>
 #include <assert.h>
 #ifdef ENABLE_AUDIO_OUTPUT
-#include "audio.h"
+#include "BlueSCSI_audio.h"
 #endif
 
 extern "C" {
@@ -702,9 +702,7 @@ void doReadHeader(bool MSF, uint32_t lba, uint16_t allocationLength)
 
 #if ENABLE_AUDIO_OUTPUT
     // terminate audio playback if active on this target (Annex C)
-    if (audio_get_owner() == (img.scsiId & 7)) {
-        audio_stop();
-    }
+    audio_stop(img.scsiId & 7);
 #endif
 
     CUEParser parser;
@@ -864,9 +862,7 @@ bool cdromSwitchNextImage(image_config_t &img)
 
 #ifdef ENABLE_AUDIO_OUTPUT
     // if in progress for this device, terminate audio playback immediately (Annex C)
-    if (audio_get_owner() == target_idx) {
-        audio_stop();
-    }
+    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);
@@ -946,7 +942,7 @@ void cdromGetAudioPlaybackStatus(uint8_t *status, uint32_t *current_lba, bool cu
 #ifdef ENABLE_AUDIO_OUTPUT
     if (status) {
         if (current_only) {
-            *status = audio_get_owner() == target ? 1 : 0;
+            *status = audio_is_playing(target) ? 1 : 0;
         } else {
             *status = (uint8_t) audio_get_status_code(target);
         }
@@ -969,9 +965,7 @@ static void doPlayAudio(uint32_t lba, uint32_t 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
-    if ((img.scsiId & 7) == audio_get_owner()) {
-        audio_stop();
-    }
+    audio_stop(img.scsiId & 7);
 
     // if transfer length is zero no audio playback happens.
     // don't treat as an error per SCSI-2; handle via short-circuit
@@ -1066,9 +1060,9 @@ static void doPauseResumeAudio(bool resume)
     image_config_t &img = *(image_config_t*)scsiDev.target->cfg;
     uint8_t target_id = img.scsiId & 7;
 
-    if (audio_get_owner() == target_id)
+    if (audio_is_playing(target_id))
     {
-        audio_set_paused(!resume);
+        audio_set_paused(target_id, !resume);
         scsiDev.status = 0;
         scsiDev.phase = STATUS;
     }
@@ -1123,9 +1117,7 @@ static void doReadCD(uint32_t lba, uint32_t length, uint8_t sector_type,
 
 #if ENABLE_AUDIO_OUTPUT
     // terminate audio playback if active on this target (Annex C)
-    if (audio_get_owner() == (img.scsiId & 7)) {
-        audio_stop();
-    }
+    audio_stop(img.scsiId & 7);
 #endif
 
     CUEParser parser;
@@ -1398,9 +1390,7 @@ extern "C" int scsiCDRomCommand()
     {
 #if ENABLE_AUDIO_OUTPUT
         // terminate audio playback if active on this target (Annex C)
-        if (audio_get_owner() == (img.scsiId & 7)) {
-            audio_stop();
-        }
+        audio_stop(img.scsiId & 7);
 #endif
         if ((scsiDev.cdb[4] & 2))
         {