24 Bit Playback Using DirectSound - Please Help Me (Nearly Begging)
Hi, I have been relentlessly searching the web for information on how to specify to a 24 bit capable soundcard that I wish to playback audio in 24 bit mode. I have written a great number of audio apps and experimental programs over the years mostly using the old waveOut* functions with Visual C++ and also some using DirectSound with Visual C++.
The thing I do not understand is where you tell a 24 bit capable audio output device to play audio in 24 bit. For example, if I'm using the waveOut* functions all I can do is setup the WAVEFORMATEX structure as follows:
WAVEFORMATEX waveFormat;
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
waveFormat.nChannels = 2;
waveFormat.nSamplesPerSec = 44100;
waveFormat.wBitsPerSample = 16;
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels;
waveFormat.nBlockAlign = waveFormat.nChannels * (waveFormat.wBitsPerSample / 8);
waveFormat.cbSize = 0;
...now, if I understand correctly, all this is doing is telling this audio API system what format the audio data will be coming in as. So, I just read my 16 bit PCM audio data into a buffer, prepare it and send it to waveOutWrite() and that's all I can do. But what actually determines what bit resolution quality the audio will be played back as by the soundcard. Is this determined by the Windows kernal mixer?
Same with using DirectSound to playback audio. With DirectSound8 I can even specify that I am going to be giving it 32 bit floating point audio data by setting up the waveFormatIEEEFloatEx as follows:
waveFormatIEEEFloatEx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
waveFormatIEEEFloatEx.Format.nChannels = 2;
waveFormatIEEEFloatEx.Format.nSamplesPerSec = 44100L;
waveFormatIEEEFloatEx.Format.wBitsPerSample = 32;
waveFormatIEEEFloatEx.Format.cbSize = 22;
waveFormatIEEEFloatEx.Format.nBlockAlign = (waveFormatIEEEFloatEx.Format.nChannels * waveFormatIEEEFloatEx.Format.wBitsPerSample) / 8;
waveFormatIEEEFloatEx.Format.nAvgBytesPerSec = waveFormatIEEEFloatEx.Format.nBlockAlign * waveFormatIEEEFloatEx.Format.nSamplesPerSec;
waveFormatIEEEFloatEx.Samples.wValidBitsPerSample = 32;
waveFormatIEEEFloatEx.dwChannelMask = 0;
waveFormatIEEEFloatEx.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;...but isn't it the same case as using waveOut? All I am doing here is specifying the format of the data I will be sending to the audio API (DirectSound in this case). I am not saying anything about what quality (bit resolution) the soundcard will finally playback the audio at. So, same question here: What actually determines what bit resolution quality the audio will be played back as by the soundcard. Is this determined by the Windows kernal mixer?
The thing that completely puzzles me about this is how do higher end audio recording programs (those used mainly by professionals) allow you to specify whether you want to record and playback in either 24 bit or 16 bit. They do allow this option and if they allow this option it has to be controlled from the audio I/O API right?
I just want to write a little audio app that I know for certain is playing back audio in 24 bit out of my SB Audigy 2 and/or A-Audio Delta 44. If anyone can shed some light on this for me I would be greatly appreciative. Thank you.
Terry
[4533 byte] By [
TREMS] at [2007-12-25]
Hi Terry. Yes, the format you specify to the sound APIs tells them which format the incoming data will be in. The system mixer (kmixer.sys) will convert this to the device's final output format. Controlling this format is a little tricky. Here are four suggestions that apply to XP (on Vista it's a different story):
1. If your cards support hardware dsound acceleration (unlikely if it's a pro audio card), you can circumvent kmixer by creating your buffer with the DSBCAPS_LOCHARDWARE flag. Then the card should play it in the exact format you specify.
2. There may be some shovelware included with the card (e.g. a custom configuration panel) that lets you specify its output format.
3. kmixer only connects to the soundcard when some app is using kmixer. So if you create a 24-bit buffer when no other audio apps are running, it may connect at 24-bit (I've never tested this myself, since 24-bit cards are hard to come by.)
4. Finally, you can try creating a DSBCAPS_PRIMARYBUFFER buffer (after setting the cooperative level to DSSCL_PRIORITY) and calling SetFormat on it. This is supposed to set the global device format. Again, I haven't tested this, and it may only work if no other apps are playing at the time, since I believe kmixer cannot change its output bit-depth on the fly. Note that you have to specify high-bit-depth formats (>16 bits) using a WAVEFORMATEXTENSIBLE; WAVEFORMATEX will be rejected because it can be ambiguous for high-bit-depth audio.
Let me know if that helps...
Dugan Porter - Game Audio Team - Microsoft
This posting is provided "as is" with no warranties, and confers no rights
Dugan,
Hi, thanks for the reply - yes, your information helps a lot. I forgot to even consider KMixer. It's my understanding the any audio card that uses the standard Windows Volume Control is using the KMixer system driver. When I refer to the "Windows Volume Control" I mean the dialog box controls accessable by double clicking on the small speaker icon located in the lower right hand corner of the screen - just to the left of the clock.
Based on what I know about KMixer there are many different ways it can change the audio data around as far as sample rates (and possibly bit resolution?) and mixing multiple streams - I really don't feel it's saf eto assume that it would always be outputting audio at 24 bit when using a soundcard capable of 24 bit.
I have two cards in my primary development machine: an SB Audigy 2 and an M-Audio Delta 44. I consider the SoundBlaster to not be a pro level audio card and it uses the Windows Volume Control so I am assuming it uses KMixer. The Aduigy is supposedbly capable of 24 bit playback of audio but since it's going through KMixer I don't think I'll ever know for sure if it's really playing back the audio at 24 bit.
The M-Audio Delta 44 audio I/O device is something I consider to be more in the realm of a pro audio device. It does not use the Windows Volume Control and has it's own Control Panel so I am assuming that it does not use KMixer and has it's own system driver to handle the same things KMixer would do in the area between the application I've written and the actual audio hardware.
I suppose to be sure playback is in 24 bit I need to A) use a pro level audio card that does not use KMixer and B) probably start looking into lower level access to the audio I/O device - possibly WDM, kernal streaming or the ASIO SDK - all of which I do not know much about.
Do you have any advice as far as going in that direction with WDM, kernal streaming and the ASIO SDK? Or any other info you think might be helpful, I appreciate your feedback.
Terry
Actually, it's not the case that only unaccelerated devices use the Windows Volume Control (SndVol32.exe) . SndVol32 should control the output volume of any standard device. Are you sure it doesn't work for your M-Audio? Have you tried running SndVol32 directly from the command line?
Here's how acceleration works. A driver without H/W acceleration provides a single "pin" (output stream). Only KMixer gets to connect to this pin. The sound coming from all applications is mixed down to a single stream by KMixer and send to the pin. A driver with H/W acceleration provides multiple pins, e.g. 64. KMixer always grabs one of them, but the other 63 are available to dsound apps (they're what you get when you ask for DSBCAPS_LOCHARDWARE buffer). Software buffers are mixed by kmixer, and hardware ones are delivered directly to the driver/device.
You are correct that KMixer can mess with audio in many ways - sample rate conversion, bit-depth changes, stereo <-> 5.1 mapping etc. Hence, if your M-Audio card support hardware buffers, I would use them for 24-bit audio. It's very likely to work.
Failing that, going straight to the WDM/KS level is an option, but I think using ASIO would be better and easier.
I'd also suggest contacting M-Audio for advice on all this. I'm sure they understand all these issues better than I do.
Dugan Porter - Game Audio Team - Microsoft
This posting is provided "as is" with no warranties, and confers no rights Dugan, you're right. If I set the M-Audio device as the default playback device and then run sndvol32.exe it the volume control gives me control over Wave/MP3, SW Synth and CD Player. For general playback of digital audio the Wave/MP3 control works in controlling the output.
This surprised me because upon installing the M-Audio device the small speaker icon located in the tray disappeared and a new M-Audio icon displayed which activates the M-Audio Control Panel when double clicking on it. So, based on other vague misc things I knew about sndvol32.exe and KMixer I assumed the two were tied together somehow and a pro audio card would want to bypass KMixer and that's why sndvol32.exe was not of use and therefore the M-Audio installation would remove the icon to allow access to it.
So, based on what you say it sounds like all audio apps that use the MM WaveOut* API or DirectSound (except when using hardware buffers) are going to send the audio data through KMixer. And it sounds like KMixer is something I want to avoid because who knows what exactly it will do with the audio data. Also, I want to make some apps that will work with general pro quality audio cards in 24 bit so it sounds like ASIO might be the way to go. But before doing that I should probably spend some time with DirectSound's DSBCAPS_LOCALHARDWARE setting because that might work for what I want to do.
Thanks again for the feedback. You're explanation on KMixer interacts with the actual audio I/O device is very helpful.
Terry