Browse Source

Add volume scalar to audio sample processing.

saybur 2 năm trước cách đây
mục cha
commit
0105bbbe5b
2 tập tin đã thay đổi với 59 bổ sung16 xóa
  1. 33 16
      lib/BlueSCSI_platform_RP2040/audio.cpp
  2. 26 0
      src/BlueSCSI_audio.h

+ 33 - 16
lib/BlueSCSI_platform_RP2040/audio.cpp

@@ -140,6 +140,12 @@ static uint32_t fleft;
 // historical playback status information
 static audio_status_code audio_last_status[8] = {ASC_NO_STATUS};
 
+// volume information for targets
+static volatile uint8_t volumes[8] = {
+    DEFAULT_VOLUME_LEVEL, DEFAULT_VOLUME_LEVEL, DEFAULT_VOLUME_LEVEL, DEFAULT_VOLUME_LEVEL,
+    DEFAULT_VOLUME_LEVEL, DEFAULT_VOLUME_LEVEL, DEFAULT_VOLUME_LEVEL, DEFAULT_VOLUME_LEVEL
+};
+
 // mechanism for cleanly stopping DMA units
 static volatile bool audio_stopping = false;
 
@@ -158,31 +164,34 @@ static uint8_t invert = 0; // biphase encode help: set if last wire bit was '1'
  * output.
  */
 static void snd_encode(uint8_t* samples, uint16_t* wire_patterns, uint16_t len, uint8_t swap) {
+    uint8_t vol = volumes[audio_owner & 7];
+    // limit maximum volume; with my DACs I've had persistent issues
+    // with signal clipping when sending data in the highest bit position
+    vol = vol >> 2;
+
     uint16_t widx = 0;
     for (uint16_t i = 0; i < len; i += 2) {
         uint32_t sample = 0;
         uint8_t parity = 0;
         if (samples != NULL) {
+            int32_t rsamp;
             if (swap) {
-                sample = samples[i + 1] + (samples[i] << 8);
+                rsamp = (int16_t)(samples[i + 1] + (samples[i] << 8));
             } else {
-                sample = samples[i] + (samples[i + 1] << 8);
+                rsamp = (int16_t)(samples[i] + (samples[i + 1] << 8));
             }
-            // determine parity, simplified to one lookup via an XOR
-            parity = (sample >> 8) ^ sample;
+            // linear scale to requested audio value
+            rsamp *= vol;
+            // use 20 bits of value only, which allows ignoring the lowest 8
+            // bits during biphase conversion (after including sample shift)
+            sample = ((uint32_t)rsamp) & 0xFFFFF0;
+
+            // determine parity, simplified to one lookup via XOR
+            parity = ((sample >> 16) ^ (sample >> 8)) ^ sample;
             parity = snd_parity[parity];
 
-            /*
-             * Shift sample into the correct bit positions of the sub-frame. This
-             * would normally be << 12, but with my DACs I've had persistent issues
-             * with signal clipping when sending data in the highest bit position.
-             */
-            sample = sample << 11;
-            if (sample & 0x04000000) {
-                // handle two's complement
-                sample |= 0x08000000;
-                parity++;
-            }
+            // shift sample into the correct bit positions of the sub-frame.
+            sample = sample << 4;
         }
 
         // if needed, establish even parity with P bit
@@ -202,7 +211,7 @@ static void snd_encode(uint8_t* samples, uint16_t* wire_patterns, uint16_t len,
         if (invert) wp = ~wp;
         invert = wp & 1;
         wire_patterns[widx++] = wp;
-        // next 8 bits (only high 4 have data)
+        // next 8 bits
         wp = biphase[(uint8_t) (sample >> 8)];
         if (invert) wp = ~wp;
         invert = wp & 1;
@@ -544,4 +553,12 @@ audio_status_code audio_get_status_code(uint8_t id) {
     return tmp;
 }
 
+uint8_t audio_get_volume(uint8_t id) {
+    return volumes[id & 7];
+}
+
+void audio_set_volume(uint8_t id, uint8_t vol) {
+    volumes[id & 7] = vol;
+}
+
 #endif // ENABLE_AUDIO_OUTPUT

+ 26 - 0
src/BlueSCSI_audio.h

@@ -24,6 +24,14 @@
 #include <stdint.h>
 #include "ImageBackingStore.h"
 
+/*
+ * Starting volume level for audio output, with 0 being muted and 255 being
+ * max volume. SCSI-2 says this should be 25% of maximum by default, MMC-1
+ * says 100%. Testing shows this tends to be obnoxious at high volumes, so
+ * go with SCSI-2.
+ */
+#define DEFAULT_VOLUME_LEVEL 63
+
 /*
  * Status codes for audio playback, matching the SCSI 'audio status codes'.
  *
@@ -86,3 +94,21 @@ void audio_stop(uint8_t id);
  * \return      The matching audio status code.
  */
 audio_status_code audio_get_status_code(uint8_t id);
+
+/**
+ * Gets the current volume level for a target. This is a range from 0-255,
+ * with 0 being muted and 255 being max volume. See 0x0E mode page for more.
+ *
+ * \param id    SCSI ID to provide volume for.
+ * \return      The matching volume level.
+ */
+uint8_t audio_get_volume(uint8_t id);
+
+/**
+ * Sets the volume level for a target. This is a range from 0-255, with 0
+ * being muted and 255 being max volume. See 0x0E mode page for more.
+ *
+ * \param id    SCSI ID to set volume for.
+ * \param vol   The new volume level.
+ */
+void audio_set_volume(uint8_t id, uint8_t vol);