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 "common/memstream.h"
24 #include "audio/mixer.h"
25 #include "neverhood/sound.h"
26 #include "neverhood/resource.h"
27 #include "neverhood/resourceman.h"
28
29 // Convert volume from percent to 0..255
30 #define VOLUME(volume) (Audio::Mixer::kMaxChannelVolume / 100 * (volume))
31
32 // Convert panning from percent (50% equals center) to -127..0..+127
33 #define PANNING(panning) (254 / 100 * (panning) - 127)
34
35 namespace Neverhood {
36
SoundResource(NeverhoodEngine * vm)37 SoundResource::SoundResource(NeverhoodEngine *vm)
38 : _vm(vm), _soundIndex(-1) {
39 }
40
~SoundResource()41 SoundResource::~SoundResource() {
42 unload();
43 }
44
isPlaying()45 bool SoundResource::isPlaying() {
46 AudioResourceManSoundItem *soundItem = getSoundItem();
47 return soundItem ? soundItem->isPlaying() : false;
48 }
49
load(uint32 fileHash)50 void SoundResource::load(uint32 fileHash) {
51 unload();
52 _soundIndex = _vm->_audioResourceMan->addSound(fileHash);
53 AudioResourceManSoundItem *soundItem = getSoundItem();
54 if (soundItem)
55 soundItem->loadSound();
56 }
57
unload()58 void SoundResource::unload() {
59 if (_soundIndex >= 0) {
60 _vm->_audioResourceMan->removeSound(_soundIndex);
61 _soundIndex = -1;
62 }
63 }
64
play(uint32 fileHash)65 void SoundResource::play(uint32 fileHash) {
66 load(fileHash);
67 play();
68 }
69
play()70 void SoundResource::play() {
71 AudioResourceManSoundItem *soundItem = getSoundItem();
72 if (soundItem)
73 soundItem->playSound(false);
74 }
75
playLooping()76 void SoundResource::playLooping() {
77 AudioResourceManSoundItem *soundItem = getSoundItem();
78 if (soundItem)
79 soundItem->playSound(true);
80 }
81
stop()82 void SoundResource::stop() {
83 AudioResourceManSoundItem *soundItem = getSoundItem();
84 if (soundItem)
85 soundItem->stopSound();
86 }
87
setVolume(int16 volume)88 void SoundResource::setVolume(int16 volume) {
89 AudioResourceManSoundItem *soundItem = getSoundItem();
90 if (soundItem)
91 soundItem->setVolume(volume);
92 }
93
setPan(int16 pan)94 void SoundResource::setPan(int16 pan) {
95 AudioResourceManSoundItem *soundItem = getSoundItem();
96 if (soundItem)
97 soundItem->setPan(pan);
98 }
99
getSoundItem()100 AudioResourceManSoundItem *SoundResource::getSoundItem() {
101 return _vm->_audioResourceMan->getSoundItem(_soundIndex);
102 }
103
MusicResource(NeverhoodEngine * vm)104 MusicResource::MusicResource(NeverhoodEngine *vm)
105 : _vm(vm), _musicIndex(-1) {
106 }
107
isPlaying()108 bool MusicResource::isPlaying() {
109 AudioResourceManMusicItem *musicItem = getMusicItem();
110 return musicItem && musicItem->isPlaying();
111 }
112
load(uint32 fileHash)113 void MusicResource::load(uint32 fileHash) {
114 unload();
115 _musicIndex = _vm->_audioResourceMan->loadMusic(fileHash);
116 }
117
unload()118 void MusicResource::unload() {
119 AudioResourceManMusicItem *musicItem = getMusicItem();
120 if (musicItem) {
121 musicItem->unloadMusic();
122 _musicIndex = -1;
123 }
124 }
125
play(int16 fadeVolumeStep)126 void MusicResource::play(int16 fadeVolumeStep) {
127 AudioResourceManMusicItem *musicItem = getMusicItem();
128 if (musicItem)
129 musicItem->playMusic(fadeVolumeStep);
130 }
131
stop(int16 fadeVolumeStep)132 void MusicResource::stop(int16 fadeVolumeStep) {
133 AudioResourceManMusicItem *musicItem = getMusicItem();
134 if (musicItem)
135 musicItem->stopMusic(fadeVolumeStep);
136 }
137
setVolume(int16 volume)138 void MusicResource::setVolume(int16 volume) {
139 AudioResourceManMusicItem *musicItem = getMusicItem();
140 if (musicItem)
141 musicItem->setVolume(volume);
142 }
143
getMusicItem()144 AudioResourceManMusicItem *MusicResource::getMusicItem() {
145 return _vm->_audioResourceMan->getMusicItem(_musicIndex);
146 }
147
MusicItem(NeverhoodEngine * vm,uint32 groupNameHash,uint32 musicFileHash)148 MusicItem::MusicItem(NeverhoodEngine *vm, uint32 groupNameHash, uint32 musicFileHash)
149 : _vm(vm), _musicResource(NULL) {
150
151 _groupNameHash = groupNameHash;
152 _fileHash = musicFileHash;
153 _play = false;
154 _stop = false;
155 _fadeVolumeStep = 0;
156 _countdown = 24;
157 _musicResource = new MusicResource(_vm);
158 _musicResource->load(musicFileHash);
159 }
160
~MusicItem()161 MusicItem::~MusicItem() {
162 if (_musicResource)
163 _musicResource->unload();
164 delete _musicResource;
165 }
166
startMusic(int16 countdown,int16 fadeVolumeStep)167 void MusicItem::startMusic(int16 countdown, int16 fadeVolumeStep) {
168 _play = true;
169 _stop = false;
170 _countdown = countdown;
171 _fadeVolumeStep = fadeVolumeStep;
172 }
173
stopMusic(int16 countdown,int16 fadeVolumeStep)174 void MusicItem::stopMusic(int16 countdown, int16 fadeVolumeStep) {
175 _play = false;
176 _stop = true;
177 _countdown = countdown;
178 _fadeVolumeStep = fadeVolumeStep;
179 }
180
update()181 void MusicItem::update() {
182 if (_countdown) {
183 --_countdown;
184 } else if (_play && !_musicResource->isPlaying()) {
185 debug(1, "MusicItem: play music %08X (fade %d)", _fileHash, _fadeVolumeStep);
186 _musicResource->play(_fadeVolumeStep);
187 _fadeVolumeStep = 0;
188 } else if (_stop) {
189 debug(1, "MusicItem: stop music %08X (fade %d)", _fileHash, _fadeVolumeStep);
190 _musicResource->stop(_fadeVolumeStep);
191 _fadeVolumeStep = 0;
192 _stop = false;
193 }
194 }
195
SoundItem(NeverhoodEngine * vm,uint32 groupNameHash,uint32 soundFileHash,bool playOnceAfterRandomCountdown,int16 minCountdown,int16 maxCountdown,bool playOnceAfterCountdown,int16 initialCountdown,bool playLooping,int16 currCountdown)196 SoundItem::SoundItem(NeverhoodEngine *vm, uint32 groupNameHash, uint32 soundFileHash,
197 bool playOnceAfterRandomCountdown, int16 minCountdown, int16 maxCountdown,
198 bool playOnceAfterCountdown, int16 initialCountdown, bool playLooping, int16 currCountdown)
199 : _vm(vm), _soundResource(NULL), _groupNameHash(groupNameHash), _fileHash(soundFileHash),
200 _playOnceAfterRandomCountdown(false), _minCountdown(0), _maxCountdown(0),
201 _playOnceAfterCountdown(playOnceAfterCountdown), _initialCountdown(initialCountdown),
202 _playLooping(false), _currCountdown(currCountdown) {
203
204 _soundResource = new SoundResource(vm);
205 _soundResource->load(soundFileHash);
206 }
207
~SoundItem()208 SoundItem::~SoundItem() {
209 if (_soundResource)
210 _soundResource->unload();
211 delete _soundResource;
212 }
213
setSoundParams(bool playOnceAfterRandomCountdown,int16 minCountdown,int16 maxCountdown,int16 firstMinCountdown,int16 firstMaxCountdown)214 void SoundItem::setSoundParams(bool playOnceAfterRandomCountdown, int16 minCountdown, int16 maxCountdown,
215 int16 firstMinCountdown, int16 firstMaxCountdown) {
216
217 _playOnceAfterCountdown = false;
218 _playLooping = false;
219 _playOnceAfterRandomCountdown = playOnceAfterRandomCountdown;
220 if (minCountdown > 0)
221 _minCountdown = minCountdown;
222 if (maxCountdown > 0)
223 _maxCountdown = maxCountdown;
224 if (firstMinCountdown > firstMaxCountdown)
225 _currCountdown = firstMinCountdown;
226 else if (firstMinCountdown > 0 && firstMaxCountdown > 0 && firstMinCountdown < firstMaxCountdown)
227 _currCountdown = _vm->_rnd->getRandomNumberRng(firstMinCountdown, firstMaxCountdown);
228 }
229
playSoundLooping()230 void SoundItem::playSoundLooping() {
231 _playOnceAfterRandomCountdown = false;
232 _playOnceAfterCountdown = false;
233 _playLooping = true;
234 }
235
stopSound()236 void SoundItem::stopSound() {
237 _playOnceAfterRandomCountdown = false;
238 _playOnceAfterCountdown = false;
239 _playLooping = false;
240 _soundResource->stop();
241 }
242
setVolume(int volume)243 void SoundItem::setVolume(int volume) {
244 _soundResource->setVolume(volume);
245 }
246
update()247 void SoundItem::update() {
248 if (_playOnceAfterCountdown) {
249 if (_currCountdown == 0)
250 _currCountdown = _initialCountdown;
251 else if (--_currCountdown <= 0)
252 _soundResource->play();
253 } else if (_playOnceAfterRandomCountdown) {
254 if (_currCountdown == 0) {
255 if (_minCountdown > 0 && _maxCountdown > 0 && _minCountdown < _maxCountdown)
256 _currCountdown = _vm->_rnd->getRandomNumberRng(_minCountdown, _maxCountdown);
257 } else if (--_currCountdown <= 0)
258 _soundResource->play();
259 } else if (_playLooping && !_soundResource->isPlaying())
260 _soundResource->playLooping();
261 }
262
263 // SoundMan
264
SoundMan(NeverhoodEngine * vm)265 SoundMan::SoundMan(NeverhoodEngine *vm)
266 : _vm(vm), _soundIndex1(-1), _soundIndex2(-1), _soundIndex3(-1),
267 _initialCountdown(15), _playOnceAfterCountdown(false),
268 _initialCountdown3(9), _playOnceAfterCountdown3(false) {
269 }
270
~SoundMan()271 SoundMan::~SoundMan() {
272 stopAllMusic();
273 stopAllSounds();
274 }
275
stopAllMusic()276 void SoundMan::stopAllMusic() {
277 for (uint i = 0; i < _musicItems.size(); ++i) {
278 if (_musicItems[i]) {
279 _musicItems[i]->stopMusic(0, 0);
280 delete _musicItems[i];
281 _musicItems[i] = NULL;
282 }
283 }
284 }
285
stopAllSounds()286 void SoundMan::stopAllSounds() {
287 for (uint i = 0; i < _soundItems.size(); ++i) {
288 if (_soundItems[i]) {
289 _soundItems[i]->stopSound();
290 delete _soundItems[i];
291 _soundItems[i] = NULL;
292 }
293 }
294
295 _soundIndex1 = _soundIndex2 = _soundIndex3 = -1;
296 }
297
addMusic(uint32 groupNameHash,uint32 musicFileHash)298 void SoundMan::addMusic(uint32 groupNameHash, uint32 musicFileHash) {
299 addMusicItem(new MusicItem(_vm, groupNameHash, musicFileHash));
300 }
301
deleteMusic(uint32 musicFileHash)302 void SoundMan::deleteMusic(uint32 musicFileHash) {
303 MusicItem *musicItem = getMusicItemByHash(musicFileHash);
304 if (musicItem) {
305 delete musicItem;
306 for (uint i = 0; i < _musicItems.size(); ++i)
307 if (_musicItems[i] == musicItem) {
308 _musicItems[i] = NULL;
309 break;
310 }
311 }
312 }
313
startMusic(uint32 musicFileHash,int16 countdown,int16 fadeVolumeStep)314 void SoundMan::startMusic(uint32 musicFileHash, int16 countdown, int16 fadeVolumeStep) {
315 MusicItem *musicItem = getMusicItemByHash(musicFileHash);
316 if (musicItem)
317 musicItem->startMusic(countdown, fadeVolumeStep);
318 }
319
stopMusic(uint32 musicFileHash,int16 countdown,int16 fadeVolumeStep)320 void SoundMan::stopMusic(uint32 musicFileHash, int16 countdown, int16 fadeVolumeStep) {
321 MusicItem *musicItem = getMusicItemByHash(musicFileHash);
322 if (musicItem)
323 musicItem->stopMusic(countdown, fadeVolumeStep);
324 }
325
addSound(uint32 groupNameHash,uint32 soundFileHash)326 void SoundMan::addSound(uint32 groupNameHash, uint32 soundFileHash) {
327 addSoundItem(new SoundItem(_vm, groupNameHash, soundFileHash, false, 50, 600, false, 0, false, 0));
328 }
329
addSoundList(uint32 groupNameHash,const uint32 * soundFileHashList)330 void SoundMan::addSoundList(uint32 groupNameHash, const uint32 *soundFileHashList) {
331 while (*soundFileHashList)
332 addSound(groupNameHash, *soundFileHashList++);
333 }
334
deleteSound(uint32 soundFileHash)335 void SoundMan::deleteSound(uint32 soundFileHash) {
336 SoundItem *soundItem = getSoundItemByHash(soundFileHash);
337 if (soundItem) {
338 delete soundItem;
339 for (uint i = 0; i < _soundItems.size(); ++i)
340 if (_soundItems[i] == soundItem) {
341 _soundItems[i] = NULL;
342 break;
343 }
344 }
345 }
346
setSoundParams(uint32 soundFileHash,bool playOnceAfterRandomCountdown,int16 minCountdown,int16 maxCountdown,int16 firstMinCountdown,int16 firstMaxCountdown)347 void SoundMan::setSoundParams(uint32 soundFileHash, bool playOnceAfterRandomCountdown,
348 int16 minCountdown, int16 maxCountdown, int16 firstMinCountdown, int16 firstMaxCountdown) {
349
350 SoundItem *soundItem = getSoundItemByHash(soundFileHash);
351 if (soundItem)
352 soundItem->setSoundParams(playOnceAfterRandomCountdown, minCountdown, maxCountdown,
353 firstMinCountdown, firstMaxCountdown);
354 }
355
setSoundListParams(const uint32 * soundFileHashList,bool playOnceAfterRandomCountdown,int16 minCountdown,int16 maxCountdown,int16 firstMinCountdown,int16 firstMaxCountdown)356 void SoundMan::setSoundListParams(const uint32 *soundFileHashList, bool playOnceAfterRandomCountdown,
357 int16 minCountdown, int16 maxCountdown, int16 firstMinCountdown, int16 firstMaxCountdown) {
358
359 while (*soundFileHashList)
360 setSoundParams(*soundFileHashList++, playOnceAfterRandomCountdown,
361 minCountdown, maxCountdown, firstMinCountdown, firstMaxCountdown);
362 }
363
playSoundLooping(uint32 soundFileHash)364 void SoundMan::playSoundLooping(uint32 soundFileHash) {
365 SoundItem *soundItem = getSoundItemByHash(soundFileHash);
366 if (soundItem)
367 soundItem->playSoundLooping();
368 }
369
stopSound(uint32 soundFileHash)370 void SoundMan::stopSound(uint32 soundFileHash) {
371 SoundItem *soundItem = getSoundItemByHash(soundFileHash);
372 if (soundItem)
373 soundItem->stopSound();
374 }
375
setSoundVolume(uint32 soundFileHash,int volume)376 void SoundMan::setSoundVolume(uint32 soundFileHash, int volume) {
377 SoundItem *soundItem = getSoundItemByHash(soundFileHash);
378 if (soundItem)
379 soundItem->setVolume(volume);
380 }
381
update()382 void SoundMan::update() {
383
384 for (uint i = 0; i < _soundItems.size(); ++i) {
385 SoundItem *soundItem = _soundItems[i];
386 if (soundItem)
387 soundItem->update();
388 }
389 for (uint i = 0; i < _musicItems.size(); ++i) {
390 MusicItem *musicItem = _musicItems[i];
391 if (musicItem)
392 musicItem->update();
393 }
394
395 }
396
deleteGroup(uint32 groupNameHash)397 void SoundMan::deleteGroup(uint32 groupNameHash) {
398 deleteMusicGroup(groupNameHash);
399 deleteSoundGroup(groupNameHash);
400 }
401
deleteMusicGroup(uint32 groupNameHash)402 void SoundMan::deleteMusicGroup(uint32 groupNameHash) {
403 for (uint index = 0; index < _musicItems.size(); ++index) {
404 MusicItem *musicItem = _musicItems[index];
405 if (musicItem && musicItem->getGroupNameHash() == groupNameHash) {
406 delete musicItem;
407 _musicItems[index] = NULL;
408 }
409 }
410 }
411
deleteSoundGroup(uint32 groupNameHash)412 void SoundMan::deleteSoundGroup(uint32 groupNameHash) {
413
414 if (_soundIndex1 != -1 && _soundItems[_soundIndex1]->getGroupNameHash() == groupNameHash) {
415 deleteSoundByIndex(_soundIndex1);
416 _soundIndex1 = -1;
417 }
418
419 if (_soundIndex2 != -1 && _soundItems[_soundIndex2]->getGroupNameHash() == groupNameHash) {
420 deleteSoundByIndex(_soundIndex2);
421 _soundIndex2 = -1;
422 }
423
424 if (_soundIndex3 != -1 && _soundItems[_soundIndex3]->getGroupNameHash() == groupNameHash) {
425 deleteSoundByIndex(_soundIndex3);
426 _soundIndex3 = -1;
427 }
428
429 for (uint index = 0; index < _soundItems.size(); ++index)
430 if (_soundItems[index] && _soundItems[index]->getGroupNameHash() == groupNameHash)
431 deleteSoundByIndex(index);
432
433 }
434
playTwoSounds(uint32 groupNameHash,uint32 soundFileHash1,uint32 soundFileHash2,int16 initialCountdown)435 void SoundMan::playTwoSounds(uint32 groupNameHash, uint32 soundFileHash1, uint32 soundFileHash2, int16 initialCountdown) {
436
437 int16 currCountdown1 = _initialCountdown;
438 int16 currCountdown2 = _initialCountdown / 2;
439
440 if (_soundIndex1 != -1) {
441 currCountdown1 = _soundItems[_soundIndex1]->getCurrCountdown();
442 deleteSoundByIndex(_soundIndex1);
443 _soundIndex1 = -1;
444 }
445
446 if (_soundIndex2 != -1) {
447 currCountdown2 = _soundItems[_soundIndex2]->getCurrCountdown();
448 deleteSoundByIndex(_soundIndex2);
449 _soundIndex2 = -1;
450 }
451
452 if (initialCountdown > 0)
453 _initialCountdown = initialCountdown;
454
455 if (soundFileHash1 != 0) {
456 SoundItem *soundItem = new SoundItem(_vm, groupNameHash, soundFileHash1, false, 0, 0,
457 _playOnceAfterCountdown, _initialCountdown, false, currCountdown1);
458 soundItem->setVolume(80);
459 _soundIndex1 = addSoundItem(soundItem);
460 }
461
462 if (soundFileHash2 != 0) {
463 SoundItem *soundItem = new SoundItem(_vm, groupNameHash, soundFileHash2, false, 0, 0,
464 _playOnceAfterCountdown, _initialCountdown, false, currCountdown2);
465 soundItem->setVolume(80);
466 _soundIndex2 = addSoundItem(soundItem);
467 }
468
469 }
470
playSoundThree(uint32 groupNameHash,uint32 soundFileHash)471 void SoundMan::playSoundThree(uint32 groupNameHash, uint32 soundFileHash) {
472
473 if (_soundIndex3 != -1) {
474 deleteSoundByIndex(_soundIndex3);
475 _soundIndex3 = -1;
476 }
477
478 if (soundFileHash != 0) {
479 SoundItem *soundItem = new SoundItem(_vm, groupNameHash, soundFileHash, false, 0, 0, false, _initialCountdown3, false, 0);
480 _soundIndex3 = addSoundItem(soundItem);
481 }
482
483 }
484
setTwoSoundsPlayFlag(bool playOnceAfterCountdown)485 void SoundMan::setTwoSoundsPlayFlag(bool playOnceAfterCountdown) {
486 if (_soundIndex1 != -1)
487 _soundItems[_soundIndex1]->setPlayOnceAfterCountdown(playOnceAfterCountdown);
488 if (_soundIndex2 != -1)
489 _soundItems[_soundIndex2]->setPlayOnceAfterCountdown(playOnceAfterCountdown);
490 _playOnceAfterCountdown = playOnceAfterCountdown;
491 }
492
setSoundThreePlayFlag(bool playOnceAfterCountdown)493 void SoundMan::setSoundThreePlayFlag(bool playOnceAfterCountdown) {
494 if (_soundIndex3 != -1)
495 _soundItems[_soundIndex3]->setPlayOnceAfterCountdown(playOnceAfterCountdown);
496 _playOnceAfterCountdown3 = playOnceAfterCountdown;
497 }
498
getMusicItemByHash(uint32 musicFileHash)499 MusicItem *SoundMan::getMusicItemByHash(uint32 musicFileHash) {
500 for (uint i = 0; i < _musicItems.size(); ++i)
501 if (_musicItems[i] && _musicItems[i]->getFileHash() == musicFileHash)
502 return _musicItems[i];
503 return NULL;
504 }
505
getSoundItemByHash(uint32 soundFileHash)506 SoundItem *SoundMan::getSoundItemByHash(uint32 soundFileHash) {
507 for (uint i = 0; i < _soundItems.size(); ++i)
508 if (_soundItems[i] && _soundItems[i]->getFileHash() == soundFileHash)
509 return _soundItems[i];
510 return NULL;
511 }
512
addMusicItem(MusicItem * musicItem)513 int16 SoundMan::addMusicItem(MusicItem *musicItem) {
514 for (uint i = 0; i < _musicItems.size(); ++i)
515 if (!_musicItems[i]) {
516 _musicItems[i] = musicItem;
517 return i;
518 }
519 int16 musicIndex = _musicItems.size();
520 _musicItems.push_back(musicItem);
521 return musicIndex;
522 }
523
addSoundItem(SoundItem * soundItem)524 int16 SoundMan::addSoundItem(SoundItem *soundItem) {
525 for (uint i = 0; i < _soundItems.size(); ++i)
526 if (!_soundItems[i]) {
527 _soundItems[i] = soundItem;
528 return i;
529 }
530 int16 soundIndex = _soundItems.size();
531 _soundItems.push_back(soundItem);
532 return soundIndex;
533 }
534
deleteSoundByIndex(int index)535 void SoundMan::deleteSoundByIndex(int index) {
536 delete _soundItems[index];
537 _soundItems[index] = NULL;
538 }
539
540 // NeverhoodAudioStream
541
NeverhoodAudioStream(int rate,byte shiftValue,bool isLooping,DisposeAfterUse::Flag disposeStream,Common::SeekableReadStream * stream)542 NeverhoodAudioStream::NeverhoodAudioStream(int rate, byte shiftValue, bool isLooping, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream)
543 : _rate(rate), _shiftValue(shiftValue), _isLooping(isLooping), _isStereo(false), _stream(stream, disposeStream), _endOfData(false), _buffer(0),
544 _isCompressed(_shiftValue != 0xFF), _prevValue(0) {
545 // Setup our buffer for readBuffer
546 _buffer = new byte[kSampleBufferLength * (_isCompressed ? 1 : 2)];
547 assert(_buffer);
548 }
549
~NeverhoodAudioStream()550 NeverhoodAudioStream::~NeverhoodAudioStream() {
551 delete[] _buffer;
552 }
553
readBuffer(int16 * buffer,const int numSamples)554 int NeverhoodAudioStream::readBuffer(int16 *buffer, const int numSamples) {
555 int samplesLeft = numSamples;
556
557 while (samplesLeft > 0 && !_endOfData) {
558
559 const int maxSamples = MIN<int>(kSampleBufferLength, samplesLeft);
560 const int bytesToRead = maxSamples * (_isCompressed ? 1 : 2);
561 int bytesRead = _stream->read(_buffer, bytesToRead);
562 int samplesRead = bytesRead / (_isCompressed ? 1 : 2);
563
564 samplesLeft -= samplesRead;
565
566 const byte *src = _buffer;
567 if (_isCompressed) {
568 while (samplesRead--) {
569 _prevValue += (int8)(*src++);
570 *buffer++ = _prevValue << _shiftValue;
571 }
572 } else {
573 while (samplesRead--) {
574 *buffer++ = READ_LE_UINT16(src);
575 src += 2;
576 }
577 }
578
579 if (bytesRead < bytesToRead || _stream->pos() >= _stream->size() || _stream->err() || _stream->eos()) {
580 if (_isLooping) {
581 _stream->seek(0);
582 _prevValue = 0;
583 } else {
584 _endOfData = true;
585 }
586 }
587
588 }
589
590 return numSamples - samplesLeft;
591 }
592
AudioResourceManSoundItem(NeverhoodEngine * vm,uint32 fileHash)593 AudioResourceManSoundItem::AudioResourceManSoundItem(NeverhoodEngine *vm, uint32 fileHash)
594 : _vm(vm), _fileHash(fileHash), _data(NULL), _isLoaded(false), _isPlaying(false),
595 _volume(100), _panning(50) {
596
597 _vm->_res->queryResource(_fileHash, _resourceHandle);
598 _soundHandle = new Audio::SoundHandle();
599 }
600
~AudioResourceManSoundItem()601 AudioResourceManSoundItem::~AudioResourceManSoundItem() {
602 delete _soundHandle;
603 }
604
loadSound()605 void AudioResourceManSoundItem::loadSound() {
606 if (!_data && _resourceHandle.isValid() &&
607 (_resourceHandle.type() == kResTypeSound || _resourceHandle.type() == kResTypeMusic)) {
608 _vm->_res->loadResource(_resourceHandle, _vm->applyResourceFixes());
609 _data = _resourceHandle.data();
610 }
611 }
612
unloadSound()613 void AudioResourceManSoundItem::unloadSound() {
614 if (_vm->_mixer->isSoundHandleActive(*_soundHandle))
615 _vm->_mixer->stopHandle(*_soundHandle);
616 _vm->_res->unloadResource(_resourceHandle);
617 _data = NULL;
618 }
619
setVolume(int16 volume)620 void AudioResourceManSoundItem::setVolume(int16 volume) {
621 _volume = MIN<int16>(volume, 100);
622 if (_isPlaying && _vm->_mixer->isSoundHandleActive(*_soundHandle))
623 _vm->_mixer->setChannelVolume(*_soundHandle, VOLUME(_volume));
624 }
625
setPan(int16 pan)626 void AudioResourceManSoundItem::setPan(int16 pan) {
627 _panning = MIN<int16>(pan, 100);
628 if (_isPlaying && _vm->_mixer->isSoundHandleActive(*_soundHandle))
629 _vm->_mixer->setChannelVolume(*_soundHandle, PANNING(_panning));
630 }
631
playSound(bool looping)632 void AudioResourceManSoundItem::playSound(bool looping) {
633 if (!_data)
634 loadSound();
635 if (_data) {
636 const byte *shiftValue = _resourceHandle.extData();
637 Common::MemoryReadStream *stream = new Common::MemoryReadStream(_data, _resourceHandle.size(), DisposeAfterUse::NO);
638 NeverhoodAudioStream *audioStream = new NeverhoodAudioStream(22050, *shiftValue, looping, DisposeAfterUse::YES, stream);
639 _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, _soundHandle,
640 audioStream, -1, VOLUME(_volume), PANNING(_panning));
641 debug(1, "playing sound %08X", _fileHash);
642 _isPlaying = true;
643 }
644 }
645
stopSound()646 void AudioResourceManSoundItem::stopSound() {
647 if (_vm->_mixer->isSoundHandleActive(*_soundHandle))
648 _vm->_mixer->stopHandle(*_soundHandle);
649 _isPlaying = false;
650 }
651
isPlaying()652 bool AudioResourceManSoundItem::isPlaying() {
653 return _vm->_mixer->isSoundHandleActive(*_soundHandle);
654 }
655
AudioResourceManMusicItem(NeverhoodEngine * vm,uint32 fileHash)656 AudioResourceManMusicItem::AudioResourceManMusicItem(NeverhoodEngine *vm, uint32 fileHash)
657 : _vm(vm), _fileHash(fileHash), _terminate(false), _canRestart(false),
658 _volume(100), _panning(50), _start(false), _isFadingIn(false), _isFadingOut(false), _isPlaying(false),
659 _fadeVolume(0), _fadeVolumeStep(0) {
660
661 _soundHandle = new Audio::SoundHandle();
662 }
663
~AudioResourceManMusicItem()664 AudioResourceManMusicItem::~AudioResourceManMusicItem() {
665 delete _soundHandle;
666 }
667
playMusic(int16 fadeVolumeStep)668 void AudioResourceManMusicItem::playMusic(int16 fadeVolumeStep) {
669 if (!_isPlaying) {
670 _isFadingIn = false;
671 _isFadingOut = false;
672 if (fadeVolumeStep != 0) {
673 _isFadingIn = true;
674 _fadeVolume = 0;
675 _fadeVolumeStep = fadeVolumeStep;
676 }
677 _start = true;
678 _terminate = false;
679 }
680 }
681
stopMusic(int16 fadeVolumeStep)682 void AudioResourceManMusicItem::stopMusic(int16 fadeVolumeStep) {
683 if (_vm->_mixer->isSoundHandleActive(*_soundHandle)) {
684 if (fadeVolumeStep != 0) {
685 if (_isFadingIn)
686 _isFadingIn = false;
687 else
688 _fadeVolume = _volume;
689 _isFadingOut = true;
690 _fadeVolumeStep = fadeVolumeStep;
691 } else {
692 _vm->_mixer->stopHandle(*_soundHandle);
693 }
694 _isPlaying = false;
695 }
696 }
697
unloadMusic()698 void AudioResourceManMusicItem::unloadMusic() {
699 if (_isFadingOut) {
700 _canRestart = true;
701 } else {
702 if (_vm->_mixer->isSoundHandleActive(*_soundHandle))
703 _vm->_mixer->stopHandle(*_soundHandle);
704 _isPlaying = false;
705 _terminate = true;
706 }
707 }
708
setVolume(int16 volume)709 void AudioResourceManMusicItem::setVolume(int16 volume) {
710 _volume = MIN<int16>(volume, 100);
711 if (_isPlaying && _vm->_mixer->isSoundHandleActive(*_soundHandle))
712 _vm->_mixer->setChannelVolume(*_soundHandle, VOLUME(_volume));
713 }
714
restart()715 void AudioResourceManMusicItem::restart() {
716 _canRestart = false;
717 _isFadingOut = false;
718 _isFadingIn = true;
719 }
720
update()721 void AudioResourceManMusicItem::update() {
722
723 if (_start && !_vm->_mixer->isSoundHandleActive(*_soundHandle)) {
724 ResourceHandle resourceHandle;
725 _vm->_res->queryResource(_fileHash, resourceHandle);
726 Common::SeekableReadStream *stream = _vm->_res->createStream(_fileHash);
727 const byte *shiftValue = resourceHandle.extData();
728 NeverhoodAudioStream *audioStream = new NeverhoodAudioStream(22050, *shiftValue, true, DisposeAfterUse::YES, stream);
729 _vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, _soundHandle,
730 audioStream, -1, VOLUME(_isFadingIn ? _fadeVolume : _volume),
731 PANNING(_panning));
732 _start = false;
733 _isPlaying = true;
734 }
735
736 if (_vm->_mixer->isSoundHandleActive(*_soundHandle)) {
737 if (_isFadingIn) {
738 _fadeVolume += _fadeVolumeStep;
739 if (_fadeVolume >= _volume) {
740 _fadeVolume = _volume;
741 _isFadingIn = false;
742 }
743 _vm->_mixer->setChannelVolume(*_soundHandle, VOLUME(_fadeVolume));
744 }
745 if (_isFadingOut) {
746 _fadeVolume -= _fadeVolumeStep;
747 if (_fadeVolume < 0)
748 _fadeVolume = 0;
749 _vm->_mixer->setChannelVolume(*_soundHandle, VOLUME(_fadeVolume));
750 if (_fadeVolume == 0) {
751 _isFadingOut = false;
752 stopMusic(0);
753 if (_canRestart)
754 unloadMusic();
755 }
756 }
757 }
758
759 }
760
AudioResourceMan(NeverhoodEngine * vm)761 AudioResourceMan::AudioResourceMan(NeverhoodEngine *vm)
762 : _vm(vm) {
763 }
764
stopAllMusic()765 void AudioResourceMan::stopAllMusic() {
766 for (uint i = 0; i < _musicItems.size(); ++i) {
767 if (_musicItems[i]) {
768 _musicItems[i]->stopMusic(0);
769 delete _musicItems[i];
770 _musicItems[i] = NULL;
771 }
772 }
773 }
774
stopAllSounds()775 void AudioResourceMan::stopAllSounds() {
776 for (uint i = 0; i < _soundItems.size(); ++i) {
777 if (_soundItems[i]) {
778 _soundItems[i]->stopSound();
779 delete _soundItems[i];
780 _soundItems[i] = NULL;
781 }
782 }
783 }
784
~AudioResourceMan()785 AudioResourceMan::~AudioResourceMan() {
786 stopAllMusic();
787 stopAllSounds();
788 }
789
addSound(uint32 fileHash)790 int16 AudioResourceMan::addSound(uint32 fileHash) {
791 AudioResourceManSoundItem *soundItem = new AudioResourceManSoundItem(_vm, fileHash);
792
793 for (uint i = 0; i < _soundItems.size(); ++i)
794 if (!_soundItems[i]) {
795 _soundItems[i] = soundItem;
796 return i;
797 }
798
799 int16 soundIndex = (int16)_soundItems.size();
800 _soundItems.push_back(soundItem);
801 return soundIndex;
802 }
803
removeSound(int16 soundIndex)804 void AudioResourceMan::removeSound(int16 soundIndex) {
805 AudioResourceManSoundItem *soundItem = getSoundItem(soundIndex);
806 if (soundItem) {
807 soundItem->unloadSound();
808 delete soundItem;
809 _soundItems[soundIndex] = NULL;
810 }
811 }
812
loadMusic(uint32 fileHash)813 int16 AudioResourceMan::loadMusic(uint32 fileHash) {
814 AudioResourceManMusicItem *musicItem;
815
816 for (uint i = 0; i < _musicItems.size(); ++i) {
817 musicItem = _musicItems[i];
818 if (musicItem && musicItem->getFileHash() == fileHash && musicItem->canRestart()) {
819 musicItem->restart();
820 return i;
821 }
822 }
823
824 musicItem = new AudioResourceManMusicItem(_vm, fileHash);
825
826 for (uint i = 0; i < _musicItems.size(); ++i) {
827 if (!_musicItems[i]) {
828 _musicItems[i] = musicItem;
829 return i;
830 }
831 }
832
833 int16 musicIndex = _musicItems.size();
834 _musicItems.push_back(musicItem);
835 return musicIndex;
836
837 }
838
updateMusic()839 void AudioResourceMan::updateMusic() {
840 for (uint musicIndex = 0; musicIndex < _musicItems.size(); ++musicIndex) {
841 AudioResourceManMusicItem *musicItem = _musicItems[musicIndex];
842 if (musicItem) {
843 musicItem->update();
844 if (musicItem->isTerminated()) {
845 delete musicItem;
846 _musicItems[musicIndex] = NULL;
847 }
848 }
849 }
850 }
851
getSoundItem(int16 index)852 AudioResourceManSoundItem *AudioResourceMan::getSoundItem(int16 index) {
853 return (index >= 0 && index < (int16)_soundItems.size()) ? _soundItems[index] : NULL;
854 }
855
getMusicItem(int16 index)856 AudioResourceManMusicItem *AudioResourceMan::getMusicItem(int16 index) {
857 return (index >= 0 && index < (int16)_musicItems.size()) ? _musicItems[index] : NULL;
858 }
859
860 } // End of namespace Neverhood
861