Skip to content

Commit

Permalink
Use average of both output ports to determine audio level.
Browse files Browse the repository at this point in the history
This appears to match the behavior expected from old drives, even though it does not appear within the specifications.
  • Loading branch information
saybur committed May 27, 2023
1 parent c4db86d commit bc285e0
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 20 deletions.
9 changes: 5 additions & 4 deletions lib/ZuluSCSI_platform_RP2040/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ static uint32_t fleft;
static audio_status_code audio_last_status[8] = {ASC_NO_STATUS};

// volume information for targets
static volatile uint8_t volumes[8] = {
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
};
Expand All @@ -164,7 +164,8 @@ 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];
uint16_t wvol = volumes[audio_owner & 7];
uint8_t vol = ((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;
Expand Down Expand Up @@ -553,11 +554,11 @@ audio_status_code audio_get_status_code(uint8_t id) {
return tmp;
}

uint8_t audio_get_volume(uint8_t id) {
uint16_t audio_get_volume(uint8_t id) {
return volumes[id & 7];
}

void audio_set_volume(uint8_t id, uint8_t vol) {
void audio_set_volume(uint8_t id, uint16_t vol) {
volumes[id & 7] = vol;
}

Expand Down
19 changes: 12 additions & 7 deletions src/ZuluSCSI_audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@
* 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.
*
* This implementation uses the high byte for output port 1 and the low byte
* for port 0. The two values are averaged to determine final volume level.
*/
#define DEFAULT_VOLUME_LEVEL 63
#define DEFAULT_VOLUME_LEVEL 0x3F3F

/*
* Status codes for audio playback, matching the SCSI 'audio status codes'.
Expand Down Expand Up @@ -96,19 +99,21 @@ void audio_stop(uint8_t id);
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.
* Gets the current volume level for a target. This is a pair of 8-bit values
* ranging from 0-255 that are averaged together to determine the final output
* level, where 0 is muted and 255 is maximum volume. The high byte corresponds
* to 0x0E channel 1 and the low byte to 0x0E channel 0. See the spec's mode
* page documentation for more details.
*
* \param id SCSI ID to provide volume for.
* \return The matching volume level.
*/
uint8_t audio_get_volume(uint8_t id);
uint16_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.
* Sets the volume level for a target, as above. 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);
void audio_set_volume(uint8_t id, uint16_t vol);
16 changes: 7 additions & 9 deletions src/ZuluSCSI_mode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,9 @@ int modeSenseCDAudioControlPage(int pc, int idx, int pageCode, int* pageFound)
if (pc == 0x00)
{
// report current volume level
scsiDev.data[idx+9] = audio_get_volume(scsiDev.target->targetId);
scsiDev.data[idx+11] = audio_get_volume(scsiDev.target->targetId);
uint16_t vol = audio_get_volume(scsiDev.target->targetId);
scsiDev.data[idx+9] = vol & 0xFF;
scsiDev.data[idx+11] = vol >> 8;
}
else if (pc == 0x01)
{
Expand All @@ -122,8 +123,8 @@ 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+9] = DEFAULT_VOLUME_LEVEL;
scsiDev.data[idx+11] = DEFAULT_VOLUME_LEVEL;
scsiDev.data[idx+9] = DEFAULT_VOLUME_LEVEL & 0xFF;
scsiDev.data[idx+11] = DEFAULT_VOLUME_LEVEL >> 8;
}
return sizeof(CDROMAudioControlParametersPage);
}
Expand All @@ -143,11 +144,8 @@ int modeSelectCDAudioControlPage(int pageLen, int idx)
if (scsiDev.target->cfg->deviceType == S2S_CFG_OPTICAL)
{
if (pageLen != 0x0E) return 0;
uint8_t volL = scsiDev.data[idx+9];
uint8_t volR = scsiDev.data[idx+11];
// only support setting channels to same volume, just pick higher
uint8_t vol = (volL > volR) ? volL : volR;
dbgmsg("------ CD audio control page volume (", volL, ",", volR, ")");
uint16_t vol = (scsiDev.data[idx+11] << 8) + scsiDev.data[idx+9];
dbgmsg("------ CD audio control page volume (", vol, ")");
audio_set_volume(scsiDev.target->targetId, vol);
return 1;
}
Expand Down

0 comments on commit bc285e0

Please sign in to comment.