Mercurial > SDL_sound_CoreAudio
annotate decoders/timidity/instrum_dls.c @ 459:4d2febf33dc7
Changed some SDL_Error()s to __Sound_SetError() to fix linking issues.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 10 Oct 2003 08:00:42 +0000 |
parents | 69c8ba97f4bd |
children | d02c00ce16d9 |
rev | line source |
---|---|
455 | 1 /* |
2 | |
3 TiMidity -- Experimental MIDI to WAVE converter | |
4 Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi> | |
5 | |
6 This program is free software; you can redistribute it and/or modify | |
7 it under the terms of the GNU General Public License as published by | |
8 the Free Software Foundation; either version 2 of the License, or | |
9 (at your option) any later version. | |
10 | |
11 This program is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 GNU General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with this program; if not, write to the Free Software | |
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | |
20 instrum.h | |
21 | |
22 */ | |
23 | |
24 #include <stdlib.h> | |
25 #include <string.h> | |
26 | |
27 #include "SDL.h" | |
28 #include "SDL_endian.h" | |
29 #include "SDL_rwops.h" | |
30 | |
31 #include "SDL_sound.h" | |
32 | |
33 #define __SDL_SOUND_INTERNAL__ | |
34 #include "SDL_sound_internal.h" | |
35 | |
36 #include "timidity.h" | |
37 #include "options.h" | |
38 #include "instrum.h" | |
39 #include "tables.h" | |
40 #include "common.h" | |
41 | |
42 /*-------------------------------------------------------------------------*/ | |
43 /* * * * * * * * * * * * * * * * * load_riff.h * * * * * * * * * * * * * * */ | |
44 /*-------------------------------------------------------------------------*/ | |
45 typedef struct _RIFF_Chunk { | |
46 Uint32 magic; | |
47 Uint32 length; | |
48 Uint32 subtype; | |
49 Uint8 *data; | |
50 struct _RIFF_Chunk *child; | |
51 struct _RIFF_Chunk *next; | |
52 } RIFF_Chunk; | |
53 | |
54 extern DECLSPEC RIFF_Chunk* SDLCALL LoadRIFF(SDL_RWops *src); | |
55 extern DECLSPEC void SDLCALL FreeRIFF(RIFF_Chunk *chunk); | |
56 extern DECLSPEC void SDLCALL PrintRIFF(RIFF_Chunk *chunk, int level); | |
57 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
58 | |
59 /*-------------------------------------------------------------------------*/ | |
60 /* * * * * * * * * * * * * * * * * load_riff.c * * * * * * * * * * * * * * */ | |
61 /*-------------------------------------------------------------------------*/ | |
62 #define RIFF 0x46464952 /* "RIFF" */ | |
63 #define LIST 0x5453494c /* "LIST" */ | |
64 | |
65 static RIFF_Chunk *AllocRIFFChunk() | |
66 { | |
67 RIFF_Chunk *chunk = (RIFF_Chunk *)malloc(sizeof(*chunk)); | |
68 if ( !chunk ) { | |
459
4d2febf33dc7
Changed some SDL_Error()s to __Sound_SetError() to fix linking issues.
Ryan C. Gordon <icculus@icculus.org>
parents:
458
diff
changeset
|
69 __Sound_SetError(ERR_OUT_OF_MEMORY); |
455 | 70 return NULL; |
71 } | |
72 memset(chunk, 0, sizeof(*chunk)); | |
73 return chunk; | |
74 } | |
75 | |
76 static void FreeRIFFChunk(RIFF_Chunk *chunk) | |
77 { | |
78 if ( chunk->child ) { | |
79 FreeRIFFChunk(chunk->child); | |
80 } | |
458
69c8ba97f4bd
Fixed memory corruption when freeing DLS instruments
hercules
parents:
455
diff
changeset
|
81 if ( chunk->next ) { |
69c8ba97f4bd
Fixed memory corruption when freeing DLS instruments
hercules
parents:
455
diff
changeset
|
82 FreeRIFFChunk(chunk->next); |
455 | 83 } |
84 free(chunk); | |
85 } | |
86 | |
87 static int ChunkHasSubType(Uint32 magic) | |
88 { | |
89 static Uint32 chunk_list[] = { | |
90 RIFF, LIST | |
91 }; | |
92 int i; | |
93 for ( i = 0; i < SDL_TABLESIZE(chunk_list); ++i ) { | |
94 if ( magic == chunk_list[i] ) { | |
95 return 1; | |
96 } | |
97 } | |
98 return 0; | |
99 } | |
100 | |
101 static int ChunkHasSubChunks(Uint32 magic) | |
102 { | |
103 static Uint32 chunk_list[] = { | |
104 RIFF, LIST | |
105 }; | |
106 int i; | |
107 for ( i = 0; i < SDL_TABLESIZE(chunk_list); ++i ) { | |
108 if ( magic == chunk_list[i] ) { | |
109 return 1; | |
110 } | |
111 } | |
112 return 0; | |
113 } | |
114 | |
115 static void LoadSubChunks(RIFF_Chunk *chunk, Uint8 *data, Uint32 left) | |
116 { | |
117 Uint8 *subchunkData; | |
118 Uint32 subchunkDataLen; | |
119 | |
120 while ( left > 8 ) { | |
121 RIFF_Chunk *child = AllocRIFFChunk(); | |
122 RIFF_Chunk *next, *prev = NULL; | |
123 for ( next = chunk->child; next; next = next->next ) { | |
124 prev = next; | |
125 } | |
126 if ( prev ) { | |
127 prev->next = child; | |
128 } else { | |
129 chunk->child = child; | |
130 } | |
131 | |
132 child->magic = (data[0] << 0) | | |
133 (data[1] << 8) | | |
134 (data[2] << 16) | | |
135 (data[3] << 24); | |
136 data += 4; | |
137 left -= 4; | |
138 child->length = (data[0] << 0) | | |
139 (data[1] << 8) | | |
140 (data[2] << 16) | | |
141 (data[3] << 24); | |
142 data += 4; | |
143 left -= 4; | |
144 child->data = data; | |
145 | |
146 if ( child->length > left ) { | |
147 child->length = left; | |
148 } | |
149 | |
150 subchunkData = child->data; | |
151 subchunkDataLen = child->length; | |
152 if ( ChunkHasSubType(child->magic) && subchunkDataLen >= 4 ) { | |
153 child->subtype = (subchunkData[0] << 0) | | |
154 (subchunkData[1] << 8) | | |
155 (subchunkData[2] << 16) | | |
156 (subchunkData[3] << 24); | |
157 subchunkData += 4; | |
158 subchunkDataLen -= 4; | |
159 } | |
160 if ( ChunkHasSubChunks(child->magic) ) { | |
161 LoadSubChunks(child, subchunkData, subchunkDataLen); | |
162 } | |
163 | |
164 data += child->length; | |
165 left -= child->length; | |
166 } | |
167 } | |
168 | |
169 RIFF_Chunk *LoadRIFF(SDL_RWops *src) | |
170 { | |
171 RIFF_Chunk *chunk; | |
172 Uint8 *subchunkData; | |
173 Uint32 subchunkDataLen; | |
174 | |
175 /* Allocate the chunk structure */ | |
176 chunk = AllocRIFFChunk(); | |
177 | |
178 /* Make sure the file is in RIFF format */ | |
179 chunk->magic = SDL_ReadLE32(src); | |
180 chunk->length = SDL_ReadLE32(src); | |
181 if ( chunk->magic != RIFF ) { | |
459
4d2febf33dc7
Changed some SDL_Error()s to __Sound_SetError() to fix linking issues.
Ryan C. Gordon <icculus@icculus.org>
parents:
458
diff
changeset
|
182 __Sound_SetError("Not a RIFF file"); |
455 | 183 FreeRIFFChunk(chunk); |
184 return NULL; | |
185 } | |
186 chunk->data = (Uint8 *)malloc(chunk->length); | |
187 if ( chunk->data == NULL ) { | |
459
4d2febf33dc7
Changed some SDL_Error()s to __Sound_SetError() to fix linking issues.
Ryan C. Gordon <icculus@icculus.org>
parents:
458
diff
changeset
|
188 __Sound_SetError(ERR_OUT_OF_MEMORY); |
455 | 189 FreeRIFFChunk(chunk); |
190 return NULL; | |
191 } | |
192 if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) { | |
459
4d2febf33dc7
Changed some SDL_Error()s to __Sound_SetError() to fix linking issues.
Ryan C. Gordon <icculus@icculus.org>
parents:
458
diff
changeset
|
193 __Sound_SetError(ERR_IO_ERROR); |
455 | 194 FreeRIFF(chunk); |
195 return NULL; | |
196 } | |
197 subchunkData = chunk->data; | |
198 subchunkDataLen = chunk->length; | |
199 if ( ChunkHasSubType(chunk->magic) && subchunkDataLen >= 4 ) { | |
200 chunk->subtype = (subchunkData[0] << 0) | | |
201 (subchunkData[1] << 8) | | |
202 (subchunkData[2] << 16) | | |
203 (subchunkData[3] << 24); | |
204 subchunkData += 4; | |
205 subchunkDataLen -= 4; | |
206 } | |
207 if ( ChunkHasSubChunks(chunk->magic) ) { | |
208 LoadSubChunks(chunk, subchunkData, subchunkDataLen); | |
209 } | |
210 return chunk; | |
211 } | |
212 | |
213 void FreeRIFF(RIFF_Chunk *chunk) | |
214 { | |
215 free(chunk->data); | |
216 FreeRIFFChunk(chunk); | |
217 } | |
218 | |
219 void PrintRIFF(RIFF_Chunk *chunk, int level) | |
220 { | |
221 static char prefix[128]; | |
222 | |
223 if ( level == sizeof(prefix)-1 ) { | |
224 return; | |
225 } | |
226 if ( level > 0 ) { | |
227 prefix[(level-1)*2] = ' '; | |
228 prefix[(level-1)*2+1] = ' '; | |
229 } | |
230 prefix[level*2] = '\0'; | |
231 printf("%sChunk: %c%c%c%c (%d bytes)", prefix, | |
232 ((chunk->magic >> 0) & 0xFF), | |
233 ((chunk->magic >> 8) & 0xFF), | |
234 ((chunk->magic >> 16) & 0xFF), | |
235 ((chunk->magic >> 24) & 0xFF), chunk->length); | |
236 if ( chunk->subtype ) { | |
237 printf(" subtype: %c%c%c%c", | |
238 ((chunk->subtype >> 0) & 0xFF), | |
239 ((chunk->subtype >> 8) & 0xFF), | |
240 ((chunk->subtype >> 16) & 0xFF), | |
241 ((chunk->subtype >> 24) & 0xFF)); | |
242 } | |
243 printf("\n"); | |
244 if ( chunk->child ) { | |
245 printf("%s{\n", prefix); | |
246 PrintRIFF(chunk->child, level + 1); | |
247 printf("%s}\n", prefix); | |
248 } | |
249 if ( chunk->next ) { | |
250 PrintRIFF(chunk->next, level); | |
251 } | |
252 if ( level > 0 ) { | |
253 prefix[(level-1)*2] = '\0'; | |
254 } | |
255 } | |
256 | |
257 #ifdef TEST_MAIN_RIFF | |
258 | |
259 main(int argc, char *argv[]) | |
260 { | |
261 int i; | |
262 for ( i = 1; i < argc; ++i ) { | |
263 RIFF_Chunk *chunk; | |
264 SDL_RWops *src = SDL_RWFromFile(argv[i], "rb"); | |
265 if ( !src ) { | |
266 fprintf(stderr, "Couldn't open %s: %s", argv[i], SDL_GetError()); | |
267 continue; | |
268 } | |
269 chunk = LoadRIFF(src); | |
270 if ( chunk ) { | |
271 PrintRIFF(chunk, 0); | |
272 FreeRIFF(chunk); | |
273 } else { | |
274 fprintf(stderr, "Couldn't load %s: %s\n", argv[i], SDL_GetError()); | |
275 } | |
276 SDL_RWclose(src); | |
277 } | |
278 } | |
279 | |
280 #endif // TEST_MAIN | |
281 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
282 | |
283 /*-------------------------------------------------------------------------*/ | |
284 /* * * * * * * * * * * * * * * * * load_dls.h * * * * * * * * * * * * * * */ | |
285 /*-------------------------------------------------------------------------*/ | |
286 /* This code is based on the DLS spec version 1.1, available at: | |
287 http://www.midi.org/about-midi/dls/dlsspec.shtml | |
288 */ | |
289 | |
290 /* Some typedefs so the public dls headers don't need to be modified */ | |
291 #define FAR | |
292 typedef Uint8 BYTE; | |
293 typedef Sint16 SHORT; | |
294 typedef Uint16 USHORT; | |
295 typedef Uint16 WORD; | |
296 typedef Sint32 LONG; | |
297 typedef Uint32 ULONG; | |
298 typedef Uint32 DWORD; | |
299 #define mmioFOURCC(A, B, C, D) \ | |
300 (((A) << 0) | ((B) << 8) | ((C) << 16) | ((D) << 24)) | |
301 #define DEFINE_GUID(A, B, C, E, F, G, H, I, J, K, L, M) | |
302 | |
303 #include "dls1.h" | |
304 #include "dls2.h" | |
305 | |
306 typedef struct _WaveFMT { | |
307 WORD wFormatTag; | |
308 WORD wChannels; | |
309 DWORD dwSamplesPerSec; | |
310 DWORD dwAvgBytesPerSec; | |
311 WORD wBlockAlign; | |
312 WORD wBitsPerSample; | |
313 } WaveFMT; | |
314 | |
315 typedef struct _DLS_Wave { | |
316 WaveFMT *format; | |
317 Uint8 *data; | |
318 Uint32 length; | |
319 WSMPL *wsmp; | |
320 WLOOP *wsmp_loop; | |
321 } DLS_Wave; | |
322 | |
323 typedef struct _DLS_Region { | |
324 RGNHEADER *header; | |
325 WAVELINK *wlnk; | |
326 WSMPL *wsmp; | |
327 WLOOP *wsmp_loop; | |
328 CONNECTIONLIST *art; | |
329 CONNECTION *artList; | |
330 } DLS_Region; | |
331 | |
332 typedef struct _DLS_Instrument { | |
333 const char *name; | |
334 INSTHEADER *header; | |
335 DLS_Region *regions; | |
336 CONNECTIONLIST *art; | |
337 CONNECTION *artList; | |
338 } DLS_Instrument; | |
339 | |
340 typedef struct _DLS_Data { | |
341 struct _RIFF_Chunk *chunk; | |
342 | |
343 Uint32 cInstruments; | |
344 DLS_Instrument *instruments; | |
345 | |
346 POOLTABLE *ptbl; | |
347 POOLCUE *ptblList; | |
348 DLS_Wave *waveList; | |
349 | |
350 const char *name; | |
351 const char *artist; | |
352 const char *copyright; | |
353 const char *comments; | |
354 } DLS_Data; | |
355 | |
356 extern DECLSPEC DLS_Data* SDLCALL LoadDLS(SDL_RWops *src); | |
357 extern DECLSPEC void SDLCALL FreeDLS(DLS_Data *chunk); | |
358 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
359 | |
360 /*-------------------------------------------------------------------------*/ | |
361 /* * * * * * * * * * * * * * * * * load_dls.c * * * * * * * * * * * * * * */ | |
362 /*-------------------------------------------------------------------------*/ | |
363 | |
364 #define FOURCC_LIST 0x5453494c /* "LIST" */ | |
365 #define FOURCC_FMT 0x20746D66 /* "fmt " */ | |
366 #define FOURCC_DATA 0x61746164 /* "data" */ | |
367 #define FOURCC_INFO mmioFOURCC('I','N','F','O') | |
368 #define FOURCC_IARL mmioFOURCC('I','A','R','L') | |
369 #define FOURCC_IART mmioFOURCC('I','A','R','T') | |
370 #define FOURCC_ICMS mmioFOURCC('I','C','M','S') | |
371 #define FOURCC_ICMT mmioFOURCC('I','C','M','T') | |
372 #define FOURCC_ICOP mmioFOURCC('I','C','O','P') | |
373 #define FOURCC_ICRD mmioFOURCC('I','C','R','D') | |
374 #define FOURCC_IENG mmioFOURCC('I','E','N','G') | |
375 #define FOURCC_IGNR mmioFOURCC('I','G','N','R') | |
376 #define FOURCC_IKEY mmioFOURCC('I','K','E','Y') | |
377 #define FOURCC_IMED mmioFOURCC('I','M','E','D') | |
378 #define FOURCC_INAM mmioFOURCC('I','N','A','M') | |
379 #define FOURCC_IPRD mmioFOURCC('I','P','R','D') | |
380 #define FOURCC_ISBJ mmioFOURCC('I','S','B','J') | |
381 #define FOURCC_ISFT mmioFOURCC('I','S','F','T') | |
382 #define FOURCC_ISRC mmioFOURCC('I','S','R','C') | |
383 #define FOURCC_ISRF mmioFOURCC('I','S','R','F') | |
384 #define FOURCC_ITCH mmioFOURCC('I','T','C','H') | |
385 | |
386 | |
387 static void FreeRegions(DLS_Instrument *instrument) | |
388 { | |
389 if ( instrument->regions ) { | |
390 free(instrument->regions); | |
391 } | |
392 } | |
393 | |
394 static void AllocRegions(DLS_Instrument *instrument) | |
395 { | |
396 int datalen = (instrument->header->cRegions * sizeof(DLS_Region)); | |
397 FreeRegions(instrument); | |
398 instrument->regions = (DLS_Region *)malloc(datalen); | |
399 if ( instrument->regions ) { | |
400 memset(instrument->regions, 0, datalen); | |
401 } | |
402 } | |
403 | |
404 static void FreeInstruments(DLS_Data *data) | |
405 { | |
406 if ( data->instruments ) { | |
407 Uint32 i; | |
408 for ( i = 0; i < data->cInstruments; ++i ) { | |
409 FreeRegions(&data->instruments[i]); | |
410 } | |
411 free(data->instruments); | |
412 } | |
413 } | |
414 | |
415 static void AllocInstruments(DLS_Data *data) | |
416 { | |
417 int datalen = (data->cInstruments * sizeof(DLS_Instrument)); | |
418 FreeInstruments(data); | |
419 data->instruments = (DLS_Instrument *)malloc(datalen); | |
420 if ( data->instruments ) { | |
421 memset(data->instruments, 0, datalen); | |
422 } | |
423 } | |
424 | |
425 static void FreeWaveList(DLS_Data *data) | |
426 { | |
427 if ( data->waveList ) { | |
428 free(data->waveList); | |
429 } | |
430 } | |
431 | |
432 static void AllocWaveList(DLS_Data *data) | |
433 { | |
434 int datalen = (data->ptbl->cCues * sizeof(DLS_Wave)); | |
435 FreeWaveList(data); | |
436 data->waveList = (DLS_Wave *)malloc(datalen); | |
437 if ( data->waveList ) { | |
438 memset(data->waveList, 0, datalen); | |
439 } | |
440 } | |
441 | |
442 static void Parse_colh(DLS_Data *data, RIFF_Chunk *chunk) | |
443 { | |
444 data->cInstruments = SDL_SwapLE32(*(Uint32 *)chunk->data); | |
445 AllocInstruments(data); | |
446 } | |
447 | |
448 static void Parse_insh(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) | |
449 { | |
450 INSTHEADER *header = (INSTHEADER *)chunk->data; | |
451 header->cRegions = SDL_SwapLE32(header->cRegions); | |
452 header->Locale.ulBank = SDL_SwapLE32(header->Locale.ulBank); | |
453 header->Locale.ulInstrument = SDL_SwapLE32(header->Locale.ulInstrument); | |
454 instrument->header = header; | |
455 AllocRegions(instrument); | |
456 } | |
457 | |
458 static void Parse_rgnh(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region) | |
459 { | |
460 RGNHEADER *header = (RGNHEADER *)chunk->data; | |
461 header->RangeKey.usLow = SDL_SwapLE16(header->RangeKey.usLow); | |
462 header->RangeKey.usHigh = SDL_SwapLE16(header->RangeKey.usHigh); | |
463 header->RangeVelocity.usLow = SDL_SwapLE16(header->RangeVelocity.usLow); | |
464 header->RangeVelocity.usHigh = SDL_SwapLE16(header->RangeVelocity.usHigh); | |
465 header->fusOptions = SDL_SwapLE16(header->fusOptions); | |
466 header->usKeyGroup = SDL_SwapLE16(header->usKeyGroup); | |
467 region->header = header; | |
468 } | |
469 | |
470 static void Parse_wlnk(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region) | |
471 { | |
472 WAVELINK *wlnk = (WAVELINK *)chunk->data; | |
473 wlnk->fusOptions = SDL_SwapLE16(wlnk->fusOptions); | |
474 wlnk->usPhaseGroup = SDL_SwapLE16(wlnk->usPhaseGroup); | |
475 wlnk->ulChannel = SDL_SwapLE16(wlnk->ulChannel); | |
476 wlnk->ulTableIndex = SDL_SwapLE16(wlnk->ulTableIndex); | |
477 region->wlnk = wlnk; | |
478 } | |
479 | |
480 static void Parse_wsmp(DLS_Data *data, RIFF_Chunk *chunk, WSMPL **wsmp_ptr, WLOOP **wsmp_loop_ptr) | |
481 { | |
482 Uint32 i; | |
483 WSMPL *wsmp = (WSMPL *)chunk->data; | |
484 WLOOP *loop; | |
485 wsmp->cbSize = SDL_SwapLE32(wsmp->cbSize); | |
486 wsmp->usUnityNote = SDL_SwapLE16(wsmp->usUnityNote); | |
487 wsmp->sFineTune = SDL_SwapLE16(wsmp->sFineTune); | |
488 wsmp->lAttenuation = SDL_SwapLE32(wsmp->lAttenuation); | |
489 wsmp->fulOptions = SDL_SwapLE32(wsmp->fulOptions); | |
490 wsmp->cSampleLoops = SDL_SwapLE32(wsmp->cSampleLoops); | |
491 loop = (WLOOP *)((Uint8 *)chunk->data + wsmp->cbSize); | |
492 *wsmp_ptr = wsmp; | |
493 *wsmp_loop_ptr = loop; | |
494 for ( i = 0; i < wsmp->cSampleLoops; ++i ) { | |
495 loop->cbSize = SDL_SwapLE32(loop->cbSize); | |
496 loop->ulType = SDL_SwapLE32(loop->ulType); | |
497 loop->ulStart = SDL_SwapLE32(loop->ulStart); | |
498 loop->ulLength = SDL_SwapLE32(loop->ulLength); | |
499 ++loop; | |
500 } | |
501 } | |
502 | |
503 static void Parse_art(DLS_Data *data, RIFF_Chunk *chunk, CONNECTIONLIST **art_ptr, CONNECTION **artList_ptr) | |
504 { | |
505 Uint32 i; | |
506 CONNECTIONLIST *art = (CONNECTIONLIST *)chunk->data; | |
507 CONNECTION *artList; | |
508 art->cbSize = SDL_SwapLE32(art->cbSize); | |
509 art->cConnections = SDL_SwapLE32(art->cConnections); | |
510 artList = (CONNECTION *)((Uint8 *)chunk->data + art->cbSize); | |
511 *art_ptr = art; | |
512 *artList_ptr = artList; | |
513 for ( i = 0; i < art->cConnections; ++i ) { | |
514 artList->usSource = SDL_SwapLE16(artList->usSource); | |
515 artList->usControl = SDL_SwapLE16(artList->usControl); | |
516 artList->usDestination = SDL_SwapLE16(artList->usDestination); | |
517 artList->usTransform = SDL_SwapLE16(artList->usTransform); | |
518 artList->lScale = SDL_SwapLE32(artList->lScale); | |
519 ++artList; | |
520 } | |
521 } | |
522 | |
523 static void Parse_lart(DLS_Data *data, RIFF_Chunk *chunk, CONNECTIONLIST **conn_ptr, CONNECTION **connList_ptr) | |
524 { | |
525 /* FIXME: This only supports one set of connections */ | |
526 for ( chunk = chunk->child; chunk; chunk = chunk->next ) { | |
527 Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; | |
528 switch(magic) { | |
529 case FOURCC_ART1: | |
530 case FOURCC_ART2: | |
531 Parse_art(data, chunk, conn_ptr, connList_ptr); | |
532 return; | |
533 } | |
534 } | |
535 } | |
536 | |
537 static void Parse_rgn(DLS_Data *data, RIFF_Chunk *chunk, DLS_Region *region) | |
538 { | |
539 for ( chunk = chunk->child; chunk; chunk = chunk->next ) { | |
540 Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; | |
541 switch(magic) { | |
542 case FOURCC_RGNH: | |
543 Parse_rgnh(data, chunk, region); | |
544 break; | |
545 case FOURCC_WLNK: | |
546 Parse_wlnk(data, chunk, region); | |
547 break; | |
548 case FOURCC_WSMP: | |
549 Parse_wsmp(data, chunk, ®ion->wsmp, ®ion->wsmp_loop); | |
550 break; | |
551 case FOURCC_LART: | |
552 case FOURCC_LAR2: | |
553 Parse_lart(data, chunk, ®ion->art, ®ion->artList); | |
554 break; | |
555 } | |
556 } | |
557 } | |
558 | |
559 static void Parse_lrgn(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) | |
560 { | |
561 Uint32 region = 0; | |
562 for ( chunk = chunk->child; chunk; chunk = chunk->next ) { | |
563 Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; | |
564 switch(magic) { | |
565 case FOURCC_RGN: | |
566 case FOURCC_RGN2: | |
567 if ( region < instrument->header->cRegions ) { | |
568 Parse_rgn(data, chunk, &instrument->regions[region++]); | |
569 } | |
570 break; | |
571 } | |
572 } | |
573 } | |
574 | |
575 static void Parse_INFO_INS(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) | |
576 { | |
577 for ( chunk = chunk->child; chunk; chunk = chunk->next ) { | |
578 Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; | |
579 switch(magic) { | |
580 case FOURCC_INAM: /* Name */ | |
581 instrument->name = chunk->data; | |
582 break; | |
583 } | |
584 } | |
585 } | |
586 | |
587 static void Parse_ins(DLS_Data *data, RIFF_Chunk *chunk, DLS_Instrument *instrument) | |
588 { | |
589 for ( chunk = chunk->child; chunk; chunk = chunk->next ) { | |
590 Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; | |
591 switch(magic) { | |
592 case FOURCC_INSH: | |
593 Parse_insh(data, chunk, instrument); | |
594 break; | |
595 case FOURCC_LRGN: | |
596 Parse_lrgn(data, chunk, instrument); | |
597 break; | |
598 case FOURCC_LART: | |
599 case FOURCC_LAR2: | |
600 Parse_lart(data, chunk, &instrument->art, &instrument->artList); | |
601 break; | |
602 case FOURCC_INFO: | |
603 Parse_INFO_INS(data, chunk, instrument); | |
604 break; | |
605 } | |
606 } | |
607 } | |
608 | |
609 static void Parse_lins(DLS_Data *data, RIFF_Chunk *chunk) | |
610 { | |
611 Uint32 instrument = 0; | |
612 for ( chunk = chunk->child; chunk; chunk = chunk->next ) { | |
613 Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; | |
614 switch(magic) { | |
615 case FOURCC_INS: | |
616 if ( instrument < data->cInstruments ) { | |
617 Parse_ins(data, chunk, &data->instruments[instrument++]); | |
618 } | |
619 break; | |
620 } | |
621 } | |
622 } | |
623 | |
624 static void Parse_ptbl(DLS_Data *data, RIFF_Chunk *chunk) | |
625 { | |
626 Uint32 i; | |
627 POOLTABLE *ptbl = (POOLTABLE *)chunk->data; | |
628 ptbl->cbSize = SDL_SwapLE32(ptbl->cbSize); | |
629 ptbl->cCues = SDL_SwapLE32(ptbl->cCues); | |
630 data->ptbl = ptbl; | |
631 data->ptblList = (POOLCUE *)((Uint8 *)chunk->data + ptbl->cbSize); | |
632 for ( i = 0; i < ptbl->cCues; ++i ) { | |
633 data->ptblList[i].ulOffset = SDL_SwapLE32(data->ptblList[i].ulOffset); | |
634 } | |
635 AllocWaveList(data); | |
636 } | |
637 | |
638 static void Parse_fmt(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave) | |
639 { | |
640 WaveFMT *fmt = (WaveFMT *)chunk->data; | |
641 fmt->wFormatTag = SDL_SwapLE16(fmt->wFormatTag); | |
642 fmt->wChannels = SDL_SwapLE16(fmt->wChannels); | |
643 fmt->dwSamplesPerSec = SDL_SwapLE32(fmt->dwSamplesPerSec); | |
644 fmt->dwAvgBytesPerSec = SDL_SwapLE32(fmt->dwAvgBytesPerSec); | |
645 fmt->wBlockAlign = SDL_SwapLE16(fmt->wBlockAlign); | |
646 fmt->wBitsPerSample = SDL_SwapLE16(fmt->wBitsPerSample); | |
647 wave->format = fmt; | |
648 } | |
649 | |
650 static void Parse_data(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave) | |
651 { | |
652 wave->data = chunk->data; | |
653 wave->length = chunk->length; | |
654 } | |
655 | |
656 static void Parse_wave(DLS_Data *data, RIFF_Chunk *chunk, DLS_Wave *wave) | |
657 { | |
658 for ( chunk = chunk->child; chunk; chunk = chunk->next ) { | |
659 Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; | |
660 switch(magic) { | |
661 case FOURCC_FMT: | |
662 Parse_fmt(data, chunk, wave); | |
663 break; | |
664 case FOURCC_DATA: | |
665 Parse_data(data, chunk, wave); | |
666 break; | |
667 case FOURCC_WSMP: | |
668 Parse_wsmp(data, chunk, &wave->wsmp, &wave->wsmp_loop); | |
669 break; | |
670 } | |
671 } | |
672 } | |
673 | |
674 static void Parse_wvpl(DLS_Data *data, RIFF_Chunk *chunk) | |
675 { | |
676 Uint32 wave = 0; | |
677 for ( chunk = chunk->child; chunk; chunk = chunk->next ) { | |
678 Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; | |
679 switch(magic) { | |
680 case FOURCC_wave: | |
681 if ( wave < data->ptbl->cCues ) { | |
682 Parse_wave(data, chunk, &data->waveList[wave++]); | |
683 } | |
684 break; | |
685 } | |
686 } | |
687 } | |
688 | |
689 static void Parse_INFO_DLS(DLS_Data *data, RIFF_Chunk *chunk) | |
690 { | |
691 for ( chunk = chunk->child; chunk; chunk = chunk->next ) { | |
692 Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; | |
693 switch(magic) { | |
694 case FOURCC_IARL: /* Archival Location */ | |
695 break; | |
696 case FOURCC_IART: /* Artist */ | |
697 data->artist = chunk->data; | |
698 break; | |
699 case FOURCC_ICMS: /* Commisioned */ | |
700 break; | |
701 case FOURCC_ICMT: /* Comments */ | |
702 data->comments = chunk->data; | |
703 break; | |
704 case FOURCC_ICOP: /* Copyright */ | |
705 data->copyright = chunk->data; | |
706 break; | |
707 case FOURCC_ICRD: /* Creation Date */ | |
708 break; | |
709 case FOURCC_IENG: /* Engineer */ | |
710 break; | |
711 case FOURCC_IGNR: /* Genre */ | |
712 break; | |
713 case FOURCC_IKEY: /* Keywords */ | |
714 break; | |
715 case FOURCC_IMED: /* Medium */ | |
716 break; | |
717 case FOURCC_INAM: /* Name */ | |
718 data->name = chunk->data; | |
719 break; | |
720 case FOURCC_IPRD: /* Product */ | |
721 break; | |
722 case FOURCC_ISBJ: /* Subject */ | |
723 break; | |
724 case FOURCC_ISFT: /* Software */ | |
725 break; | |
726 case FOURCC_ISRC: /* Source */ | |
727 break; | |
728 case FOURCC_ISRF: /* Source Form */ | |
729 break; | |
730 case FOURCC_ITCH: /* Technician */ | |
731 break; | |
732 } | |
733 } | |
734 } | |
735 | |
736 DLS_Data *LoadDLS(SDL_RWops *src) | |
737 { | |
738 RIFF_Chunk *chunk; | |
739 DLS_Data *data = (DLS_Data *)malloc(sizeof(*data)); | |
740 if ( !data ) { | |
459
4d2febf33dc7
Changed some SDL_Error()s to __Sound_SetError() to fix linking issues.
Ryan C. Gordon <icculus@icculus.org>
parents:
458
diff
changeset
|
741 __Sound_SetError(ERR_OUT_OF_MEMORY); |
455 | 742 return NULL; |
743 } | |
744 memset(data, 0, sizeof(*data)); | |
745 | |
746 data->chunk = LoadRIFF(src); | |
747 if ( !data->chunk ) { | |
748 FreeDLS(data); | |
749 return NULL; | |
750 } | |
751 | |
752 for ( chunk = data->chunk->child; chunk; chunk = chunk->next ) { | |
753 Uint32 magic = (chunk->magic == FOURCC_LIST) ? chunk->subtype : chunk->magic; | |
754 switch(magic) { | |
755 case FOURCC_COLH: | |
756 Parse_colh(data, chunk); | |
757 break; | |
758 case FOURCC_LINS: | |
759 Parse_lins(data, chunk); | |
760 break; | |
761 case FOURCC_PTBL: | |
762 Parse_ptbl(data, chunk); | |
763 break; | |
764 case FOURCC_WVPL: | |
765 Parse_wvpl(data, chunk); | |
766 break; | |
767 case FOURCC_INFO: | |
768 Parse_INFO_DLS(data, chunk); | |
769 break; | |
770 } | |
771 } | |
772 return data; | |
773 } | |
774 | |
775 void FreeDLS(DLS_Data *data) | |
776 { | |
777 if ( data->chunk ) { | |
778 FreeRIFF(data->chunk); | |
779 } | |
780 FreeInstruments(data); | |
781 FreeWaveList(data); | |
782 free(data); | |
783 } | |
784 | |
785 static const char *SourceToString(USHORT usSource) | |
786 { | |
787 switch(usSource) { | |
788 case CONN_SRC_NONE: | |
789 return "NONE"; | |
790 case CONN_SRC_LFO: | |
791 return "LFO"; | |
792 case CONN_SRC_KEYONVELOCITY: | |
793 return "KEYONVELOCITY"; | |
794 case CONN_SRC_KEYNUMBER: | |
795 return "KEYNUMBER"; | |
796 case CONN_SRC_EG1: | |
797 return "EG1"; | |
798 case CONN_SRC_EG2: | |
799 return "EG2"; | |
800 case CONN_SRC_PITCHWHEEL: | |
801 return "PITCHWHEEL"; | |
802 case CONN_SRC_CC1: | |
803 return "CC1"; | |
804 case CONN_SRC_CC7: | |
805 return "CC7"; | |
806 case CONN_SRC_CC10: | |
807 return "CC10"; | |
808 case CONN_SRC_CC11: | |
809 return "CC11"; | |
810 case CONN_SRC_POLYPRESSURE: | |
811 return "POLYPRESSURE"; | |
812 case CONN_SRC_CHANNELPRESSURE: | |
813 return "CHANNELPRESSURE"; | |
814 case CONN_SRC_VIBRATO: | |
815 return "VIBRATO"; | |
816 case CONN_SRC_MONOPRESSURE: | |
817 return "MONOPRESSURE"; | |
818 case CONN_SRC_CC91: | |
819 return "CC91"; | |
820 case CONN_SRC_CC93: | |
821 return "CC93"; | |
822 default: | |
823 return "UNKNOWN"; | |
824 } | |
825 } | |
826 | |
827 static const char *TransformToString(USHORT usTransform) | |
828 { | |
829 switch (usTransform) { | |
830 case CONN_TRN_NONE: | |
831 return "NONE"; | |
832 case CONN_TRN_CONCAVE: | |
833 return "CONCAVE"; | |
834 case CONN_TRN_CONVEX: | |
835 return "CONVEX"; | |
836 case CONN_TRN_SWITCH: | |
837 return "SWITCH"; | |
838 default: | |
839 return "UNKNOWN"; | |
840 } | |
841 } | |
842 | |
843 static const char *DestinationToString(USHORT usDestination) | |
844 { | |
845 switch (usDestination) { | |
846 case CONN_DST_NONE: | |
847 return "NONE"; | |
848 case CONN_DST_ATTENUATION: | |
849 return "ATTENUATION"; | |
850 case CONN_DST_PITCH: | |
851 return "PITCH"; | |
852 case CONN_DST_PAN: | |
853 return "PAN"; | |
854 case CONN_DST_LFO_FREQUENCY: | |
855 return "LFO_FREQUENCY"; | |
856 case CONN_DST_LFO_STARTDELAY: | |
857 return "LFO_STARTDELAY"; | |
858 case CONN_DST_EG1_ATTACKTIME: | |
859 return "EG1_ATTACKTIME"; | |
860 case CONN_DST_EG1_DECAYTIME: | |
861 return "EG1_DECAYTIME"; | |
862 case CONN_DST_EG1_RELEASETIME: | |
863 return "EG1_RELEASETIME"; | |
864 case CONN_DST_EG1_SUSTAINLEVEL: | |
865 return "EG1_SUSTAINLEVEL"; | |
866 case CONN_DST_EG2_ATTACKTIME: | |
867 return "EG2_ATTACKTIME"; | |
868 case CONN_DST_EG2_DECAYTIME: | |
869 return "EG2_DECAYTIME"; | |
870 case CONN_DST_EG2_RELEASETIME: | |
871 return "EG2_RELEASETIME"; | |
872 case CONN_DST_EG2_SUSTAINLEVEL: | |
873 return "EG2_SUSTAINLEVEL"; | |
874 case CONN_DST_KEYNUMBER: | |
875 return "KEYNUMBER"; | |
876 case CONN_DST_LEFT: | |
877 return "LEFT"; | |
878 case CONN_DST_RIGHT: | |
879 return "RIGHT"; | |
880 case CONN_DST_CENTER: | |
881 return "CENTER"; | |
882 case CONN_DST_LEFTREAR: | |
883 return "LEFTREAR"; | |
884 case CONN_DST_RIGHTREAR: | |
885 return "RIGHTREAR"; | |
886 case CONN_DST_LFE_CHANNEL: | |
887 return "LFE_CHANNEL"; | |
888 case CONN_DST_CHORUS: | |
889 return "CHORUS"; | |
890 case CONN_DST_REVERB: | |
891 return "REVERB"; | |
892 case CONN_DST_VIB_FREQUENCY: | |
893 return "VIB_FREQUENCY"; | |
894 case CONN_DST_VIB_STARTDELAY: | |
895 return "VIB_STARTDELAY"; | |
896 case CONN_DST_EG1_DELAYTIME: | |
897 return "EG1_DELAYTIME"; | |
898 case CONN_DST_EG1_HOLDTIME: | |
899 return "EG1_HOLDTIME"; | |
900 case CONN_DST_EG1_SHUTDOWNTIME: | |
901 return "EG1_SHUTDOWNTIME"; | |
902 case CONN_DST_EG2_DELAYTIME: | |
903 return "EG2_DELAYTIME"; | |
904 case CONN_DST_EG2_HOLDTIME: | |
905 return "EG2_HOLDTIME"; | |
906 case CONN_DST_FILTER_CUTOFF: | |
907 return "FILTER_CUTOFF"; | |
908 case CONN_DST_FILTER_Q: | |
909 return "FILTER_Q"; | |
910 default: | |
911 return "UNKOWN"; | |
912 } | |
913 } | |
914 | |
915 static void PrintArt(const char *type, CONNECTIONLIST *art, CONNECTION *artList) | |
916 { | |
917 Uint32 i; | |
918 printf("%s Connections:\n", type); | |
919 for ( i = 0; i < art->cConnections; ++i ) { | |
920 printf(" Source: %s, Control: %s, Destination: %s, Transform: %s, Scale: %d\n", | |
921 SourceToString(artList[i].usSource), | |
922 SourceToString(artList[i].usControl), | |
923 DestinationToString(artList[i].usDestination), | |
924 TransformToString(artList[i].usTransform), | |
925 artList[i].lScale); | |
926 } | |
927 } | |
928 | |
929 static void PrintWave(DLS_Wave *wave, Uint32 index) | |
930 { | |
931 WaveFMT *format = wave->format; | |
932 if ( format ) { | |
933 printf(" Wave %u: Format: %hu, %hu channels, %u Hz, %hu bits (length = %u)\n", index, format->wFormatTag, format->wChannels, format->dwSamplesPerSec, format->wBitsPerSample, wave->length); | |
934 } | |
935 if ( wave->wsmp ) { | |
936 Uint32 i; | |
937 printf(" wsmp->usUnityNote = %hu\n", wave->wsmp->usUnityNote); | |
938 printf(" wsmp->sFineTune = %hd\n", wave->wsmp->sFineTune); | |
939 printf(" wsmp->lAttenuation = %d\n", wave->wsmp->lAttenuation); | |
940 printf(" wsmp->fulOptions = 0x%8.8x\n", wave->wsmp->fulOptions); | |
941 printf(" wsmp->cSampleLoops = %u\n", wave->wsmp->cSampleLoops); | |
942 for ( i = 0; i < wave->wsmp->cSampleLoops; ++i ) { | |
943 WLOOP *loop = &wave->wsmp_loop[i]; | |
944 printf(" Loop %u:\n", i); | |
945 printf(" ulStart = %u\n", loop->ulStart); | |
946 printf(" ulLength = %u\n", loop->ulLength); | |
947 } | |
948 } | |
949 } | |
950 | |
951 static void PrintRegion(DLS_Region *region, Uint32 index) | |
952 { | |
953 printf(" Region %u:\n", index); | |
954 if ( region->header ) { | |
955 printf(" RangeKey = { %hu - %hu }\n", region->header->RangeKey.usLow, region->header->RangeKey.usHigh); | |
956 printf(" RangeVelocity = { %hu - %hu }\n", region->header->RangeVelocity.usLow, region->header->RangeVelocity.usHigh); | |
957 printf(" fusOptions = 0x%4.4hx\n", region->header->fusOptions); | |
958 printf(" usKeyGroup = %hu\n", region->header->usKeyGroup); | |
959 } | |
960 if ( region->wlnk ) { | |
961 printf(" wlnk->fusOptions = 0x%4.4hx\n", region->wlnk->fusOptions); | |
962 printf(" wlnk->usPhaseGroup = %hu\n", region->wlnk->usPhaseGroup); | |
963 printf(" wlnk->ulChannel = %u\n", region->wlnk->ulChannel); | |
964 printf(" wlnk->ulTableIndex = %u\n", region->wlnk->ulTableIndex); | |
965 } | |
966 if ( region->wsmp ) { | |
967 Uint32 i; | |
968 printf(" wsmp->usUnityNote = %hu\n", region->wsmp->usUnityNote); | |
969 printf(" wsmp->sFineTune = %hd\n", region->wsmp->sFineTune); | |
970 printf(" wsmp->lAttenuation = %d\n", region->wsmp->lAttenuation); | |
971 printf(" wsmp->fulOptions = 0x%8.8x\n", region->wsmp->fulOptions); | |
972 printf(" wsmp->cSampleLoops = %u\n", region->wsmp->cSampleLoops); | |
973 for ( i = 0; i < region->wsmp->cSampleLoops; ++i ) { | |
974 WLOOP *loop = ®ion->wsmp_loop[i]; | |
975 printf(" Loop %u:\n", i); | |
976 printf(" ulStart = %u\n", loop->ulStart); | |
977 printf(" ulLength = %u\n", loop->ulLength); | |
978 } | |
979 } | |
980 if ( region->art && region->art->cConnections > 0 ) { | |
981 PrintArt("Region", region->art, region->artList); | |
982 } | |
983 } | |
984 | |
985 static void PrintInstrument(DLS_Instrument *instrument, Uint32 index) | |
986 { | |
987 printf("Instrument %u:\n", index); | |
988 if ( instrument->name ) { | |
989 printf(" Name: %s\n", instrument->name); | |
990 } | |
991 if ( instrument->header ) { | |
992 Uint32 i; | |
993 printf(" ulBank = 0x%8.8x\n", instrument->header->Locale.ulBank); | |
994 printf(" ulInstrument = %u\n", instrument->header->Locale.ulInstrument); | |
995 printf(" Regions: %u\n", instrument->header->cRegions); | |
996 for ( i = 0; i < instrument->header->cRegions; ++i ) { | |
997 PrintRegion(&instrument->regions[i], i); | |
998 } | |
999 } | |
1000 if ( instrument->art && instrument->art->cConnections > 0 ) { | |
1001 PrintArt("Instrument", instrument->art, instrument->artList); | |
1002 } | |
1003 }; | |
1004 | |
1005 void PrintDLS(DLS_Data *data) | |
1006 { | |
1007 printf("DLS Data:\n"); | |
1008 printf("cInstruments = %u\n", data->cInstruments); | |
1009 if ( data->instruments ) { | |
1010 Uint32 i; | |
1011 for ( i = 0; i < data->cInstruments; ++i ) { | |
1012 PrintInstrument(&data->instruments[i], i); | |
1013 } | |
1014 } | |
1015 if ( data->ptbl && data->ptbl->cCues > 0 ) { | |
1016 Uint32 i; | |
1017 printf("Cues: "); | |
1018 for ( i = 0; i < data->ptbl->cCues; ++i ) { | |
1019 if ( i > 0 ) { | |
1020 printf(", "); | |
1021 } | |
1022 printf("%u", data->ptblList[i].ulOffset); | |
1023 } | |
1024 printf("\n"); | |
1025 } | |
1026 if ( data->waveList ) { | |
1027 Uint32 i; | |
1028 printf("Waves:\n"); | |
1029 for ( i = 0; i < data->ptbl->cCues; ++i ) { | |
1030 PrintWave(&data->waveList[i], i); | |
1031 } | |
1032 } | |
1033 if ( data->name ) { | |
1034 printf("Name: %s\n", data->name); | |
1035 } | |
1036 if ( data->artist ) { | |
1037 printf("Artist: %s\n", data->artist); | |
1038 } | |
1039 if ( data->copyright ) { | |
1040 printf("Copyright: %s\n", data->copyright); | |
1041 } | |
1042 if ( data->comments ) { | |
1043 printf("Comments: %s\n", data->comments); | |
1044 } | |
1045 } | |
1046 | |
1047 #ifdef TEST_MAIN_DLS | |
1048 | |
1049 main(int argc, char *argv[]) | |
1050 { | |
1051 int i; | |
1052 for ( i = 1; i < argc; ++i ) { | |
1053 DLS_Data *data; | |
1054 SDL_RWops *src = SDL_RWFromFile(argv[i], "rb"); | |
1055 if ( !src ) { | |
1056 fprintf(stderr, "Couldn't open %s: %s", argv[i], SDL_GetError()); | |
1057 continue; | |
1058 } | |
1059 data = LoadDLS(src); | |
1060 if ( data ) { | |
1061 PrintRIFF(data->chunk, 0); | |
1062 PrintDLS(data); | |
1063 FreeDLS(data); | |
1064 } else { | |
1065 fprintf(stderr, "Couldn't load %s: %s\n", argv[i], SDL_GetError()); | |
1066 } | |
1067 SDL_RWclose(src); | |
1068 } | |
1069 } | |
1070 | |
1071 #endif // TEST_MAIN | |
1072 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
1073 | |
1074 /*-------------------------------------------------------------------------*/ | |
1075 /* * * * * * * * * * * * * * * * * instrum_dls.c * * * * * * * * * * * * * */ | |
1076 /*-------------------------------------------------------------------------*/ | |
1077 | |
1078 DLS_Data *Timidity_LoadDLS(SDL_RWops *src) | |
1079 { | |
1080 DLS_Data *patches = LoadDLS(src); | |
1081 if (!patches) { | |
1082 SNDDBG(("%s", SDL_GetError())); | |
1083 } | |
1084 return patches; | |
1085 } | |
1086 | |
1087 void Timidity_FreeDLS(DLS_Data *patches) | |
1088 { | |
1089 FreeDLS(patches); | |
1090 } | |
1091 | |
1092 /* convert timecents to sec */ | |
1093 static double to_msec(int timecent) | |
1094 { | |
1095 if (timecent == 0x80000000 || timecent == 0) | |
1096 return 0.0; | |
1097 return 1000.0 * pow(2.0, (double)(timecent / 65536) / 1200.0); | |
1098 } | |
1099 | |
1100 /* convert decipercent to {0..1} */ | |
1101 static double to_normalized_percent(int decipercent) | |
1102 { | |
1103 return ((double)(decipercent / 65536)) / 1000.0; | |
1104 } | |
1105 | |
1106 /* convert from 8bit value to fractional offset (15.15) */ | |
1107 static Sint32 to_offset(int offset) | |
1108 { | |
1109 return (Sint32)offset << (7+15); | |
1110 } | |
1111 | |
1112 /* calculate ramp rate in fractional unit; | |
1113 * diff = 8bit, time = msec | |
1114 */ | |
1115 static Sint32 calc_rate(MidiSong *song, int diff, int sample_rate, double msec) | |
1116 { | |
1117 double rate; | |
1118 | |
1119 if(msec < 6) | |
1120 msec = 6; | |
1121 if(diff == 0) | |
1122 diff = 255; | |
1123 diff <<= (7+15); | |
1124 rate = ((double)diff / song->rate) * song->control_ratio * 1000.0 / msec; | |
1125 return (Sint32)rate; | |
1126 } | |
1127 | |
1128 static int load_connection(ULONG cConnections, CONNECTION *artList, USHORT destination) | |
1129 { | |
1130 ULONG i; | |
1131 int value = 0; | |
1132 for (i = 0; i < cConnections; ++i) { | |
1133 CONNECTION *conn = &artList[i]; | |
1134 if(conn->usDestination == destination) { | |
1135 // The formula for the destination is: | |
1136 // usDestination = usDestination + usTransform(usSource * (usControl * lScale)) | |
1137 // Since we are only handling source/control of NONE and identity | |
1138 // transform, this simplifies to: usDestination = usDestination + lScale | |
1139 if (conn->usSource == CONN_SRC_NONE && | |
1140 conn->usControl == CONN_SRC_NONE && | |
1141 conn->usTransform == CONN_TRN_NONE) | |
1142 value += conn->lScale; | |
1143 } | |
1144 } | |
1145 return value; | |
1146 } | |
1147 | |
1148 static void load_region_dls(MidiSong *song, Sample *sample, DLS_Instrument *ins, Uint32 index) | |
1149 { | |
1150 DLS_Region *rgn = &ins->regions[index]; | |
1151 DLS_Wave *wave = &song->patches->waveList[rgn->wlnk->ulTableIndex]; | |
1152 | |
1153 sample->low_freq = freq_table[rgn->header->RangeKey.usLow]; | |
1154 sample->high_freq = freq_table[rgn->header->RangeKey.usHigh]; | |
1155 sample->root_freq = freq_table[rgn->wsmp->usUnityNote]; | |
1156 sample->low_vel = rgn->header->RangeVelocity.usLow; | |
1157 sample->high_vel = rgn->header->RangeVelocity.usHigh; | |
1158 | |
1159 sample->modes = MODES_16BIT; | |
1160 sample->sample_rate = wave->format->dwSamplesPerSec; | |
1161 sample->data_length = wave->length / 2; | |
1162 sample->data = (sample_t *)safe_malloc(wave->length); | |
1163 memcpy(sample->data, wave->data, wave->length); | |
1164 if (rgn->wsmp->cSampleLoops) { | |
1165 sample->modes |= (MODES_LOOPING|MODES_SUSTAIN); | |
1166 sample->loop_start = rgn->wsmp_loop->ulStart / 2; | |
1167 sample->loop_end = sample->loop_start + (rgn->wsmp_loop->ulLength / 2); | |
1168 } | |
1169 sample->volume = 1.0f; | |
1170 | |
1171 if (sample->modes & MODES_SUSTAIN) { | |
1172 int value; | |
1173 double attack, hold, decay, release; int sustain; | |
1174 CONNECTIONLIST *art = NULL; | |
1175 CONNECTION *artList = NULL; | |
1176 | |
1177 if (ins->art && ins->art->cConnections > 0 && ins->artList) { | |
1178 art = ins->art; | |
1179 artList = ins->artList; | |
1180 } else { | |
1181 art = rgn->art; | |
1182 artList = rgn->artList; | |
1183 } | |
1184 | |
1185 value = load_connection(art->cConnections, artList, CONN_DST_EG1_ATTACKTIME); | |
1186 attack = to_msec(value); | |
1187 value = load_connection(art->cConnections, artList, CONN_DST_EG1_HOLDTIME); | |
1188 hold = to_msec(value); | |
1189 value = load_connection(art->cConnections, artList, CONN_DST_EG1_DECAYTIME); | |
1190 decay = to_msec(value); | |
1191 value = load_connection(art->cConnections, artList, CONN_DST_EG1_RELEASETIME); | |
1192 release = to_msec(value); | |
1193 value = load_connection(art->cConnections, artList, CONN_DST_EG1_SUSTAINLEVEL); | |
1194 sustain = (int)((1.0 - to_normalized_percent(value)) * 250.0); | |
1195 value = load_connection(art->cConnections, artList, CONN_DST_PAN); | |
1196 sample->panning = (int)((0.5 + to_normalized_percent(value)) * 127.0); | |
1197 | |
1198 /* | |
1199 printf("%d, Rate=%d LV=%d HV=%d Low=%d Hi=%d Root=%d Pan=%d Attack=%f Hold=%f Sustain=%d Decay=%f Release=%f\n", index, sample->sample_rate, rgn->header->RangeVelocity.usLow, rgn->header->RangeVelocity.usHigh, sample->low_freq, sample->high_freq, sample->root_freq, sample->panning, attack, hold, sustain, decay, release); | |
1200 */ | |
1201 | |
1202 sample->envelope_offset[0] = to_offset(255); | |
1203 sample->envelope_rate[0] = calc_rate(song, 255, sample->sample_rate, attack); | |
1204 | |
1205 sample->envelope_offset[1] = to_offset(250); | |
1206 sample->envelope_rate[1] = calc_rate(song, 5, sample->sample_rate, hold); | |
1207 | |
1208 sample->envelope_offset[2] = to_offset(sustain); | |
1209 sample->envelope_rate[2] = calc_rate(song, 255 - sustain, sample->sample_rate, decay); | |
1210 | |
1211 sample->envelope_offset[3] = to_offset(0); | |
1212 sample->envelope_rate[3] = calc_rate(song, 5 + sustain, sample->sample_rate, release); | |
1213 | |
1214 sample->envelope_offset[4] = to_offset(0); | |
1215 sample->envelope_rate[4] = to_offset(1); | |
1216 | |
1217 sample->envelope_offset[5] = to_offset(0); | |
1218 sample->envelope_rate[5] = to_offset(1); | |
1219 | |
1220 sample->modes |= MODES_ENVELOPE; | |
1221 } | |
1222 | |
1223 sample->data_length <<= FRACTION_BITS; | |
1224 sample->loop_start <<= FRACTION_BITS; | |
1225 sample->loop_end <<= FRACTION_BITS; | |
1226 } | |
1227 | |
1228 Instrument *load_instrument_dls(MidiSong *song, int drum, int bank, int instrument) | |
1229 { | |
1230 Instrument *inst; | |
1231 Uint32 i; | |
1232 DLS_Instrument *dls_ins; | |
1233 | |
1234 if (!song->patches) | |
1235 return(NULL); | |
1236 | |
1237 drum = drum ? 0x80000000 : 0; | |
1238 for (i = 0; i < song->patches->cInstruments; ++i) { | |
1239 dls_ins = &song->patches->instruments[i]; | |
1240 if ((dls_ins->header->Locale.ulBank & 0x80000000) == drum && | |
1241 ((dls_ins->header->Locale.ulBank >> 8) & 0xFF) == bank && | |
1242 dls_ins->header->Locale.ulInstrument == instrument) | |
1243 break; | |
1244 } | |
1245 if (i == song->patches->cInstruments && !bank) { | |
1246 for (i = 0; i < song->patches->cInstruments; ++i) { | |
1247 dls_ins = &song->patches->instruments[i]; | |
1248 if ((dls_ins->header->Locale.ulBank & 0x80000000) == drum && | |
1249 dls_ins->header->Locale.ulInstrument == instrument) | |
1250 break; | |
1251 } | |
1252 } | |
1253 if (i == song->patches->cInstruments) { | |
1254 SNDDBG(("Couldn't find %s instrument %d in bank %d\n", drum ? "drum" : "melodic", instrument, bank)); | |
1255 return(NULL); | |
1256 } | |
1257 | |
1258 inst = (Instrument *)safe_malloc(sizeof(*inst)); | |
1259 inst->samples = dls_ins->header->cRegions; | |
1260 inst->sample = (Sample *)safe_malloc(inst->samples * sizeof(*inst->sample)); | |
1261 memset(inst->sample, 0, inst->samples * sizeof(*inst->sample)); | |
1262 /* | |
1263 printf("Found %s instrument %d in bank %d named %s with %d regions\n", drum ? "drum" : "melodic", instrument, bank, dls_ins->name, inst->samples); | |
1264 */ | |
1265 for (i = 0; i < dls_ins->header->cRegions; ++i) { | |
1266 load_region_dls(song, &inst->sample[i], dls_ins, i); | |
1267 } | |
1268 return(inst); | |
1269 } |