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 "hopkins/sound.h"
24 
25 #include "hopkins/globals.h"
26 #include "hopkins/hopkins.h"
27 
28 #include "audio/decoders/adpcm_intern.h"
29 #include "audio/decoders/wave.h"
30 #include "audio/softsynth/pcspk.h"
31 #include "common/system.h"
32 #include "common/config-manager.h"
33 #include "common/file.h"
34 #include "common/textconsole.h"
35 #include "audio/audiostream.h"
36 #include "audio/mods/module.h"
37 #include "audio/mods/protracker.h"
38 #include "audio/decoders/raw.h"
39 
40 namespace Hopkins {
41 
42 class APC_ADPCMStream : public Audio::DVI_ADPCMStream {
43 public:
APC_ADPCMStream(Common::SeekableReadStream * stream,DisposeAfterUse::Flag disposeAfterUse,int rate,int channels)44 	APC_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, int rate, int channels) : DVI_ADPCMStream(stream, disposeAfterUse, stream->size(), rate, channels, 0) {
45 		stream->seek(-12, SEEK_CUR);
46 		_status.ima_ch[0].last = _startValue[0] = stream->readUint32LE();
47 		_status.ima_ch[1].last = _startValue[1] = stream->readUint32LE();
48 		stream->seek(4, SEEK_CUR);
49 	}
50 
reset()51 	void reset() override {
52 		DVI_ADPCMStream::reset();
53 		_status.ima_ch[0].last = _startValue[0];
54 		_status.ima_ch[1].last = _startValue[1];
55 	}
56 
57 private:
58 	int16 _startValue[2];
59 };
60 
makeAPCStream(Common::SeekableReadStream * stream,DisposeAfterUse::Flag disposeAfterUse)61 Audio::RewindableAudioStream *makeAPCStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
62 	if (stream->readUint32BE() != MKTAG('C', 'R', 'Y', 'O'))
63 		return 0;
64 	if (stream->readUint32BE() != MKTAG('_', 'A', 'P', 'C'))
65 		return 0;
66 	stream->readUint32BE(); // version
67 	stream->readUint32LE(); // out size
68 	uint32 rate = stream->readUint32LE();
69 	stream->skip(8); // initial values, will be handled by the class
70 	bool stereo = stream->readUint32LE() != 0;
71 
72 	return new APC_ADPCMStream(stream, disposeAfterUse, rate, stereo ? 2 : 1);
73 }
74 
75 class TwaAudioStream : public Audio::AudioStream {
76 public:
TwaAudioStream(Common::String name,Common::SeekableReadStream * stream)77 	TwaAudioStream(Common::String name, Common::SeekableReadStream *stream) {
78 		_name = name;
79 		_cueSheet.clear();
80 		_cueStream = NULL;
81 		_cue = 0;
82 		_loadedCue = -1;
83 
84 		for (;;) {
85 			char buf[3];
86 			stream->read(buf, 3);
87 
88 			if (buf[0] == 'x' || stream->eos())
89 				break;
90 
91 			_cueSheet.push_back(atol(buf));
92 		}
93 
94 		for (_cue = 0; _cue < _cueSheet.size(); _cue++) {
95 			if (loadCue(_cue))
96 				break;
97 		}
98 	}
99 
~TwaAudioStream()100 	~TwaAudioStream() override {
101 		delete _cueStream;
102 		_cueStream = NULL;
103 	}
104 
isStereo() const105 	bool isStereo() const override {
106 		return _cueStream ? _cueStream->isStereo() : true;
107 	}
108 
getRate() const109 	int getRate() const override {
110 		return _cueStream ? _cueStream->getRate() : 22050;
111 	}
112 
endOfData() const113 	bool endOfData() const override {
114 		return _cueStream == NULL;
115 	}
116 
readBuffer(int16 * buffer,const int numSamples)117 	int readBuffer(int16 *buffer, const int numSamples) override {
118 		if (!_cueStream)
119 			return 0;
120 
121 		int16 *buf = buffer;
122 		int samplesLeft = numSamples;
123 
124 		while (samplesLeft) {
125 			if (_cueStream) {
126 				int readSamples = _cueStream->readBuffer(buf, samplesLeft);
127 				buf += readSamples;
128 				samplesLeft -= readSamples;
129 			}
130 
131 			if (samplesLeft > 0) {
132 				if (++_cue >= _cueSheet.size()) {
133 					_cue = 0;
134 				}
135 				loadCue(_cue);
136 			}
137 		}
138 
139 		return numSamples;
140 	}
141 
142 protected:
loadCue(int nr)143 	bool loadCue(int nr) {
144 		if (_loadedCue == _cueSheet[nr]) {
145 			_cueStream->rewind();
146 			return true;
147 		}
148 
149 		delete _cueStream;
150 		_cueStream = NULL;
151 		_loadedCue = _cueSheet[nr];
152 
153 		Common::String filename = Common::String::format("%s_%02d", _name.c_str(), _cueSheet[nr]);
154 		Common::File *file = new Common::File();
155 
156 		if (file->open(filename + ".APC")) {
157 			_cueStream = makeAPCStream(file, DisposeAfterUse::YES);
158 			return true;
159 		}
160 
161 		if (file->open(filename + ".WAV")) {
162 			_cueStream = Audio::makeWAVStream(file, DisposeAfterUse::YES);
163 			return true;
164 		}
165 
166 		if (file->open(filename + ".RAW")) {
167 			_cueStream = Audio::makeRawStream(file, 22050, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
168 			return true;
169 		}
170 
171 		warning("TwaAudioStream::loadCue: Missing cue %d (%s)", nr, filename.c_str());
172 		_loadedCue = -1;
173 		delete file;
174 		return false;
175 	}
176 
177 private:
178 	Common::String _name;
179 	Common::Array<int> _cueSheet;
180 	Audio::RewindableAudioStream *_cueStream;
181 	uint _cue;
182 	int _loadedCue;
183 };
184 
makeTwaStream(Common::String name,Common::SeekableReadStream * stream)185 Audio::AudioStream *makeTwaStream(Common::String name, Common::SeekableReadStream *stream) {
186 	return new TwaAudioStream(name, stream);
187 }
188 
SoundManager(HopkinsEngine * vm)189 SoundManager::SoundManager(HopkinsEngine *vm) {
190 	_vm = vm;
191 
192 	_specialSoundNum = 0;
193 	_soundVolume = 0;
194 	_voiceVolume = 0;
195 	_musicVolume = 0;
196 	_soundOffFl = true;
197 	_musicOffFl = true;
198 	_voiceOffFl = true;
199 	_textOffFl = false;
200 	_soundFl = false;
201 	_skipRefreshFl = false;
202 	_currentSoundIndex = 0;
203 	_oldSoundNumber = 0;
204 	_modPlayingFl = false;
205 }
206 
~SoundManager()207 SoundManager::~SoundManager() {
208 	stopMusic();
209 	delMusic();
210 	_vm->_mixer->stopHandle(_musicHandle);
211 	_modPlayingFl = false;
212 }
213 
checkSoundEnd()214 void SoundManager::checkSoundEnd() {
215 	if (!_soundOffFl && _soundFl) {
216 		if (!checkVoiceStatus(1)) {
217 			stopVoice(1);
218 			delWav(_currentSoundIndex);
219 		}
220 	}
221 }
222 
loadAnimSound()223 void SoundManager::loadAnimSound() {
224 	switch (_specialSoundNum) {
225 	case 2:
226 		loadSample(5, "mitra1.wav");
227 		loadSample(1, "tir2.wav");
228 		loadSample(2, "sound6.wav");
229 		loadSample(3, "sound5.WAV");
230 		loadSample(4, "sound4.WAV");
231 		break;
232 	case 5:
233 		loadWav("CRIE.WAV", 1);
234 		break;
235 	case 14:
236 		loadWav("SOUND14.WAV", 1);
237 		break;
238 	case 16:
239 		loadWav("SOUND16.WAV", 1);
240 		break;
241 	case 198:
242 		loadWav("SOUND3.WAV", 1);
243 		break;
244 	case 199:
245 		loadWav("SOUND22.WAV", 1);
246 		break;
247 	case 200:
248 		mixVoice(682, 1);
249 		break;
250 	case 208:
251 		loadWav("SOUND77.WAV", 1);
252 		break;
253 	case 210:
254 		loadWav("SOUND78.WAV", 1);
255 		break;
256 	case 211:
257 		loadWav("SOUND78.WAV", 1);
258 		break;
259 	case 229:
260 		loadWav("SOUND80.WAV", 1);
261 		loadWav("SOUND82.WAV", 2);
262 		break;
263 	default:
264 		break;
265 	}
266 }
267 
playAnimSound(int animFrame)268 void SoundManager::playAnimSound(int animFrame) {
269 	if (!_vm->_globals->_censorshipFl && _specialSoundNum == 2) {
270 		switch (animFrame) {
271 		case 20:
272 			playSample(5);
273 			break;
274 		case 57:
275 		case 63:
276 		case 69:
277 			playSample(1);
278 			break;
279 		case 75:
280 			// This removes the sound of the gun played while the guard is being shot, as this part of the scene has been
281 			// removed in the Polish version of the game
282 			if (_vm->getLanguage() != Common::PL_POL)
283 				playSample(2);
284 			break;
285 		case 95:
286 			// This fixes an original bug in the Polish version of the game, which was literally butchered for some reason
287 			if (_vm->getLanguage() == Common::PL_POL)
288 				playSample(3);
289 			break;
290 		case 109:
291 			if (_vm->getLanguage() != Common::PL_POL)
292 				playSample(3);
293 			break;
294 		case 108:
295 			// This fixes an original bug in the Polish version of the game, which was literally butchered for some reason
296 			if (_vm->getLanguage() == Common::PL_POL)
297 				playSample(4);
298 			break;
299 		case 122:
300 			if (_vm->getLanguage() != Common::PL_POL)
301 				playSample(4);
302 			break;
303 		default:
304 			break;
305 		}
306 	} else if (_specialSoundNum == 1 && animFrame == 17)
307 		playSoundFile("SOUND42.WAV");
308 	else if (_specialSoundNum == 5 && animFrame == 19)
309 		playWav(1);
310 	else if (_specialSoundNum == 14 && animFrame == 625)
311 		playWav(1);
312 	else if (_specialSoundNum == 16 && animFrame == 25)
313 		playWav(1);
314 	else if (_specialSoundNum == 17) {
315 		if (animFrame == 6)
316 			playSample(1);
317 		else if (animFrame == 14)
318 			playSample(2);
319 		else if (animFrame == 67)
320 			playSample(3);
321 	} else if (_specialSoundNum == 198 && animFrame == 15)
322 		playWav(1);
323 	else if (_specialSoundNum == 199 && animFrame == 72)
324 		playWav(1);
325 	else if (_specialSoundNum == 208 && animFrame == 40)
326 		playWav(1);
327 	else if (_specialSoundNum == 210 && animFrame == 2)
328 		playWav(1);
329 	else if (_specialSoundNum == 211 && animFrame == 22)
330 		playWav(1);
331 	else if (_specialSoundNum == 229) {
332 		if (animFrame == 15)
333 			playWav(1);
334 		else if (animFrame == 91)
335 			playWav(2);
336 	}
337 }
338 
339 static const char *const modSounds[] = {
340 	"appart", "ville", "Rock", "police", "deep",
341 	"purgat", "riviere", "SUSPENS", "labo", "cadavre",
342 	"cabane", "purgat2", "foret", "ile", "ile2",
343 	"hopkins", "peur", "URAVOLGA", "BASE", "cadavre2",
344 	"usine", "chien", "coeur", "stand", "ocean",
345 	"base3", "gloop", "cant", "feel", "lost",
346 	"tobac"
347 };
348 
playSound(int soundNumber)349 void SoundManager::playSound(int soundNumber) {
350 	if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS) {
351 		if (soundNumber > 27)
352 			return;
353 	}
354 
355 	if (_oldSoundNumber != soundNumber || !_modPlayingFl) {
356 		if (_modPlayingFl)
357 			stopSound();
358 
359 		playMod(modSounds[soundNumber - 1]);
360 		_oldSoundNumber = soundNumber;
361 	}
362 }
363 
stopSound()364 void SoundManager::stopSound() {
365 	stopVoice(0);
366 	stopVoice(1);
367 	stopVoice(2);
368 	if (_soundFl)
369 		delWav(_currentSoundIndex);
370 
371 	for (int i = 1; i <= 48; ++i)
372 		removeWavSample(i);
373 
374 	if (_modPlayingFl) {
375 		stopMusic();
376 		delMusic();
377 		_modPlayingFl = false;
378 	}
379 }
380 
playMod(const Common::String & file)381 void SoundManager::playMod(const Common::String &file) {
382 	if (_musicOffFl)
383 		return;
384 	Common::String modFile = file;
385 
386 	// HACK
387 	if (modFile == "URAVOLGA" && (_vm->getPlatform() == Common::kPlatformWindows || _vm->getPlatform() == Common::kPlatformLinux))
388 		modFile = "peur";
389 
390 	// The Windows/Linux version chops off the music file names to 5 characters
391 	if (modFile.size() > 5 && (_vm->getPlatform() == Common::kPlatformWindows || _vm->getPlatform() == Common::kPlatformLinux)) {
392 		if (!modFile.hasSuffix("2")) {
393 			while (modFile.size() > 5)
394 				modFile.deleteLastChar();
395 		} else {
396 			while (modFile.size() > 4)
397 				modFile.deleteLastChar();
398 			modFile += "2";
399 		}
400 	}
401 	if (_modPlayingFl) {
402 		stopMusic();
403 		delMusic();
404 		_modPlayingFl = false;
405 	}
406 
407 	loadMusic(modFile);
408 	playMusic();
409 	_modPlayingFl = true;
410 }
411 
loadMusic(const Common::String & file)412 void SoundManager::loadMusic(const Common::String &file) {
413 	if (_music._active)
414 		delMusic();
415 
416 	Common::File f;
417 	if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS) {
418 		Common::String filename = Common::String::format("%s.MOD", file.c_str());
419 
420 		if (!f.open(filename))
421 			error("Error opening file %s", filename.c_str());
422 
423 		Modules::Module *module;
424 		Audio::AudioStream *modStream = Audio::makeProtrackerStream(&f, 0, 44100, true, &module);
425 
426 		// WORKAROUND: This song is played at the empty lot where the
427 		// bank robbers have left the helicopter. The MOD file appears
428 		// to be slightly broken. Almost half of it is just the same
429 		// noise repeating. We fix this by only playing the working
430 		// part of it. The result is pretty close to the Windows music.
431 		if (file.equalsIgnoreCase("cadavre")) {
432 			module->songlen = 3;
433 		}
434 
435 		_vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, modStream);
436 
437 	} else {
438 		Common::String filename = Common::String::format("%s.TWA", file.c_str());
439 
440 		if (!f.open(filename))
441 			error("Error opening file %s", filename.c_str());
442 
443 		Audio::AudioStream *twaStream = makeTwaStream(file.c_str(), &f);
444 		_vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, twaStream);
445 		f.close();
446 	}
447 
448 	_music._active = true;
449 }
450 
playMusic()451 void SoundManager::playMusic() {
452 }
453 
stopMusic()454 void SoundManager::stopMusic() {
455 	_vm->_mixer->stopHandle(_musicHandle);
456 }
457 
delMusic()458 void SoundManager::delMusic() {
459 	_music._active = false;
460 }
461 
checkSounds()462 void SoundManager::checkSounds() {
463 	checkVoiceActivity();
464 }
465 
466 /**
467  * Checks voices to see if they're finished
468  */
checkVoiceActivity()469 void SoundManager::checkVoiceActivity() {
470 	// Check the status of each voice.
471 	bool hasActiveVoice = false;
472 	for (int i = 0; i < VOICE_COUNT; ++i)
473 		hasActiveVoice |= checkVoiceStatus(i);
474 
475 	if (!hasActiveVoice && _soundFl) {
476 		_soundFl = false;
477 		_currentSoundIndex = 0;
478 	}
479 }
480 
mixVoice(int voiceId,int voiceMode,bool dispTxtFl)481 bool SoundManager::mixVoice(int voiceId, int voiceMode, bool dispTxtFl) {
482 	int fileNumber;
483 	bool breakFlag;
484 	Common::String prefix;
485 	Common::String filename;
486 	Common::File f;
487 	size_t catPos, catLen;
488 
489 	fileNumber = voiceId;
490 	if (_voiceOffFl)
491 		return false;
492 
493 	if ((voiceMode == 1 || voiceMode == 2)
494 	 && (   voiceId == 4   || voiceId == 16  || voiceId == 121
495 	     || voiceId == 142 || voiceId == 182 || voiceId == 191
496 		 || voiceId == 212 || voiceId == 225 || voiceId == 239
497 		 || voiceId == 245 || voiceId == 297 || voiceId == 308
498 		 || voiceId == 333 || voiceId == 348 || voiceId == 352
499 		 || voiceId == 358 || voiceId == 364 || voiceId == 371
500 		 || voiceId == 394 || voiceId == 414 || voiceId == 429
501 		 || voiceId == 442 || voiceId == 446 || voiceId == 461
502 		 || voiceId == 468 || voiceId == 476 || voiceId == 484
503 		 || voiceId == 491 || voiceId == 497 || voiceId == 501
504 		 || voiceId == 511 || voiceId == 520 || voiceId == 536
505 		 || voiceId == 554 || voiceId == 566 || voiceId == 573
506 		 || voiceId == 632 || voiceId == 645))
507 		fileNumber = 684;
508 
509 	if (voiceMode == 1 || voiceMode == 2)
510 		prefix = "DF";
511 	else if (voiceMode == 3)
512 		prefix = "IF";
513 	else if (voiceMode == 4)
514 		prefix = "TF";
515 	else if (voiceMode == 5)
516 		prefix = "OF";
517 
518 	// BeOS and OS/2 versions are using a slightly different speech order during intro
519 	// This map those values to the ones used by the Win95 and Linux versions
520 	int mappedFileNumber = fileNumber;
521 	if (voiceMode == 3 && (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS)) {
522 		if (fileNumber == 4)
523 			mappedFileNumber = 0;
524 		else if (fileNumber > 4)
525 			mappedFileNumber = fileNumber - 1;
526 	}
527 
528 	filename = Common::String::format("%s%d", prefix.c_str(), mappedFileNumber);
529 
530 	bool fileFoundFl = false;
531 	_vm->_fileIO->searchCat(filename + ".WAV", RES_VOI, fileFoundFl);
532 	if (fileFoundFl) {
533 		if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS) {
534 			filename = "ENG_VOI.RES";
535 		} else {
536 			// Win95 and Linux versions uses another set of names
537 			switch (_vm->_globals->_language) {
538 			case LANG_FR:
539 				filename = "RES_VFR.RES";
540 				break;
541 			case LANG_EN:
542 				filename = "RES_VAN.RES";
543 				break;
544 			case LANG_SP:
545 				filename = "RES_VES.RES";
546 				break;
547 			default:
548 				break;
549 			}
550 		}
551 
552 		catPos = _vm->_fileIO->_catalogPos;
553 		catLen = _vm->_fileIO->_catalogSize;
554 	} else {
555 		_vm->_fileIO->searchCat(filename + ".APC", RES_VOI, fileFoundFl);
556 		if (fileFoundFl) {
557 			if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS) {
558 				filename = "ENG_VOI.RES";
559 			} else {
560 				// Win95 and Linux versions uses another set of names
561 				switch (_vm->_globals->_language) {
562 				case LANG_FR:
563 					filename = "RES_VFR.RES";
564 					break;
565 				case LANG_EN:
566 					filename = "RES_VAN.RES";
567 					break;
568 				case LANG_SP:
569 					filename = "RES_VES.RES";
570 					break;
571 				default:
572 					break;
573 				}
574 			}
575 
576 			catPos = _vm->_fileIO->_catalogPos;
577 			catLen = _vm->_fileIO->_catalogSize;
578 		} else {
579 			_vm->_fileIO->searchCat(filename + ".RAW", RES_VOI, fileFoundFl);
580 			if (fileFoundFl) {
581 				if (_vm->getPlatform() == Common::kPlatformOS2 || _vm->getPlatform() == Common::kPlatformBeOS) {
582 					filename = "ENG_VOI.RES";
583 				} else {
584 					// Win95 and Linux versions uses another set of names
585 					switch (_vm->_globals->_language) {
586 					case LANG_FR:
587 						filename = "RES_VFR.RES";
588 						break;
589 					case LANG_EN:
590 						filename = "RES_VAN.RES";
591 						break;
592 					case LANG_SP:
593 						filename = "RES_VES.RES";
594 						break;
595 					default:
596 						break;
597 					}
598 				}
599 
600 				catPos = _vm->_fileIO->_catalogPos;
601 				catLen = _vm->_fileIO->_catalogSize;
602 			} else {
603 				if (!f.exists(filename + ".WAV")) {
604 					if (!f.exists(filename + ".APC"))
605 						return false;
606 					filename = filename + ".APC";
607 				} else
608 					filename = filename + ".WAV";
609 
610 				catPos = 0;
611 				catLen = 0;
612 			}
613 		}
614 	}
615 	int oldMusicVol = _musicVolume;
616 	if (!loadVoice(filename, catPos, catLen, _sWav[20])) {
617 		// This case only concerns the English Win95 demo
618 		// If it's not possible to load the voice, we force the active flag
619 		// to false in order to make sure the missing buffer won't be played
620 		// accidentally later
621 		_sWav[20]._active = false;
622 	} else {
623 		_sWav[20]._active = true;
624 
625 		// Reduce music volume during speech
626 		if (!_musicOffFl && _musicVolume > 2) {
627 			_musicVolume -= _musicVolume * 9 / 20;
628 			setMODMusicVolume(_musicVolume);
629 		}
630 	}
631 	playVoice();
632 
633 	_vm->_events->_escKeyFl = false;
634 
635 	// Loop for playing voice
636 	breakFlag = false;
637 	do {
638 		if (_specialSoundNum != 4 && !_skipRefreshFl)
639 			_vm->_events->refreshScreenAndEvents();
640 		if (_vm->_events->getMouseButton())
641 			break;
642 		_vm->_events->refreshEvents();
643 		if (_vm->_events->_escKeyFl)
644 			break;
645 		// We only check the voice status if the file has been loaded properly
646 		// This avoids skipping completely the talk animations in the Win95 UK Demo
647 		if (!checkVoiceStatus(2) && _sWav[20]._active)
648 			breakFlag = true;
649 		// This is specific to the Win95 UK Demo again: if nothing is displayed,
650 		// don't wait for a click event.
651 		if (!_sWav[20]._active && !dispTxtFl)
652 			break;
653 	} while (!_vm->shouldQuit() && !breakFlag);
654 
655 
656 	stopVoice(2);
657 	removeWavSample(20);
658 
659 	// Speech is over, set the music volume back to normal
660 	_musicVolume = oldMusicVol;
661 	if (!_musicOffFl && _musicVolume > 2) {
662 		setMODMusicVolume(_musicVolume);
663 	}
664 	_vm->_events->_escKeyFl = false;
665 	_skipRefreshFl = false;
666 	return true;
667 }
668 
removeSample(int soundIndex)669 void SoundManager::removeSample(int soundIndex) {
670 	if (checkVoiceStatus(1))
671 		stopVoice(1);
672 	if (checkVoiceStatus(2))
673 		stopVoice(2);
674 	removeWavSample(soundIndex);
675 	_sound[soundIndex]._active = false;
676 }
677 
playSoundFile(const Common::String & file)678 void SoundManager::playSoundFile(const Common::String &file) {
679 	if (_soundOffFl)
680 		return;
681 
682 	// Fallback for the menu option.
683 	// The BeOS and OS/2 versions don't play sound at this point.
684 	// sound20 sounds very close to bruit2 from the linux and Win95 versions.
685 	Common::File f;
686 	Common::String filename;
687 	if (file == "bruit2.wav" && !f.exists(file))
688 		filename = "sound20.wav";
689 	else
690 		filename = file;
691 
692 	if (_soundFl)
693 		delWav(_currentSoundIndex);
694 	loadWav(filename, 1);
695 	playWav(1);
696 }
697 
directPlayWav(const Common::String & file)698 void SoundManager::directPlayWav(const Common::String &file) {
699 	if (_soundOffFl)
700 		return;
701 
702 	loadWav(file, 1);
703 	playWav(1);
704 }
705 
setMODSampleVolume()706 void SoundManager::setMODSampleVolume() {
707 	for (int idx = 0; idx < SWAV_COUNT; ++idx) {
708 		if (idx != 20 && _sWav[idx]._active) {
709 			int volume = _soundVolume * 255 / 16;
710 			_vm->_mixer->setChannelVolume(_sWav[idx]._soundHandle, volume);
711 		}
712 	}
713 }
714 
setMODVoiceVolume()715 void SoundManager::setMODVoiceVolume() {
716 	if (_sWav[20]._active) {
717 		int volume = _voiceVolume * 255 / 16;
718 		_vm->_mixer->setChannelVolume(_sWav[20]._soundHandle, volume);
719 	}
720 }
721 
setMODMusicVolume(int volume)722 void SoundManager::setMODMusicVolume(int volume) {
723 	if (_vm->_mixer->isSoundHandleActive(_musicHandle))
724 		_vm->_mixer->setChannelVolume(_musicHandle, volume * 255 / 16);
725 }
726 
loadSample(int wavIndex,const Common::String & file)727 void SoundManager::loadSample(int wavIndex, const Common::String &file) {
728 	loadWavSample(wavIndex, file, false);
729 	_sound[wavIndex]._active = true;
730 }
731 
playSample(int wavIndex,int voiceMode)732 void SoundManager::playSample(int wavIndex, int voiceMode) {
733 	if (_soundOffFl || !_sound[wavIndex]._active)
734 		return;
735 
736 	if (_soundFl)
737 		delWav(_currentSoundIndex);
738 
739 	switch (voiceMode) {
740 	case 5:
741 	// Case added to identify the former PLAY_SAMPLE2 calls
742 	case 9:
743 		if (checkVoiceStatus(1))
744 			stopVoice(1);
745 		playWavSample(1, wavIndex);
746 		break;
747 	case 6:
748 		if (checkVoiceStatus(2))
749 			stopVoice(1);
750 		playWavSample(2, wavIndex);
751 		break;
752 	default:
753 		break;
754 	}
755 }
756 
checkVoiceStatus(int voiceIndex)757 bool SoundManager::checkVoiceStatus(int voiceIndex) {
758 	if (_voice[voiceIndex]._status) {
759 		int wavIndex = _voice[voiceIndex]._wavIndex;
760 		if (_sWav[wavIndex]._audioStream && _sWav[wavIndex]._audioStream->endOfStream())
761 			stopVoice(voiceIndex);
762 	}
763 
764 	return _voice[voiceIndex]._status;
765 }
766 
stopVoice(int voiceIndex)767 void SoundManager::stopVoice(int voiceIndex) {
768 	if (_voice[voiceIndex]._status) {
769 		_voice[voiceIndex]._status = false;
770 		int wavIndex = _voice[voiceIndex]._wavIndex;
771 		if (_sWav[wavIndex]._active && _sWav[wavIndex]._freeSampleFl)
772 			removeWavSample(wavIndex);
773 	}
774 	_voice[voiceIndex]._status = false;
775 }
776 
playVoice()777 void SoundManager::playVoice() {
778 	if (!_sWav[20]._active)
779 		return;
780 
781 	if (!_voice[2]._status) {
782 		int wavIndex = _voice[2]._wavIndex;
783 		if (_sWav[wavIndex]._active && _sWav[wavIndex]._freeSampleFl)
784 			removeWavSample(wavIndex);
785 	}
786 
787 	playWavSample(2, 20);
788 }
789 
removeWavSample(int wavIndex)790 bool SoundManager::removeWavSample(int wavIndex) {
791 	if (!_sWav[wavIndex]._active)
792 		return false;
793 
794 	_vm->_mixer->stopHandle(_sWav[wavIndex]._soundHandle);
795 	delete _sWav[wavIndex]._audioStream;
796 	_sWav[wavIndex]._audioStream = NULL;
797 	_sWav[wavIndex]._active = false;
798 
799 	return true;
800 }
801 
loadVoice(const Common::String & filename,size_t fileOffset,size_t entryLength,SwavItem & item)802 bool SoundManager::loadVoice(const Common::String &filename, size_t fileOffset, size_t entryLength, SwavItem &item) {
803 	Common::File f;
804 	if (!f.open(filename)) {
805 		// Fallback to APC...
806 		if (!f.open(setExtension(filename, ".APC"))) {
807 			// The English demo doesn't include the speech file.
808 			// This avoids it to crash when discussing with other characters
809 			if (!_vm->getIsDemo())
810 				error("Could not open %s for reading", filename.c_str());
811 			return false;
812 		}
813 	}
814 
815 	f.seek(fileOffset);
816 	item._audioStream = makeSoundStream(f.readStream((entryLength == 0) ? f.size() : entryLength));
817 	f.close();
818 
819 	return true;
820 }
821 
loadWavSample(int wavIndex,const Common::String & filename,bool freeSample)822 void SoundManager::loadWavSample(int wavIndex, const Common::String &filename, bool freeSample) {
823 	if (_sWav[wavIndex]._active)
824 		removeWavSample(wavIndex);
825 
826 	if (loadVoice(filename, 0, 0, _sWav[wavIndex])) {
827 		_sWav[wavIndex]._active = true;
828 		_sWav[wavIndex]._freeSampleFl = freeSample;
829 	} else{
830 		_sWav[wavIndex]._active = false;
831 	}
832 }
833 
loadWav(const Common::String & file,int wavIndex)834 void SoundManager::loadWav(const Common::String &file, int wavIndex) {
835 	loadWavSample(wavIndex, file, true);
836 }
837 
playWav(int wavIndex)838 void SoundManager::playWav(int wavIndex) {
839 	if (_soundFl || _soundOffFl)
840 		return;
841 
842 	_soundFl = true;
843 	_currentSoundIndex = wavIndex;
844 	playWavSample(1, wavIndex);
845 }
846 
delWav(int wavIndex)847 void SoundManager::delWav(int wavIndex) {
848 	if (!removeWavSample(wavIndex))
849 		return;
850 
851 	if (checkVoiceStatus(1))
852 		stopVoice(1);
853 
854 	_currentSoundIndex = 0;
855 	_soundFl = false;
856 }
857 
playWavSample(int voiceIndex,int wavIndex)858 void SoundManager::playWavSample(int voiceIndex, int wavIndex) {
859 	if (!_sWav[wavIndex]._active)
860 		warning("Bad handle");
861 
862 	if (_voice[voiceIndex]._status && _sWav[wavIndex]._active && _sWav[wavIndex]._freeSampleFl)
863 		removeWavSample(wavIndex);
864 
865 	_voice[voiceIndex]._status = true;
866 	_voice[voiceIndex]._wavIndex = wavIndex;
867 
868 	int volume = (voiceIndex == 2) ? _voiceVolume * 255 / 16 : _soundVolume * 255 / 16;
869 
870 	// If the handle is still in use, stop it. Otherwise we'll lose the
871 	// handle to that sound. This can currently happen (but probably
872 	// shouldn't) when skipping a movie.
873 	if (_vm->_mixer->isSoundHandleActive(_sWav[wavIndex]._soundHandle))
874 		  _vm->_mixer->stopHandle(_sWav[wavIndex]._soundHandle);
875 
876 	// Start the voice playing
877 	_sWav[wavIndex]._audioStream->rewind();
878 	_vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sWav[wavIndex]._soundHandle,
879 		_sWav[wavIndex]._audioStream, -1, volume, 0, DisposeAfterUse::NO);
880 }
881 
syncSoundSettings()882 void SoundManager::syncSoundSettings() {
883 	bool muteAll = false;
884 	if (ConfMan.hasKey("mute"))
885 		muteAll = ConfMan.getBool("mute");
886 
887 	// Update the mute settings
888 	_musicOffFl = muteAll || (ConfMan.hasKey("music_mute") && ConfMan.getBool("music_mute"));
889 	_soundOffFl = muteAll || (ConfMan.hasKey("sfx_mute") && ConfMan.getBool("sfx_mute"));
890 	_voiceOffFl = muteAll || (ConfMan.hasKey("speech_mute") && ConfMan.getBool("speech_mute"));
891 
892 	// Update the volume levels
893 	_musicVolume = MIN(255, ConfMan.getInt("music_volume")) * 16 / 255;
894 	_soundVolume = MIN(255, ConfMan.getInt("sfx_volume")) * 16 / 255;
895 	_voiceVolume = MIN(255, ConfMan.getInt("speech_volume")) * 16 / 255;
896 
897 	// Update any active sounds
898 	for (int idx = 0; idx < SWAV_COUNT; ++idx) {
899 		if (_sWav[idx]._active) {
900 			int volume = (idx == 20) ? (_voiceVolume * 255 / 16) : (_soundVolume * 255 / 16);
901 			_vm->_mixer->setChannelVolume(_sWav[idx]._soundHandle, volume);
902 		}
903 	}
904 	if (_vm->_mixer->isSoundHandleActive(_musicHandle)) {
905 		_vm->_mixer->setChannelVolume(_musicHandle, _musicVolume * 255 / 16);
906 	}
907 }
908 
updateScummVMSoundSettings()909 void SoundManager::updateScummVMSoundSettings() {
910 	ConfMan.setBool("mute", _musicOffFl && _soundOffFl && _voiceOffFl);
911 	ConfMan.setBool("music_mute", _musicOffFl);
912 	ConfMan.setBool("sfx_mute", _soundOffFl);
913 	ConfMan.setBool("speech_mute", _voiceOffFl);
914 
915 	ConfMan.setInt("music_volume", _musicVolume * 255 / 16);
916 	ConfMan.setInt("sfx_volume", _soundVolume * 255 / 16);
917 	ConfMan.setInt("speech_volume", _voiceVolume * 255 / 16);
918 
919 	ConfMan.flushToDisk();
920 }
921 
922 /**
923  * Creates an audio stream based on a passed raw stream
924  */
makeSoundStream(Common::SeekableReadStream * stream)925 Audio::RewindableAudioStream *SoundManager::makeSoundStream(Common::SeekableReadStream *stream) {
926 	if (_vm->getPlatform() == Common::kPlatformWindows)
927 		return makeAPCStream(stream, DisposeAfterUse::YES);
928 	else if (_vm->getPlatform() == Common::kPlatformLinux)
929 		return Audio::makeWAVStream(stream, DisposeAfterUse::YES);
930 	else
931 		return Audio::makeRawStream(stream, 22050, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
932 }
933 
934 // Blatant rip from gob engine. Hi DrMcCoy!
setExtension(const Common::String & str,const Common::String & ext)935 Common::String SoundManager::setExtension(const Common::String &str, const Common::String &ext) {
936 	if (str.empty())
937 		return str;
938 
939 	const char *dot = strrchr(str.c_str(), '.');
940 	if (dot)
941 		return Common::String(str.c_str(), dot - str.c_str()) + ext;
942 
943 	return str + ext;
944 }
945 } // End of namespace Hopkins
946