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