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