2 * IDirectMusicBuffer Implementation
4 * Copyright (C) 2003-2004 Rok Mandeljc
5 * Copyright (C) 2012 Christian Costa
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.
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.
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
22 #include "dmusic_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dmusic
);
28 static inline IDirectMusicBufferImpl
*impl_from_IDirectMusicBuffer(IDirectMusicBuffer
*iface
)
30 return CONTAINING_RECORD(iface
, IDirectMusicBufferImpl
, IDirectMusicBuffer_iface
);
33 /* IDirectMusicBufferImpl IUnknown part: */
34 static HRESULT WINAPI
IDirectMusicBufferImpl_QueryInterface(LPDIRECTMUSICBUFFER iface
, REFIID riid
, LPVOID
*ret_iface
)
36 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_dmguid(riid
), ret_iface
);
38 if (IsEqualIID(riid
, &IID_IUnknown
) ||
39 IsEqualIID(riid
, &IID_IDirectMusicBuffer
))
41 IDirectMusicBuffer_AddRef(iface
);
48 WARN("(%p)->(%s, %p): not found\n", iface
, debugstr_dmguid(riid
), ret_iface
);
53 static ULONG WINAPI
IDirectMusicBufferImpl_AddRef(LPDIRECTMUSICBUFFER iface
)
55 IDirectMusicBufferImpl
*This
= impl_from_IDirectMusicBuffer(iface
);
56 ULONG ref
= InterlockedIncrement(&This
->ref
);
58 TRACE("(%p)->(): new ref = %u\n", iface
, ref
);
63 static ULONG WINAPI
IDirectMusicBufferImpl_Release(LPDIRECTMUSICBUFFER iface
)
65 IDirectMusicBufferImpl
*This
= impl_from_IDirectMusicBuffer(iface
);
66 ULONG ref
= InterlockedDecrement(&This
->ref
);
68 TRACE("(%p)->(): new ref = %u\n", iface
, ref
);
71 HeapFree(GetProcessHeap(), 0, This
->data
);
72 HeapFree(GetProcessHeap(), 0, This
);
73 DMUSIC_UnlockModule();
79 /* IDirectMusicBufferImpl IDirectMusicBuffer part: */
80 static HRESULT WINAPI
IDirectMusicBufferImpl_Flush(LPDIRECTMUSICBUFFER iface
)
82 IDirectMusicBufferImpl
*This
= impl_from_IDirectMusicBuffer(iface
);
84 TRACE("(%p)->()\n", iface
);
91 static HRESULT WINAPI
IDirectMusicBufferImpl_TotalTime(LPDIRECTMUSICBUFFER iface
, LPREFERENCE_TIME prtTime
)
93 IDirectMusicBufferImpl
*This
= impl_from_IDirectMusicBuffer(iface
);
95 FIXME("(%p, %p): stub\n", This
, prtTime
);
100 static HRESULT WINAPI
IDirectMusicBufferImpl_PackStructured(LPDIRECTMUSICBUFFER iface
, REFERENCE_TIME ref_time
, DWORD channel_group
, DWORD channel_message
)
102 IDirectMusicBufferImpl
*This
= impl_from_IDirectMusicBuffer(iface
);
103 DWORD new_write_pos
= This
->write_pos
+ DMUS_EVENT_SIZE(sizeof(channel_message
));
104 DMUS_EVENTHEADER
*header
;
106 TRACE("(%p)->(0x%s, %u, 0x%x)\n", iface
, wine_dbgstr_longlong(ref_time
), channel_group
, channel_message
);
108 if (new_write_pos
> This
->size
)
109 return DMUS_E_BUFFER_FULL
;
111 /* Channel_message 0xZZYYXX (3 bytes) is a midi message where XX = status byte, YY = byte 1 and ZZ = byte 2 */
113 if (!(channel_message
& 0x80))
115 /* Status byte MSB is always set */
116 return DMUS_E_INVALID_EVENT
;
119 if (!This
->write_pos
)
120 This
->start_time
= ref_time
;
122 header
= (DMUS_EVENTHEADER
*)&This
->data
[This
->write_pos
];
123 header
->cbEvent
= 3; /* Midi message takes 4 bytes space but only 3 are relevant */
124 header
->dwChannelGroup
= channel_group
;
125 header
->rtDelta
= ref_time
- This
->start_time
;
126 header
->dwFlags
= DMUS_EVENT_STRUCTURED
;
128 *(DWORD
*)&header
[1] = channel_message
;
129 This
->write_pos
= new_write_pos
;
134 static HRESULT WINAPI
IDirectMusicBufferImpl_PackUnstructured(IDirectMusicBuffer
*iface
,
135 REFERENCE_TIME ref_time
, DWORD channel_group
, DWORD len
, BYTE
*data
)
137 IDirectMusicBufferImpl
*This
= impl_from_IDirectMusicBuffer(iface
);
138 DWORD new_write_pos
= This
->write_pos
+ DMUS_EVENT_SIZE(len
);
139 DMUS_EVENTHEADER
*header
;
141 TRACE("(%p, 0x%s, %d, %d, %p)\n", This
, wine_dbgstr_longlong(ref_time
), channel_group
, len
, data
);
143 if (new_write_pos
> This
->size
)
144 return DMUS_E_BUFFER_FULL
;
146 if (!This
->write_pos
)
147 This
->start_time
= ref_time
;
149 header
= (DMUS_EVENTHEADER
*)&This
->data
[This
->write_pos
];
150 header
->cbEvent
= len
;
151 header
->dwChannelGroup
= channel_group
;
152 header
->rtDelta
= ref_time
- This
->start_time
;
155 memcpy(&header
[1], data
, len
);
156 This
->write_pos
= new_write_pos
;
161 static HRESULT WINAPI
IDirectMusicBufferImpl_ResetReadPtr(LPDIRECTMUSICBUFFER iface
)
163 IDirectMusicBufferImpl
*This
= impl_from_IDirectMusicBuffer(iface
);
165 FIXME("(%p): stub\n", This
);
170 static HRESULT WINAPI
IDirectMusicBufferImpl_GetNextEvent(LPDIRECTMUSICBUFFER iface
, LPREFERENCE_TIME prt
, LPDWORD pdwChannelGroup
, LPDWORD pdwLength
, LPBYTE
* ppData
)
172 IDirectMusicBufferImpl
*This
= impl_from_IDirectMusicBuffer(iface
);
174 FIXME("(%p, %p, %p, %p, %p): stub\n", This
, prt
, pdwChannelGroup
, pdwLength
, ppData
);
179 static HRESULT WINAPI
IDirectMusicBufferImpl_GetRawBufferPtr(LPDIRECTMUSICBUFFER iface
, LPBYTE
* data
)
181 IDirectMusicBufferImpl
*This
= impl_from_IDirectMusicBuffer(iface
);
183 TRACE("(%p)->(%p)\n", iface
, data
);
193 static HRESULT WINAPI
IDirectMusicBufferImpl_GetStartTime(LPDIRECTMUSICBUFFER iface
, LPREFERENCE_TIME ref_time
)
195 IDirectMusicBufferImpl
*This
= impl_from_IDirectMusicBuffer(iface
);
197 TRACE("(%p)->(%p)\n", iface
, ref_time
);
201 if (!This
->write_pos
)
202 return DMUS_E_BUFFER_EMPTY
;
204 *ref_time
= This
->start_time
;
209 static HRESULT WINAPI
IDirectMusicBufferImpl_GetUsedBytes(LPDIRECTMUSICBUFFER iface
, LPDWORD used_bytes
)
211 IDirectMusicBufferImpl
*This
= impl_from_IDirectMusicBuffer(iface
);
213 TRACE("(%p)->(%p)\n", iface
, used_bytes
);
218 *used_bytes
= This
->write_pos
;
223 static HRESULT WINAPI
IDirectMusicBufferImpl_GetMaxBytes(LPDIRECTMUSICBUFFER iface
, LPDWORD max_bytes
)
225 IDirectMusicBufferImpl
*This
= impl_from_IDirectMusicBuffer(iface
);
227 TRACE("(%p)->(%p)\n", iface
, max_bytes
);
232 *max_bytes
= This
->size
;
237 static HRESULT WINAPI
IDirectMusicBufferImpl_GetBufferFormat(LPDIRECTMUSICBUFFER iface
, LPGUID format
)
239 IDirectMusicBufferImpl
*This
= impl_from_IDirectMusicBuffer(iface
);
241 TRACE("(%p)->(%p)\n", iface
, format
);
246 *format
= This
->format
;
250 static HRESULT WINAPI
IDirectMusicBufferImpl_SetStartTime(LPDIRECTMUSICBUFFER iface
, REFERENCE_TIME ref_time
)
252 IDirectMusicBufferImpl
*This
= impl_from_IDirectMusicBuffer(iface
);
254 TRACE("(%p)->(0x%s)\n", This
, wine_dbgstr_longlong(ref_time
));
256 This
->start_time
= ref_time
;
261 static HRESULT WINAPI
IDirectMusicBufferImpl_SetUsedBytes(LPDIRECTMUSICBUFFER iface
, DWORD used_bytes
)
263 IDirectMusicBufferImpl
*This
= impl_from_IDirectMusicBuffer(iface
);
265 TRACE("(%p)->(%u)\n", iface
, used_bytes
);
267 if (used_bytes
> This
->size
)
268 return DMUS_E_BUFFER_FULL
;
270 This
->write_pos
= used_bytes
;
275 static const IDirectMusicBufferVtbl DirectMusicBuffer_Vtbl
= {
276 IDirectMusicBufferImpl_QueryInterface
,
277 IDirectMusicBufferImpl_AddRef
,
278 IDirectMusicBufferImpl_Release
,
279 IDirectMusicBufferImpl_Flush
,
280 IDirectMusicBufferImpl_TotalTime
,
281 IDirectMusicBufferImpl_PackStructured
,
282 IDirectMusicBufferImpl_PackUnstructured
,
283 IDirectMusicBufferImpl_ResetReadPtr
,
284 IDirectMusicBufferImpl_GetNextEvent
,
285 IDirectMusicBufferImpl_GetRawBufferPtr
,
286 IDirectMusicBufferImpl_GetStartTime
,
287 IDirectMusicBufferImpl_GetUsedBytes
,
288 IDirectMusicBufferImpl_GetMaxBytes
,
289 IDirectMusicBufferImpl_GetBufferFormat
,
290 IDirectMusicBufferImpl_SetStartTime
,
291 IDirectMusicBufferImpl_SetUsedBytes
294 HRESULT
DMUSIC_CreateDirectMusicBufferImpl(LPDMUS_BUFFERDESC desc
, LPVOID
* ret_iface
)
296 IDirectMusicBufferImpl
* dmbuffer
;
298 TRACE("(%p, %p)\n", desc
, ret_iface
);
302 dmbuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IDirectMusicBufferImpl
));
304 return E_OUTOFMEMORY
;
306 dmbuffer
->IDirectMusicBuffer_iface
.lpVtbl
= &DirectMusicBuffer_Vtbl
;
309 if (IsEqualGUID(&desc
->guidBufferFormat
, &GUID_NULL
))
310 dmbuffer
->format
= KSDATAFORMAT_SUBTYPE_MIDI
;
312 dmbuffer
->format
= desc
->guidBufferFormat
;
313 dmbuffer
->size
= (desc
->cbBuffer
+ 3) & ~3; /* Buffer size must be multiple of 4 bytes */
315 dmbuffer
->data
= HeapAlloc(GetProcessHeap(), 0, dmbuffer
->size
);
316 if (!dmbuffer
->data
) {
317 HeapFree(GetProcessHeap(), 0, dmbuffer
);
318 return E_OUTOFMEMORY
;
322 *ret_iface
= &dmbuffer
->IDirectMusicBuffer_iface
;