On Sat, Jul 14, 2012 at 05:00:02PM +1000, Donny Yang wrote:
Andrew, I've removed the two driver edits. IAudioClient_GetMixFormat() needs an initialised client parameter which doesn't exist in DirectSoundDevice_Create(), so it can only be done after the client is initialised, which is approximately where I put the code.
No, you can call GetMixFormat with an IAudioClient that hasn't been initialized.
Also, I'm new to this, so is this the correct way to resend a patch?
No, you'll have to resend the patch to wine-patches. It's probably best to resend the entire series, and of course be sure to test your changes before sending :)
Thanks, Andrew
On Fri, Jul 13, 2012 at 11:10 PM, Andrew Eikum aeikum@codeweavers.com wrote:
Thanks, Donny. Nice work overall. Some comments below.
On Fri, Jul 13, 2012 at 05:57:48PM +1000, Donny Yang wrote:
This patch makes dsound automatically get the output format when a output device is initialised and also allows up to 8 output channels to be used for ALSA and PulseAudio. Using ALSA with over 2 channels outputs the channels in the wrong speakers with my testing but I don't know why so I can't fix that.
You probably already discovered that ALSA's multi-channel support is primitive at best. You have to test each channel and hand-craft an asoundrc to match your hardware. See some more information here: http://drona.csa.iisc.ernet.in/~uday/alsamch.shtml
@@ -1492,6 +1493,24 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG } else WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
- hr = IAudioClient_GetMixFormat(device->client, &pwfx);
- if(FAILED(hr)){
WARN("IAudioClient_GetMixFormat failed: %08x; Falling back to default output format\n", hr);
- }else{
DWORD oldPriolevel = device->priolevel;
device->priolevel = DSSCL_WRITEPRIMARY;
hr = primarybuffer_SetFormat(device, pwfx);
device->priolevel = oldPriolevel;
This looks like a hack. I think it fits better in DirectSoundDevice_Create, where the default values are copied in. Is there a reason it couldn't be done there?
-void put_mono2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) +void put_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) {
- dsb->put_aux(dsb, pos, 0, value);
- dsb->put_aux(dsb, pos, 1, value);
- /* XXX: Is this how Windows does this? */
- DWORD c;
- for (c = 0; c < dsb->device->pwfx->nChannels; ++c)
dsb->put_aux(dsb, pos, c, value);
}
I think this is fine. I wonder if we should skip the LOWFREQ channel, though we'd have to be careful not to affect performance too much, as this runs in a really tight loop.
void mixieee32(float *src, float *dst, unsigned samples) diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c index 072b25a..538534d 100644 --- a/dlls/dsound/dsound_main.c +++ b/dlls/dsound/dsound_main.c @@ -642,7 +642,7 @@ DirectSoundCaptureEnumerateW( */
typedef HRESULT (*FnCreateInstance)(REFIID riid, LPVOID *ppobj);
typedef struct { IClassFactory IClassFactory_iface; REFCLSID rclsid; @@ -702,7 +702,7 @@ static HRESULT WINAPI DSCF_CreateInstance( *ppobj = NULL; return This->pfnCreateInstance(riid, ppobj); }
static HRESULT WINAPI DSCF_LockServer(LPCLASSFACTORY iface, BOOL dolock) { IClassFactoryImpl *This = impl_from_IClassFactory(iface);
The only changes to this file are whitespace changes. I'd exclude these changes when you resend.
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 1cf6daa..68f6242 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -202,7 +202,7 @@ struct IDirectSoundBufferImpl };
float get_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel) DECLSPEC_HIDDEN; -void put_mono2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) DECLSPEC_HIDDEN; +void put_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) DECLSPEC_HIDDEN;
HRESULT IDirectSoundBufferImpl_Create( DirectSoundDevice *device, @@ -288,7 +288,7 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX wfex) LONG capped_refcount_dec(LONG *ref) DECLSPEC_HIDDEN;
/* duplex.c */
HRESULT DSOUND_FullDuplexCreate(REFIID riid, LPDIRECTSOUNDFULLDUPLEX* ppDSFD) DECLSPEC_HIDDEN;
/* mixer.c */ @@ -305,7 +305,7 @@ DWORD CALLBACK DSOUND_mixthread(void *ptr) DECLSPEC_HIDDEN; void DSOUND_Calc3DBuffer(IDirectSoundBufferImpl *dsb) DECLSPEC_HIDDEN;
/* capture.c */
HRESULT DSOUND_CaptureCreate(REFIID riid, LPDIRECTSOUNDCAPTURE *ppDSC) DECLSPEC_HIDDEN; HRESULT DSOUND_CaptureCreate8(REFIID riid, LPDIRECTSOUNDCAPTURE8 *ppDSC8) DECLSPEC_HIDDEN;
Likewise, more unneeded whitespace changes.
diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c index 93e2b8d..fa6b05a 100644 --- a/dlls/winealsa.drv/mmdevdrv.c +++ b/dlls/winealsa.drv/mmdevdrv.c @@ -1544,7 +1544,7 @@ static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface, goto exit; } if(max > 8)
max = 2;
if(fmt->nChannels > max){ hr = S_FALSE; closest->nChannels = max;max = 8;
@@ -1649,8 +1649,8 @@ static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface, goto exit; }
- if(max_channels > 2)
fmt->Format.nChannels = 2;
- if(max_channels > 8)
else fmt->Format.nChannels = max_channels;fmt->Format.nChannels = 8;
This needs to be a separate patch. Also, winealsa's multi-channel handling needs a closer examination. My current thinking is GetMixFormat should just return some sane, supported default (2ch, 48kHz, 16bps, or less as supported). It seems impossible to detect what the ALSA device actually supports, so we probably shouldn't even try like we do now.
diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c index b374b53..e86ed08 100644 --- a/dlls/winepulse.drv/mmdevdrv.c +++ b/dlls/winepulse.drv/mmdevdrv.c @@ -1050,13 +1050,13 @@ static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt) This->ss.format = PA_SAMPLE_INVALID; switch(fmt->wFormatTag) { case WAVE_FORMAT_IEEE_FLOAT:
if (!fmt->nChannels || fmt->nChannels > 2 || fmt->wBitsPerSample != 32)
case WAVE_FORMAT_PCM:if (!fmt->nChannels || fmt->nChannels > 8 || fmt->wBitsPerSample != 32) break; This->ss.format = PA_SAMPLE_FLOAT32LE; pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA); break;
if (!fmt->nChannels || fmt->nChannels > 2)
if (!fmt->nChannels || fmt->nChannels > 8) break; if (fmt->wBitsPerSample == 8) This->ss.format = PA_SAMPLE_U8;
Wine doesn't have a PulseAudio driver yet, so this chunk won't apply.
Andrew
From 4d454498c8f4cf6593d4afe405fb602ebb0e2722 Mon Sep 17 00:00:00 2001 From: Donny Yang xiao.tai.lang.de.email@gmail.com Date: Sat, 14 Jul 2012 16:40:07 +1000 Subject: dsound: Add detection of output format and upmixing from mono to any number of channels
dlls/dsound/dsound.c | 19 +++++++++++++++++++ dlls/dsound/dsound_convert.c | 8 +++++--- dlls/dsound/dsound_private.h | 2 +- dlls/dsound/mixer.c | 7 +++---- dlls/dsound/primary.c | 28 ++++++++++++++++++++++++++++ 5 files changed, 56 insertions(+), 8 deletions(-)
diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c index e401725..7d75760 100644 --- a/dlls/dsound/dsound.c +++ b/dlls/dsound/dsound.c @@ -1382,6 +1382,7 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG GUID devGUID; DirectSoundDevice *device; IMMDevice *mmdevice;
WAVEFORMATEX *pwfx;
TRACE("(%p,%s)\n",ppDevice,debugstr_guid(lpcGUID));
@@ -1492,6 +1493,24 @@ HRESULT DirectSoundDevice_Initialize(DirectSoundDevice ** ppDevice, LPCGUID lpcG } else WARN("DSOUND_PrimaryCreate failed: %08x\n", hr);
- hr = IAudioClient_GetMixFormat(device->client, &pwfx);
- if(FAILED(hr)){
WARN("IAudioClient_GetMixFormat failed: %08x; Falling back to default output format\n", hr);
- }else{
DWORD oldPriolevel = device->priolevel;
device->priolevel = DSSCL_WRITEPRIMARY;
hr = primarybuffer_SetFormat(device, pwfx);
device->priolevel = oldPriolevel;
CoTaskMemFree(pwfx);
if(FAILED(hr)){
HeapFree(GetProcessHeap(), 0, device);
LeaveCriticalSection(&DSOUND_renderers_lock);
IMMDevice_Release(mmdevice);
WARN("primarybuffer_SetFormat failed: %08x\n", hr);
return hr;
}
- }
- *ppDevice = device; list_add_tail(&DSOUND_renderers, &device->entry);
diff --git a/dlls/dsound/dsound_convert.c b/dlls/dsound/dsound_convert.c index d3d686a..a8c929c 100644 --- a/dlls/dsound/dsound_convert.c +++ b/dlls/dsound/dsound_convert.c @@ -159,10 +159,12 @@ void putieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, floa *fbuf = value; }
-void put_mono2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) +void put_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) {
- dsb->put_aux(dsb, pos, 0, value);
- dsb->put_aux(dsb, pos, 1, value);
- /* XXX: Is this how Windows does this? */
- DWORD c;
- for (c = 0; c < dsb->device->pwfx->nChannels; ++c)
dsb->put_aux(dsb, pos, c, value);
}
void mixieee32(float *src, float *dst, unsigned samples) diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h index 1cf6daa..68f6242 100644 --- a/dlls/dsound/dsound_private.h +++ b/dlls/dsound/dsound_private.h @@ -202,7 +202,7 @@ struct IDirectSoundBufferImpl };
float get_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel) DECLSPEC_HIDDEN; -void put_mono2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) DECLSPEC_HIDDEN; +void put_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value) DECLSPEC_HIDDEN;
HRESULT IDirectSoundBufferImpl_Create( DirectSoundDevice *device, diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c index 13eb03d..547c666 100644 --- a/dlls/dsound/mixer.c +++ b/dlls/dsound/mixer.c @@ -157,7 +157,7 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) else if (ichannels == 1) { dsb->mix_channels = 1;
dsb->put = put_mono2stereo;
} else if (ochannels == 1) {dsb->put = put_mono;
@@ -166,9 +166,8 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb) } else {
if (ichannels > 2)
FIXME("Conversion from %u to %u channels is not implemented, falling back to stereo\n", ichannels, ochannels);
dsb->mix_channels = 2;
FIXME("Conversion from %u to %u channels is not implemented, falling back to %u channels\n", ichannels, ochannels, ochannels);
}dsb->mix_channels = ochannels;
}
diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c index cfe674e..9fd1ff2 100644 --- a/dlls/dsound/primary.c +++ b/dlls/dsound/primary.c @@ -484,6 +484,34 @@ HRESULT primarybuffer_SetFormat(DirectSoundDevice *device, LPCWAVEFORMATEX passe goto done;
opened:
- switch(device->pwfx->nChannels){
case 0:
device->speaker_config = DSSPEAKER_DIRECTOUT;
break;
case 1:
device->speaker_config = DSSPEAKER_MONO;
break;
case 2:
case 3:
device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE);
break;
case 4:
case 5:
device->speaker_config = DSSPEAKER_QUAD;
break;
case 6:
case 7:
device->speaker_config = DSSPEAKER_5POINT1_SURROUND;
break;
case 8:
device->speaker_config = DSSPEAKER_7POINT1_SURROUND;
break;
default:
FIXME("Unknown speaker configuration: %u\n", device->pwfx->nChannels);
device->speaker_config = DSSPEAKER_DIRECTOUT;
break;
- }
- err = DSOUND_PrimaryOpen(device); if (err != DS_OK) { WARN("DSOUND_PrimaryOpen failed\n");
-- 1.7.9.5