Open perlun opened 4 years ago
Hmm... I played around with this, but whenever I try to use the 0xB6
command, I can get no sound - the audio never starts playing and I probably don't get any interrupts (or perhaps only one).
With the 0xC6
code, for playing 8-bit audio, things are working nicely, which is rather annoying. :slightly_frowning_face: I looked at the VirtualBox SB16 emulation code and it should work with 16-bit autoinitialized transfers as well. For reference: https://www.virtualbox.org/browser/vbox/trunk/src/VBox/Devices/Audio/DevSB16.cpp
One notable difference I can tell is that I need to read from base_port + 0x0F
instead of base_port + 0x0E
in the IRQ handler to acknowledge the interrupt to the card. But, even after changing this, it still doesn't work.
My next strategy: change our existing 8-bit playing code to use 0xC6
at least, i.e. use those parts of this PR. That way, we are closer to 16-bit audio but not quite there yet. (but we can probably fix 8-bit stereo output very easily then, which is always nice, still a step in the right direction... i.e. 16-bit stereo in the end.)
For reference, here is my diff so far:
diff --git a/servers/sound/soundblaster/soundblaster.c b/servers/sound/soundblaster/soundblaster.c
index bf18d82..56fea1c 100644
--- a/servers/sound/soundblaster/soundblaster.c
+++ b/servers/sound/soundblaster/soundblaster.c
@@ -54,14 +54,14 @@ static tag_type empty_tag =
static void dsp_write(uint8_t data)
{
- while ((system_port_in_uint8_t (DSP_DATA_WRITE) & 0x80) != 0);
- system_port_out_uint8_t (DSP_DATA_WRITE, (data));
+ while ((system_port_in_uint8_t(DSP_DATA_WRITE) & 0x80) != 0);
+ system_port_out_uint8_t(DSP_DATA_WRITE, (data));
}
static uint8_t dsp_read(void)
{
- while ((system_port_in_uint8_t (DSP_DATA_AVAILABLE) & 0x80) == 0);
- return system_port_in_uint8_t (DSP_DATA_READ);
+ while ((system_port_in_uint8_t(DSP_DATA_AVAILABLE_8BIT) & 0x80) == 0);
+ return system_port_in_uint8_t(DSP_DATA_READ);
}
static void dsp_mixer_write(uint8_t which_register, uint8_t data)
@@ -77,15 +77,15 @@ static bool detect_sb(void)
system_call_port_range_register(base_port, 16, "Sound Blaster");
// Reset the DSP.
- system_port_out_uint8_t (DSP_RESET, 0x01);
+ system_port_out_uint8_t(DSP_RESET, 0x01);
system_sleep(4);
- system_port_out_uint8_t (DSP_RESET, 0x00);
+ system_port_out_uint8_t(DSP_RESET, 0x00);
// FIXME: Should only wait for a maximum of 100 us.
- while ((system_port_in_uint8_t (DSP_DATA_AVAILABLE) & (1 << 7)) == 0);
+ while ((system_port_in_uint8_t(DSP_DATA_AVAILABLE_8BIT) & (1 << 7)) == 0);
// Check if the DSP was reset successfully.
- if (system_port_in_uint8_t (DSP_DATA_READ) == 0xAA)
+ if (system_port_in_uint8_t(DSP_DATA_READ) == 0xAA)
{
// Let's check which kind of SB this is.
dsp_write(DSP_VERSION);
@@ -177,17 +177,16 @@ int main(void)
}
}
-
- // Because we only support soundblaster 2.0-functionality, treat every card as a sb2.0 whatever
- // card is installed
+ // TODO: Consider supporting other cards than SB16, or at least log
+ // an error when they are being used.
soundblaster_device.irq = irq;
soundblaster_device.base_port = base_port;
soundblaster_device.dma_channel = dma_channel;
- soundblaster_device.max_frequency_output = 22050;
+ soundblaster_device.max_frequency_output = 44100;
soundblaster_device.supports_8bit_output = TRUE;
- soundblaster_device.supports_16bit_output = FALSE;
+ soundblaster_device.supports_16bit_output = TRUE;
soundblaster_device.supports_autoinit_dma = TRUE;
- soundblaster_device.device_name = "Sound Blaster 2.0";
+ soundblaster_device.device_name = "Sound Blaster 16";
// Register the DMA channel.
if (system_call_dma_register(soundblaster_device.dma_channel,
@@ -254,7 +253,7 @@ void irq_handler(irq_handler_data_type *irq_handler_data)
log_print(&log_structure, LOG_URGENCY_DEBUG, "Received hardware interrupt");
// Acknowledge the SB interrupt.
- system_port_in_uint8_t(DSP_DATA_AVAILABLE);
+ system_port_in_uint8_t(DSP_DATA_AVAILABLE_16BIT);
// Send an acknowledgement message to the client program.
message_parameter.protocol = IPC_PROTOCOL_NONE;
@@ -375,7 +374,7 @@ void handle_connection(mailbox_id_type reply_mailbox_id)
// transferred)
length = sound_message->length-1;
- dsp_write(DSP_MODE_DMA_8BIT_DAC);
+ dsp_write(DSP_MODE_DMA_16BIT_DAC); // TODO: fix
dsp_write((uint8_t) length);
dsp_write((uint8_t)(length >> 8));
@@ -441,13 +440,13 @@ void handle_connection(mailbox_id_type reply_mailbox_id)
// Program Sound Blaster buffer length (triggers an interrupt after 'length'
// bytes transferred).
length = sound_message->length - 1;
- dsp_write(DSP_SET_DMA_BLOCK_SIZE);
- dsp_write((uint8_t) length);
- dsp_write((uint8_t)(length >> 8));
// Enable 8-bit auto-initializing DMA-based playing. See sblaster.doc for
- // more details (the 01Ch command)
- dsp_write(DSP_MODE_DMA_8BIT_AUTOINIT_DAC);
+ // more details (0Bxh/0Cxh Generic DAC/ADC DMA)
+ dsp_write(DSP_MODE_DMA_16BIT_AUTOINIT_DAC);
+ dsp_write(0); // Bit 5 = stereo, bit 4 = signed. 0 means "mono, unsigned"
+ dsp_write((uint8_t) length);
+ dsp_write((uint8_t)(length >> 8));
// Now the sample is hopefully being played, so set some variables.
soundblaster_event.is_playing = TRUE;
diff --git a/servers/sound/soundblaster/soundblaster.h b/servers/sound/soundblaster/soundblaster.h
index 0ffa067..e5169be 100644
--- a/servers/sound/soundblaster/soundblaster.h
+++ b/servers/sound/soundblaster/soundblaster.h
@@ -15,7 +15,8 @@
#define DSP_RESET (base_port + 0x06)
#define DSP_DATA_READ (base_port + 0x0A)
#define DSP_DATA_WRITE (base_port + 0x0C)
-#define DSP_DATA_AVAILABLE (base_port + 0x0E)
+#define DSP_DATA_AVAILABLE_8BIT (base_port + 0x0E)
+#define DSP_DATA_AVAILABLE_16BIT (base_port + 0x0F)
// Commands (sent to DSP_DATA_WRITE).
#define DSP_VERSION (0xE1)
@@ -29,6 +30,9 @@
#define DSP_SET_TIME_CONSTANT (0x40)
#define DSP_SET_DMA_BLOCK_SIZE (0x48)
+#define DSP_MODE_DMA_16BIT_DAC (0xB0)
+#define DSP_MODE_DMA_16BIT_AUTOINIT_DAC (0xB6) // FIXME: should be 0xB6
+
typedef struct
{
unsigned int irq;
The SB16 code we have currently only supports 8-bit monaural playback, up to 44 kHz. This is quite inferior to 16-bit stereo playback. Even though the
.mod
files don't always have 16-bit samples, it would still make sense to try and get 16-bit stereo playback working for some potential improvements in the audio quality. Should't be more than just a matter of sending the right commands to the card, I think - the VirtualBox emulates a SB16 card anyway.