From: Yuxuan Shui yshui@codeweavers.com
--- dlls/dmime/audiopath.c | 38 +---------- dlls/dmime/dmime_private.h | 32 ++++++++++ dlls/dmime/performance.c | 125 ++++++++++++++++++++++++++++++++++++- 3 files changed, 158 insertions(+), 37 deletions(-)
diff --git a/dlls/dmime/audiopath.c b/dlls/dmime/audiopath.c index acc90271108..da99e2779dc 100644 --- a/dlls/dmime/audiopath.c +++ b/dlls/dmime/audiopath.c @@ -32,33 +32,6 @@ struct IDirectMusicAudioPathImpl { BOOL fActive; };
-struct audio_path_pchannel_to_buffer -{ - struct list entry; - DMUS_IO_PCHANNELTOBUFFER_HEADER header; - - ULONG num_of_guids; - GUID *guids; -}; - -struct audio_path_port_config -{ - struct list entry; - DMUS_IO_PORTCONFIG_HEADER header; - DMUS_PORTPARAMS8 params; - - struct list pchannel_to_buffer_entries; -}; - -struct audio_path_config -{ - IUnknown IUnknown_iface; - struct dmobject dmobj; - LONG ref; - - struct list port_config_entries; -}; - static inline struct IDirectMusicAudioPathImpl *impl_from_IDirectMusicAudioPath(IDirectMusicAudioPath *iface) { return CONTAINING_RECORD(iface, struct IDirectMusicAudioPathImpl, IDirectMusicAudioPath_iface); @@ -565,14 +538,9 @@ static const IPersistStreamVtbl persiststream_vtbl = { unimpl_IPersistStream_GetSizeMax };
-static struct audio_path_config *impl_from_IUnknown(IUnknown *iface) -{ - return CONTAINING_RECORD(iface, struct audio_path_config, IUnknown_iface); -} - static HRESULT WINAPI path_config_IUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppobj) { - struct audio_path_config *This = impl_from_IUnknown(iface); + struct audio_path_config *This = path_config_from_IUnknown(iface);
TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
@@ -597,7 +565,7 @@ static HRESULT WINAPI path_config_IUnknown_QueryInterface(IUnknown *iface, REFII
static ULONG WINAPI path_config_IUnknown_AddRef(IUnknown *unk) { - struct audio_path_config *This = impl_from_IUnknown(unk); + struct audio_path_config *This = path_config_from_IUnknown(unk); ULONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p): ref=%ld\n", This, ref); @@ -607,7 +575,7 @@ static ULONG WINAPI path_config_IUnknown_AddRef(IUnknown *unk)
static ULONG WINAPI path_config_IUnknown_Release(IUnknown *unk) { - struct audio_path_config *This = impl_from_IUnknown(unk); + struct audio_path_config *This = path_config_from_IUnknown(unk); ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p): ref=%ld\n", This, ref); diff --git a/dlls/dmime/dmime_private.h b/dlls/dmime/dmime_private.h index 7b744419c38..f55b6b7290c 100644 --- a/dlls/dmime/dmime_private.h +++ b/dlls/dmime/dmime_private.h @@ -105,6 +105,38 @@ typedef struct _DMUS_PRIVATE_TEMPO_PLAY_STATE { DWORD dummy; } DMUS_PRIVATE_TEMPO_PLAY_STATE, *LPDMUS_PRIVATE_TEMPO_PLAY_STATE;
+struct audio_path_pchannel_to_buffer +{ + struct list entry; + DMUS_IO_PCHANNELTOBUFFER_HEADER header; + + ULONG num_of_guids; + GUID *guids; +}; + +struct audio_path_port_config +{ + struct list entry; + DMUS_IO_PORTCONFIG_HEADER header; + DMUS_PORTPARAMS8 params; + + struct list pchannel_to_buffer_entries; +}; + +struct audio_path_config +{ + IUnknown IUnknown_iface; + struct dmobject dmobj; + LONG ref; + + struct list port_config_entries; +}; + +static inline struct audio_path_config *path_config_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct audio_path_config, IUnknown_iface); +} + /***************************************************************************** * Misc. */ diff --git a/dlls/dmime/performance.c b/dlls/dmime/performance.c index bce5f96352b..646d3a08013 100644 --- a/dlls/dmime/performance.c +++ b/dlls/dmime/performance.c @@ -1650,17 +1650,138 @@ static HRESULT WINAPI performance_CreateAudioPath(IDirectMusicPerformance8 *ifac IUnknown *pSourceConfig, BOOL fActivate, IDirectMusicAudioPath **ret_iface) { struct performance *This = impl_from_IDirectMusicPerformance8(iface); + struct audio_path_config *audio_path_config; + struct list *first_port_config, *first_pchannel_to_buffer; + struct audio_path_port_config *port_config; + struct audio_path_pchannel_to_buffer *pchannel_to_buffer; IDirectMusicAudioPath *pPath; + IDirectMusicObject *dmo; + IDirectSoundBuffer *buffer, *primary_buffer; + DMUS_OBJECTDESC objDesc; + DMUS_PORTPARAMS8 port_params; + HRESULT hr; + WAVEFORMATEX format; + DSBUFFERDESC desc; + GUID *buffer_guids;
- FIXME("(%p, %p, %d, %p): stub\n", This, pSourceConfig, fActivate, ret_iface); + FIXME("(%p, %p, %d, %p): semi-stub\n", This, pSourceConfig, fActivate, ret_iface);
if (!ret_iface || !pSourceConfig) return E_POINTER; if (!This->audio_paths_enabled) return DMUS_E_AUDIOPATH_INACTIVE;
+ hr = IUnknown_QueryInterface(pSourceConfig, &IID_IDirectMusicObject, (void **)&dmo); + if (FAILED(hr)) + return hr; + + hr = IDirectMusicObject_GetDescriptor(dmo, &objDesc); + IDirectMusicObject_Release(dmo); + if (FAILED(hr)) + return hr; + + if (!IsEqualCLSID(&objDesc.guidClass, &CLSID_DirectMusicAudioPathConfig)) + { + ERR("Unexpected object class %s for source config.\n", debugstr_dmguid(&objDesc.guidClass)); + return E_INVALIDARG; + } + + audio_path_config = path_config_from_IUnknown(pSourceConfig); + first_port_config = list_head(&audio_path_config->port_config_entries); + if (list_next(&audio_path_config->port_config_entries, first_port_config)) + FIXME("Only one port config supported. %p -> %p\n", first_port_config, list_next(&audio_path_config->port_config_entries, first_port_config)); + port_config = LIST_ENTRY(first_port_config, struct audio_path_port_config, entry); + first_pchannel_to_buffer = list_head(&port_config->pchannel_to_buffer_entries); + if (list_next(&port_config->pchannel_to_buffer_entries, first_pchannel_to_buffer)) + FIXME("Only one pchannel to buffer entry supported.\n"); + pchannel_to_buffer = LIST_ENTRY(first_pchannel_to_buffer, struct audio_path_pchannel_to_buffer, entry); + + /* Secondary buffer description */ + memset(&format, 0, sizeof(format)); + format.wFormatTag = WAVE_FORMAT_PCM; + format.nChannels = 1; + format.nSamplesPerSec = 44000; + format.nAvgBytesPerSec = 44000*2; + format.nBlockAlign = 2; + format.wBitsPerSample = 16; + format.cbSize = 0; + + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + desc.dwFlags = DSBCAPS_CTRLFX | DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS; + desc.dwBufferBytes = DSBSIZE_MIN; + desc.dwReserved = 0; + desc.lpwfxFormat = &format; + desc.guid3DAlgorithm = GUID_NULL; + + buffer_guids = pchannel_to_buffer->guids; + if (pchannel_to_buffer->num_of_guids == 2) + { + if ((!IsEqualGUID(&buffer_guids[0], &GUID_Buffer_Reverb) && !IsEqualGUID(&buffer_guids[0], &GUID_Buffer_Stereo)) || + (!IsEqualGUID(&buffer_guids[1], &GUID_Buffer_Reverb) && !IsEqualGUID(&buffer_guids[1], &GUID_Buffer_Stereo))) + FIXME("Only a stereo plus reverb buffer is supported\n"); + else + { + desc.dwFlags |= DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY; + format.nChannels = 2; + format.nBlockAlign *= 2; + format.nAvgBytesPerSec *=2; + } + } + else if (pchannel_to_buffer->num_of_guids == 1) + { + if (IsEqualGUID(buffer_guids, &GUID_Buffer_Stereo)) + { + desc.dwFlags |= DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY; + format.nChannels = 2; + format.nBlockAlign *= 2; + format.nAvgBytesPerSec *=2; + } + else if (IsEqualGUID(buffer_guids, &GUID_Buffer_3D_Dry)) + desc.dwFlags |= DSBCAPS_CTRL3D | DSBCAPS_CTRLFREQUENCY | DSBCAPS_MUTE3DATMAXDISTANCE; + else if (IsEqualGUID(buffer_guids, &GUID_Buffer_Mono)) + desc.dwFlags |= DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY; + else + FIXME("Unsupported buffer guid %s\n", debugstr_dmguid(buffer_guids)); + } + else + FIXME("Multiple buffers not supported\n"); + + port_params = port_config->params; + if (!(port_params.dwValidParams & DMUS_PORTPARAMS_CHANNELGROUPS)) + { + port_params.dwValidParams |= DMUS_PORTPARAMS_CHANNELGROUPS; + port_params.dwChannelGroups = (port_config->header.dwPChannelCount + 15) / 16; + } + if (!(port_params.dwValidParams & DMUS_PORTPARAMS_AUDIOCHANNELS)) + { + port_params.dwValidParams |= DMUS_PORTPARAMS_AUDIOCHANNELS; + port_params.dwAudioChannels = format.nChannels; + } + hr = perf_dmport_create(This, &port_config->params); + if (FAILED(hr)) + return hr; + + hr = IDirectSound_CreateSoundBuffer(This->dsound, &desc, &buffer, NULL); + if (FAILED(hr)) + return DSERR_BUFFERLOST; + + /* Update description for creating primary buffer */ + desc.dwFlags |= DSBCAPS_PRIMARYBUFFER; + desc.dwFlags &= ~DSBCAPS_CTRLFX; + desc.dwBufferBytes = 0; + desc.lpwfxFormat = NULL; + + hr = IDirectSound_CreateSoundBuffer(This->dsound, &desc, &primary_buffer, NULL); + if (FAILED(hr)) { + IDirectSoundBuffer_Release(buffer); + return DSERR_BUFFERLOST; + } + create_dmaudiopath(&IID_IDirectMusicAudioPath, (void **)&pPath); set_audiopath_perf_pointer(pPath, iface); + set_audiopath_dsound_buffer(pPath, buffer); + set_audiopath_primary_dsound_buffer(pPath, primary_buffer); + TRACE(" returning IDirectMusicAudioPath interface at %p.\n", *ret_iface);
- /** TODO */ *ret_iface = pPath; return IDirectMusicAudioPath_Activate(*ret_iface, fActivate); }