diff --git a/dlls/dsound/dsound_convert.c b/dlls/dsound/dsound_convert.c index c9ce42614c2..d3d686a2cbd 100644 --- a/dlls/dsound/dsound_convert.c +++ b/dlls/dsound/dsound_convert.c @@ -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); diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 26e59ffcbea..1d43c5a1264 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -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 */ diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index 9d4b35bce01..06e5773d2e0 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -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) { diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c index 6633124f876..b3b77f9cda4 100644 --- a/dlls/dsound/primary.c +++ b/dlls/dsound/primary.c @@ -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 ||