synthsink.c 10.4 KB
Newer Older
1 2
/*
 * IDirectMusicSynthSink Implementation
3
 *
4
 * Copyright (C) 2003-2004 Rok Mandeljc
5
 * Copyright (C) 2012 Christian Costa
6
 *
7 8 9 10
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
11 12 13
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
16
 *
17 18 19
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21
 */

22 23
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
24
#include "dmsynth_private.h"
25 26
#include "initguid.h"
#include "uuids.h"
27

28
WINE_DEFAULT_DEBUG_CHANNEL(dmsynth);
29

30 31 32 33 34
static inline IDirectMusicSynthSinkImpl *impl_from_IDirectMusicSynthSink(IDirectMusicSynthSink *iface)
{
    return CONTAINING_RECORD(iface, IDirectMusicSynthSinkImpl, IDirectMusicSynthSink_iface);
}

35
/* IDirectMusicSynthSinkImpl IUnknown part: */
36 37
static HRESULT WINAPI IDirectMusicSynthSinkImpl_QueryInterface(IDirectMusicSynthSink *iface,
        REFIID riid, void **ret_iface)
38
{
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
    IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface);

    TRACE("(%p)->(%s, %p)\n", iface, debugstr_dmguid(riid), ret_iface);

    if (IsEqualIID (riid, &IID_IUnknown) ||
        IsEqualIID (riid, &IID_IDirectMusicSynthSink))
    {
        IUnknown_AddRef(iface);
        *ret_iface = iface;
        return S_OK;
    }
    else if (IsEqualIID(riid, &IID_IKsControl))
    {
        IUnknown_AddRef(iface);
        *ret_iface = &This->IKsControl_iface;
        return S_OK;
55 56
    }

57 58 59 60 61
    *ret_iface = NULL;

    WARN("(%p)->(%s, %p): not found\n", iface, debugstr_dmguid(riid), ret_iface);

    return E_NOINTERFACE;
62 63
}

64
static ULONG WINAPI IDirectMusicSynthSinkImpl_AddRef(IDirectMusicSynthSink *iface)
65
{
66 67
    IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface);
    ULONG ref = InterlockedIncrement(&This->ref);
68

69
    TRACE("(%p): new ref = %lu\n", This, ref);
70

71
    return ref;
72 73
}

74
static ULONG WINAPI IDirectMusicSynthSinkImpl_Release(IDirectMusicSynthSink *iface)
75
{
76 77
    IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface);
    ULONG ref = InterlockedDecrement(&This->ref);
78

79
    TRACE("(%p): new ref = %lu\n", This, ref);
80

81 82 83
    if (!ref) {
        if (This->latency_clock)
            IReferenceClock_Release(This->latency_clock);
84 85
        if (This->master_clock)
            IReferenceClock_Release(This->master_clock);
86
        HeapFree(GetProcessHeap(), 0, This);
87
        DMSYNTH_UnlockModule();
88
    }
89

90
    return ref;
91 92
}

93
/* IDirectMusicSynthSinkImpl IDirectMusicSynthSink part: */
94 95
static HRESULT WINAPI IDirectMusicSynthSinkImpl_Init(IDirectMusicSynthSink *iface,
        IDirectMusicSynth *synth)
96 97 98
{
    IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface);

99 100 101 102 103
    TRACE("(%p)->(%p)\n", This, synth);

    /* Not holding a reference to avoid circular dependencies.
       The synth will release the sink during the synth's destruction. */
    This->synth = synth;
104 105

    return S_OK;
106 107
}

108 109
static HRESULT WINAPI IDirectMusicSynthSinkImpl_SetMasterClock(IDirectMusicSynthSink *iface,
        IReferenceClock *clock)
110 111 112
{
    IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface);

113 114 115 116 117 118 119 120 121
    TRACE("(%p)->(%p)\n", This, clock);

    if (!clock)
        return E_POINTER;
    if (This->active)
        return E_FAIL;

    IReferenceClock_AddRef(clock);
    This->master_clock = clock;
122 123

    return S_OK;
124 125
}

126 127
static HRESULT WINAPI IDirectMusicSynthSinkImpl_GetLatencyClock(IDirectMusicSynthSink *iface,
        IReferenceClock **clock)
128 129 130
{
    IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface);

131 132 133 134 135 136 137
    TRACE("(%p)->(%p)\n", iface, clock);

    if (!clock)
        return E_POINTER;

    *clock = This->latency_clock;
    IReferenceClock_AddRef(This->latency_clock);
138 139

    return S_OK;
140 141
}

142 143
static HRESULT WINAPI IDirectMusicSynthSinkImpl_Activate(IDirectMusicSynthSink *iface,
        BOOL enable)
144 145 146 147 148 149
{
    IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface);

    FIXME("(%p)->(%d): stub\n", This, enable);

    return S_OK;
150 151
}

152 153
static HRESULT WINAPI IDirectMusicSynthSinkImpl_SampleToRefTime(IDirectMusicSynthSink *iface,
        LONGLONG sample_time, REFERENCE_TIME *ref_time)
154 155 156 157 158 159
{
    IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface);

    FIXME("(%p)->(0x%s, %p): stub\n", This, wine_dbgstr_longlong(sample_time), ref_time);

    return S_OK;
160 161
}

162 163
static HRESULT WINAPI IDirectMusicSynthSinkImpl_RefTimeToSample(IDirectMusicSynthSink *iface,
        REFERENCE_TIME ref_time, LONGLONG *sample_time)
164 165 166 167 168 169
{
    IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface);

    FIXME("(%p)->(0x%s, %p): stub\n", This, wine_dbgstr_longlong(ref_time), sample_time);

    return S_OK;
170 171
}

172 173
static HRESULT WINAPI IDirectMusicSynthSinkImpl_SetDirectSound(IDirectMusicSynthSink *iface,
        IDirectSound *dsound, IDirectSoundBuffer *dsound_buffer)
174 175 176 177 178 179
{
    IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface);

    FIXME("(%p)->(%p, %p): stub\n", This, dsound, dsound_buffer);

    return S_OK;
180 181
}

182
static HRESULT WINAPI IDirectMusicSynthSinkImpl_GetDesiredBufferSize(IDirectMusicSynthSink *iface,
183
        DWORD *size)
184 185
{
    IDirectMusicSynthSinkImpl *This = impl_from_IDirectMusicSynthSink(iface);
186 187
    WAVEFORMATEX format;
    DWORD fmtsize = sizeof(format);
188

189 190 191 192 193 194 195 196 197 198
    TRACE("(%p, %p)\n", This, size);

    if (!size)
        return E_POINTER;
    if (!This->synth)
        return DMUS_E_SYNTHNOTCONFIGURED;

    if (FAILED(IDirectMusicSynth_GetFormat(This->synth, &format, &fmtsize)))
        return E_UNEXPECTED;
    *size = format.nSamplesPerSec * format.nChannels * 4;
199 200

    return S_OK;
201 202
}

203
static const IDirectMusicSynthSinkVtbl DirectMusicSynthSink_Vtbl = {
204 205 206 207 208 209 210 211 212 213 214 215 216
	IDirectMusicSynthSinkImpl_QueryInterface,
	IDirectMusicSynthSinkImpl_AddRef,
	IDirectMusicSynthSinkImpl_Release,
	IDirectMusicSynthSinkImpl_Init,
	IDirectMusicSynthSinkImpl_SetMasterClock,
	IDirectMusicSynthSinkImpl_GetLatencyClock,
	IDirectMusicSynthSinkImpl_Activate,
	IDirectMusicSynthSinkImpl_SampleToRefTime,
	IDirectMusicSynthSinkImpl_RefTimeToSample,
	IDirectMusicSynthSinkImpl_SetDirectSound,
	IDirectMusicSynthSinkImpl_GetDesiredBufferSize
};

217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
static inline IDirectMusicSynthSinkImpl *impl_from_IKsControl(IKsControl *iface)
{
    return CONTAINING_RECORD(iface, IDirectMusicSynthSinkImpl, IKsControl_iface);
}

static HRESULT WINAPI DMSynthSinkImpl_IKsControl_QueryInterface(IKsControl* iface, REFIID riid, LPVOID *ppobj)
{
    IDirectMusicSynthSinkImpl *This = impl_from_IKsControl(iface);

    return IDirectMusicSynthSinkImpl_QueryInterface(&This->IDirectMusicSynthSink_iface, riid, ppobj);
}

static ULONG WINAPI DMSynthSinkImpl_IKsControl_AddRef(IKsControl* iface)
{
    IDirectMusicSynthSinkImpl *This = impl_from_IKsControl(iface);

    return IDirectMusicSynthSinkImpl_AddRef(&This->IDirectMusicSynthSink_iface);
}

static ULONG WINAPI DMSynthSinkImpl_IKsControl_Release(IKsControl* iface)
{
    IDirectMusicSynthSinkImpl *This = impl_from_IKsControl(iface);

    return IDirectMusicSynthSinkImpl_Release(&This->IDirectMusicSynthSink_iface);
}

static HRESULT WINAPI DMSynthSinkImpl_IKsControl_KsProperty(IKsControl* iface, PKSPROPERTY Property, ULONG PropertyLength, LPVOID PropertyData,
                                                            ULONG DataLength, ULONG* BytesReturned)
{
246
    TRACE("(%p, %p, %lu, %p, %lu, %p)\n", iface, Property, PropertyLength, PropertyData, DataLength, BytesReturned);
247

248
    TRACE("Property = %s - %lu - %lu\n", debugstr_guid(&Property->u.s.Set), Property->u.s.Id, Property->u.s.Flags);
249

250
    if (Property->u.s.Flags != KSPROPERTY_TYPE_GET)
251
    {
252
        FIXME("Property flags %lu not yet supported\n", Property->u.s.Flags);
253 254 255 256
        return S_FALSE;
    }

    if (DataLength <  sizeof(DWORD))
257
        return E_NOT_SUFFICIENT_BUFFER;
258

259
    if (IsEqualGUID(&Property->u.s.Set, &GUID_DMUS_PROP_SinkUsesDSound))
260 261 262 263 264 265
    {
        *(DWORD*)PropertyData = TRUE;
        *BytesReturned = sizeof(DWORD);
    }
    else
    {
266
        FIXME("Unknown property %s\n", debugstr_guid(&Property->u.s.Set));
267 268 269 270 271
        *(DWORD*)PropertyData = FALSE;
        *BytesReturned = sizeof(DWORD);
    }

    return S_OK;
272 273 274 275 276
}

static HRESULT WINAPI DMSynthSinkImpl_IKsControl_KsMethod(IKsControl* iface, PKSMETHOD Method, ULONG MethodLength, LPVOID MethodData,
                                                          ULONG DataLength, ULONG* BytesReturned)
{
277
    FIXME("(%p, %p, %lu, %p, %lu, %p): stub\n", iface, Method, MethodLength, MethodData, DataLength, BytesReturned);
278 279 280 281 282 283 284

    return E_NOTIMPL;
}

static HRESULT WINAPI DMSynthSinkImpl_IKsControl_KsEvent(IKsControl* iface, PKSEVENT Event, ULONG EventLength, LPVOID EventData,
                                                         ULONG DataLength, ULONG* BytesReturned)
{
285
    FIXME("(%p, %p, %lu, %p, %lu, %p): stub\n", iface, Event, EventLength, EventData, DataLength, BytesReturned);
286 287 288 289 290 291 292 293 294 295 296 297 298 299

    return E_NOTIMPL;
}


static const IKsControlVtbl DMSynthSinkImpl_IKsControl_Vtbl = {
    DMSynthSinkImpl_IKsControl_QueryInterface,
    DMSynthSinkImpl_IKsControl_AddRef,
    DMSynthSinkImpl_IKsControl_Release,
    DMSynthSinkImpl_IKsControl_KsProperty,
    DMSynthSinkImpl_IKsControl_KsMethod,
    DMSynthSinkImpl_IKsControl_KsEvent
};

300
/* for ClassFactory */
301
HRESULT DMUSIC_CreateDirectMusicSynthSinkImpl(REFIID riid, void **ret_iface)
302 303 304 305
{
    IDirectMusicSynthSinkImpl *obj;
    HRESULT hr;

306
    TRACE("(%s, %p)\n", debugstr_guid(riid), ret_iface);
307 308 309 310 311 312 313 314

    *ret_iface = NULL;

    obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicSynthSinkImpl));
    if (!obj)
        return E_OUTOFMEMORY;

    obj->IDirectMusicSynthSink_iface.lpVtbl = &DirectMusicSynthSink_Vtbl;
315
    obj->IKsControl_iface.lpVtbl = &DMSynthSinkImpl_IKsControl_Vtbl;
316
    obj->ref = 1;
317 318 319 320 321 322 323 324

    hr = CoCreateInstance(&CLSID_SystemClock, NULL, CLSCTX_INPROC_SERVER, &IID_IReferenceClock, (LPVOID*)&obj->latency_clock);
    if (FAILED(hr))
    {
        HeapFree(GetProcessHeap(), 0, obj);
        return hr;
    }

325
    DMSYNTH_LockModule();
326 327
    hr = IDirectMusicSynthSink_QueryInterface(&obj->IDirectMusicSynthSink_iface, riid, ret_iface);
    IDirectMusicSynthSink_Release(&obj->IDirectMusicSynthSink_iface);
328

329
    return hr;
330
}