Sync with trunk r58740.
[reactos.git] / dll / directx / dmusic / buffer.c
index c8c7ca1..f6156f3 100644 (file)
@@ -1,6 +1,8 @@
-/* IDirectMusicBuffer Implementation
+/*
+ * IDirectMusicBuffer Implementation
  *
  * Copyright (C) 2003-2004 Rok Mandeljc
+ * Copyright (C) 2012 Christian Costa
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  */
 
 #include "dmusic_private.h"
+//#include "initguid.h"
+#include "dmksctrl.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(dmusic);
 
+static inline IDirectMusicBufferImpl *impl_from_IDirectMusicBuffer(IDirectMusicBuffer *iface)
+{
+    return CONTAINING_RECORD(iface, IDirectMusicBufferImpl, IDirectMusicBuffer_iface);
+}
+
 /* IDirectMusicBufferImpl IUnknown part: */
-static HRESULT WINAPI IDirectMusicBufferImpl_QueryInterface (LPDIRECTMUSICBUFFER iface, REFIID riid, LPVOID *ppobj) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       TRACE("(%p, (%s, %p)\n",This,debugstr_dmguid(riid),ppobj);
-       if (IsEqualIID (riid, &IID_IUnknown) 
-               || IsEqualIID (riid, &IID_IDirectMusicBuffer)) {
-               IUnknown_AddRef(iface);
-               *ppobj = This;
-               return S_OK;
-       }
-       WARN("(%p, (%s, %p): not found\n",This,debugstr_dmguid(riid),ppobj);
-       return E_NOINTERFACE;
+static HRESULT WINAPI IDirectMusicBufferImpl_QueryInterface(LPDIRECTMUSICBUFFER iface, REFIID riid, LPVOID *ret_iface)
+{
+    TRACE("(%p)->(%s, %p)\n", iface, debugstr_dmguid(riid), ret_iface);
+
+    if (IsEqualIID(riid, &IID_IUnknown) ||
+        IsEqualIID(riid, &IID_IDirectMusicBuffer))
+    {
+        IDirectMusicBuffer_AddRef(iface);
+        *ret_iface = iface;
+        return S_OK;
+    }
+
+    *ret_iface = NULL;
+
+    WARN("(%p)->(%s, %p): not found\n", iface, debugstr_dmguid(riid), ret_iface);
+
+    return E_NOINTERFACE;
 }
 
-static ULONG WINAPI IDirectMusicBufferImpl_AddRef (LPDIRECTMUSICBUFFER iface) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       ULONG refCount = InterlockedIncrement(&This->ref);
+static ULONG WINAPI IDirectMusicBufferImpl_AddRef(LPDIRECTMUSICBUFFER iface)
+{
+    IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
 
-       TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
+    TRACE("(%p)->(): new ref = %u\n", iface, ref);
 
-       DMUSIC_LockModule();
+    DMUSIC_LockModule();
 
-       return refCount;
+    return ref;
 }
 
-static ULONG WINAPI IDirectMusicBufferImpl_Release (LPDIRECTMUSICBUFFER iface) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       ULONG refCount = InterlockedDecrement(&This->ref);
+static ULONG WINAPI IDirectMusicBufferImpl_Release(LPDIRECTMUSICBUFFER iface)
+{
+    IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
 
-       TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
+    TRACE("(%p)->(): new ref = %u\n", iface, ref);
 
-       if (!refCount) {
-               HeapFree(GetProcessHeap(), 0, This);
-       }
+    if (!ref) {
+        HeapFree(GetProcessHeap(), 0, This->data);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
 
-       DMUSIC_UnlockModule();
-       
-       return refCount;
+    DMUSIC_UnlockModule();
+
+    return ref;
 }
 
 /* IDirectMusicBufferImpl IDirectMusicBuffer part: */
-static HRESULT WINAPI IDirectMusicBufferImpl_Flush (LPDIRECTMUSICBUFFER iface) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       FIXME("(%p): stub\n", This);
-       return S_OK;
+static HRESULT WINAPI IDirectMusicBufferImpl_Flush(LPDIRECTMUSICBUFFER iface)
+{
+    IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
+
+    TRACE("(%p)->()\n", iface);
+
+    This->write_pos = 0;
+
+    return S_OK;
 }
 
-static HRESULT WINAPI IDirectMusicBufferImpl_TotalTime (LPDIRECTMUSICBUFFER iface, LPREFERENCE_TIME prtTime) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       FIXME("(%p, %p): stub\n", This, prtTime);       
-       return S_OK;
+static HRESULT WINAPI IDirectMusicBufferImpl_TotalTime(LPDIRECTMUSICBUFFER iface, LPREFERENCE_TIME prtTime)
+{
+    IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
+
+    FIXME("(%p, %p): stub\n", This, prtTime);
+
+    return S_OK;
 }
 
-static HRESULT WINAPI IDirectMusicBufferImpl_PackStructured (LPDIRECTMUSICBUFFER iface, REFERENCE_TIME rt, DWORD dwChannelGroup, DWORD dwChannelMessage) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       FIXME("(%p, 0x%s, %d, %d): stub\n", This, wine_dbgstr_longlong(rt), dwChannelGroup, dwChannelMessage);
-       return S_OK;
+static HRESULT WINAPI IDirectMusicBufferImpl_PackStructured(LPDIRECTMUSICBUFFER iface, REFERENCE_TIME ref_time, DWORD channel_group, DWORD channel_message)
+{
+    IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
+    DWORD new_write_pos = This->write_pos + sizeof(DMUS_EVENTHEADER) + sizeof(DWORD);
+    DMUS_EVENTHEADER header;
+
+    TRACE("(%p)->(0x%s, %u, 0x%x)\n", iface, wine_dbgstr_longlong(ref_time), channel_group, channel_message);
+
+    if (new_write_pos > This->size)
+        return DMUS_E_BUFFER_FULL;
+
+    /* Channel_message 0xZZYYXX (3 bytes) is a midi message where XX = status byte, YY = byte 1 and ZZ = byte 2 */
+
+    if (!(channel_message & 0x80))
+    {
+        /* Status byte MSB is always set */
+        return DMUS_E_INVALID_EVENT;
+    }
+
+    if (!This->write_pos)
+        This->start_time = ref_time;
+
+    header.cbEvent = 3; /* Midi message takes 4 bytes space but only 3 are relevant */
+    header.dwChannelGroup = channel_group;
+    header.rtDelta = ref_time - This->start_time;
+    header.dwFlags = DMUS_EVENT_STRUCTURED;
+
+    memcpy(This->data + This->write_pos, &header, sizeof(header));
+    *(DWORD*)(This->data + This->write_pos + sizeof(header)) = channel_message;
+    This->write_pos = new_write_pos;
+
+    return S_OK;
 }
 
-static HRESULT WINAPI IDirectMusicBufferImpl_PackUnstructured (LPDIRECTMUSICBUFFER iface, REFERENCE_TIME rt, DWORD dwChannelGroup, DWORD cb, LPBYTE lpb) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       FIXME("(%p, 0x%s, %d, %d, %p): stub\n", This, wine_dbgstr_longlong(rt), dwChannelGroup, cb, lpb);
-       return S_OK;
+static HRESULT WINAPI IDirectMusicBufferImpl_PackUnstructured(LPDIRECTMUSICBUFFER iface, REFERENCE_TIME rt, DWORD dwChannelGroup, DWORD cb, LPBYTE lpb)
+{
+    IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
+
+    FIXME("(%p, 0x%s, %d, %d, %p): stub\n", This, wine_dbgstr_longlong(rt), dwChannelGroup, cb, lpb);
+
+    return S_OK;
 }
 
-static HRESULT WINAPI IDirectMusicBufferImpl_ResetReadPtr (LPDIRECTMUSICBUFFER iface) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       FIXME("(%p): stub\n", This);
-       return S_OK;
+static HRESULT WINAPI IDirectMusicBufferImpl_ResetReadPtr(LPDIRECTMUSICBUFFER iface)
+{
+    IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
+
+    FIXME("(%p): stub\n", This);
+
+    return S_OK;
 }
 
-static HRESULT WINAPI IDirectMusicBufferImpl_GetNextEvent (LPDIRECTMUSICBUFFER iface, LPREFERENCE_TIME prt, LPDWORD pdwChannelGroup, LPDWORD pdwLength, LPBYTE* ppData) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       FIXME("(%p, %p, %p, %p, %p): stub\n", This, prt, pdwChannelGroup, pdwLength, ppData);
-       return S_OK;
+static HRESULT WINAPI IDirectMusicBufferImpl_GetNextEvent(LPDIRECTMUSICBUFFER iface, LPREFERENCE_TIME prt, LPDWORD pdwChannelGroup, LPDWORD pdwLength, LPBYTE* ppData)
+{
+    IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
+
+    FIXME("(%p, %p, %p, %p, %p): stub\n", This, prt, pdwChannelGroup, pdwLength, ppData);
+
+    return S_OK;
 }
 
-static HRESULT WINAPI IDirectMusicBufferImpl_GetRawBufferPtr (LPDIRECTMUSICBUFFER iface, LPBYTE* ppData) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       FIXME("(%p, %p): stub\n", This, ppData);
-       return S_OK;
+static HRESULT WINAPI IDirectMusicBufferImpl_GetRawBufferPtr(LPDIRECTMUSICBUFFER iface, LPBYTE* data)
+{
+    IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
+
+    TRACE("(%p)->(%p)\n", iface, data);
+
+    if (!data)
+        return E_POINTER;
+
+    *data = This->data;
+
+    return S_OK;
 }
 
-static HRESULT WINAPI IDirectMusicBufferImpl_GetStartTime (LPDIRECTMUSICBUFFER iface, LPREFERENCE_TIME prt) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       FIXME("(%p, %p): stub\n", This, prt);
-       return S_OK;
+static HRESULT WINAPI IDirectMusicBufferImpl_GetStartTime(LPDIRECTMUSICBUFFER iface, LPREFERENCE_TIME ref_time)
+{
+    IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
+
+    TRACE("(%p)->(%p)\n", iface, ref_time);
+
+    if (!ref_time)
+        return E_POINTER;
+    if (!This->write_pos)
+        return DMUS_E_BUFFER_EMPTY;
+
+    *ref_time = This->start_time;
+
+    return S_OK;
 }
 
-static HRESULT WINAPI IDirectMusicBufferImpl_GetUsedBytes (LPDIRECTMUSICBUFFER iface, LPDWORD pcb) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       FIXME("(%p, %p): stub\n", This, pcb);
-       return S_OK;
+static HRESULT WINAPI IDirectMusicBufferImpl_GetUsedBytes(LPDIRECTMUSICBUFFER iface, LPDWORD used_bytes)
+{
+    IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
+
+    TRACE("(%p)->(%p)\n", iface, used_bytes);
+
+    if (!used_bytes)
+        return E_POINTER;
+
+    *used_bytes = This->write_pos;
+
+    return S_OK;
 }
 
-static HRESULT WINAPI IDirectMusicBufferImpl_GetMaxBytes (LPDIRECTMUSICBUFFER iface, LPDWORD pcb) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       FIXME("(%p, %p): stub\n", This, pcb);
-       return S_OK;
+static HRESULT WINAPI IDirectMusicBufferImpl_GetMaxBytes(LPDIRECTMUSICBUFFER iface, LPDWORD max_bytes)
+{
+    IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
+
+    TRACE("(%p)->(%p)\n", iface, max_bytes);
+
+    if (!max_bytes)
+        return E_POINTER;
+
+    *max_bytes = This->size;
+
+    return S_OK;
 }
 
-static HRESULT WINAPI IDirectMusicBufferImpl_GetBufferFormat (LPDIRECTMUSICBUFFER iface, LPGUID pGuidFormat) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       FIXME("(%p, %p): stub\n", This, pGuidFormat);
-       return S_OK;
+static HRESULT WINAPI IDirectMusicBufferImpl_GetBufferFormat(LPDIRECTMUSICBUFFER iface, LPGUID format)
+{
+    IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
+
+    TRACE("(%p)->(%p)\n", iface, format);
+
+    if (!format)
+        return E_POINTER;
+
+    *format = This->format;
+    return S_OK;
 }
 
-static HRESULT WINAPI IDirectMusicBufferImpl_SetStartTime (LPDIRECTMUSICBUFFER iface, REFERENCE_TIME rt) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       FIXME("(%p, 0x%s): stub\n", This, wine_dbgstr_longlong(rt));
-       return S_OK;
+static HRESULT WINAPI IDirectMusicBufferImpl_SetStartTime(LPDIRECTMUSICBUFFER iface, REFERENCE_TIME ref_time)
+{
+    IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
+
+    TRACE("(%p)->(0x%s)\n", This, wine_dbgstr_longlong(ref_time));
+
+    This->start_time = ref_time;
+
+    return S_OK;
 }
 
-static HRESULT WINAPI IDirectMusicBufferImpl_SetUsedBytes (LPDIRECTMUSICBUFFER iface, DWORD cb) {
-       IDirectMusicBufferImpl *This = (IDirectMusicBufferImpl *)iface;
-       FIXME("(%p, %d): stub\n", This, cb);
-       return S_OK;
+static HRESULT WINAPI IDirectMusicBufferImpl_SetUsedBytes(LPDIRECTMUSICBUFFER iface, DWORD used_bytes)
+{
+    IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
+
+    TRACE("(%p)->(%u)\n", iface, used_bytes);
+
+    if (used_bytes > This->size)
+        return DMUS_E_BUFFER_FULL;
+
+    This->write_pos = used_bytes;
+
+    return S_OK;
 }
 
 static const IDirectMusicBufferVtbl DirectMusicBuffer_Vtbl = {
@@ -159,17 +276,40 @@ static const IDirectMusicBufferVtbl DirectMusicBuffer_Vtbl = {
        IDirectMusicBufferImpl_SetUsedBytes
 };
 
-/* for ClassFactory */
-HRESULT WINAPI DMUSIC_CreateDirectMusicBufferImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) {
-       IDirectMusicBufferImpl* dmbuff;
-       
-       dmbuff = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicBufferImpl));
-       if (NULL == dmbuff) {
-               *ppobj = NULL;
-               return E_OUTOFMEMORY;
-       }
-       dmbuff->lpVtbl = &DirectMusicBuffer_Vtbl;
-       dmbuff->ref = 0; /* will be inited by QueryInterface */
-       
-       return IDirectMusicBufferImpl_QueryInterface ((LPDIRECTMUSICBUFFER)dmbuff, lpcGUID, ppobj);
+HRESULT DMUSIC_CreateDirectMusicBufferImpl(LPDMUS_BUFFERDESC desc, LPVOID* ret_iface)
+{
+    IDirectMusicBufferImpl* dmbuffer;
+    HRESULT hr;
+
+    TRACE("(%p, %p)\n", desc, ret_iface);
+
+    *ret_iface = NULL;
+
+    dmbuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicBufferImpl));
+    if (!dmbuffer)
+        return E_OUTOFMEMORY;
+
+    dmbuffer->IDirectMusicBuffer_iface.lpVtbl = &DirectMusicBuffer_Vtbl;
+    dmbuffer->ref = 0; /* Will be inited by QueryInterface */
+
+    if (IsEqualGUID(&desc->guidBufferFormat, &GUID_NULL))
+        dmbuffer->format = KSDATAFORMAT_SUBTYPE_MIDI;
+    else
+        dmbuffer->format = desc->guidBufferFormat;
+    dmbuffer->size = (desc->cbBuffer + 3) & ~3; /* Buffer size must be multiple of 4 bytes */
+
+    dmbuffer->data = HeapAlloc(GetProcessHeap(), 0, dmbuffer->size);
+    if (!dmbuffer->data) {
+        HeapFree(GetProcessHeap(), 0, dmbuffer);
+        return E_OUTOFMEMORY;
+    }
+
+    hr = IDirectMusicBufferImpl_QueryInterface((LPDIRECTMUSICBUFFER)dmbuffer, &IID_IDirectMusicBuffer, ret_iface);
+    if (FAILED(hr))
+    {
+        HeapFree(GetProcessHeap(), 0, dmbuffer->data);
+        HeapFree(GetProcessHeap(), 0, dmbuffer);
+    }
+
+    return hr;
 }