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