ソースを参照

Add support for enabling/disabling channels within the audio ports.

saybur 2 年 前
コミット
e795baac2b
3 ファイル変更64 行追加5 行削除
  1. 26 3
      lib/BlueSCSI_platform_RP2040/audio.cpp
  2. 27 0
      src/BlueSCSI_audio.h
  3. 11 2
      src/BlueSCSI_mode.cpp

+ 26 - 3
lib/BlueSCSI_platform_RP2040/audio.cpp

@@ -145,6 +145,10 @@ static volatile uint16_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
 };
+static volatile uint16_t channels[8] = {
+    AUDIO_CHANNEL_ENABLE_MASK, AUDIO_CHANNEL_ENABLE_MASK, AUDIO_CHANNEL_ENABLE_MASK, AUDIO_CHANNEL_ENABLE_MASK,
+    AUDIO_CHANNEL_ENABLE_MASK, AUDIO_CHANNEL_ENABLE_MASK, AUDIO_CHANNEL_ENABLE_MASK, AUDIO_CHANNEL_ENABLE_MASK
+};
 
 // mechanism for cleanly stopping DMA units
 static volatile bool audio_stopping = false;
@@ -165,10 +169,17 @@ static uint8_t invert = 0; // biphase encode help: set if last wire bit was '1'
  */
 static void snd_encode(uint8_t* samples, uint16_t* wire_patterns, uint16_t len, uint8_t swap) {
     uint16_t wvol = volumes[audio_owner & 7];
-    uint8_t vol = ((wvol >> 8) + (wvol & 0xFF)) >> 1; // average of both values
+    uint8_t lvol = ((wvol >> 8) + (wvol & 0xFF)) >> 1; // average of both values
     // 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;
+    lvol = lvol >> 2;
+    uint8_t rvol = lvol;
+    // enable or disable based on the channel information for both output
+    // ports, where the high byte and mask control the right channel, and
+    // the low control the left channel
+    uint16_t chn = channels[audio_owner & 7] & AUDIO_CHANNEL_ENABLE_MASK;
+    if (!(chn >> 8)) rvol = 0;
+    if (!(chn & 0xFF)) lvol = 0;
 
     uint16_t widx = 0;
     for (uint16_t i = 0; i < len; i += 2) {
@@ -182,7 +193,11 @@ static void snd_encode(uint8_t* samples, uint16_t* wire_patterns, uint16_t len,
                 rsamp = (int16_t)(samples[i] + (samples[i + 1] << 8));
             }
             // linear scale to requested audio value
-            rsamp *= vol;
+            if (i & 2) {
+                rsamp *= rvol;
+            } else {
+                rsamp *= lvol;
+            }
             // 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;
@@ -562,4 +577,12 @@ void audio_set_volume(uint8_t id, uint16_t vol) {
     volumes[id & 7] = vol;
 }
 
+uint16_t audio_get_channel(uint8_t id) {
+    return channels[id & 7];
+}
+
+void audio_set_channel(uint8_t id, uint16_t chn) {
+    channels[id & 7] = chn;
+}
+
 #endif // ENABLE_AUDIO_OUTPUT

+ 27 - 0
src/BlueSCSI_audio.h

@@ -34,6 +34,13 @@
  * for port 0. The two values are averaged to determine final volume level.
  */
 #define DEFAULT_VOLUME_LEVEL 0x3F3F
+/*
+ * Defines the 'enable' masks for the two audio output ports of each device.
+ * If this mask is matched with audio_get_channel() the relevant port will
+ * have audio output to it, otherwise it will be muted, regardless of the
+ * volume level.
+ */
+#define AUDIO_CHANNEL_ENABLE_MASK 0x0201
 
 /*
  * Status codes for audio playback, matching the SCSI 'audio status codes'.
@@ -117,3 +124,23 @@ uint16_t audio_get_volume(uint8_t id);
  * \param vol   The new volume level.
  */
 void audio_set_volume(uint8_t id, uint16_t vol);
+
+/**
+ * Gets the 0x0E channel information for both audio ports. The high byte
+ * corresponds to port 1 and the low byte to port 0. If the bits defined in
+ * AUDIO_CHANNEL_ENABLE_MASK are not set for the respective ports, that
+ * output will be muted, regardless of volume set.
+ *
+ * \param id    SCSI ID to provide channel information for.
+ * \return      The channel information.
+ */
+uint16_t audio_get_channel(uint8_t id);
+
+/**
+ * Sets the 0x0E channel information for a target, as above. See 0x0E mode
+ * page for more.
+ *
+ * \param id    SCSI ID to set channel information for.
+ * \param chn   The new channel information.
+ */
+void audio_set_channel(uint8_t id, uint16_t chn);

+ 11 - 2
src/BlueSCSI_mode.cpp

@@ -107,15 +107,20 @@ int modeSenseCDAudioControlPage(int pc, int idx, int pageCode, int* pageFound)
             sizeof(CDROMAudioControlParametersPage));
         if (pc == 0x00)
         {
-            // report current volume level
+            // report current port assignments and volume level
+            uint16_t chn = audio_get_channel(scsiDev.target->targetId);
             uint16_t vol = audio_get_volume(scsiDev.target->targetId);
+            scsiDev.data[idx+8] = chn & 0xFF;
             scsiDev.data[idx+9] = vol & 0xFF;
+            scsiDev.data[idx+10] = chn >> 8;
             scsiDev.data[idx+11] = vol >> 8;
         }
         else if (pc == 0x01)
         {
             // report bits that can be set
+            scsiDev.data[idx+8] = 0xFF;
             scsiDev.data[idx+9] = 0xFF;
+            scsiDev.data[idx+10] = 0xFF;
             scsiDev.data[idx+11] = 0xFF;
         }
         else
@@ -123,7 +128,9 @@ int modeSenseCDAudioControlPage(int pc, int idx, int pageCode, int* pageFound)
             // report defaults for 0x02
             // also report same for 0x03, though we are actually supposed
             // to terminate with CHECK CONDITION and SAVING PARAMETERS NOT SUPPORTED
+            scsiDev.data[idx+8] = AUDIO_CHANNEL_ENABLE_MASK & 0xFF;
             scsiDev.data[idx+9] = DEFAULT_VOLUME_LEVEL & 0xFF;
+            scsiDev.data[idx+10] = AUDIO_CHANNEL_ENABLE_MASK >> 8;
             scsiDev.data[idx+11] = DEFAULT_VOLUME_LEVEL >> 8;
         }
         return sizeof(CDROMAudioControlParametersPage);
@@ -144,8 +151,10 @@ int modeSelectCDAudioControlPage(int pageLen, int idx)
     if (scsiDev.target->cfg->deviceType == S2S_CFG_OPTICAL)
     {
         if (pageLen != 0x0E) return 0;
+        uint16_t chn = (scsiDev.data[idx+10] << 8) + scsiDev.data[idx+8];
         uint16_t vol = (scsiDev.data[idx+11] << 8) + scsiDev.data[idx+9];
-        debuglog("------ CD audio control page volume (", vol, ")");
+        debuglog("------ CD audio control page channels (", chn, "), volume (", vol, ")");
+        audio_set_channel(scsiDev.target->targetId, chn);
         audio_set_volume(scsiDev.target->targetId, vol);
         return 1;
     }