Discussion:
Playing float samples with DirectSound
(too old to reply)
nicolasr
2006-02-03 01:49:12 UTC
Permalink
Hi,

I'm currently working at an audio program that
works with integer PCM data and outputs the
samples via DirectSound as integer PCM data.

After trying to implement several sound processing
algorithms I found it much easier to work with
float data. I have now written a converter to get float data
from .wav files and work with float samples internally.

My question is:

can I use the WAVEFORMATIEEEFLOATEX structure
to tell DirectSound to play float samples?

What are the requirements to play float samples via
DirectSound?
Does it depend on the operating system, the sound
card or the DirectX version?

Should I, for compatibility reasons, always convert the data to
a standard format myself before playing it with DirectSound?

(my minimum OS requirement is Win2K)

thanks for sharing your experience.
Nick
Chris P. [MVP]
2006-02-03 14:20:11 UTC
Permalink
Post by nicolasr
can I use the WAVEFORMATIEEEFLOATEX structure
to tell DirectSound to play float samples?
Yes. Although WAVEFORMATIEEEFLOATEX is just a typedef for
WAVEFORMATEXTENSIBLE.
Post by nicolasr
What are the requirements to play float samples via
DirectSound?
Does it depend on the operating system, the sound
card or the DirectX version?
It works on all WDM systems. If the sound card driver reports to the
kernel mixer that it supports IEEE-FLOAT then data can pass directly
through.
Post by nicolasr
Should I, for compatibility reasons, always convert the data to
a standard format myself before playing it with DirectSound?
(my minimum OS requirement is Win2K)
The kernel mixer will do the conversion for you if the sound card doesn't
support it. The only issue I've had is with the RealTek on-board audio
chip as used on several motherboards. The driver reports that it supports
IEEE float but does not correctly handle the data stream. It does
correctly handle 32-bit integer PCM however.
nicolasr
2006-02-03 15:55:05 UTC
Permalink
thanks for the reply. I tried to set up a test project
that plays back float samples but the program fails.
Here is a reduced code snippet (actually it's code
for Borland C++ Builder but I tried to avoid any dependencies
as much as possible)

#include <sstream>
void DSCheck(HRESULT hr)
{
if(!SUCCEEDED(hr))
{
std::stringstream s;
s << hr;
throw std::runtime_error(s.str());
}
}

void TForm1::Test()
{
GUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
DSCheck(CLSIDFromString(L"{00000003-0000-0010-8000-00aa00389b71}",
&KSDATAFORMAT_SUBTYPE_IEEE_FLOAT));


IDirectSound8* directSound = NULL;
IDirectSoundBuffer* primaryBuffer = NULL;
IDirectSoundBuffer* secondaryBuffer = NULL;

try
{
DSCheck(DirectSoundCreate8(NULL, &directSound, NULL));

DSCheck(directSound->SetCooperativeLevel(Handle, DSSCL_PRIORITY));

//create primary buffer

DSBUFFERDESC pbd = {0};
pbd.dwSize = sizeof(pbd);
pbd.dwFlags = DSBCAPS_PRIMARYBUFFER;

DSCheck(directSound->CreateSoundBuffer(&pbd, &primaryBuffer, NULL));

//wave format used for both primary and secondary buffer
WAVEFORMATIEEEFLOATEX wf = {0};
wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wf.Format.nChannels = 1;
wf.Format.nSamplesPerSec = 44100;
wf.Format.wBitsPerSample = 32;
wf.Format.cbSize = 22;
wf.Format.nBlockAlign = (wf.Format.nChannels *
wf.Format.wBitsPerSample) / 8;
wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign *
wf.Format.nSamplesPerSec;
wf.Samples.wValidBitsPerSample = 32;
wf.dwChannelMask = 0;
wf.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;

DSCheck(primaryBuffer->SetFormat((WAVEFORMATEX*)&wf));


//create a secondary buffer

DSBUFFERDESC sbd = {0};
sbd.dwSize = sizeof(sbd);
sbd.dwFlags = DSBCAPS_LOCSOFTWARE ;
sbd.lpwfxFormat = (WAVEFORMATEX*)&wf;
sbd.dwBufferBytes = 2*wf.Format.nAvgBytesPerSec;

DSCheck(directSound->CreateSoundBuffer(&sbd, &secondaryBuffer, NULL));
//**********

}
__finally
{
if(secondaryBuffer)
secondaryBuffer->Release();
if(primaryBuffer)
primaryBuffer->Release();
if(directSound)
directSound->Release();
}
}

the line marked with ********* fails with error -2147467263 (0x80004001)
= E_NOTIMPL with Description= "The function called is not supported at this
time"

I must be doing something wrong??

thanks
Nick
Chris P. [MVP]
2006-02-03 16:02:13 UTC
Permalink
Post by nicolasr
thanks for the reply. I tried to set up a test project
that plays back float samples but the program fails.
Here is a reduced code snippet (actually it's code
for Borland C++ Builder but I tried to avoid any dependencies
as much as possible)
...
Post by nicolasr
the line marked with ********* fails with error -2147467263 (0x80004001)
= E_NOTIMPL with Description= "The function called is not supported at this
time"
I must be doing something wrong??
Yes. Set the format on the secondary buffer only. Setting the format of
the primary buffer is a legacy operation for pre DX8.
nicolasr
2006-02-03 17:20:23 UTC
Permalink
Post by Chris P. [MVP]
Yes. Set the format on the secondary buffer only. Setting the format of
the primary buffer is a legacy operation for pre DX8.
Ok, thanks for that. I removed the line that set the format on the primary
buffer. Unfortunately the error remains.
Any other ideas?
(I have installed DirectX 9 SDK on WinXP SP2)

Nick
Chris P. [MVP]
2006-02-03 19:04:21 UTC
Permalink
Post by nicolasr
Post by Chris P. [MVP]
Yes. Set the format on the secondary buffer only. Setting the format of
the primary buffer is a legacy operation for pre DX8.
Ok, thanks for that. I removed the line that set the format on the primary
buffer. Unfortunately the error remains.
Any other ideas?
(I have installed DirectX 9 SDK on WinXP SP2)
Hmm should be working. What happens if you use KSDATAFORMAT_SUBTYPE_PCM
with 32-bit?
nicolasr
2006-02-04 02:08:15 UTC
Permalink
Ok, I found the problem.

The wFormatTag must be set to WAVE_FORMAT_IEEE_FLOAT.

The documentation of WAVEFORMATIEEEFLOATEX directs me
directly to the documentation of WAVEFORMATEXTENSIBLE
which states that the wFormatTag must be WAVE_FORMAT_EXTENSIBLE,
quite misleading...

Further down in the docs I found a list with the correct
format/subformat pairs.

thanks,
Nick
Post by Chris P. [MVP]
Hmm should be working. What happens if you use KSDATAFORMAT_SUBTYPE_PCM
with 32-bit?
Chris P. [MVP]
2006-02-06 13:34:29 UTC
Permalink
Post by nicolasr
Ok, I found the problem.
The wFormatTag must be set to WAVE_FORMAT_IEEE_FLOAT.
The documentation of WAVEFORMATIEEEFLOATEX directs me
directly to the documentation of WAVEFORMATEXTENSIBLE
which states that the wFormatTag must be WAVE_FORMAT_EXTENSIBLE,
quite misleading...
Hmm, that doesn't make sense to me. I'm fairly certain I've used it that
way.
Post by nicolasr
Further down in the docs I found a list with the correct
format/subformat pairs.
The table shown at the bottom of that page are not the values that you are
supposed to use, it is a translation from old to new format.

By using a tag of WAVE_FORMAT_IEEE_FLOAT you are not using
WAVEFORMATEXTENSIBLE. To me it sounds like a driver bug, or just a grossly
out-of-date driver that hasn't been updated for WAVEFORMATEXTENSIBLE
support.
nicolasr
2006-02-06 14:49:20 UTC
Permalink
Post by Chris P. [MVP]
By using a tag of WAVE_FORMAT_IEEE_FLOAT you are not using
WAVEFORMATEXTENSIBLE. To me it sounds like a driver bug, or just a grossly
out-of-date driver that hasn't been updated for WAVEFORMATEXTENSIBLE
support.
I will check the code on different systems and see what happens there.

thanks for your time,
Nick

nicolasr
2006-02-04 02:18:46 UTC
Permalink
One last question.
I was just wondering because Windows documentation
always calls the format IEEE Float. Concerning implementation
in C++ is there any difference between IEEE Float and 'float'.
What about 'double' and IEEE Float with 64 bit?

thanks again,
Nick
Chris P. [MVP]
2006-02-06 13:28:08 UTC
Permalink
Post by nicolasr
One last question.
I was just wondering because Windows documentation
always calls the format IEEE Float. Concerning implementation
in C++ is there any difference between IEEE Float and 'float'.
What about 'double' and IEEE Float with 64 bit?
Correct. 32-bit IEEE Float is synonymous with the C type 'float', 64-bit
IEEE Float is synonymous with the C type 'double'.
Loading...