dsound: Mix float natively.
Signed-off-by: Andrew Eikum <aeikum@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
95287ac2df
commit
09890d7142
@ -238,7 +238,6 @@ static ULONG DirectSoundDevice_Release(DirectSoundDevice * device)
|
|||||||
IAudioStreamVolume_Release(device->volume);
|
IAudioStreamVolume_Release(device->volume);
|
||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
|
HeapFree(GetProcessHeap(), 0, device->tmp_buffer);
|
||||||
HeapFree(GetProcessHeap(), 0, device->mix_buffer);
|
|
||||||
HeapFree(GetProcessHeap(), 0, device->buffer);
|
HeapFree(GetProcessHeap(), 0, device->buffer);
|
||||||
RtlDeleteResource(&device->buffer_list_lock);
|
RtlDeleteResource(&device->buffer_list_lock);
|
||||||
device->mixlock.DebugInfo->Spare[0] = 0;
|
device->mixlock.DebugInfo->Spare[0] = 0;
|
||||||
|
@ -263,27 +263,9 @@ static void norm32(float *src, INT *dst, unsigned len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void normieee32(float *src, float *dst, unsigned len)
|
const normfunc normfunctions[4] = {
|
||||||
{
|
|
||||||
TRACE("%p - %p %d\n", src, dst, len);
|
|
||||||
len /= 4;
|
|
||||||
while (len--)
|
|
||||||
{
|
|
||||||
if(*src > 1)
|
|
||||||
*dst = 1;
|
|
||||||
else if(*src < -1)
|
|
||||||
*dst = -1;
|
|
||||||
else
|
|
||||||
*dst = *src;
|
|
||||||
++dst;
|
|
||||||
++src;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const normfunc normfunctions[5] = {
|
|
||||||
(normfunc)norm8,
|
(normfunc)norm8,
|
||||||
(normfunc)norm16,
|
(normfunc)norm16,
|
||||||
(normfunc)norm24,
|
(normfunc)norm24,
|
||||||
(normfunc)norm32,
|
(normfunc)norm32,
|
||||||
(normfunc)normieee32
|
|
||||||
};
|
};
|
||||||
|
@ -49,7 +49,7 @@ extern const bitsgetfunc getbpp[5] DECLSPEC_HIDDEN;
|
|||||||
void putieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) 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;
|
void mixieee32(float *src, float *dst, unsigned samples) DECLSPEC_HIDDEN;
|
||||||
typedef void (*normfunc)(const void *, void *, unsigned);
|
typedef void (*normfunc)(const void *, void *, unsigned);
|
||||||
extern const normfunc normfunctions[5] DECLSPEC_HIDDEN;
|
extern const normfunc normfunctions[4] DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
typedef struct _DSVOLUMEPAN
|
typedef struct _DSVOLUMEPAN
|
||||||
{
|
{
|
||||||
@ -87,7 +87,7 @@ struct DirectSoundDevice
|
|||||||
int speaker_num[DS_MAX_CHANNELS];
|
int speaker_num[DS_MAX_CHANNELS];
|
||||||
int num_speakers;
|
int num_speakers;
|
||||||
int lfe_channel;
|
int lfe_channel;
|
||||||
float *mix_buffer, *tmp_buffer;
|
float *tmp_buffer;
|
||||||
DWORD tmp_buffer_len, mix_buffer_len;
|
DWORD tmp_buffer_len, mix_buffer_len;
|
||||||
|
|
||||||
DSVOLUMEPAN volpan;
|
DSVOLUMEPAN volpan;
|
||||||
|
@ -468,7 +468,7 @@ static void DSOUND_MixerVol(const IDirectSoundBufferImpl *dsb, INT frames)
|
|||||||
* writepos = position (offset) in device buffer to write at
|
* writepos = position (offset) in device buffer to write at
|
||||||
* fraglen = number of bytes to mix
|
* fraglen = number of bytes to mix
|
||||||
*/
|
*/
|
||||||
static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD fraglen)
|
static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, float *mix_buffer, DWORD writepos, DWORD fraglen)
|
||||||
{
|
{
|
||||||
INT len = fraglen;
|
INT len = fraglen;
|
||||||
float *ibuf;
|
float *ibuf;
|
||||||
@ -493,7 +493,7 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWO
|
|||||||
/* Apply volume if needed */
|
/* Apply volume if needed */
|
||||||
DSOUND_MixerVol(dsb, frames);
|
DSOUND_MixerVol(dsb, frames);
|
||||||
|
|
||||||
mixieee32(ibuf, dsb->device->mix_buffer, frames * dsb->device->pwfx->nChannels);
|
mixieee32(ibuf, mix_buffer, frames * dsb->device->pwfx->nChannels);
|
||||||
|
|
||||||
/* check for notification positions */
|
/* check for notification positions */
|
||||||
if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY &&
|
if (dsb->dsbd.dwFlags & DSBCAPS_CTRLPOSITIONNOTIFY &&
|
||||||
@ -517,7 +517,7 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBufferImpl *dsb, DWORD writepos, DWO
|
|||||||
*
|
*
|
||||||
* Returns: the number of bytes beyond the writepos that were mixed.
|
* Returns: the number of bytes beyond the writepos that were mixed.
|
||||||
*/
|
*/
|
||||||
static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mixlen)
|
static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, float *mix_buffer, DWORD writepos, DWORD mixlen)
|
||||||
{
|
{
|
||||||
DWORD primary_done = 0;
|
DWORD primary_done = 0;
|
||||||
|
|
||||||
@ -544,7 +544,7 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mi
|
|||||||
/* First try to mix to the end of the buffer if possible
|
/* First try to mix to the end of the buffer if possible
|
||||||
* Theoretically it would allow for better optimization
|
* Theoretically it would allow for better optimization
|
||||||
*/
|
*/
|
||||||
primary_done += DSOUND_MixInBuffer(dsb, writepos, mixlen);
|
primary_done += DSOUND_MixInBuffer(dsb, mix_buffer, writepos, mixlen);
|
||||||
|
|
||||||
TRACE("total mixed data=%d\n", primary_done);
|
TRACE("total mixed data=%d\n", primary_done);
|
||||||
|
|
||||||
@ -559,14 +559,12 @@ static DWORD DSOUND_MixOne(IDirectSoundBufferImpl *dsb, DWORD writepos, DWORD mi
|
|||||||
* writepos = the current safe-to-write position in the primary buffer
|
* writepos = the current safe-to-write position in the primary buffer
|
||||||
* mixlen = the maximum amount to mix into the primary buffer
|
* mixlen = the maximum amount to mix into the primary buffer
|
||||||
* (beyond the current writepos)
|
* (beyond the current writepos)
|
||||||
* recover = true if the sound device may have been reset and the write
|
|
||||||
* position in the device buffer changed
|
|
||||||
* all_stopped = reports back if all buffers have stopped
|
* all_stopped = reports back if all buffers have stopped
|
||||||
*
|
*
|
||||||
* Returns: the length beyond the writepos that was mixed to.
|
* Returns: the length beyond the writepos that was mixed to.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos, DWORD mixlen, BOOL recover, BOOL *all_stopped)
|
static void DSOUND_MixToPrimary(const DirectSoundDevice *device, float *mix_buffer, DWORD writepos, DWORD mixlen, BOOL *all_stopped)
|
||||||
{
|
{
|
||||||
INT i;
|
INT i;
|
||||||
IDirectSoundBufferImpl *dsb;
|
IDirectSoundBufferImpl *dsb;
|
||||||
@ -574,7 +572,7 @@ static void DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos,
|
|||||||
/* unless we find a running buffer, all have stopped */
|
/* unless we find a running buffer, all have stopped */
|
||||||
*all_stopped = TRUE;
|
*all_stopped = TRUE;
|
||||||
|
|
||||||
TRACE("(%d,%d,%d)\n", writepos, mixlen, recover);
|
TRACE("(%d,%d)\n", writepos, mixlen);
|
||||||
for (i = 0; i < device->nrofbuffers; i++) {
|
for (i = 0; i < device->nrofbuffers; i++) {
|
||||||
dsb = device->buffers[i];
|
dsb = device->buffers[i];
|
||||||
|
|
||||||
@ -594,7 +592,7 @@ static void DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos,
|
|||||||
dsb->state = STATE_PLAYING;
|
dsb->state = STATE_PLAYING;
|
||||||
|
|
||||||
/* mix next buffer into the main buffer */
|
/* mix next buffer into the main buffer */
|
||||||
DSOUND_MixOne(dsb, writepos, mixlen);
|
DSOUND_MixOne(dsb, mix_buffer, writepos, mixlen);
|
||||||
|
|
||||||
*all_stopped = FALSE;
|
*all_stopped = FALSE;
|
||||||
}
|
}
|
||||||
@ -646,8 +644,7 @@ done:
|
|||||||
* secondary->buffer (secondary format)
|
* secondary->buffer (secondary format)
|
||||||
* =[Resample]=> device->tmp_buffer (float format)
|
* =[Resample]=> device->tmp_buffer (float format)
|
||||||
* =[Volume]=> device->tmp_buffer (float format)
|
* =[Volume]=> device->tmp_buffer (float format)
|
||||||
* =[Mix]=> device->mix_buffer (float format)
|
* =[Reformat]=> device->buffer (device format, skipped on float)
|
||||||
* =[Reformat]=> device->buffer (device format)
|
|
||||||
*/
|
*/
|
||||||
static void DSOUND_PerformMix(DirectSoundDevice *device)
|
static void DSOUND_PerformMix(DirectSoundDevice *device)
|
||||||
{
|
{
|
||||||
@ -686,7 +683,7 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
|
|||||||
if (device->priolevel != DSSCL_WRITEPRIMARY) {
|
if (device->priolevel != DSSCL_WRITEPRIMARY) {
|
||||||
BOOL all_stopped = FALSE;
|
BOOL all_stopped = FALSE;
|
||||||
int nfiller;
|
int nfiller;
|
||||||
DWORD bpp = device->pwfx->wBitsPerSample>>3;
|
void *buffer = NULL;
|
||||||
|
|
||||||
/* the sound of silence */
|
/* the sound of silence */
|
||||||
nfiller = device->pwfx->wBitsPerSample == 8 ? 128 : 0;
|
nfiller = device->pwfx->wBitsPerSample == 8 ? 128 : 0;
|
||||||
@ -700,24 +697,32 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
|
|||||||
TRACE("Buffer restarting\n");
|
TRACE("Buffer restarting\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(device->mix_buffer, nfiller, maxq);
|
hr = IAudioRenderClient_GetBuffer(device->render, maxq / block, (void*)&buffer);
|
||||||
|
if(FAILED(hr)){
|
||||||
/* do the mixing */
|
WARN("GetBuffer failed: %08x\n", hr);
|
||||||
DSOUND_MixToPrimary(device, writepos, maxq, TRUE, &all_stopped);
|
LeaveCriticalSection(&device->mixlock);
|
||||||
|
return;
|
||||||
if (maxq + writepos > device->buflen) {
|
|
||||||
DWORD todo = device->buflen - writepos;
|
|
||||||
|
|
||||||
device->normfunction(device->mix_buffer, device->buffer + writepos, todo);
|
|
||||||
DSOUND_WaveQueue(device, device->buffer + writepos, todo);
|
|
||||||
|
|
||||||
device->normfunction(device->mix_buffer + todo / bpp, device->buffer, (maxq - todo));
|
|
||||||
DSOUND_WaveQueue(device, device->buffer, maxq - todo);
|
|
||||||
} else {
|
|
||||||
device->normfunction(device->mix_buffer, device->buffer + writepos, maxq);
|
|
||||||
DSOUND_WaveQueue(device, device->buffer + writepos, maxq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(buffer, nfiller, maxq);
|
||||||
|
|
||||||
|
if (!device->normfunction)
|
||||||
|
DSOUND_MixToPrimary(device, buffer, writepos, maxq, &all_stopped);
|
||||||
|
else {
|
||||||
|
memset(device->buffer, nfiller, device->buflen);
|
||||||
|
|
||||||
|
/* do the mixing */
|
||||||
|
DSOUND_MixToPrimary(device, (float*)device->buffer, writepos, maxq, &all_stopped);
|
||||||
|
|
||||||
|
device->normfunction(device->buffer, buffer, maxq);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = IAudioRenderClient_ReleaseBuffer(device->render, maxq / block, 0);
|
||||||
|
if(FAILED(hr))
|
||||||
|
ERR("ReleaseBuffer failed: %08x\n", hr);
|
||||||
|
|
||||||
|
device->pad += maxq;
|
||||||
|
|
||||||
if (maxq) {
|
if (maxq) {
|
||||||
if (device->state == STATE_STARTING ||
|
if (device->state == STATE_STARTING ||
|
||||||
device->state == STATE_STOPPED) {
|
device->state == STATE_STOPPED) {
|
||||||
|
@ -338,11 +338,7 @@ HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
|
|||||||
device->buflen = ds_hel_buflen;
|
device->buflen = ds_hel_buflen;
|
||||||
device->buflen -= device->buflen % device->pwfx->nBlockAlign;
|
device->buflen -= device->buflen % device->pwfx->nBlockAlign;
|
||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, device->mix_buffer);
|
|
||||||
device->mix_buffer_len = (device->buflen / (device->pwfx->wBitsPerSample / 8)) * sizeof(float);
|
device->mix_buffer_len = (device->buflen / (device->pwfx->wBitsPerSample / 8)) * sizeof(float);
|
||||||
device->mix_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, device->mix_buffer_len);
|
|
||||||
if (!device->mix_buffer)
|
|
||||||
return DSERR_OUTOFMEMORY;
|
|
||||||
|
|
||||||
if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
|
if (device->state == STATE_PLAYING) device->state = STATE_STARTING;
|
||||||
else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED;
|
else if (device->state == STATE_STOPPING) device->state = STATE_STOPPED;
|
||||||
@ -370,21 +366,13 @@ HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
|
|||||||
(device->pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
(device->pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
||||||
IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)device->pwfx)->SubFormat,
|
IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)device->pwfx)->SubFormat,
|
||||||
&KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
|
&KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
|
||||||
device->normfunction = normfunctions[4];
|
device->normfunction = NULL;
|
||||||
else
|
else
|
||||||
device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
|
device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
|
||||||
|
|
||||||
FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
|
FillMemory(device->buffer, device->buflen, (device->pwfx->wBitsPerSample == 8) ? 128 : 0);
|
||||||
FillMemory(device->mix_buffer, device->mix_buffer_len, 0);
|
|
||||||
device->playpos = 0;
|
device->playpos = 0;
|
||||||
|
|
||||||
if (device->pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
|
|
||||||
(device->pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
|
||||||
IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)device->pwfx)->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
|
|
||||||
device->normfunction = normfunctions[4];
|
|
||||||
else
|
|
||||||
device->normfunction = normfunctions[device->pwfx->wBitsPerSample/8 - 1];
|
|
||||||
|
|
||||||
for (i = 0; i < device->nrofbuffers; i++) {
|
for (i = 0; i < device->nrofbuffers; i++) {
|
||||||
RtlAcquireResourceExclusive(&dsb[i]->lock, TRUE);
|
RtlAcquireResourceExclusive(&dsb[i]->lock, TRUE);
|
||||||
DSOUND_RecalcFormat(dsb[i]);
|
DSOUND_RecalcFormat(dsb[i]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user