1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * 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
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23
24 #include "common/scummsys.h"
25
26 #include "audio/audiostream.h"
27 #include "audio/decoders/flac.h"
28 #include "audio/decoders/voc.h"
29 #include "audio/decoders/vorbis.h"
30 #include "audio/decoders/mp3.h"
31
32 #include "scumm/resource.h"
33 #include "scumm/scumm.h"
34 #include "scumm/imuse_digi/dimuse_bndmgr.h"
35 #include "scumm/imuse_digi/dimuse_codecs.h"
36 #include "scumm/imuse_digi/dimuse_sndmgr.h"
37
38 namespace Scumm {
39
ImuseDigiSndMgr(ScummEngine * scumm)40 ImuseDigiSndMgr::ImuseDigiSndMgr(ScummEngine *scumm) {
41 for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) {
42 memset(&_sounds[l], 0, sizeof(SoundDesc));
43 }
44 _vm = scumm;
45 _disk = 0;
46 _cacheBundleDir = new BundleDirCache();
47 assert(_cacheBundleDir);
48 BundleCodecs::initializeImcTables();
49 }
50
~ImuseDigiSndMgr()51 ImuseDigiSndMgr::~ImuseDigiSndMgr() {
52 for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) {
53 closeSound(&_sounds[l]);
54 }
55
56 delete _cacheBundleDir;
57 BundleCodecs::releaseImcTables();
58 }
59
countElements(byte * ptr,int & numRegions,int & numJumps,int & numSyncs,int & numMarkers)60 void ImuseDigiSndMgr::countElements(byte *ptr, int &numRegions, int &numJumps, int &numSyncs, int &numMarkers) {
61 uint32 tag;
62 int32 size = 0;
63
64 do {
65 tag = READ_BE_UINT32(ptr); ptr += 4;
66 switch (tag) {
67 case MKTAG('S','T','O','P'):
68 case MKTAG('F','R','M','T'):
69 case MKTAG('D','A','T','A'):
70 size = READ_BE_UINT32(ptr); ptr += size + 4;
71 break;
72 case MKTAG('T','E','X','T'):
73 if (!scumm_stricmp((const char *)(ptr + 8), "exit"))
74 numMarkers++;
75 size = READ_BE_UINT32(ptr); ptr += size + 4;
76 break;
77 case MKTAG('R','E','G','N'):
78 numRegions++;
79 size = READ_BE_UINT32(ptr); ptr += size + 4;
80 break;
81 case MKTAG('J','U','M','P'):
82 numJumps++;
83 size = READ_BE_UINT32(ptr); ptr += size + 4;
84 break;
85 case MKTAG('S','Y','N','C'):
86 numSyncs++;
87 size = READ_BE_UINT32(ptr); ptr += size + 4;
88 break;
89 default:
90 error("ImuseDigiSndMgr::countElements() Unknown sfx header '%s'", tag2str(tag));
91 }
92 } while (tag != MKTAG('D','A','T','A'));
93 }
94
prepareSoundFromRMAP(Common::SeekableReadStream * file,SoundDesc * sound,int32 offset,int32 size)95 void ImuseDigiSndMgr::prepareSoundFromRMAP(Common::SeekableReadStream *file, SoundDesc *sound, int32 offset, int32 size) {
96 int l;
97
98 file->seek(offset, SEEK_SET);
99 uint32 tag = file->readUint32BE();
100 assert(tag == MKTAG('R','M','A','P'));
101 int32 version = file->readUint32BE();
102 if (version != 3) {
103 if (version == 2) {
104 warning("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version of compressed *.bun file, expected 3, but it's 2");
105 warning("Suggested to recompress with latest tool from daily builds");
106 } else
107 error("ImuseDigiSndMgr::prepareSoundFromRMAP: Wrong version number, expected 3, but it's: %d", version);
108 }
109 sound->bits = file->readUint32BE();
110 sound->freq = file->readUint32BE();
111 sound->channels = file->readUint32BE();
112 sound->numRegions = file->readUint32BE();
113 sound->numJumps = file->readUint32BE();
114 sound->numSyncs = file->readUint32BE();
115 if (version >= 3)
116 sound->numMarkers = file->readUint32BE();
117 else
118 sound->numMarkers = 0;
119
120 sound->region = new Region[sound->numRegions];
121 assert(sound->region);
122 sound->jump = new Jump[sound->numJumps];
123 assert(sound->jump);
124 sound->sync = new Sync[sound->numSyncs];
125 assert(sound->sync);
126 sound->marker = new Marker[sound->numMarkers];
127 assert(sound->marker);
128
129 for (l = 0; l < sound->numRegions; l++) {
130 sound->region[l].offset = file->readUint32BE();
131 sound->region[l].length = file->readUint32BE();
132 }
133 for (l = 0; l < sound->numJumps; l++) {
134 sound->jump[l].offset = file->readUint32BE();
135 sound->jump[l].dest = file->readUint32BE();
136 sound->jump[l].hookId = file->readUint32BE();
137 sound->jump[l].fadeDelay = file->readUint32BE();
138 }
139 for (l = 0; l < sound->numSyncs; l++) {
140 sound->sync[l].size = file->readUint32BE();
141 sound->sync[l].ptr = new byte[sound->sync[l].size];
142 file->read(sound->sync[l].ptr, sound->sync[l].size);
143 }
144 if (version >= 3) {
145 for (l = 0; l < sound->numMarkers; l++) {
146 sound->marker[l].pos = file->readUint32BE();
147 sound->marker[l].length = file->readUint32BE();
148 sound->marker[l].ptr = new char[sound->marker[l].length];
149 file->read(sound->marker[l].ptr, sound->marker[l].length);
150 }
151 }
152 }
153
prepareSound(byte * ptr,SoundDesc * sound)154 void ImuseDigiSndMgr::prepareSound(byte *ptr, SoundDesc *sound) {
155 if (READ_BE_UINT32(ptr) == MKTAG('C','r','e','a')) {
156 bool quit = false;
157 int len;
158
159 int32 offset = READ_LE_UINT16(ptr + 20);
160 int16 code = READ_LE_UINT16(ptr + 24);
161
162 sound->numRegions = 0;
163 sound->region = new Region[70];
164 assert(sound->region);
165
166 sound->numJumps = 0;
167 sound->jump = new Jump[1];
168 assert(sound->jump);
169
170 sound->numSyncs = 0;
171
172 sound->resPtr = ptr;
173 sound->bits = 8;
174 sound->channels = 1;
175
176 while (!quit) {
177 len = READ_LE_UINT32(ptr + offset);
178 code = len & 0xFF;
179 if ((code != 0) && (code != 1) && (code != 6) && (code != 7)) {
180 // try again with 2 bytes forward (workaround for some FT sounds (ex.362, 363)
181 offset += 2;
182 len = READ_LE_UINT32(ptr + offset);
183 code = len & 0xFF;
184 if ((code != 0) && (code != 1) && (code != 6) && (code != 7)) {
185 error("Invalid code in VOC file : %d", code);
186 }
187 }
188 offset += 4;
189 len >>= 8;
190 switch (code) {
191 case 0:
192 quit = true;
193 break;
194 case 1:
195 {
196 int time_constant = ptr[offset];
197 offset += 2;
198 len -= 2;
199 sound->freq = Audio::getSampleRateFromVOCRate(time_constant);
200 sound->region[sound->numRegions].offset = offset;
201 sound->region[sound->numRegions].length = len;
202 sound->numRegions++;
203 }
204 break;
205 case 6: // begin of loop
206 sound->jump[0].dest = offset + 8;
207 sound->jump[0].hookId = 0;
208 sound->jump[0].fadeDelay = 0;
209 break;
210 case 7: // end of loop
211 sound->jump[0].offset = offset - 4;
212 sound->numJumps++;
213 sound->region[sound->numRegions].offset = offset - 4;
214 sound->region[sound->numRegions].length = 0;
215 sound->numRegions++;
216 break;
217 default:
218 error("Invalid code in VOC file : %d", code);
219 quit = true;
220 break;
221 }
222 offset += len;
223 }
224 } else if (READ_BE_UINT32(ptr) == MKTAG('i','M','U','S')) {
225 uint32 tag;
226 int32 size = 0;
227 byte *s_ptr = ptr;
228 ptr += 16;
229
230 int curIndexRegion = 0;
231 int curIndexJump = 0;
232 int curIndexSync = 0;
233 int curIndexMarker = 0;
234
235 sound->numRegions = 0;
236 sound->numJumps = 0;
237 sound->numSyncs = 0;
238 sound->numMarkers = 0;
239 countElements(ptr, sound->numRegions, sound->numJumps, sound->numSyncs, sound->numMarkers);
240 sound->region = new Region[sound->numRegions];
241 assert(sound->region);
242 sound->jump = new Jump[sound->numJumps];
243 assert(sound->jump);
244 sound->sync = new Sync[sound->numSyncs];
245 assert(sound->sync);
246 sound->marker = new Marker[sound->numMarkers];
247 assert(sound->marker);
248
249 do {
250 tag = READ_BE_UINT32(ptr); ptr += 4;
251 switch (tag) {
252 case MKTAG('F','R','M','T'):
253 ptr += 12;
254 sound->bits = READ_BE_UINT32(ptr); ptr += 4;
255 sound->freq = READ_BE_UINT32(ptr); ptr += 4;
256 sound->channels = READ_BE_UINT32(ptr); ptr += 4;
257 break;
258 case MKTAG('T','E','X','T'):
259 if (!scumm_stricmp((const char *)(ptr + 8), "exit")) {
260 sound->marker[curIndexMarker].pos = READ_BE_UINT32(ptr + 4);
261 sound->marker[curIndexMarker].length = strlen((const char *)(ptr + 8)) + 1;
262 sound->marker[curIndexMarker].ptr = new char[sound->marker[curIndexMarker].length];
263 assert(sound->marker[curIndexMarker].ptr);
264 strcpy(sound->marker[curIndexMarker].ptr, (const char *)(ptr + 8));
265 curIndexMarker++;
266 }
267 size = READ_BE_UINT32(ptr); ptr += size + 4;
268 break;
269 case MKTAG('S','T','O','P'):
270 size = READ_BE_UINT32(ptr); ptr += size + 4;
271 break;
272 case MKTAG('R','E','G','N'):
273 ptr += 4;
274 sound->region[curIndexRegion].offset = READ_BE_UINT32(ptr); ptr += 4;
275 sound->region[curIndexRegion].length = READ_BE_UINT32(ptr); ptr += 4;
276 curIndexRegion++;
277 break;
278 case MKTAG('J','U','M','P'):
279 ptr += 4;
280 sound->jump[curIndexJump].offset = READ_BE_UINT32(ptr); ptr += 4;
281 sound->jump[curIndexJump].dest = READ_BE_UINT32(ptr); ptr += 4;
282 sound->jump[curIndexJump].hookId = READ_BE_UINT32(ptr); ptr += 4;
283 sound->jump[curIndexJump].fadeDelay = READ_BE_UINT32(ptr); ptr += 4;
284 curIndexJump++;
285 break;
286 case MKTAG('S','Y','N','C'):
287 size = READ_BE_UINT32(ptr); ptr += 4;
288 sound->sync[curIndexSync].size = size;
289 sound->sync[curIndexSync].ptr = new byte[size];
290 assert(sound->sync[curIndexSync].ptr);
291 memcpy(sound->sync[curIndexSync].ptr, ptr, size);
292 curIndexSync++;
293 ptr += size;
294 break;
295 case MKTAG('D','A','T','A'):
296 ptr += 4;
297 break;
298 default:
299 error("ImuseDigiSndMgr::prepareSound(%d/%s) Unknown sfx header '%s'", sound->soundId, sound->name, tag2str(tag));
300 }
301 } while (tag != MKTAG('D','A','T','A'));
302 sound->offsetData = ptr - s_ptr;
303 } else {
304 error("ImuseDigiSndMgr::prepareSound(): Unknown sound format");
305 }
306 }
307
allocSlot()308 ImuseDigiSndMgr::SoundDesc *ImuseDigiSndMgr::allocSlot() {
309 for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) {
310 if (!_sounds[l].inUse) {
311 _sounds[l].inUse = true;
312 return &_sounds[l];
313 }
314 }
315
316 return NULL;
317 }
318
openMusicBundle(SoundDesc * sound,int & disk)319 bool ImuseDigiSndMgr::openMusicBundle(SoundDesc *sound, int &disk) {
320 bool result = false;
321
322 sound->bundle = new BundleMgr(_cacheBundleDir);
323 assert(sound->bundle);
324 if (_vm->_game.id == GID_CMI) {
325 if (_vm->_game.features & GF_DEMO) {
326 result = sound->bundle->open("music.bun", sound->compressed);
327 } else {
328 char musicfile[20];
329 if (disk == -1)
330 disk = _vm->VAR(_vm->VAR_CURRENTDISK);
331 sprintf(musicfile, "musdisk%d.bun", disk);
332 // if (_disk != _vm->VAR(_vm->VAR_CURRENTDISK)) {
333 // _vm->_imuseDigital->parseScriptCmds(0x1000, 0, 0, 0, 0, 0, 0, 0);
334 // _vm->_imuseDigital->parseScriptCmds(0x2000, 0, 0, 0, 0, 0, 0, 0);
335 // _vm->_imuseDigital->stopAllSounds();
336 // sound->bundle->closeFile();
337 // }
338
339 result = sound->bundle->open(musicfile, sound->compressed, true);
340
341 // FIXME: Shouldn't we only set _disk if result == true?
342 _disk = (byte)_vm->VAR(_vm->VAR_CURRENTDISK);
343 }
344 } else if (_vm->_game.id == GID_DIG)
345 result = sound->bundle->open("digmusic.bun", sound->compressed, true);
346 else
347 error("ImuseDigiSndMgr::openMusicBundle() Don't know which bundle file to load");
348
349 _vm->VAR(_vm->VAR_MUSIC_BUNDLE_LOADED) = result ? 1 : 0;
350
351 return result;
352 }
353
openVoiceBundle(SoundDesc * sound,int & disk)354 bool ImuseDigiSndMgr::openVoiceBundle(SoundDesc *sound, int &disk) {
355 bool result = false;
356
357 sound->bundle = new BundleMgr(_cacheBundleDir);
358 assert(sound->bundle);
359 if (_vm->_game.id == GID_CMI) {
360 if (_vm->_game.features & GF_DEMO) {
361 result = sound->bundle->open("voice.bun", sound->compressed);
362 } else {
363 char voxfile[20];
364 if (disk == -1)
365 disk = _vm->VAR(_vm->VAR_CURRENTDISK);
366 sprintf(voxfile, "voxdisk%d.bun", disk);
367 // if (_disk != _vm->VAR(_vm->VAR_CURRENTDISK)) {
368 // _vm->_imuseDigital->parseScriptCmds(0x1000, 0, 0, 0, 0, 0, 0, 0);
369 // _vm->_imuseDigital->parseScriptCmds(0x2000, 0, 0, 0, 0, 0, 0, 0);
370 // _vm->_imuseDigital->stopAllSounds();
371 // sound->bundle->closeFile();
372 // }
373
374 result = sound->bundle->open(voxfile, sound->compressed);
375
376 // FIXME: Shouldn't we only set _disk if result == true?
377 _disk = (byte)_vm->VAR(_vm->VAR_CURRENTDISK);
378 }
379 } else if (_vm->_game.id == GID_DIG)
380 result = sound->bundle->open("digvoice.bun", sound->compressed);
381 else
382 error("ImuseDigiSndMgr::openVoiceBundle() Don't know which bundle file to load");
383
384 _vm->VAR(_vm->VAR_VOICE_BUNDLE_LOADED) = result ? 1 : 0;
385
386 return result;
387 }
388
openSound(int32 soundId,const char * soundName,int soundType,int volGroupId,int disk)389 ImuseDigiSndMgr::SoundDesc *ImuseDigiSndMgr::openSound(int32 soundId, const char *soundName, int soundType, int volGroupId, int disk) {
390 assert(soundId >= 0);
391 assert(soundType);
392
393 SoundDesc *sound = allocSlot();
394 if (!sound) {
395 error("ImuseDigiSndMgr::openSound() can't alloc free sound slot");
396 }
397
398 const bool header_outside = ((_vm->_game.id == GID_CMI) && !(_vm->_game.features & GF_DEMO));
399 bool result = false;
400 byte *ptr = NULL;
401
402 switch (soundType) {
403 case IMUSE_RESOURCE:
404 assert(soundName[0] == 0); // Paranoia check
405
406 _vm->ensureResourceLoaded(rtSound, soundId);
407 _vm->_res->lock(rtSound, soundId);
408 ptr = _vm->getResourceAddress(rtSound, soundId);
409 if (ptr == NULL) {
410 closeSound(sound);
411 return NULL;
412 }
413 sound->resPtr = ptr;
414 break;
415 case IMUSE_BUNDLE:
416 if (volGroupId == IMUSE_VOLGRP_VOICE)
417 result = openVoiceBundle(sound, disk);
418 else if (volGroupId == IMUSE_VOLGRP_MUSIC)
419 result = openMusicBundle(sound, disk);
420 else
421 error("ImuseDigiSndMgr::openSound() Don't know how load sound: %d", soundId);
422 if (!result) {
423 closeSound(sound);
424 return NULL;
425 }
426 if (sound->compressed) {
427 char fileName[24];
428 int32 offset = 0, size = 0;
429 sprintf(fileName, "%s.map", soundName);
430 Common::SeekableReadStream *rmapFile = sound->bundle->getFile(fileName, offset, size);
431 if (!rmapFile) {
432 closeSound(sound);
433 return NULL;
434 }
435 prepareSoundFromRMAP(rmapFile, sound, offset, size);
436 strcpy(sound->name, soundName);
437 sound->soundId = soundId;
438 sound->type = soundType;
439 sound->volGroupId = volGroupId;
440 sound->disk = disk;
441 return sound;
442 } else if (soundName[0] == 0) {
443 if (sound->bundle->decompressSampleByIndex(soundId, 0, 0x2000, &ptr, 0, header_outside) == 0 || ptr == NULL) {
444 closeSound(sound);
445 free(ptr);
446 return NULL;
447 }
448 } else {
449 if (sound->bundle->decompressSampleByName(soundName, 0, 0x2000, &ptr, header_outside) == 0 || ptr == NULL) {
450 closeSound(sound);
451 free(ptr);
452 return NULL;
453 }
454 }
455 sound->resPtr = 0;
456 break;
457 default:
458 error("ImuseDigiSndMgr::openSound() Unknown soundType %d (trying to load sound %d)", soundType, soundId);
459 }
460
461 strcpy(sound->name, soundName);
462 sound->soundId = soundId;
463 sound->type = soundType;
464 sound->volGroupId = volGroupId;
465 sound->disk = _disk;
466 prepareSound(ptr, sound);
467 if ((soundType == IMUSE_BUNDLE) && !sound->compressed) {
468 free(ptr);
469 }
470 return sound;
471 }
472
closeSound(SoundDesc * soundDesc)473 void ImuseDigiSndMgr::closeSound(SoundDesc *soundDesc) {
474 assert(checkForProperHandle(soundDesc));
475
476 if (soundDesc->resPtr) {
477 bool found = false;
478 for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) {
479 if ((_sounds[l].soundId == soundDesc->soundId) && (&_sounds[l] != soundDesc))
480 found = true;
481 }
482 if (!found)
483 _vm->_res->unlock(rtSound, soundDesc->soundId);
484 }
485
486 delete soundDesc->compressedStream;
487 delete soundDesc->bundle;
488
489 for (int r = 0; r < soundDesc->numSyncs; r++)
490 delete[] soundDesc->sync[r].ptr;
491 for (int r = 0; r < soundDesc->numMarkers; r++)
492 delete[] soundDesc->marker[r].ptr;
493 delete[] soundDesc->region;
494 delete[] soundDesc->jump;
495 delete[] soundDesc->sync;
496 delete[] soundDesc->marker;
497 memset(soundDesc, 0, sizeof(SoundDesc));
498 }
499
cloneSound(SoundDesc * soundDesc)500 ImuseDigiSndMgr::SoundDesc *ImuseDigiSndMgr::cloneSound(SoundDesc *soundDesc) {
501 ImuseDigiSndMgr::SoundDesc *desc;
502 assert(checkForProperHandle(soundDesc));
503
504 desc = openSound(soundDesc->soundId, soundDesc->name, soundDesc->type, soundDesc->volGroupId, soundDesc->disk);
505 if (!desc)
506 desc = openSound(soundDesc->soundId, soundDesc->name, soundDesc->type, soundDesc->volGroupId, 1);
507 if (!desc)
508 desc = openSound(soundDesc->soundId, soundDesc->name, soundDesc->type, soundDesc->volGroupId, 2);
509 return desc;
510 }
511
checkForProperHandle(SoundDesc * soundDesc)512 bool ImuseDigiSndMgr::checkForProperHandle(SoundDesc *soundDesc) {
513 if (!soundDesc)
514 return false;
515 for (int l = 0; l < MAX_IMUSE_SOUNDS; l++) {
516 if (soundDesc == &_sounds[l])
517 return true;
518 }
519 return false;
520 }
521
isSndDataExtComp(SoundDesc * soundDesc)522 bool ImuseDigiSndMgr::isSndDataExtComp(SoundDesc *soundDesc) {
523 assert(checkForProperHandle(soundDesc));
524 return soundDesc->compressed;
525 }
526
getFreq(SoundDesc * soundDesc)527 int ImuseDigiSndMgr::getFreq(SoundDesc *soundDesc) {
528 assert(checkForProperHandle(soundDesc));
529 return soundDesc->freq;
530 }
531
getBits(SoundDesc * soundDesc)532 int ImuseDigiSndMgr::getBits(SoundDesc *soundDesc) {
533 assert(checkForProperHandle(soundDesc));
534 return soundDesc->bits;
535 }
536
getChannels(SoundDesc * soundDesc)537 int ImuseDigiSndMgr::getChannels(SoundDesc *soundDesc) {
538 assert(checkForProperHandle(soundDesc));
539 return soundDesc->channels;
540 }
541
isEndOfRegion(SoundDesc * soundDesc,int region)542 bool ImuseDigiSndMgr::isEndOfRegion(SoundDesc *soundDesc, int region) {
543 assert(checkForProperHandle(soundDesc));
544 assert(region >= 0 && region < soundDesc->numRegions);
545 return soundDesc->endFlag;
546 }
547
getNumRegions(SoundDesc * soundDesc)548 int ImuseDigiSndMgr::getNumRegions(SoundDesc *soundDesc) {
549 assert(checkForProperHandle(soundDesc));
550 return soundDesc->numRegions;
551 }
552
getNumJumps(SoundDesc * soundDesc)553 int ImuseDigiSndMgr::getNumJumps(SoundDesc *soundDesc) {
554 assert(checkForProperHandle(soundDesc));
555 return soundDesc->numJumps;
556 }
557
getRegionOffset(SoundDesc * soundDesc,int region)558 int ImuseDigiSndMgr::getRegionOffset(SoundDesc *soundDesc, int region) {
559 debug(5, "getRegionOffset() region:%d", region);
560 assert(checkForProperHandle(soundDesc));
561 assert(region >= 0 && region < soundDesc->numRegions);
562 return soundDesc->region[region].offset;
563 }
564
getJumpIdByRegionAndHookId(SoundDesc * soundDesc,int region,int hookId)565 int ImuseDigiSndMgr::getJumpIdByRegionAndHookId(SoundDesc *soundDesc, int region, int hookId) {
566 debug(5, "getJumpIdByRegionAndHookId() region:%d, hookId:%d", region, hookId);
567 assert(checkForProperHandle(soundDesc));
568 assert(region >= 0 && region < soundDesc->numRegions);
569 int32 offset = soundDesc->region[region].offset;
570 for (int l = 0; l < soundDesc->numJumps; l++) {
571 if (offset == soundDesc->jump[l].offset) {
572 if (soundDesc->jump[l].hookId == hookId)
573 return l;
574 }
575 }
576
577 return -1;
578 }
579
checkForTriggerByRegionAndMarker(SoundDesc * soundDesc,int region,const char * marker)580 bool ImuseDigiSndMgr::checkForTriggerByRegionAndMarker(SoundDesc *soundDesc, int region, const char *marker) {
581 debug(5, "checkForTriggerByRegionAndMarker() region:%d, marker:%s", region, marker);
582 assert(checkForProperHandle(soundDesc));
583 assert(region >= 0 && region < soundDesc->numRegions);
584 assert(marker);
585 int32 offset = soundDesc->region[region].offset;
586 for (int l = 0; l < soundDesc->numMarkers; l++) {
587 if (offset == soundDesc->marker[l].pos) {
588 if (!scumm_stricmp(soundDesc->marker[l].ptr, marker))
589 return true;
590 }
591 }
592
593 return false;
594 }
595
getSyncSizeAndPtrById(SoundDesc * soundDesc,int number,int32 & sync_size,byte ** sync_ptr)596 void ImuseDigiSndMgr::getSyncSizeAndPtrById(SoundDesc *soundDesc, int number, int32 &sync_size, byte **sync_ptr) {
597 assert(checkForProperHandle(soundDesc));
598 assert(number >= 0);
599 if (number < soundDesc->numSyncs) {
600 sync_size = soundDesc->sync[number].size;
601 *sync_ptr = soundDesc->sync[number].ptr;
602 } else {
603 sync_size = 0;
604 *sync_ptr = NULL;
605 }
606 }
607
getRegionIdByJumpId(SoundDesc * soundDesc,int jumpId)608 int ImuseDigiSndMgr::getRegionIdByJumpId(SoundDesc *soundDesc, int jumpId) {
609 debug(5, "getRegionIdByJumpId() jumpId:%d", jumpId);
610 assert(checkForProperHandle(soundDesc));
611 assert(jumpId >= 0 && jumpId < soundDesc->numJumps);
612 int32 dest = soundDesc->jump[jumpId].dest;
613 for (int l = 0; l < soundDesc->numRegions; l++) {
614 if (dest == soundDesc->region[l].offset) {
615 return l;
616 }
617 }
618
619 return -1;
620 }
621
getJumpHookId(SoundDesc * soundDesc,int number)622 int ImuseDigiSndMgr::getJumpHookId(SoundDesc *soundDesc, int number) {
623 debug(5, "getJumpHookId() number:%d", number);
624 assert(checkForProperHandle(soundDesc));
625 assert(number >= 0 && number < soundDesc->numJumps);
626 return soundDesc->jump[number].hookId;
627 }
628
getJumpFade(SoundDesc * soundDesc,int number)629 int ImuseDigiSndMgr::getJumpFade(SoundDesc *soundDesc, int number) {
630 debug(5, "getJumpFade() number:%d", number);
631 assert(checkForProperHandle(soundDesc));
632 assert(number >= 0 && number < soundDesc->numJumps);
633 return soundDesc->jump[number].fadeDelay;
634 }
635
getDataFromRegion(SoundDesc * soundDesc,int region,byte ** buf,int32 offset,int32 size)636 int32 ImuseDigiSndMgr::getDataFromRegion(SoundDesc *soundDesc, int region, byte **buf, int32 offset, int32 size) {
637 debug(6, "getDataFromRegion() region:%d, offset:%d, size:%d, numRegions:%d", region, offset, size, soundDesc->numRegions);
638 assert(checkForProperHandle(soundDesc));
639 assert(buf && offset >= 0 && size >= 0);
640 assert(region >= 0 && region < soundDesc->numRegions);
641
642 int32 region_offset = soundDesc->region[region].offset;
643 int32 region_length = soundDesc->region[region].length;
644 int32 offset_data = soundDesc->offsetData;
645 int32 start = region_offset - offset_data;
646
647 if (offset + size + offset_data > region_length) {
648 size = region_length - offset;
649 soundDesc->endFlag = true;
650 } else {
651 soundDesc->endFlag = false;
652 }
653
654 int header_size = soundDesc->offsetData;
655 bool header_outside = ((_vm->_game.id == GID_CMI) && !(_vm->_game.features & GF_DEMO));
656 if ((soundDesc->bundle) && (!soundDesc->compressed)) {
657 size = soundDesc->bundle->decompressSampleByCurIndex(start + offset, size, buf, header_size, header_outside);
658 } else if (soundDesc->resPtr) {
659 *buf = (byte *)malloc(size);
660 assert(*buf);
661 memcpy(*buf, soundDesc->resPtr + start + offset + header_size, size);
662 } else if ((soundDesc->bundle) && (soundDesc->compressed)) {
663 *buf = (byte *)malloc(size);
664 assert(*buf);
665 char fileName[26];
666 int offsetMs = (((offset * 8 * 10) / soundDesc->bits) / (soundDesc->channels * soundDesc->freq)) * 100;
667 sprintf(fileName, "%s_reg%03d", soundDesc->name, region);
668 if (scumm_stricmp(fileName, soundDesc->lastFileName) != 0) {
669 int32 offs = 0, len = 0;
670 Common::SeekableReadStream *cmpFile;
671 #if defined(USE_FLAC) || defined(USE_VORBIS) || defined(USE_MAD)
672 uint8 soundMode = 0;
673 #endif
674
675 sprintf(fileName, "%s_reg%03d.fla", soundDesc->name, region);
676 cmpFile = soundDesc->bundle->getFile(fileName, offs, len);
677 if (len) {
678 #ifndef USE_FLAC
679 error("FLAC library compiled support needed");
680 #else
681 soundMode = 3;
682 #endif
683 }
684 if (!len) {
685 sprintf(fileName, "%s_reg%03d.ogg", soundDesc->name, region);
686 cmpFile = soundDesc->bundle->getFile(fileName, offs, len);
687 if (len) {
688 #ifndef USE_VORBIS
689 error("Vorbis library compiled support needed");
690 #else
691 soundMode = 2;
692 #endif
693 }
694 }
695 if (!len) {
696 sprintf(fileName, "%s_reg%03d.mp3", soundDesc->name, region);
697 cmpFile = soundDesc->bundle->getFile(fileName, offs, len);
698 if (len) {
699 #ifndef USE_MAD
700 error("Mad library compiled support needed");
701 #else
702 soundMode = 1;
703 #endif
704 }
705 }
706 assert(len);
707
708 if (!soundDesc->compressedStream) {
709 Common::SeekableReadStream *tmp = cmpFile->readStream(len);
710 assert(tmp);
711 #ifdef USE_FLAC
712 if (soundMode == 3)
713 soundDesc->compressedStream = Audio::makeFLACStream(tmp, DisposeAfterUse::YES);
714 #endif
715 #ifdef USE_VORBIS
716 if (soundMode == 2)
717 soundDesc->compressedStream = Audio::makeVorbisStream(tmp, DisposeAfterUse::YES);
718 #endif
719 #ifdef USE_MAD
720 if (soundMode == 1)
721 soundDesc->compressedStream = Audio::makeMP3Stream(tmp, DisposeAfterUse::YES);
722 #endif
723 assert(soundDesc->compressedStream);
724 soundDesc->compressedStream->seek(offsetMs);
725 }
726 strcpy(soundDesc->lastFileName, fileName);
727 }
728 size = soundDesc->compressedStream->readBuffer((int16 *)*buf, size / 2) * 2;
729 if (soundDesc->compressedStream->endOfData() || soundDesc->endFlag) {
730 delete soundDesc->compressedStream;
731 soundDesc->compressedStream = NULL;
732 soundDesc->lastFileName[0] = 0;
733 soundDesc->endFlag = true;
734 }
735 }
736
737 return size;
738 }
739
740 } // End of namespace Scumm
741