instrument.c 17.8 KB
Newer Older
1 2
/* IDirectMusicInstrument Implementation
 *
3
 * Copyright (C) 2003-2004 Rok Mandeljc
4
 *
5 6 7 8
 * 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.
9 10 11
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
14
 *
15 16 17
 * 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
18 19 20 21 22
 */

#include "dmusic_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(dmusic);
23
WINE_DECLARE_DEBUG_CHANNEL(dmfile);
24

25
static const GUID IID_IDirectMusicInstrumentPRIVATE = {0xbcb20080,0xa40c,0x11d1,{0x86,0xbc,0x00,0xc0,0x4f,0xbf,0x8f,0xef}};
26

27 28 29
static ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_AddRef (LPUNKNOWN iface);
static ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef (LPDIRECTMUSICINSTRUMENT iface);

30
/* IDirectMusicInstrument IUnknown part: */
31
static HRESULT WINAPI IDirectMusicInstrumentImpl_IUnknown_QueryInterface (LPUNKNOWN iface, REFIID riid, LPVOID *ppobj) {
32
	ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
33
	TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
34 35
	
	if (IsEqualIID (riid, &IID_IUnknown)) {
36
		*ppobj = &This->UnknownVtbl;
37 38 39
		IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
		return S_OK;	
	} else if (IsEqualIID (riid, &IID_IDirectMusicInstrument)) {
40
		*ppobj = &This->InstrumentVtbl;
41
		IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef ((LPDIRECTMUSICINSTRUMENT)&This->InstrumentVtbl);
42
		return S_OK;
43 44 45 46 47 48
	} else if (IsEqualIID (riid, &IID_IDirectMusicInstrumentPRIVATE)) {	
		/* it seems to me that this interface is only basic IUnknown, without any
			other inherited functions... *sigh* this is the worst scenario, since it means 
			that whoever calls it knows the layout of original implementation table and therefore
			tries to get data by direct access... expect crashes */
		FIXME("*sigh*... requested private/unspecified interface\n");
49
		*ppobj = &This->UnknownVtbl;
50 51
		IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
		return S_OK;	
52
	}
53
	
54
	WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ppobj);
55 56 57
	return E_NOINTERFACE;
}

58
static ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_AddRef (LPUNKNOWN iface) {
59
	ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
60 61
	ULONG refCount = InterlockedIncrement(&This->ref);

62
	TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
63

64 65
	DMUSIC_LockModule();

66
	return refCount;
67 68
}

69
static ULONG WINAPI IDirectMusicInstrumentImpl_IUnknown_Release (LPUNKNOWN iface) {
70
	ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, UnknownVtbl, iface);
71 72
	ULONG refCount = InterlockedDecrement(&This->ref);

73
	TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
74 75

	if (!refCount) {
76 77
		HeapFree(GetProcessHeap(), 0, This);
	}
78 79 80

	DMUSIC_UnlockModule();
	
81
	return refCount;
82 83
}

84
static const IUnknownVtbl DirectMusicInstrument_Unknown_Vtbl = {
85 86 87 88 89 90
	IDirectMusicInstrumentImpl_IUnknown_QueryInterface,
	IDirectMusicInstrumentImpl_IUnknown_AddRef,
	IDirectMusicInstrumentImpl_IUnknown_Release
};

/* IDirectMusicInstrumentImpl IDirectMusicInstrument part: */
91
static HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_QueryInterface (LPDIRECTMUSICINSTRUMENT iface, REFIID riid, LPVOID *ppobj) {
92 93 94
	ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
	return IDirectMusicInstrumentImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
}
95

96
static ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef (LPDIRECTMUSICINSTRUMENT iface) {
97 98
	ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
	return IDirectMusicInstrumentImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
99 100
}

101
static ULONG WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_Release (LPDIRECTMUSICINSTRUMENT iface) {
102 103 104
	ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
	return IDirectMusicInstrumentImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
}
105

106
static HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_GetPatch (LPDIRECTMUSICINSTRUMENT iface, DWORD* pdwPatch) {
107 108 109 110 111
	ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
	TRACE("(%p, %p)\n", This, pdwPatch);	
	*pdwPatch = MIDILOCALE2Patch(&This->pHeader->Locale);
	return S_OK;
}
112

113
static HRESULT WINAPI IDirectMusicInstrumentImpl_IDirectMusicInstrument_SetPatch (LPDIRECTMUSICINSTRUMENT iface, DWORD dwPatch) {
114
	ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
115
	TRACE("(%p, %d): stub\n", This, dwPatch);
116
	Patch2MIDILOCALE(dwPatch, &This->pHeader->Locale);
117 118 119
	return S_OK;
}

120
static const IDirectMusicInstrumentVtbl DirectMusicInstrument_Instrument_Vtbl = {
121 122 123 124 125
	IDirectMusicInstrumentImpl_IDirectMusicInstrument_QueryInterface,
	IDirectMusicInstrumentImpl_IDirectMusicInstrument_AddRef,
	IDirectMusicInstrumentImpl_IDirectMusicInstrument_Release,
	IDirectMusicInstrumentImpl_IDirectMusicInstrument_GetPatch,
	IDirectMusicInstrumentImpl_IDirectMusicInstrument_SetPatch
126 127 128
};

/* for ClassFactory */
129 130 131 132 133
HRESULT WINAPI DMUSIC_CreateDirectMusicInstrumentImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) {
	IDirectMusicInstrumentImpl* dminst;
	
	dminst = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicInstrumentImpl));
	if (NULL == dminst) {
134
		*ppobj = NULL;
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
		return E_OUTOFMEMORY;
	}
	dminst->UnknownVtbl = &DirectMusicInstrument_Unknown_Vtbl;
	dminst->InstrumentVtbl = &DirectMusicInstrument_Instrument_Vtbl;
	dminst->ref = 0; /* will be inited by QueryInterface */
	
	return IDirectMusicInstrumentImpl_IUnknown_QueryInterface ((LPUNKNOWN)&dminst->UnknownVtbl, lpcGUID, ppobj);
}

/* aux. function that completely loads instrument; my tests indicate that it's 
   called somewhere around IDirectMusicCollection_GetInstrument */
HRESULT WINAPI IDirectMusicInstrumentImpl_Custom_Load (LPDIRECTMUSICINSTRUMENT iface, LPSTREAM pStm) {
	ICOM_THIS_MULTI(IDirectMusicInstrumentImpl, InstrumentVtbl, iface);
	
	DMUS_PRIVATE_CHUNK Chunk;
	DWORD ListSize[4], ListCount[4];
	LARGE_INTEGER liMove; /* used when skipping chunks */
	
153
	TRACE("(%p, %p, offset = %s)\n", This, pStm, wine_dbgstr_longlong(This->liInstrumentPosition.QuadPart));
154 155 156 157 158

	/* goto the beginning of chunk */
	IStream_Seek (pStm, This->liInstrumentPosition, STREAM_SEEK_SET, NULL);
	
	IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
159
	TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
160 161 162 163 164 165 166 167 168 169 170 171
	switch (Chunk.fccID) {
		case FOURCC_LIST: {
			IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);				
			TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
			ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
			ListCount[0] = 0;
			switch (Chunk.fccID) {
				case FOURCC_INS: {
					TRACE_(dmfile)(": instrument list\n");
					do {
						IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
						ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
172
						TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
						switch (Chunk.fccID) {
							case FOURCC_INSH: {
								TRACE_(dmfile)(": instrument header chunk\n");
								/* should be already initialised */
								IStream_Read (pStm, This->pHeader, Chunk.dwSize, NULL);
								break;	
							}
							case FOURCC_DLID: {
								TRACE_(dmfile)(": DLID (GUID) chunk\n");
								/* should be already initialised */
								IStream_Read (pStm, This->pInstrumentID, Chunk.dwSize, NULL);
								break;
							}
							case FOURCC_LIST: {
								IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);				
								TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
								ListSize[1] = Chunk.dwSize - sizeof(FOURCC);
								ListCount[1] = 0;
								switch (Chunk.fccID) {
									case FOURCC_LRGN: {
										TRACE_(dmfile)(": regions list\n");
										do {
											IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
											ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
197
											TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
											switch (Chunk.fccID) {
												case FOURCC_LIST: {
													IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);				
													TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
													ListSize[2] = Chunk.dwSize - sizeof(FOURCC);
													ListCount[2] = 0;
													switch (Chunk.fccID) {
														case FOURCC_RGN: {																
															/* temporary structures */
															RGNHEADER tmpRegionHeader;
															WSMPL tmpWaveSample;
															WLOOP tmpWaveLoop;
															WAVELINK tmpWaveLink;
															
															TRACE_(dmfile)(": region list\n");
															do {
																IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
																ListCount[2] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
216
																TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
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
																switch (Chunk.fccID) {
																	case FOURCC_RGNH: {
																		TRACE_(dmfile)(": region header chunk\n");
																		memset (&tmpRegionHeader, 0, sizeof(RGNHEADER)); /* reset */
																		IStream_Read (pStm, &tmpRegionHeader, Chunk.dwSize, NULL);
																		break;
																	}
																	case FOURCC_WSMP: {
																		TRACE_(dmfile)(": wave sample chunk\n");
																		memset (&tmpWaveSample, 0, sizeof(WSMPL)); /* reset */
																		memset (&tmpWaveLoop, 0, sizeof(WLOOP)); /* reset */
																		if (Chunk.dwSize != (sizeof(WSMPL) + sizeof(WLOOP))) ERR(": incorrect chunk size\n");
																		IStream_Read (pStm, &tmpWaveSample, sizeof(WSMPL), NULL);
																		IStream_Read (pStm, &tmpWaveLoop, sizeof(WLOOP), NULL);
																		break;
																	}
																	case FOURCC_WLNK: {
																		TRACE_(dmfile)(": wave link chunk\n");
																		memset (&tmpWaveLink, 0, sizeof(WAVELINK)); /* reset */
																		IStream_Read (pStm, &tmpWaveLink, Chunk.dwSize, NULL);
																		break;
																	}
																	default: {
																		TRACE_(dmfile)(": unknown (skipping)\n");
																		liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
																		IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
																		break;						
																	}
																}
246
																TRACE_(dmfile)(": ListCount[2] = %d < ListSize[2] = %d\n", ListCount[2], ListSize[2]);
247 248 249 250 251 252 253 254 255 256 257 258 259 260
															} while (ListCount[2] < ListSize[2]);
															FIXME(": need to write temporary data to instrument data\n");
															break;
														}
														default: {
															TRACE_(dmfile)(": unknown (skipping)\n");
															liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
															IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
															break;						
														}
													}
													break;
												}				
												default: {
261
													TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
262 263 264 265 266
													liMove.QuadPart = Chunk.dwSize;
													IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
													break;						
												}
											}
267
											TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]);
268 269 270 271 272 273 274 275
										} while (ListCount[1] < ListSize[1]);
										break;
									}
									case FOURCC_LART: {
										TRACE_(dmfile)(": articulators list\n");
										do {
											IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
											ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
276
											TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
											switch (Chunk.fccID) {
												case FOURCC_ART1: {
													/* temporary structures */
													CONNECTIONLIST tmpConnectionList;
													LPCONNECTION tmpConnections;
													
													TRACE_(dmfile)(": level 1 articulator chunk\n");
													memset (&tmpConnectionList, 0, sizeof(CONNECTIONLIST)); /* reset */
													tmpConnections = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof(CONNECTION)*tmpConnectionList.cConnections);
													if (Chunk.dwSize != (sizeof(CONNECTIONLIST) + sizeof(CONNECTION)*tmpConnectionList.cConnections)) ERR(": incorrect chunk size\n");
													IStream_Read (pStm, &tmpConnectionList, sizeof(CONNECTIONLIST), NULL);
													IStream_Read (pStm, tmpConnections, sizeof(CONNECTION)*tmpConnectionList.cConnections, NULL);
													break;
												}
												default: {
292
													TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
293 294 295 296 297
													liMove.QuadPart = Chunk.dwSize;
													IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
													break;						
												}
											}
298
											TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]);
299 300 301 302 303 304 305 306
										} while (ListCount[1] < ListSize[1]);
										break;
									}
									case mmioFOURCC('I','N','F','O'): {
										TRACE_(dmfile)(": INFO list\n");
										do {
											IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
											ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
307
											TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
											switch (Chunk.fccID) {
												case mmioFOURCC('I','N','A','M'): {
													TRACE_(dmfile)(": name chunk (ignored)\n");
													if (even_or_odd(Chunk.dwSize)) {
														ListCount[1] ++;
														Chunk.dwSize++;
													}
													liMove.QuadPart = Chunk.dwSize;
													IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
													break;
												}
												case mmioFOURCC('I','A','R','T'): {
													TRACE_(dmfile)(": artist chunk (ignored)\n");
													if (even_or_odd(Chunk.dwSize)) {
														ListCount[1] ++;
														Chunk.dwSize++;
													}
													liMove.QuadPart = Chunk.dwSize;
													IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
													break;
												}
												case mmioFOURCC('I','C','O','P'): {
													/* temporary structures */
													CHAR tmpCopyright[DMUS_MAX_NAME];
													
													TRACE_(dmfile)(": copyright chunk\n");
													IStream_Read (pStm, tmpCopyright, Chunk.dwSize, NULL);
													if (even_or_odd(Chunk.dwSize)) {
														ListCount[1] ++;
														liMove.QuadPart = 1;
														IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
													}
													break;
												}
												case mmioFOURCC('I','S','B','J'): {
													TRACE_(dmfile)(": subject chunk (ignored)\n");
													if (even_or_odd(Chunk.dwSize)) {
														ListCount[1] ++;
														Chunk.dwSize++;
													}
													liMove.QuadPart = Chunk.dwSize;
													IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
													break;
												}
												case mmioFOURCC('I','C','M','T'): {
													TRACE_(dmfile)(": comment chunk (ignored)\n");
													if (even_or_odd(Chunk.dwSize)) {
														ListCount[1] ++;
														Chunk.dwSize++;
													}
													liMove.QuadPart = Chunk.dwSize;
													IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
													break;
												}
												default: {
363
													TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
364 365 366 367 368 369 370 371 372
													if (even_or_odd(Chunk.dwSize)) {
														ListCount[1] ++;
														Chunk.dwSize++;
													}
													liMove.QuadPart = Chunk.dwSize;
													IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
													break;						
												}
											}
373
											TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]);
374 375 376 377 378 379 380 381 382 383 384 385 386 387
										} while (ListCount[1] < ListSize[1]);
										break;
									}									
									
									default: {
										TRACE_(dmfile)(": unknown (skipping)\n");
										liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
										IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
										break;						
									}
								}
								break;
							}				
							default: {
388
								TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
389 390 391 392 393
								liMove.QuadPart = Chunk.dwSize;
								IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
								break;						
							}
						}
394
						TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
395 396 397 398
					} while (ListCount[0] < ListSize[0]);
					break;
				}
				default: {
399
					TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
400 401 402 403 404 405 406 407 408 409 410 411 412
					liMove.QuadPart = Chunk.dwSize;
					IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
					break;						
				}
			}
			break;
		}
		default: {
			TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
			liMove.QuadPart = Chunk.dwSize;
			IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
			return E_FAIL;
		}
413
	}
414 415 416 417
	/* DEBUG: dumps whole instrument object tree: */
/*	if (TRACE_ON(dmusic)) {		
		TRACE("*** IDirectMusicInstrument (%p) ***\n", This);
		if (This->pInstrumentID)
418
			TRACE(" - GUID = %s\n", debugstr_dmguid(This->pInstrumentID));
419 420 421 422 423 424 425 426
		
		TRACE(" - Instrument header:\n");
		TRACE("    - cRegions: %ld\n", This->pHeader->cRegions);
		TRACE("    - Locale:\n");
		TRACE("       - ulBank: %ld\n", This->pHeader->Locale.ulBank);
		TRACE("       - ulInstrument: %ld\n", This->pHeader->Locale.ulInstrument);
		TRACE("       => dwPatch: %ld\n", MIDILOCALE2Patch(&This->pHeader->Locale));		
	}*/
427

428
	return S_OK;
429
}