dsound: Resample to float, not device format.
This commit is contained in:
parent
20356f7458
commit
98c653bc8b
|
@ -125,13 +125,6 @@ static inline unsigned char f_to_8(float value)
|
|||
return lrintf((value + 1.f) * 0x80);
|
||||
}
|
||||
|
||||
static void put8(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
|
||||
{
|
||||
BYTE* buf = dsb->device->tmp_buffer;
|
||||
buf += pos + channel;
|
||||
*buf = f_to_8(value);
|
||||
}
|
||||
|
||||
static inline SHORT f_to_16(float value)
|
||||
{
|
||||
if(value <= -1.f)
|
||||
|
@ -141,13 +134,6 @@ static inline SHORT f_to_16(float value)
|
|||
return le16(lrintf(value * 0x8000));
|
||||
}
|
||||
|
||||
static void put16(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
|
||||
{
|
||||
BYTE* buf = dsb->device->tmp_buffer;
|
||||
SHORT *sbuf = (SHORT*)(buf + pos + 2 * channel);
|
||||
*sbuf = f_to_16(value);
|
||||
}
|
||||
|
||||
static LONG f_to_24(float value)
|
||||
{
|
||||
if(value <= -1.f)
|
||||
|
@ -157,17 +143,6 @@ static LONG f_to_24(float value)
|
|||
return lrintf(value * 0x80000000U);
|
||||
}
|
||||
|
||||
static void put24(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
|
||||
{
|
||||
BYTE* buf = dsb->device->tmp_buffer;
|
||||
LONG t;
|
||||
buf += pos + 3 * channel;
|
||||
t = f_to_24(value);
|
||||
buf[0] = (t >> 8) & 0xFF;
|
||||
buf[1] = (t >> 16) & 0xFF;
|
||||
buf[2] = (t >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
static inline LONG f_to_32(float value)
|
||||
{
|
||||
if(value <= -1.f)
|
||||
|
@ -177,79 +152,26 @@ static inline LONG f_to_32(float value)
|
|||
return le32(lrintf(value * 0x80000000U));
|
||||
}
|
||||
|
||||
static void put32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
|
||||
void putieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
|
||||
{
|
||||
BYTE* buf = dsb->device->tmp_buffer;
|
||||
LONG *sbuf = (LONG*)(buf + pos + 4 * channel);
|
||||
*sbuf = f_to_32(value);
|
||||
BYTE *buf = (BYTE *)dsb->device->tmp_buffer;
|
||||
float *fbuf = (float*)(buf + pos + sizeof(float) * channel);
|
||||
*fbuf = value;
|
||||
}
|
||||
|
||||
const bitsputfunc putbpp[4] = {put8, put16, put24, put32};
|
||||
|
||||
void put_mono2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
|
||||
{
|
||||
dsb->put_aux(dsb, pos, 0, value);
|
||||
dsb->put_aux(dsb, pos, 1, value);
|
||||
}
|
||||
|
||||
static void mix8(signed char *src, float *dst, unsigned len)
|
||||
void mixieee32(float *src, float *dst, unsigned samples)
|
||||
{
|
||||
TRACE("%p - %p %d\n", src, dst, len);
|
||||
while (len--)
|
||||
/* 8-bit WAV is unsigned, it's here converted to signed, normalize function will convert it back again */
|
||||
*(dst++) += ((signed char)((BYTE)*(src++) - (BYTE)0x80)) / (float)0x80;
|
||||
}
|
||||
|
||||
static void mix16(SHORT *src, float *dst, unsigned len)
|
||||
{
|
||||
TRACE("%p - %p %d\n", src, dst, len);
|
||||
len /= 2;
|
||||
while (len--)
|
||||
{
|
||||
*dst += le16(*src) / (float)0x8000U;
|
||||
++dst; ++src;
|
||||
}
|
||||
}
|
||||
|
||||
static void mix24(BYTE *src, float *dst, unsigned len)
|
||||
{
|
||||
TRACE("%p - %p %d\n", src, dst, len);
|
||||
len /= 3;
|
||||
while (len--)
|
||||
{
|
||||
DWORD field;
|
||||
field = ((DWORD)src[2] << 16) + ((DWORD)src[1] << 8) + (DWORD)src[0];
|
||||
if (src[2] & 0x80)
|
||||
field |= 0xFF000000U;
|
||||
*(dst++) += field / (float)0x800000U;
|
||||
src += 3;
|
||||
}
|
||||
}
|
||||
|
||||
static void mix32(INT *src, float *dst, unsigned len)
|
||||
{
|
||||
TRACE("%p - %p %d\n", src, dst, len);
|
||||
len /= 4;
|
||||
while (len--)
|
||||
*(dst++) += le32(*(src++)) / (float)0x80000000U;
|
||||
}
|
||||
|
||||
static void mixieee32(float *src, float *dst, unsigned len)
|
||||
{
|
||||
TRACE("%p - %p %d\n", src, dst, len);
|
||||
len /= 4;
|
||||
while (len--)
|
||||
TRACE("%p - %p %d\n", src, dst, samples);
|
||||
while (samples--)
|
||||
*(dst++) += *(src++);
|
||||
}
|
||||
|
||||
const mixfunc mixfunctions[5] = {
|
||||
(mixfunc)mix8,
|
||||
(mixfunc)mix16,
|
||||
(mixfunc)mix24,
|
||||
(mixfunc)mix32,
|
||||
(mixfunc)mixieee32
|
||||
};
|
||||
|
||||
static void norm8(float *src, unsigned char *dst, unsigned len)
|
||||
{
|
||||
TRACE("%p - %p %d\n", src, dst, len);
|
||||
|
|
|
@ -55,9 +55,8 @@ typedef struct DirectSoundCaptureDevice DirectSoundCaptureDevice;
|
|||
typedef float (*bitsgetfunc)(const IDirectSoundBufferImpl *, DWORD, DWORD);
|
||||
typedef void (*bitsputfunc)(const IDirectSoundBufferImpl *, DWORD, DWORD, float);
|
||||
extern const bitsgetfunc getbpp[5] DECLSPEC_HIDDEN;
|
||||
extern const bitsputfunc putbpp[4] DECLSPEC_HIDDEN;
|
||||
typedef void (*mixfunc)(const void *, void *, unsigned);
|
||||
extern const mixfunc mixfunctions[5] DECLSPEC_HIDDEN;
|
||||
void putieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) DECLSPEC_HIDDEN;
|
||||
void mixieee32(float *src, float *dst, unsigned samples) DECLSPEC_HIDDEN;
|
||||
typedef void (*normfunc)(const void *, void *, unsigned);
|
||||
extern const normfunc normfunctions[5] DECLSPEC_HIDDEN;
|
||||
|
||||
|
@ -94,13 +93,11 @@ struct DirectSoundDevice
|
|||
CRITICAL_SECTION mixlock;
|
||||
IDirectSoundBufferImpl *primary;
|
||||
DWORD speaker_config;
|
||||
LPBYTE tmp_buffer;
|
||||
float *mix_buffer;
|
||||
float *mix_buffer, *tmp_buffer;
|
||||
DWORD tmp_buffer_len, mix_buffer_len;
|
||||
|
||||
DSVOLUMEPAN volpan;
|
||||
|
||||
mixfunc mixfunction;
|
||||
normfunc normfunction;
|
||||
|
||||
/* DirectSound3DListener fields */
|
||||
|
|
|
@ -141,7 +141,7 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
|
|||
dsb->freqAcc = 0;
|
||||
|
||||
dsb->get_aux = ieee ? getbpp[4] : getbpp[dsb->pwfx->wBitsPerSample/8 - 1];
|
||||
dsb->put_aux = putbpp[dsb->device->pwfx->wBitsPerSample/8 - 1];
|
||||
dsb->put_aux = putieee32;
|
||||
|
||||
dsb->get = dsb->get_aux;
|
||||
dsb->put = dsb->put_aux;
|
||||
|
@ -234,10 +234,10 @@ static inline float get_current_sample(const IDirectSoundBufferImpl *dsb,
|
|||
return dsb->get(dsb, mixpos % dsb->buflen, channel);
|
||||
}
|
||||
|
||||
static UINT cp_fields_noresample(IDirectSoundBufferImpl *dsb,
|
||||
UINT ostride, UINT count)
|
||||
static UINT cp_fields_noresample(IDirectSoundBufferImpl *dsb, UINT count)
|
||||
{
|
||||
UINT istride = dsb->pwfx->nBlockAlign;
|
||||
UINT ostride = dsb->device->pwfx->nChannels * sizeof(float);
|
||||
DWORD channel, i;
|
||||
for (i = 0; i < count; i++)
|
||||
for (channel = 0; channel < dsb->mix_channels; channel++)
|
||||
|
@ -246,11 +246,11 @@ static UINT cp_fields_noresample(IDirectSoundBufferImpl *dsb,
|
|||
return count;
|
||||
}
|
||||
|
||||
static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb,
|
||||
UINT ostride, UINT count, float *freqAcc)
|
||||
static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, float *freqAcc)
|
||||
{
|
||||
UINT i, channel;
|
||||
UINT istride = dsb->pwfx->nBlockAlign;
|
||||
UINT ostride = dsb->device->pwfx->nChannels * sizeof(float);
|
||||
|
||||
float freqAdjust = dsb->freqAdjust;
|
||||
float freqAcc_start = *freqAcc;
|
||||
|
@ -314,15 +314,14 @@ static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb,
|
|||
return max_ipos;
|
||||
}
|
||||
|
||||
static void cp_fields(IDirectSoundBufferImpl *dsb,
|
||||
UINT ostride, UINT count, float *freqAcc)
|
||||
static void cp_fields(IDirectSoundBufferImpl *dsb, UINT count, float *freqAcc)
|
||||
{
|
||||
DWORD ipos, adv;
|
||||
|
||||
if (dsb->freqAdjust == 1.0)
|
||||
adv = cp_fields_noresample(dsb, ostride, count); /* *freqAcc is unmodified */
|
||||
adv = cp_fields_noresample(dsb, count); /* *freqAcc is unmodified */
|
||||
else
|
||||
adv = cp_fields_resample(dsb, ostride, count, freqAcc);
|
||||
adv = cp_fields_resample(dsb, count, freqAcc);
|
||||
|
||||
ipos = dsb->sec_mixpos + adv * dsb->pwfx->nBlockAlign;
|
||||
if (ipos >= dsb->buflen) {
|
||||
|
@ -365,89 +364,53 @@ static inline DWORD DSOUND_BufPtrDiff(DWORD buflen, DWORD ptr1, DWORD ptr2)
|
|||
*
|
||||
* NOTE: writepos + len <= buflen. When called by mixer, MixOne makes sure of this.
|
||||
*/
|
||||
static void DSOUND_MixToTemporary(IDirectSoundBufferImpl *dsb, DWORD tmp_len)
|
||||
static void DSOUND_MixToTemporary(IDirectSoundBufferImpl *dsb, DWORD frames)
|
||||
{
|
||||
INT oAdvance = dsb->device->pwfx->nBlockAlign;
|
||||
INT size = tmp_len / oAdvance;
|
||||
UINT size_bytes = frames * sizeof(float) * dsb->device->pwfx->nChannels;
|
||||
|
||||
if (dsb->device->tmp_buffer_len < tmp_len || !dsb->device->tmp_buffer)
|
||||
if (dsb->device->tmp_buffer_len < size_bytes || !dsb->device->tmp_buffer)
|
||||
{
|
||||
dsb->device->tmp_buffer_len = tmp_len;
|
||||
dsb->device->tmp_buffer_len = size_bytes;
|
||||
if (dsb->device->tmp_buffer)
|
||||
dsb->device->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0, dsb->device->tmp_buffer, tmp_len);
|
||||
dsb->device->tmp_buffer = HeapReAlloc(GetProcessHeap(), 0, dsb->device->tmp_buffer, size_bytes);
|
||||
else
|
||||
dsb->device->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, tmp_len);
|
||||
dsb->device->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, size_bytes);
|
||||
}
|
||||
|
||||
cp_fields(dsb, oAdvance, size, &dsb->freqAcc);
|
||||
cp_fields(dsb, frames, &dsb->freqAcc);
|
||||
}
|
||||
|
||||
/** Apply volume to the given soundbuffer from (primary) position writepos and length len
|
||||
* Returns: NULL if no volume needs to be applied
|
||||
* or else a memory handle that holds 'len' volume adjusted buffer */
|
||||
static LPBYTE DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, INT len)
|
||||
static void DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, INT frames)
|
||||
{
|
||||
INT i;
|
||||
BYTE *bpc;
|
||||
INT16 *bps, *mems;
|
||||
DWORD vLeft, vRight;
|
||||
INT nChannels = dsb->device->pwfx->nChannels;
|
||||
LPBYTE mem = dsb->device->tmp_buffer;
|
||||
float vLeft, vRight;
|
||||
UINT channels = dsb->device->pwfx->nChannels, chan;
|
||||
|
||||
TRACE("(%p,%d)\n",dsb,len);
|
||||
TRACE("(%p,%d)\n",dsb,frames);
|
||||
TRACE("left = %x, right = %x\n", dsb->volpan.dwTotalLeftAmpFactor,
|
||||
dsb->volpan.dwTotalRightAmpFactor);
|
||||
|
||||
if ((!(dsb->dsbd.dwFlags & DSBCAPS_CTRLPAN) || (dsb->volpan.lPan == 0)) &&
|
||||
(!(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME) || (dsb->volpan.lVolume == 0)) &&
|
||||
!(dsb->dsbd.dwFlags & DSBCAPS_CTRL3D))
|
||||
return NULL; /* Nothing to do */
|
||||
return; /* Nothing to do */
|
||||
|
||||
if (nChannels != 1 && nChannels != 2)
|
||||
if (channels != 1 && channels != 2)
|
||||
{
|
||||
FIXME("There is no support for %d channels\n", nChannels);
|
||||
return NULL;
|
||||
FIXME("There is no support for %u channels\n", channels);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dsb->device->pwfx->wBitsPerSample != 8 && dsb->device->pwfx->wBitsPerSample != 16)
|
||||
{
|
||||
FIXME("There is no support for %d bpp\n", dsb->device->pwfx->wBitsPerSample);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(dsb->device->tmp_buffer_len >= len && dsb->device->tmp_buffer);
|
||||
|
||||
bpc = dsb->device->tmp_buffer;
|
||||
bps = (INT16 *)bpc;
|
||||
mems = (INT16 *)mem;
|
||||
vLeft = dsb->volpan.dwTotalLeftAmpFactor;
|
||||
if (nChannels > 1)
|
||||
vRight = dsb->volpan.dwTotalRightAmpFactor;
|
||||
else
|
||||
vRight = vLeft;
|
||||
|
||||
switch (dsb->device->pwfx->wBitsPerSample) {
|
||||
case 8:
|
||||
/* 8-bit WAV is unsigned, but we need to operate */
|
||||
/* on signed data for this to work properly */
|
||||
for (i = 0; i < len-1; i+=2) {
|
||||
*(bpc++) = (((*(mem++) - 128) * vLeft) >> 16) + 128;
|
||||
*(bpc++) = (((*(mem++) - 128) * vRight) >> 16) + 128;
|
||||
vLeft = dsb->volpan.dwTotalLeftAmpFactor / ((float)0xFFFF);
|
||||
vRight = dsb->volpan.dwTotalRightAmpFactor / ((float)0xFFFF);
|
||||
for(i = 0; i < frames; ++i){
|
||||
for(chan = 0; chan < channels; ++chan){
|
||||
if(chan == 0)
|
||||
dsb->device->tmp_buffer[i * channels + chan] *= vLeft;
|
||||
else
|
||||
dsb->device->tmp_buffer[i * channels + chan] *= vRight;
|
||||
}
|
||||
if (len % 2 == 1 && nChannels == 1)
|
||||
*(bpc++) = (((*(mem++) - 128) * vLeft) >> 16) + 128;
|
||||
break;
|
||||
case 16:
|
||||
/* 16-bit WAV is signed -- much better */
|
||||
for (i = 0; i < len-3; i += 4) {
|
||||
*(bps++) = (*(mems++) * vLeft) >> 16;
|
||||
*(bps++) = (*(mems++) * vRight) >> 16;
|
||||
}
|
||||
if (len % 4 == 2 && nChannels == 1)
|
||||
*(bps++) = ((INT)*(mems++) * vLeft) >> 16;
|
||||
break;
|
||||
}
|
||||
return dsb->device->tmp_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -466,8 +429,9 @@ static LPBYTE DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, INT len)
|
|||
static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen)
|
||||
{
|
||||
INT len = fraglen;
|
||||
BYTE *ibuf, *volbuf;
|
||||
float *ibuf;
|
||||
DWORD oldpos;
|
||||
UINT frames = fraglen / dsb->device->pwfx->nBlockAlign;
|
||||
|
||||
TRACE("sec_mixpos=%d/%d\n", dsb->sec_mixpos, dsb->buflen);
|
||||
TRACE("(%p,%d,%d)\n",dsb,writepos,fraglen);
|
||||
|
@ -481,15 +445,13 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWO
|
|||
/* Resample buffer to temporary buffer specifically allocated for this purpose, if needed */
|
||||
oldpos = dsb->sec_mixpos;
|
||||
|
||||
DSOUND_MixToTemporary(dsb, len);
|
||||
DSOUND_MixToTemporary(dsb, frames);
|
||||
ibuf = dsb->device->tmp_buffer;
|
||||
|
||||
/* Apply volume if needed */
|
||||
volbuf = DSOUND_MixerVol(dsb, len);
|
||||
if (volbuf)
|
||||
ibuf = volbuf;
|
||||
DSOUND_MixerVol(dsb, frames);
|
||||
|
||||
dsb->device->mixfunction(ibuf, dsb->device->mix_buffer, len);
|
||||
mixieee32(ibuf, dsb->device->mix_buffer, frames * dsb->device->pwfx->nChannels);
|
||||
|
||||
/* check for notification positions */
|
||||
if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY &&
|
||||
|
@ -694,6 +656,14 @@ static void DSOUND_WaveQueue(DirectSoundDevice *device, BOOL force)
|
|||
* Perform mixing for a Direct Sound device. That is, go through all the
|
||||
* secondary buffers (the sound bites currently playing) and mix them in
|
||||
* to the primary buffer (the device buffer).
|
||||
*
|
||||
* The mixing procedure goes:
|
||||
*
|
||||
* secondary->buffer (secondary format)
|
||||
* =[Resample]=> device->tmp_buffer (float format)
|
||||
* =[Volume]=> device->tmp_buffer (float format)
|
||||
* =[Mix]=> device->mix_buffer (float format)
|
||||
* =[Reformat]=> device->buffer (device format)
|
||||
*/
|
||||
static void DSOUND_PerformMix(DirectSoundDevice *device)
|
||||
{
|
||||
|
|
|
@ -189,13 +189,10 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
|
|||
if(device->pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
|
||||
(device->pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
||||
IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)device->pwfx)->SubFormat,
|
||||
&KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
|
||||
device->mixfunction = mixfunctions[4];
|
||||
&KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
|
||||
device->normfunction = normfunctions[4];
|
||||
}else{
|
||||
device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1];
|
||||
else
|
||||
device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
|
||||
}
|
||||
|
||||
FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
|
||||
FillMemory(device->mix_buffer, device->mix_buffer_len, 0);
|
||||
|
@ -512,16 +509,14 @@ opened:
|
|||
WARN("DSOUND_PrimaryOpen(2) failed: %08x\n", err);
|
||||
}
|
||||
|
||||
|
||||
if(device->pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
|
||||
(device->pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
||||
IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)device->pwfx)->SubFormat,
|
||||
&KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){
|
||||
device->mixfunction = mixfunctions[4];
|
||||
&KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
|
||||
device->normfunction = normfunctions[4];
|
||||
}else{
|
||||
device->mixfunction = mixfunctions[device->pwfx->wBitsPerSample/8 - 1];
|
||||
else
|
||||
device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
|
||||
}
|
||||
|
||||
if (old_fmt->nSamplesPerSec != device->pwfx->nSamplesPerSec ||
|
||||
old_fmt->wBitsPerSample != device->pwfx->wBitsPerSample ||
|
||||
|
|
Loading…
Reference in New Issue