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 #include "scumm/actor.h"
24 #include "scumm/file.h"
25 #include "scumm/imuse/imuse.h"
26 #include "scumm/resource.h"
27 #include "scumm/scumm.h"
28 #include "scumm/he/sound_he.h"
29 #include "scumm/he/intern_he.h"
30 #include "scumm/util.h"
31
32 #include "common/config-manager.h"
33 #include "common/memstream.h"
34 #include "common/timer.h"
35 #include "common/util.h"
36
37 #include "audio/audiostream.h"
38 #include "audio/decoders/adpcm.h"
39 #include "audio/mixer.h"
40 #include "audio/decoders/raw.h"
41 #include "audio/decoders/wave.h"
42 #include "audio/decoders/mp3.h"
43 #include "audio/decoders/vorbis.h"
44 #include "audio/decoders/flac.h"
45
46 namespace Scumm {
47
SoundHE(ScummEngine * parent,Audio::Mixer * mixer)48 SoundHE::SoundHE(ScummEngine *parent, Audio::Mixer *mixer)
49 :
50 Sound(parent, mixer),
51 _vm((ScummEngine_v60he *)parent),
52 _overrideFreq(0),
53 _heMusic(0),
54 _heMusicTracks(0) {
55
56 memset(_heChannel, 0, sizeof(_heChannel));
57 _heSoundChannels = new Audio::SoundHandle[8]();
58 }
59
~SoundHE()60 SoundHE::~SoundHE() {
61 free(_heMusic);
62 delete[] _heSoundChannels;
63 }
64
addSoundToQueue(int sound,int heOffset,int heChannel,int heFlags,int heFreq,int hePan,int heVol)65 void SoundHE::addSoundToQueue(int sound, int heOffset, int heChannel, int heFlags, int heFreq, int hePan, int heVol) {
66 if (_vm->VAR_LAST_SOUND != 0xFF)
67 _vm->VAR(_vm->VAR_LAST_SOUND) = sound;
68
69 if (heFlags & 8) {
70 playHESound(sound, heOffset, heChannel, heFlags, heFreq, hePan, heVol);
71 } else {
72 Sound::addSoundToQueue(sound, heOffset, heChannel, heFlags, heFreq, hePan, heVol);
73 }
74 }
75
addSoundToQueue2(int sound,int heOffset,int heChannel,int heFlags,int heFreq,int hePan,int heVol)76 void SoundHE::addSoundToQueue2(int sound, int heOffset, int heChannel, int heFlags, int heFreq, int hePan, int heVol) {
77 int i = _soundQue2Pos;
78 while (i--) {
79 if (_soundQue2[i].sound == sound && !(heFlags & 2))
80 return;
81 }
82
83 Sound::addSoundToQueue2(sound, heOffset, heChannel, heFlags, heFreq, hePan, heVol);
84 }
85
processSoundQueues()86 void SoundHE::processSoundQueues() {
87 int snd, heOffset, heChannel, heFlags, heFreq, hePan, heVol;
88
89 if (_vm->_game.heversion >= 72) {
90 for (int i = 0; i <_soundQue2Pos; i++) {
91 snd = _soundQue2[i].sound;
92 heOffset = _soundQue2[i].offset;
93 heChannel = _soundQue2[i].channel;
94 heFlags = _soundQue2[i].flags;
95 heFreq = _soundQue2[_soundQue2Pos].freq;
96 hePan = _soundQue2[_soundQue2Pos].pan;
97 heVol = _soundQue2[_soundQue2Pos].vol;
98 if (snd)
99 playHESound(snd, heOffset, heChannel, heFlags, heFreq, hePan, heVol);
100 }
101 _soundQue2Pos = 0;
102 } else {
103 while (_soundQue2Pos) {
104 _soundQue2Pos--;
105 snd = _soundQue2[_soundQue2Pos].sound;
106 heOffset = _soundQue2[_soundQue2Pos].offset;
107 heChannel = _soundQue2[_soundQue2Pos].channel;
108 heFlags = _soundQue2[_soundQue2Pos].flags;
109 heFreq = _soundQue2[_soundQue2Pos].freq;
110 hePan = _soundQue2[_soundQue2Pos].pan;
111 heVol = _soundQue2[_soundQue2Pos].vol;
112 if (snd)
113 playHESound(snd, heOffset, heChannel, heFlags, heFreq, hePan, heVol);
114 }
115 }
116
117 Sound::processSoundQueues();
118 }
119
isSoundRunning(int sound) const120 int SoundHE::isSoundRunning(int sound) const {
121 if (_vm->_game.heversion >= 70) {
122 if (sound >= 10000) {
123 return _mixer->getSoundID(_heSoundChannels[sound - 10000]);
124 }
125 } else if (_vm->_game.heversion >= 60) {
126 if (sound == -2) {
127 sound = _heChannel[0].sound;
128 } else if (sound == -1) {
129 sound = _currentMusic;
130 }
131 }
132
133 if (_mixer->isSoundIDActive(sound))
134 return sound;
135
136 if (isSoundInQueue(sound))
137 return sound;
138
139 if (_vm->_musicEngine &&_vm->_musicEngine->getSoundStatus(sound))
140 return sound;
141
142 return 0;
143 }
144
stopSound(int sound)145 void SoundHE::stopSound(int sound) {
146 if (_vm->_game.heversion >= 70) {
147 if ( sound >= 10000) {
148 stopSoundChannel(sound - 10000);
149 }
150 } else if (_vm->_game.heversion >= 60) {
151 if (sound == -2) {
152 sound = _heChannel[0].sound;
153 } else if (sound == -1) {
154 sound = _currentMusic;
155 }
156 }
157
158 Sound::stopSound(sound);
159
160 for (int i = 0; i < ARRAYSIZE(_heChannel); i++) {
161 if (_heChannel[i].sound == sound) {
162 _heChannel[i].sound = 0;
163 _heChannel[i].priority = 0;
164 _heChannel[i].rate = 0;
165 _heChannel[i].timer = 0;
166 _heChannel[i].sbngBlock = 0;
167 _heChannel[i].codeOffs = 0;
168 memset(_heChannel[i].soundVars, 0, sizeof(_heChannel[i].soundVars));
169 }
170 }
171
172 if (_vm->_game.heversion >= 70 && sound == 1) {
173 _vm->_haveMsg = 3;
174 _vm->_talkDelay = 0;
175 }
176 }
177
stopAllSounds()178 void SoundHE::stopAllSounds() {
179 // Clear sound channels for HE games
180 memset(_heChannel, 0, sizeof(_heChannel));
181
182 Sound::stopAllSounds();
183 }
184
setupSound()185 void SoundHE::setupSound() {
186 Sound::setupSound();
187
188 if (_vm->_game.heversion >= 70) {
189 setupHEMusicFile();
190 }
191 }
192
stopSoundChannel(int chan)193 void SoundHE::stopSoundChannel(int chan) {
194 if (_heChannel[chan].sound == 1) {
195 _vm->_haveMsg = 3;
196 _vm->_talkDelay = 0;
197 }
198
199 _mixer->stopHandle(_heSoundChannels[chan]);
200
201 _heChannel[chan].sound = 0;
202 _heChannel[chan].priority = 0;
203 _heChannel[chan].rate = 0;
204 _heChannel[chan].timer = 0;
205 _heChannel[chan].sbngBlock = 0;
206 _heChannel[chan].codeOffs = 0;
207 memset(_heChannel[chan].soundVars, 0, sizeof(_heChannel[chan].soundVars));
208
209 for (int i = 0; i < ARRAYSIZE(_soundQue2); i++) {
210 if (_soundQue2[i].channel == chan) {
211 _soundQue2[i].sound = 0;
212 _soundQue2[i].offset = 0;
213 _soundQue2[i].channel = 0;
214 _soundQue2[i].flags = 0;
215 }
216 }
217 }
218
findFreeSoundChannel()219 int SoundHE::findFreeSoundChannel() {
220 int chan, min;
221
222 min = _vm->VAR(_vm->VAR_RESERVED_SOUND_CHANNELS);
223 if (min == 0) {
224 _vm->VAR(_vm->VAR_RESERVED_SOUND_CHANNELS) = 8;
225 return 1;
226 }
227
228 if (min < 8) {
229 for (chan = min; chan < ARRAYSIZE(_heChannel); chan++) {
230 if (_mixer->isSoundHandleActive(_heSoundChannels[chan]) == 0)
231 return chan;
232 }
233 } else {
234 return 1;
235 }
236
237 return min;
238 }
239
isSoundCodeUsed(int sound)240 int SoundHE::isSoundCodeUsed(int sound) {
241 int chan = -1;
242 for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) {
243 if (_heChannel[i].sound == sound)
244 chan = i;
245 }
246
247 if (chan != -1 && _mixer->isSoundHandleActive(_heSoundChannels[chan])) {
248 return _heChannel[chan].sbngBlock;
249 } else {
250 return 0;
251 }
252 }
253
getSoundPos(int sound)254 int SoundHE::getSoundPos(int sound) {
255 int chan = -1;
256 for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) {
257 if (_heChannel[i].sound == sound)
258 chan = i;
259 }
260
261 if (chan != -1 && _mixer->isSoundHandleActive(_heSoundChannels[chan])) {
262 int time = _vm->getHETimer(chan + 4) * _heChannel[chan].rate / 1000;
263 return time;
264 } else {
265 return 0;
266 }
267 }
268
getSoundVar(int sound,int var)269 int SoundHE::getSoundVar(int sound, int var) {
270 if (_vm->_game.heversion >= 90 && var == 26) {
271 return isSoundCodeUsed(sound);
272 }
273
274 assertRange(0, var, 25, "sound variable");
275
276 int chan = -1;
277 for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) {
278 if (_heChannel[i].sound == sound)
279 chan = i;
280 }
281
282 if (chan != -1 && _mixer->isSoundHandleActive(_heSoundChannels[chan])) {
283 debug(5, "getSoundVar: sound %d var %d result %d", sound, var, _heChannel[chan].soundVars[var]);
284 return _heChannel[chan].soundVars[var];
285 } else {
286 return 0;
287 }
288 }
289
setSoundVar(int sound,int var,int val)290 void SoundHE::setSoundVar(int sound, int var, int val) {
291 assertRange(0, var, 25, "sound variable");
292
293 int chan = -1;
294 for (int i = 0; i < ARRAYSIZE(_heChannel); i ++) {
295 if (_heChannel[i].sound == sound)
296 chan = i;
297 }
298
299 if (chan != -1) {
300 debug(5, "setSoundVar: sound %d var %d val %d", sound, var, val);
301 _heChannel[chan].soundVars[var] = val;
302 }
303 }
304
setOverrideFreq(int freq)305 void SoundHE::setOverrideFreq(int freq) {
306 _overrideFreq = freq;
307 }
308
setupHEMusicFile()309 void SoundHE::setupHEMusicFile() {
310 int i;
311 Common::File musicFile;
312 Common::String buf(_vm->generateFilename(-4));
313
314 if (musicFile.open(buf) == true) {
315 musicFile.seek(4, SEEK_SET);
316 /*int total_size =*/ musicFile.readUint32BE();
317 musicFile.seek(16, SEEK_SET);
318 _heMusicTracks = musicFile.readUint32LE();
319 debug(5, "Total music tracks %d", _heMusicTracks);
320
321 int musicStart = (_vm->_game.heversion >= 80) ? 56 : 20;
322 musicFile.seek(musicStart, SEEK_SET);
323
324 _heMusic = (HEMusic *)malloc((_heMusicTracks + 1) * sizeof(HEMusic));
325 for (i = 0; i < _heMusicTracks; i++) {
326 _heMusic[i].id = musicFile.readUint32LE();
327 _heMusic[i].offset = musicFile.readUint32LE();
328 _heMusic[i].size = musicFile.readUint32LE();
329
330 if (_vm->_game.heversion >= 80) {
331 musicFile.seek(+9, SEEK_CUR);
332 } else {
333 musicFile.seek(+13, SEEK_CUR);
334 }
335 }
336
337 musicFile.close();
338 }
339 }
340
getHEMusicDetails(int id,int & musicOffs,int & musicSize)341 bool SoundHE::getHEMusicDetails(int id, int &musicOffs, int &musicSize) {
342 int i;
343
344 for (i = 0; i < _heMusicTracks; i++) {
345 if (_heMusic[i].id == id) {
346 musicOffs = _heMusic[i].offset;
347 musicSize = _heMusic[i].size;
348 return 1;
349 }
350 }
351
352 return 0;
353 }
354
processSoundCode()355 void SoundHE::processSoundCode() {
356 byte *codePtr;
357 int chan, tmr, size, time;
358
359 for (chan = 0; chan < ARRAYSIZE(_heChannel); chan++) {
360 if (_heChannel[chan].sound == 0) {
361 continue;
362 }
363
364 if (_heChannel[chan].codeOffs == -1) {
365 continue;
366 }
367
368 tmr = _vm->getHETimer(chan + 4) * _heChannel[chan].rate / 1000;
369 tmr += _vm->VAR(_vm->VAR_SOUNDCODE_TMR);
370 if (tmr < 0)
371 tmr = 0;
372
373 if (_heChannel[chan].sound > _vm->_numSounds) {
374 codePtr = _vm->getResourceAddress(rtSpoolBuffer, chan);
375 } else {
376 codePtr = _vm->getResourceAddress(rtSound, _heChannel[chan].sound);
377 }
378 assert(codePtr);
379 codePtr += _heChannel[chan].codeOffs;
380
381 while (1) {
382 size = READ_LE_UINT16(codePtr);
383 time = READ_LE_UINT32(codePtr + 2);
384
385 if (size == 0) {
386 _heChannel[chan].codeOffs = -1;
387 break;
388 }
389
390 debug(5, "Channel %d Timer %d Time %d", chan, tmr, time);
391 if (time >= tmr)
392 break;
393
394 processSoundOpcodes(_heChannel[chan].sound, codePtr + 6, _heChannel[chan].soundVars);
395
396 codePtr += size;
397 _heChannel[chan].codeOffs += size;
398 }
399 }
400
401 for (chan = 0; chan < ARRAYSIZE(_heChannel); chan++) {
402 if (_heChannel[chan].sound == 0)
403 continue;
404
405 if (_heChannel[chan].timer == 0)
406 continue;
407
408 if (_vm->getHETimer(chan + 4) > _heChannel[chan].timer) {
409 if (_heChannel[chan].sound == 1) {
410 _vm->stopTalk();
411 }
412
413 _heChannel[chan].sound = 0;
414 _heChannel[chan].priority = 0;
415 _heChannel[chan].rate = 0;
416 _heChannel[chan].timer = 0;
417 _heChannel[chan].sbngBlock = 0;
418 _heChannel[chan].codeOffs = 0;
419 _heChannel[chan].soundVars[0] = 0;
420 }
421 }
422 }
423
processSoundOpcodes(int sound,byte * codePtr,int * soundVars)424 void SoundHE::processSoundOpcodes(int sound, byte *codePtr, int *soundVars) {
425 int arg, opcode, var, val;
426
427 while (READ_LE_UINT16(codePtr) != 0) {
428 codePtr += 2;
429 opcode = READ_LE_UINT16(codePtr); codePtr += 2;
430 opcode = (opcode & 0xFFF) >> 4;
431 arg = opcode & 3;
432 opcode &= ~3;
433 debug(5, "processSoundOpcodes: sound %d opcode %d", sound, opcode);
434 switch (opcode) {
435 case 0: // Continue
436 break;
437 case 16: // Set talk state
438 val = READ_LE_UINT16(codePtr); codePtr += 2;
439 setSoundVar(sound, 19, val);
440 break;
441 case 32: // Set var
442 var = READ_LE_UINT16(codePtr); codePtr += 2;
443 val = READ_LE_UINT16(codePtr); codePtr += 2;
444 if (arg == 2) {
445 val = getSoundVar(sound, val);
446 }
447 setSoundVar(sound, var, val);
448 break;
449 case 48: // Add
450 var = READ_LE_UINT16(codePtr); codePtr += 2;
451 val = READ_LE_UINT16(codePtr); codePtr += 2;
452 if (arg == 2) {
453 val = getSoundVar(sound, val);
454 }
455 val = getSoundVar(sound, var) + val;
456 setSoundVar(sound, var, val);
457 break;
458 case 56: // Subtract
459 var = READ_LE_UINT16(codePtr); codePtr += 2;
460 val = READ_LE_UINT16(codePtr); codePtr += 2;
461 if (arg == 2) {
462 val = getSoundVar(sound, val);
463 }
464 val = getSoundVar(sound, var) - val;
465 setSoundVar(sound, var, val);
466 break;
467 case 64: // Multiple
468 var = READ_LE_UINT16(codePtr); codePtr += 2;
469 val = READ_LE_UINT16(codePtr); codePtr += 2;
470 if (arg == 2) {
471 val = getSoundVar(sound, val);
472 }
473 val = getSoundVar(sound, var) * val;
474 setSoundVar(sound, var, val);
475 break;
476 case 80: // Divide
477 var = READ_LE_UINT16(codePtr); codePtr += 2;
478 val = READ_LE_UINT16(codePtr); codePtr += 2;
479 if (arg == 2) {
480 val = getSoundVar(sound, val);
481 }
482 if (!val) {
483 val = 1; // Safeguard for division by zero
484 warning("Incorrect value 0 for processSoundOpcodes() kludge DIV");
485 }
486 val = getSoundVar(sound, var) / val;
487 setSoundVar(sound, var, val);
488 break;
489 case 96: // Increment
490 var = READ_LE_UINT16(codePtr); codePtr += 2;
491 val = getSoundVar(sound, var) + 1;
492 setSoundVar(sound, var, val);
493 break;
494 case 104: // Decrement
495 var = READ_LE_UINT16(codePtr); codePtr += 2;
496 val = getSoundVar(sound, var) - 1;
497 setSoundVar(sound, var, val);
498 break;
499 default:
500 error("Illegal sound %d opcode %d", sound, opcode);
501 }
502 }
503 }
504
findSoundTag(uint32 tag,byte * ptr)505 byte *findSoundTag(uint32 tag, byte *ptr) {
506 byte *endPtr;
507 uint32 offset, size;
508
509 if (READ_BE_UINT32(ptr) == MKTAG('W','S','O','U')) {
510 ptr += 8;
511 }
512
513 if (READ_BE_UINT32(ptr) != MKTAG('R','I','F','F'))
514 return NULL;
515
516 endPtr = (ptr + 12);
517 size = READ_LE_UINT32(ptr + 4);
518
519 while (endPtr < ptr + size) {
520 offset = READ_LE_UINT32(endPtr + 4);
521
522 if (offset <= 0)
523 error("Illegal chunk length - %d bytes.", offset);
524
525 if (offset > size)
526 error("Chunk extends beyond file end - %d versus %d.", offset, size);
527
528 if (READ_BE_UINT32(endPtr) == tag)
529 return endPtr;
530
531 endPtr = endPtr + offset + 8;
532 }
533
534 return NULL;
535 }
536
playHESound(int soundID,int heOffset,int heChannel,int heFlags,int heFreq,int hePan,int heVol)537 void SoundHE::playHESound(int soundID, int heOffset, int heChannel, int heFlags, int heFreq, int hePan, int heVol) {
538 Audio::RewindableAudioStream *stream = 0;
539 byte *ptr, *spoolPtr;
540 int size = -1;
541 int priority, rate;
542 byte flags = Audio::FLAG_UNSIGNED;
543
544 Audio::Mixer::SoundType type = Audio::Mixer::kSFXSoundType;
545 if (soundID > _vm->_numSounds)
546 type = Audio::Mixer::kMusicSoundType;
547 else if (soundID == 1)
548 type = Audio::Mixer::kSpeechSoundType;
549
550
551 if (heChannel == -1)
552 heChannel = (_vm->VAR_RESERVED_SOUND_CHANNELS != 0xFF) ? findFreeSoundChannel() : 1;
553
554 debug(5,"playHESound: soundID %d heOffset %d heChannel %d heFlags %d", soundID, heOffset, heChannel, heFlags);
555
556 if (soundID >= 10000) {
557 // Special codes, used in pjgames
558 return;
559 }
560
561 if (soundID > _vm->_numSounds) {
562 int music_offs;
563 Common::File musicFile;
564 Common::String buf(_vm->generateFilename(-4));
565
566 if (musicFile.open(buf) == false) {
567 warning("playHESound: Can't open music file %s", buf.c_str());
568 return;
569 }
570 if (!getHEMusicDetails(soundID, music_offs, size)) {
571 debug(0, "playHESound: musicID %d not found", soundID);
572 return;
573 }
574
575 musicFile.seek(music_offs, SEEK_SET);
576
577 _mixer->stopHandle(_heSoundChannels[heChannel]);
578 spoolPtr = _vm->_res->createResource(rtSpoolBuffer, heChannel, size);
579 assert(spoolPtr);
580 musicFile.read(spoolPtr, size);
581 musicFile.close();
582
583 if (_vm->_game.heversion == 70) {
584 stream = Audio::makeRawStream(spoolPtr, size, 11025, flags, DisposeAfterUse::NO);
585 _mixer->playStream(type, &_heSoundChannels[heChannel], stream, soundID);
586 return;
587 }
588 }
589
590 if (soundID > _vm->_numSounds) {
591 ptr = _vm->getResourceAddress(rtSpoolBuffer, heChannel);
592 } else {
593 ptr = _vm->getResourceAddress(rtSound, soundID);
594 }
595
596 if (!ptr) {
597 return;
598 }
599
600 // Support for sound in later HE games
601 if (READ_BE_UINT32(ptr) == MKTAG('R','I','F','F') || READ_BE_UINT32(ptr) == MKTAG('W','S','O','U')) {
602 uint16 compType;
603 int blockAlign;
604 int codeOffs = -1;
605
606 priority = (soundID > _vm->_numSounds) ? 255 : *(ptr + 18);
607
608 byte *sbngPtr = findSoundTag(MKTAG('S','B','N','G'), ptr);
609 if (sbngPtr != NULL) {
610 codeOffs = sbngPtr - ptr + 8;
611 }
612
613 if (_mixer->isSoundHandleActive(_heSoundChannels[heChannel])) {
614 int curSnd = _heChannel[heChannel].sound;
615 if (curSnd == 1 && soundID != 1)
616 return;
617 if (curSnd != 0 && curSnd != 1 && soundID != 1 && _heChannel[heChannel].priority > priority)
618 return;
619 }
620
621 if (READ_BE_UINT32(ptr) == MKTAG('W','S','O','U'))
622 ptr += 8;
623
624 size = READ_LE_UINT32(ptr + 4);
625 Common::MemoryReadStream memStream(ptr, size);
626
627 if (!Audio::loadWAVFromStream(memStream, size, rate, flags, &compType, &blockAlign)) {
628 error("playHESound: Not a valid WAV file (%d)", soundID);
629 }
630
631 assert(heOffset >= 0 && heOffset < size);
632
633 // FIXME: Disabled sound offsets, due to asserts been triggered
634 heOffset = 0;
635
636 _vm->setHETimer(heChannel + 4);
637 _heChannel[heChannel].sound = soundID;
638 _heChannel[heChannel].priority = priority;
639 _heChannel[heChannel].rate = rate;
640 _heChannel[heChannel].sbngBlock = (codeOffs != -1) ? 1 : 0;
641 _heChannel[heChannel].codeOffs = codeOffs;
642 memset(_heChannel[heChannel].soundVars, 0, sizeof(_heChannel[heChannel].soundVars));
643
644 // TODO: Extra sound flags
645 if (heFlags & 1) {
646 _heChannel[heChannel].timer = 0;
647 } else {
648 _heChannel[heChannel].timer = size * 1000 / (rate * blockAlign);
649 }
650
651 _mixer->stopHandle(_heSoundChannels[heChannel]);
652 if (compType == 17) {
653 Audio::AudioStream *voxStream = Audio::makeADPCMStream(&memStream, DisposeAfterUse::NO, size, Audio::kADPCMMSIma, rate, (flags & Audio::FLAG_STEREO) ? 2 : 1, blockAlign);
654
655 // FIXME: Get rid of this crude hack to turn a ADPCM stream into a raw stream.
656 // It seems it is only there to allow looping -- if that is true, we certainly
657 // can do without it, using a LoopingAudioStream.
658
659 byte *sound = (byte *)malloc(size * 4);
660 /* On systems where it matters, malloc will return
661 * even addresses, so the use of (void *) in the
662 * following cast shuts the compiler from warning
663 * unnecessarily. */
664 size = voxStream->readBuffer((int16 *)(void *)sound, size * 2);
665 size *= 2; // 16bits.
666 delete voxStream;
667
668 _heChannel[heChannel].rate = rate;
669 if (_heChannel[heChannel].timer)
670 _heChannel[heChannel].timer = size * 1000 / (rate * blockAlign);
671
672 // makeADPCMStream returns a stream in native endianness, but RawMemoryStream
673 // defaults to big endian. If we're on a little endian system, set the LE flag.
674 #ifdef SCUMM_LITTLE_ENDIAN
675 flags |= Audio::FLAG_LITTLE_ENDIAN;
676 #endif
677 stream = Audio::makeRawStream(sound + heOffset, size - heOffset, rate, flags);
678 } else {
679 stream = Audio::makeRawStream(ptr + memStream.pos() + heOffset, size - heOffset, rate, flags, DisposeAfterUse::NO);
680 }
681 _mixer->playStream(type, &_heSoundChannels[heChannel],
682 Audio::makeLoopingAudioStream(stream, (heFlags & 1) ? 0 : 1), soundID);
683 }
684 // Support for sound in Humongous Entertainment games
685 else if (READ_BE_UINT32(ptr) == MKTAG('D','I','G','I') || READ_BE_UINT32(ptr) == MKTAG('T','A','L','K')) {
686 byte *sndPtr = ptr;
687 int codeOffs = -1;
688
689 priority = (soundID > _vm->_numSounds) ? 255 : *(ptr + 18);
690 rate = READ_LE_UINT16(ptr + 22);
691
692 // Skip DIGI/TALK (8) and HSHD (24) blocks
693 ptr += 32;
694
695 if (_mixer->isSoundHandleActive(_heSoundChannels[heChannel])) {
696 int curSnd = _heChannel[heChannel].sound;
697 if (curSnd == 1 && soundID != 1)
698 return;
699 if (curSnd != 0 && curSnd != 1 && soundID != 1 && _heChannel[heChannel].priority > priority)
700 return;
701 }
702
703 if (READ_BE_UINT32(ptr) == MKTAG('S','B','N','G')) {
704 codeOffs = ptr - sndPtr + 8;
705 ptr += READ_BE_UINT32(ptr + 4);
706 }
707
708 assert(READ_BE_UINT32(ptr) == MKTAG('S','D','A','T'));
709 size = READ_BE_UINT32(ptr + 4) - 8;
710 if (heOffset < 0 || heOffset > size) {
711 // Occurs when making fireworks in puttmoon
712 heOffset = 0;
713 }
714 size -= heOffset;
715
716 if (_overrideFreq) {
717 // Used by the piano in Fatty Bear's Birthday Surprise
718 rate = _overrideFreq;
719 _overrideFreq = 0;
720 }
721
722 tryLoadSoundOverride(soundID, &stream);
723
724 _vm->setHETimer(heChannel + 4);
725 _heChannel[heChannel].sound = soundID;
726 _heChannel[heChannel].priority = priority;
727 _heChannel[heChannel].rate = rate;
728 _heChannel[heChannel].sbngBlock = (codeOffs != -1) ? 1 : 0;
729 _heChannel[heChannel].codeOffs = codeOffs;
730 memset(_heChannel[heChannel].soundVars, 0, sizeof(_heChannel[heChannel].soundVars));
731
732 // TODO: Extra sound flags
733 if (heFlags & 1) {
734 _heChannel[heChannel].timer = 0;
735 } else {
736 _heChannel[heChannel].timer = size * 1000 / rate;
737 }
738
739 _mixer->stopHandle(_heSoundChannels[heChannel]);
740
741 if (!stream) {
742 stream = Audio::makeRawStream(ptr + heOffset + 8, size, rate, flags, DisposeAfterUse::NO);
743 }
744 _mixer->playStream(type, &_heSoundChannels[heChannel],
745 Audio::makeLoopingAudioStream(stream, (heFlags & 1) ? 0 : 1), soundID);
746 }
747 // Support for PCM music in 3DO versions of Humongous Entertainment games
748 else if (READ_BE_UINT32(ptr) == MKTAG('M','R','A','W')) {
749 priority = *(ptr + 18);
750 rate = READ_LE_UINT16(ptr + 22);
751
752 // Skip DIGI (8) and HSHD (24) blocks
753 ptr += 32;
754
755 assert(READ_BE_UINT32(ptr) == MKTAG('S','D','A','T'));
756 size = READ_BE_UINT32(ptr + 4) - 8;
757
758 byte *sound = (byte *)malloc(size);
759 memcpy(sound, ptr + 8, size);
760
761 _mixer->stopID(_currentMusic);
762 _currentMusic = soundID;
763
764 stream = Audio::makeRawStream(sound, size, rate, 0);
765 _mixer->playStream(Audio::Mixer::kMusicSoundType, NULL, stream, soundID);
766 }
767 else if (READ_BE_UINT32(ptr) == MKTAG('M','I','D','I')) {
768 if (_vm->_imuse) {
769 // This is used in the DOS version of Fatty Bear's
770 // Birthday Surprise to change the note on the piano
771 // when not using a digitized instrument.
772 _vm->_imuse->stopSound(_currentMusic);
773 _currentMusic = soundID;
774 _vm->_imuse->startSoundWithNoteOffset(soundID, heOffset);
775 } else if (_vm->_musicEngine) {
776 _vm->_musicEngine->stopSound(_currentMusic);
777 _currentMusic = soundID;
778 _vm->_musicEngine->startSoundWithTrackID(soundID, heOffset);
779 }
780 }
781 }
782
tryLoadSoundOverride(int soundID,Audio::RewindableAudioStream ** stream)783 void SoundHE::tryLoadSoundOverride(int soundID, Audio::RewindableAudioStream **stream) {
784 const char *formats[] = {
785 #ifdef USE_FLAC
786 "flac",
787 #endif
788 "wav",
789 #ifdef USE_VORBIS
790 "ogg",
791 #endif
792 #ifdef USE_MAD
793 "mp3",
794 #endif
795 };
796
797 Audio::SeekableAudioStream *(*formatDecoders[])(Common::SeekableReadStream *, DisposeAfterUse::Flag) = {
798 #ifdef USE_FLAC
799 Audio::makeFLACStream,
800 #endif
801 Audio::makeWAVStream,
802 #ifdef USE_VORBIS
803 Audio::makeVorbisStream,
804 #endif
805 #ifdef USE_MAD
806 Audio::makeMP3Stream,
807 #endif
808 };
809
810 STATIC_ASSERT(
811 ARRAYSIZE(formats) == ARRAYSIZE(formatDecoders),
812 formats_formatDecoders_must_have_same_size
813 );
814
815 for (int i = 0; i < ARRAYSIZE(formats); i++) {
816 debug(5, "tryLoadSoundOverride: %d %s", soundID, formats[i]);
817
818 Common::File soundFileOverride;
819 Common::String buf(Common::String::format("sound%d.%s", soundID, formats[i]));
820
821 // First check if the file exists before opening it to
822 // reduce the amount of "opening %s failed" in the console.
823 if (soundFileOverride.exists(buf) && soundFileOverride.open(buf)) {
824 soundFileOverride.seek(0, SEEK_SET);
825 Common::SeekableReadStream *oStr = soundFileOverride.readStream(soundFileOverride.size());
826 soundFileOverride.close();
827
828 *stream = formatDecoders[i](oStr, DisposeAfterUse::YES);
829 debug(5, "tryLoadSoundOverride: %s loaded", formats[i]);
830 return;
831 }
832 }
833
834 debug(5, "tryLoadSoundOverride: file not found");
835 }
836
startHETalkSound(uint32 offset)837 void SoundHE::startHETalkSound(uint32 offset) {
838 byte *ptr;
839 int32 size;
840
841 if (ConfMan.getBool("speech_mute"))
842 return;
843
844 if (_sfxFilename.empty()) {
845 // This happens in the Pajama Sam's Lost & Found demo, on the
846 // main menu screen, so don't make it a fatal error.
847 warning("startHETalkSound: Speech file is not found");
848 return;
849 }
850
851 ScummFile file;
852 if (!_vm->openFile(file, _sfxFilename)) {
853 warning("startHETalkSound: Could not open speech file %s", _sfxFilename.c_str());
854 return;
855 }
856 file.setEnc(_sfxFileEncByte);
857
858 _sfxMode |= 2;
859 _vm->_res->nukeResource(rtSound, 1);
860
861 file.seek(offset + 4, SEEK_SET);
862 size = file.readUint32BE();
863 file.seek(offset, SEEK_SET);
864
865 _vm->_res->createResource(rtSound, 1, size);
866 ptr = _vm->getResourceAddress(rtSound, 1);
867 file.read(ptr, size);
868
869 int channel = (_vm->VAR_TALK_CHANNEL != 0xFF) ? _vm->VAR(_vm->VAR_TALK_CHANNEL) : 0;
870 addSoundToQueue2(1, 0, channel, 0);
871 }
872
873 #ifdef ENABLE_HE
createSound(int snd1id,int snd2id)874 void ScummEngine_v80he::createSound(int snd1id, int snd2id) {
875 byte *snd1Ptr, *snd2Ptr;
876 byte *sbng1Ptr, *sbng2Ptr;
877 byte *sdat1Ptr, *sdat2Ptr;
878 byte *src, *dst;
879 int len, offs, size;
880 int sdat1size, sdat2size;
881
882 sbng1Ptr = NULL;
883 sbng2Ptr = NULL;
884
885 if (snd2id == -1) {
886 _sndPtrOffs = 0;
887 _sndTmrOffs = 0;
888 _sndDataSize = 0;
889 return;
890 }
891
892 if (snd1id != _curSndId) {
893 _curSndId = snd1id;
894 _sndPtrOffs = 0;
895 _sndTmrOffs = 0;
896 _sndDataSize = 0;
897 }
898
899 snd1Ptr = getResourceAddress(rtSound, snd1id);
900 assert(snd1Ptr);
901 snd2Ptr = getResourceAddress(rtSound, snd2id);
902 assert(snd2Ptr);
903
904 int i;
905 int chan = -1;
906 for (i = 0; i < ARRAYSIZE(((SoundHE *)_sound)->_heChannel); i++) {
907 if (((SoundHE *)_sound)->_heChannel[i].sound == snd1id)
908 chan = i;
909 }
910
911 if (!findSoundTag(MKTAG('d','a','t','a'), snd1Ptr)) {
912 sbng1Ptr = heFindResource(MKTAG('S','B','N','G'), snd1Ptr);
913 sbng2Ptr = heFindResource(MKTAG('S','B','N','G'), snd2Ptr);
914 }
915
916 if (sbng1Ptr != NULL && sbng2Ptr != NULL) {
917 if (chan != -1 && ((SoundHE *)_sound)->_heChannel[chan].codeOffs > 0) {
918 // Copy any code left over to the beginning of the code block
919 int curOffs = ((SoundHE *)_sound)->_heChannel[chan].codeOffs;
920
921 src = snd1Ptr + curOffs;
922 dst = sbng1Ptr + 8;
923 size = READ_BE_UINT32(sbng1Ptr + 4);
924 len = sbng1Ptr - snd1Ptr + size - curOffs;
925
926 memmove(dst, src, len);
927
928 // Now seek to the end of this code block
929 dst = sbng1Ptr + 8;
930 while ((size = READ_LE_UINT16(dst)) != 0)
931 dst += size;
932 } else {
933 // We're going to overwrite the code block completely
934 dst = sbng1Ptr + 8;
935 }
936
937 // Reset the current code offset to the beginning of the code block
938 if (chan >= 0)
939 ((SoundHE *)_sound)->_heChannel[chan].codeOffs = sbng1Ptr - snd1Ptr + 8;
940
941 // Seek to the end of the code block for sound 2
942 byte *tmp = sbng2Ptr + 8;
943 while ((offs = READ_LE_UINT16(tmp)) != 0) {
944 tmp += offs;
945 }
946
947 // Copy the code block for sound 2 to the code block for sound 1
948 src = sbng2Ptr + 8;
949 len = tmp - sbng2Ptr - 6;
950 memcpy(dst, src, len);
951
952 // Rewrite the time for this new code block to be after the sound 1 code block
953 int32 time;
954 while ((size = READ_LE_UINT16(dst)) != 0) {
955 time = READ_LE_UINT32(dst + 2);
956 time += _sndTmrOffs;
957 WRITE_LE_UINT32(dst + 2, time);
958 dst += size;
959 }
960 }
961
962 // Find the data pointers and sizes
963 if (findSoundTag(MKTAG('d','a','t','a'), snd1Ptr)) {
964 sdat1Ptr = findSoundTag(MKTAG('d','a','t','a'), snd1Ptr);
965 assert(sdat1Ptr);
966 sdat2Ptr = findSoundTag(MKTAG('d','a','t','a'), snd2Ptr);
967 assert(sdat2Ptr);
968
969 if (!_sndDataSize)
970 _sndDataSize = READ_LE_UINT32(sdat1Ptr + 4) - 8;
971
972 sdat2size = READ_LE_UINT32(sdat2Ptr + 4) - 8;
973 } else {
974 sdat1Ptr = heFindResource(MKTAG('S','D','A','T'), snd1Ptr);
975 assert(sdat1Ptr);
976 sdat2Ptr = heFindResource(MKTAG('S','D','A','T'), snd2Ptr);
977 assert(sdat2Ptr);
978
979 _sndDataSize = READ_BE_UINT32(sdat1Ptr + 4) - 8;
980
981 sdat2size = READ_BE_UINT32(sdat2Ptr + 4) - 8;
982 }
983
984 sdat1size = _sndDataSize - _sndPtrOffs;
985 if (sdat2size < sdat1size) {
986 // We have space leftover at the end of sound 1
987 // -> Just append sound 2
988 src = sdat2Ptr + 8;
989 dst = sdat1Ptr + 8 + _sndPtrOffs;
990 len = sdat2size;
991
992 memcpy(dst, src, len);
993
994 _sndPtrOffs += sdat2size;
995 _sndTmrOffs += sdat2size;
996 } else {
997 // We might not have enough space leftover at the end of sound 1
998 // -> Append as much of possible of sound 2 to sound 1
999 src = sdat2Ptr + 8;
1000 dst = sdat1Ptr + 8 + _sndPtrOffs;
1001 len = sdat1size;
1002
1003 memcpy(dst, src, len);
1004
1005 if (sdat2size != sdat1size) {
1006 // We don't have enough space
1007 // -> Start overwriting the beginning of the sound again
1008 src = sdat2Ptr + 8 + sdat1size;
1009 dst = sdat1Ptr + 8;
1010 len = sdat2size - sdat1size;
1011
1012 memcpy(dst, src, len);
1013 }
1014
1015 _sndPtrOffs = sdat2size - sdat1size;
1016 _sndTmrOffs += sdat2size;
1017 }
1018 }
1019 #endif
1020
1021 } // End of namespace Scumm
1022