dmusic: Implement IDirectMusicBufferImpl_PackStructured.
[wine] / dlls / dmusic / buffer.c
1 /* IDirectMusicBuffer Implementation
2  *
3  * Copyright (C) 2003-2004 Rok Mandeljc
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include "dmusic_private.h"
21 #include "initguid.h"
22 #include "dmksctrl.h"
23
24 WINE_DEFAULT_DEBUG_CHANNEL(dmusic);
25
26 static inline IDirectMusicBufferImpl *impl_from_IDirectMusicBuffer(IDirectMusicBuffer *iface)
27 {
28     return CONTAINING_RECORD(iface, IDirectMusicBufferImpl, IDirectMusicBuffer_iface);
29 }
30
31 /* IDirectMusicBufferImpl IUnknown part: */
32 static HRESULT WINAPI IDirectMusicBufferImpl_QueryInterface(LPDIRECTMUSICBUFFER iface, REFIID riid, LPVOID *ret_iface)
33 {
34     TRACE("(%p)->(%s, %p)\n", iface, debugstr_dmguid(riid), ret_iface);
35
36     if (IsEqualIID(riid, &IID_IUnknown) ||
37         IsEqualIID(riid, &IID_IDirectMusicBuffer))
38     {
39         IDirectMusicBuffer_AddRef(iface);
40         *ret_iface = iface;
41         return S_OK;
42     }
43
44     *ret_iface = NULL;
45
46     WARN("(%p)->(%s, %p): not found\n", iface, debugstr_dmguid(riid), ret_iface);
47
48     return E_NOINTERFACE;
49 }
50
51 static ULONG WINAPI IDirectMusicBufferImpl_AddRef(LPDIRECTMUSICBUFFER iface)
52 {
53     IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
54     ULONG ref = InterlockedIncrement(&This->ref);
55
56     TRACE("(%p)->(): new ref = %u\n", iface, ref);
57
58     DMUSIC_LockModule();
59
60     return ref;
61 }
62
63 static ULONG WINAPI IDirectMusicBufferImpl_Release(LPDIRECTMUSICBUFFER iface)
64 {
65     IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
66     ULONG ref = InterlockedDecrement(&This->ref);
67
68     TRACE("(%p)->(): new ref = %u\n", iface, ref);
69
70     if (!ref) {
71         HeapFree(GetProcessHeap(), 0, This->data);
72         HeapFree(GetProcessHeap(), 0, This);
73     }
74
75     DMUSIC_UnlockModule();
76
77     return ref;
78 }
79
80 /* IDirectMusicBufferImpl IDirectMusicBuffer part: */
81 static HRESULT WINAPI IDirectMusicBufferImpl_Flush(LPDIRECTMUSICBUFFER iface)
82 {
83     IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
84
85     FIXME("(%p): stub\n", This);
86
87     return S_OK;
88 }
89
90 static HRESULT WINAPI IDirectMusicBufferImpl_TotalTime(LPDIRECTMUSICBUFFER iface, LPREFERENCE_TIME prtTime)
91 {
92     IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
93
94     FIXME("(%p, %p): stub\n", This, prtTime);
95
96     return S_OK;
97 }
98
99 static HRESULT WINAPI IDirectMusicBufferImpl_PackStructured(LPDIRECTMUSICBUFFER iface, REFERENCE_TIME ref_time, DWORD channel_group, DWORD channel_message)
100 {
101     IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
102     DWORD new_write_pos = This->write_pos + sizeof(DMUS_EVENTHEADER) + sizeof(DWORD);
103     DMUS_EVENTHEADER header;
104
105     TRACE("(%p)->(0x%s, %u, 0x%x)\n", iface, wine_dbgstr_longlong(ref_time), channel_group, channel_message);
106
107     if (new_write_pos > This->size)
108         return DMUS_E_BUFFER_FULL;
109
110     /* Channel_message 0xZZYYXX is a midi message where XX = status byte, YY = byte 1 and ZZ = byte 2 */
111
112     if (!(channel_message & 0x80))
113     {
114         /* Status byte MSB is always set */
115         return DMUS_E_INVALID_EVENT;
116     }
117
118     header.cbEvent = sizeof(channel_message);
119     header.dwChannelGroup = channel_group;
120     header.rtDelta = ref_time;
121     header.dwFlags = DMUS_EVENT_STRUCTURED;
122
123     memcpy(This->data + This->write_pos, &header, sizeof(header));
124     *(DWORD*)(This->data + This->write_pos + sizeof(header)) = channel_message;
125     This->write_pos = new_write_pos;
126
127     return S_OK;
128 }
129
130 static HRESULT WINAPI IDirectMusicBufferImpl_PackUnstructured(LPDIRECTMUSICBUFFER iface, REFERENCE_TIME rt, DWORD dwChannelGroup, DWORD cb, LPBYTE lpb)
131 {
132     IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
133
134     FIXME("(%p, 0x%s, %d, %d, %p): stub\n", This, wine_dbgstr_longlong(rt), dwChannelGroup, cb, lpb);
135
136     return S_OK;
137 }
138
139 static HRESULT WINAPI IDirectMusicBufferImpl_ResetReadPtr(LPDIRECTMUSICBUFFER iface)
140 {
141     IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
142
143     FIXME("(%p): stub\n", This);
144
145     return S_OK;
146 }
147
148 static HRESULT WINAPI IDirectMusicBufferImpl_GetNextEvent(LPDIRECTMUSICBUFFER iface, LPREFERENCE_TIME prt, LPDWORD pdwChannelGroup, LPDWORD pdwLength, LPBYTE* ppData)
149 {
150     IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
151
152     FIXME("(%p, %p, %p, %p, %p): stub\n", This, prt, pdwChannelGroup, pdwLength, ppData);
153
154     return S_OK;
155 }
156
157 static HRESULT WINAPI IDirectMusicBufferImpl_GetRawBufferPtr(LPDIRECTMUSICBUFFER iface, LPBYTE* data)
158 {
159     IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
160
161     TRACE("(%p)->(%p)\n", iface, data);
162
163     if (!data)
164         return E_POINTER;
165
166     *data = This->data;
167
168     return S_OK;
169 }
170
171 static HRESULT WINAPI IDirectMusicBufferImpl_GetStartTime(LPDIRECTMUSICBUFFER iface, LPREFERENCE_TIME prt)
172 {
173     IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
174
175     FIXME("(%p, %p): stub\n", This, prt);
176
177     return S_OK;
178 }
179
180 static HRESULT WINAPI IDirectMusicBufferImpl_GetUsedBytes(LPDIRECTMUSICBUFFER iface, LPDWORD pcb)
181 {
182     IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
183
184     FIXME("(%p, %p): stub\n", This, pcb);
185
186     return S_OK;
187 }
188
189 static HRESULT WINAPI IDirectMusicBufferImpl_GetMaxBytes(LPDIRECTMUSICBUFFER iface, LPDWORD max_bytes)
190 {
191     IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
192
193     TRACE("(%p)->(%p)\n", iface, max_bytes);
194
195     if (!max_bytes)
196         return E_POINTER;
197
198     *max_bytes = This->size;
199
200     return S_OK;
201 }
202
203 static HRESULT WINAPI IDirectMusicBufferImpl_GetBufferFormat(LPDIRECTMUSICBUFFER iface, LPGUID format)
204 {
205     IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
206
207     TRACE("(%p)->(%p)\n", iface, format);
208
209     if (!format)
210         return E_POINTER;
211
212     *format = This->format;
213     return S_OK;
214 }
215
216 static HRESULT WINAPI IDirectMusicBufferImpl_SetStartTime(LPDIRECTMUSICBUFFER iface, REFERENCE_TIME rt)
217 {
218     IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
219
220     FIXME("(%p, 0x%s): stub\n", This, wine_dbgstr_longlong(rt));
221
222     return S_OK;
223 }
224
225 static HRESULT WINAPI IDirectMusicBufferImpl_SetUsedBytes (LPDIRECTMUSICBUFFER iface, DWORD cb)
226 {
227     IDirectMusicBufferImpl *This = impl_from_IDirectMusicBuffer(iface);
228
229     FIXME("(%p, %d): stub\n", This, cb);
230
231     return S_OK;
232 }
233
234 static const IDirectMusicBufferVtbl DirectMusicBuffer_Vtbl = {
235         IDirectMusicBufferImpl_QueryInterface,
236         IDirectMusicBufferImpl_AddRef,
237         IDirectMusicBufferImpl_Release,
238         IDirectMusicBufferImpl_Flush,
239         IDirectMusicBufferImpl_TotalTime,
240         IDirectMusicBufferImpl_PackStructured,
241         IDirectMusicBufferImpl_PackUnstructured,
242         IDirectMusicBufferImpl_ResetReadPtr,
243         IDirectMusicBufferImpl_GetNextEvent,
244         IDirectMusicBufferImpl_GetRawBufferPtr,
245         IDirectMusicBufferImpl_GetStartTime,
246         IDirectMusicBufferImpl_GetUsedBytes,
247         IDirectMusicBufferImpl_GetMaxBytes,
248         IDirectMusicBufferImpl_GetBufferFormat,
249         IDirectMusicBufferImpl_SetStartTime,
250         IDirectMusicBufferImpl_SetUsedBytes
251 };
252
253 HRESULT DMUSIC_CreateDirectMusicBufferImpl(LPDMUS_BUFFERDESC desc, LPVOID* ret_iface)
254 {
255     IDirectMusicBufferImpl* dmbuffer;
256     HRESULT hr;
257
258     TRACE("(%p, %p)\n", desc, ret_iface);
259
260     *ret_iface = NULL;
261
262     dmbuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicBufferImpl));
263     if (!dmbuffer)
264         return E_OUTOFMEMORY;
265
266     dmbuffer->IDirectMusicBuffer_iface.lpVtbl = &DirectMusicBuffer_Vtbl;
267     dmbuffer->ref = 0; /* Will be inited by QueryInterface */
268
269     if (IsEqualGUID(&desc->guidBufferFormat, &GUID_NULL))
270         dmbuffer->format = KSDATAFORMAT_SUBTYPE_MIDI;
271     else
272         dmbuffer->format = desc->guidBufferFormat;
273     dmbuffer->size = (desc->cbBuffer + 3) & ~3; /* Buffer size must be multiple of 4 bytes */
274
275     dmbuffer->data = HeapAlloc(GetProcessHeap(), 0, dmbuffer->size);
276     if (!dmbuffer->data) {
277         HeapFree(GetProcessHeap(), 0, dmbuffer);
278         return E_OUTOFMEMORY;
279     }
280
281     hr = IDirectMusicBufferImpl_QueryInterface((LPDIRECTMUSICBUFFER)dmbuffer, &IID_IDirectMusicBuffer, ret_iface);
282     if (FAILED(hr))
283     {
284         HeapFree(GetProcessHeap(), 0, dmbuffer->data);
285         HeapFree(GetProcessHeap(), 0, dmbuffer);
286     }
287
288     return hr;
289 }