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  * Additional copyright for this file:
8  * Copyright (C) 1994-1998 Revolution Software Ltd.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24 
25 // One feature still missing is the original's DipMusic() function which, as
26 // far as I can understand, softened the music volume when someone was
27 // speaking, but only (?) if the music was playing loudly at the time.
28 //
29 // All things considered, I think this is more bother than it's worth.
30 
31 
32 #include "common/file.h"
33 #include "common/memstream.h"
34 #include "common/substream.h"
35 #include "common/system.h"
36 #include "common/textconsole.h"
37 
38 #include "audio/audiostream.h"
39 #include "audio/mixer.h"
40 #include "audio/decoders/mp3.h"
41 #include "audio/decoders/vorbis.h"
42 #include "audio/decoders/flac.h"
43 #include "audio/decoders/xa.h"
44 #include "audio/rate.h"
45 
46 #include "sword2/sword2.h"
47 #include "sword2/defs.h"
48 #include "sword2/header.h"
49 #include "sword2/resman.h"
50 #include "sword2/sound.h"
51 
52 namespace Sword2 {
53 
54 static Audio::AudioStream *makeCLUStream(Common::File *fp, int size);
55 static Audio::AudioStream *makePSXCLUStream(Common::File *fp, int size);
56 
getAudioStream(SoundFileHandle * fh,const char * base,int cd,uint32 id,uint32 * numSamples)57 static Audio::AudioStream *getAudioStream(SoundFileHandle *fh, const char *base, int cd, uint32 id, uint32 *numSamples) {
58 	bool alreadyOpen;
59 
60 	if (!fh->file.isOpen()) {
61 		alreadyOpen = false;
62 
63 		struct {
64 			const char *ext;
65 			int mode;
66 		} file_types[] = {
67 #ifdef USE_FLAC
68 			{ "clf", kFLACMode },
69 #endif
70 #ifdef USE_VORBIS
71 			{ "clg", kVorbisMode },
72 #endif
73 #ifdef USE_MAD
74 			{ "cl3", kMP3Mode },
75 #endif
76 			{ "clu", kCLUMode }
77 		};
78 
79 		int soundMode = 0;
80 		char filename[20];
81 
82 		for (int i = 0; i < ARRAYSIZE(file_types); i++) {
83 			sprintf(filename, "%s%d.%s", base, cd, file_types[i].ext);
84 			if (Common::File::exists(filename)) {
85 				soundMode = file_types[i].mode;
86 				break;
87 			}
88 
89 			sprintf(filename, "%s.%s", base, file_types[i].ext);
90 			if (Common::File::exists(filename)) {
91 				soundMode = file_types[i].mode;
92 				break;
93 			}
94 		}
95 
96 		if (soundMode == 0)
97 			return NULL;
98 
99 		fh->file.open(filename);
100 		fh->fileType = soundMode;
101 		if (!fh->file.isOpen()) {
102 			warning("BS2 getAudioStream: Failed opening file '%s'", filename);
103 			return NULL;
104 		}
105 		if (fh->fileSize != fh->file.size()) {
106 			free(fh->idxTab);
107 			fh->idxTab = NULL;
108 		}
109 	} else
110 		alreadyOpen = true;
111 
112 	uint32 entrySize = (fh->fileType == kCLUMode) ? 2 : 3;
113 
114 	if (!fh->idxTab) {
115 		fh->file.seek(0);
116 		fh->idxLen = fh->file.readUint32LE();
117 		fh->file.seek(entrySize * 4);
118 
119 		fh->idxTab = (uint32 *)malloc(fh->idxLen * 3 * sizeof(uint32));
120 		for (uint32 cnt = 0; cnt < fh->idxLen; cnt++) {
121 			fh->idxTab[cnt * 3 + 0] = fh->file.readUint32LE();
122 			fh->idxTab[cnt * 3 + 1] = fh->file.readUint32LE();
123 			if (fh->fileType == kCLUMode) {
124 				fh->idxTab[cnt * 3 + 2] = fh->idxTab[cnt * 3 + 1];
125 				fh->idxTab[cnt * 3 + 1]--;
126 			} else
127 				fh->idxTab[cnt * 3 + 2] = fh->file.readUint32LE();
128 		}
129 	}
130 
131 	// FIXME: In the forest maze on Zombie Island, the scripts will often
132 	// try to play song 451, which doesn't exist. We could easily substitute
133 	// another for it here, but which one? There are roughly 250 musical
134 	// cues to choose from.
135 
136 	uint32 pos = fh->idxTab[id * 3 + 0];
137 	uint32 len = fh->idxTab[id * 3 + 1];
138 	uint32 enc_len = fh->idxTab[id * 3 + 2];
139 
140 	if (numSamples)
141 		*numSamples = len;
142 
143 	if (!pos || !len) {
144 		// We couldn't find the sound. Possibly as a result of a bad
145 		// installation (e.g. using the music file from CD 2 as the
146 		// first music file). Don't close the file if it was already
147 		// open though, because something is playing from it.
148 		warning("getAudioStream: Could not find %s ID %d! Possibly the wrong file", base, id);
149 		if (!alreadyOpen)
150 			fh->file.close();
151 		return NULL;
152 	}
153 
154 	fh->file.seek(pos, SEEK_SET);
155 
156 	switch (fh->fileType) {
157 	case kCLUMode:
158 		if (Sword2Engine::isPsx())
159 			return makePSXCLUStream(&fh->file, enc_len);
160 		else
161 			return makeCLUStream(&fh->file, enc_len);
162 #ifdef USE_MAD
163 	case kMP3Mode: {
164 		Common::SafeSeekableSubReadStream *tmp = new Common::SafeSeekableSubReadStream(&fh->file, pos, pos + enc_len);
165 		return Audio::makeMP3Stream(tmp, DisposeAfterUse::YES);
166 		}
167 #endif
168 #ifdef USE_VORBIS
169 	case kVorbisMode: {
170 		Common::SafeSeekableSubReadStream *tmp = new Common::SafeSeekableSubReadStream(&fh->file, pos, pos + enc_len);
171 		return Audio::makeVorbisStream(tmp, DisposeAfterUse::YES);
172 		}
173 #endif
174 #ifdef USE_FLAC
175 	case kFLACMode: {
176 		Common::SafeSeekableSubReadStream *tmp = new Common::SafeSeekableSubReadStream(&fh->file, pos, pos + enc_len);
177 		return Audio::makeFLACStream(tmp, DisposeAfterUse::YES);
178 		}
179 #endif
180 	default:
181 		return NULL;
182 	}
183 }
184 
185 // ----------------------------------------------------------------------------
186 // Custom AudioStream class to handle Broken Sword 2's audio compression.
187 // ----------------------------------------------------------------------------
188 
189 #define GetCompressedShift(n)      (((n) >> 4) & 0x0F)
190 #define GetCompressedSign(n)       ((n) & 0x08)
191 #define GetCompressedAmplitude(n)  ((n) & 0x07)
192 
CLUInputStream(Common::File * file,int size)193 CLUInputStream::CLUInputStream(Common::File *file, int size)
194 	: _file(file), _firstTime(true), _bufferEnd(_outbuf + BUFFER_SIZE) {
195 
196 	// Determine the end position.
197 	_file_pos = _file->pos();
198 	_end_pos = _file_pos + size;
199 
200 	// Read in initial data
201 	refill();
202 }
203 
~CLUInputStream()204 CLUInputStream::~CLUInputStream() {
205 }
206 
readBuffer(int16 * buffer,const int numSamples)207 int CLUInputStream::readBuffer(int16 *buffer, const int numSamples) {
208 	int samples = 0;
209 	while (samples < numSamples && !eosIntern()) {
210 		const int len = MIN(numSamples - samples, (int)(_bufferEnd - _pos));
211 		memcpy(buffer, _pos, len * 2);
212 		buffer += len;
213 		_pos += len;
214 		samples += len;
215 		if (_pos >= _bufferEnd) {
216 			refill();
217 		}
218 	}
219 	return samples;
220 }
221 
refill()222 void CLUInputStream::refill() {
223 	byte *in = _inbuf;
224 	int16 *out = _outbuf;
225 
226 	_file->seek(_file_pos, SEEK_SET);
227 
228 	uint len_left = _file->read(in, MIN((uint32)BUFFER_SIZE, _end_pos - _file->pos()));
229 
230 	_file_pos = _file->pos();
231 
232 	while (len_left > 0) {
233 		uint16 sample;
234 
235 		if (_firstTime) {
236 			_firstTime = false;
237 			_prev = READ_LE_UINT16(in);
238 			sample = _prev;
239 			len_left -= 2;
240 			in += 2;
241 		} else {
242 			uint16 delta = GetCompressedAmplitude(*in) << GetCompressedShift(*in);
243 			if (GetCompressedSign(*in))
244 				sample = _prev - delta;
245 			else
246 				sample = _prev + delta;
247 
248 			_prev = sample;
249 			len_left--;
250 			in++;
251 		}
252 
253 		*out++ = (int16)sample;
254 	}
255 
256 	_pos = _outbuf;
257 	_bufferEnd = out;
258 }
259 
makeCLUStream(Common::File * file,int size)260 Audio::AudioStream *makeCLUStream(Common::File *file, int size) {
261 	return new CLUInputStream(file, size);
262 }
263 
makePSXCLUStream(Common::File * file,int size)264 Audio::AudioStream *makePSXCLUStream(Common::File *file, int size) {
265 
266 	// Buffer audio file data, and ask MemoryReadStream to dispose of it
267 	// when not needed anymore.
268 
269 	byte *buffer = (byte *)malloc(size);
270 	file->read(buffer, size);
271 	return Audio::makeXAStream(new Common::MemoryReadStream(buffer, size, DisposeAfterUse::YES), 11025);
272 }
273 
274 // ----------------------------------------------------------------------------
275 // Another custom AudioStream class, to wrap around the various AudioStream
276 // classes used for music decompression, and to add looping, fading, etc.
277 // ----------------------------------------------------------------------------
278 
279 // The length of a fade-in/out, in milliseconds.
280 #define FADE_LENGTH 3000
281 
MusicInputStream(int cd,SoundFileHandle * fh,uint32 musicId,bool looping)282 MusicInputStream::MusicInputStream(int cd, SoundFileHandle *fh, uint32 musicId, bool looping) {
283 	_cd = cd;
284 	_fh = fh;
285 	_musicId = musicId;
286 	_looping = looping;
287 
288 	_bufferEnd = _buffer + BUFFER_SIZE;
289 	_remove = false;
290 	_fading = 0;
291 
292 	_decoder = getAudioStream(_fh, "music", _cd, _musicId, &_numSamples);
293 	if (_decoder) {
294 		_samplesLeft = _numSamples;
295 		_fadeSamples = (getRate() * FADE_LENGTH) / 1000;
296 		fadeUp();
297 
298 		// Read in initial data
299 		refill();
300 	}
301 }
302 
~MusicInputStream()303 MusicInputStream::~MusicInputStream() {
304 	delete _decoder;
305 	_decoder = NULL;
306 }
307 
readBuffer(int16 * buffer,const int numSamples)308 int MusicInputStream::readBuffer(int16 *buffer, const int numSamples) {
309 	if (!_decoder)
310 		return 0;
311 
312 	int samples = 0;
313 	while (samples < numSamples && !eosIntern()) {
314 		const int len = MIN(numSamples - samples, (int)(_bufferEnd - _pos));
315 		memcpy(buffer, _pos, len * 2);
316 		buffer += len;
317 		_pos += len;
318 		samples += len;
319 		if (_pos >= _bufferEnd) {
320 			refill();
321 		}
322 	}
323 	return samples;
324 }
325 
refill()326 void MusicInputStream::refill() {
327 	int16 *buf = _buffer;
328 	uint32 numSamples = 0;
329 	uint32 len_left;
330 	bool endFade = false;
331 
332 	len_left = BUFFER_SIZE;
333 
334 	if (_fading > 0 && (uint32)_fading < len_left)
335 		len_left = _fading;
336 
337 	if (_samplesLeft < len_left)
338 		len_left = _samplesLeft;
339 
340 	if (!_looping) {
341 		// Non-looping music is faded out at the end. If this fade
342 		// out would have started somewhere within the len_left samples
343 		// to read, we only read up to that point. This way, we can
344 		// treat this fade as any other.
345 
346 		if (!_fading) {
347 			uint32 currentlyAt = _numSamples - _samplesLeft;
348 			uint32 fadeOutAt = _numSamples - _fadeSamples;
349 			uint32 readTo = currentlyAt + len_left;
350 
351 			if (fadeOutAt == currentlyAt)
352 				fadeDown();
353 			else if (fadeOutAt > currentlyAt && fadeOutAt <= readTo) {
354 				len_left = fadeOutAt - currentlyAt;
355 				endFade = true;
356 			}
357 		}
358 	}
359 
360 	int desired = len_left - numSamples;
361 	int len = _decoder->readBuffer(buf, desired);
362 
363 	// Shouldn't happen, but if it does it could cause an infinite loop.
364 	// Of course there were bugs that caused it to happen several times
365 	// during development. :-)
366 
367 	if (len < desired) {
368 		warning("Expected %d samples, but got %d", desired, len);
369 		_samplesLeft = len;
370 	}
371 
372 	buf += len;
373 	numSamples += len;
374 	len_left -= len;
375 	_samplesLeft -= len;
376 
377 	int16 *ptr;
378 
379 	if (_fading > 0) {
380 		// Fade down
381 		for (ptr = _buffer; ptr < buf; ptr++) {
382 			if (_fading > 0) {
383 				_fading--;
384 				*ptr = (*ptr * _fading) / _fadeSamples;
385 			}
386 			if (_fading == 0) {
387 				_looping = false;
388 				_remove = true;
389 				*ptr = 0;
390 			}
391 		}
392 	} else if (_fading < 0) {
393 		// Fade up
394 		for (ptr = _buffer; ptr < buf; ptr++) {
395 			_fading--;
396 			*ptr = -(*ptr * _fading) / _fadeSamples;
397 			if (_fading <= -_fadeSamples) {
398 				_fading = 0;
399 				break;
400 			}
401 		}
402 	}
403 
404 	if (endFade)
405 		fadeDown();
406 
407 	if (!_samplesLeft) {
408 		if (_looping) {
409 			delete _decoder;
410 			_decoder = getAudioStream(_fh, "music", _cd, _musicId, &_numSamples);
411 			_samplesLeft = _numSamples;
412 		} else
413 			_remove = true;
414 	}
415 
416 	_pos = _buffer;
417 	_bufferEnd = buf;
418 }
419 
fadeUp()420 void MusicInputStream::fadeUp() {
421 	if (_fading > 0)
422 		_fading = -_fading;
423 	else if (_fading == 0)
424 		_fading = -1;
425 }
426 
fadeDown()427 void MusicInputStream::fadeDown() {
428 	if (_fading < 0)
429 		_fading = -_fading;
430 	else if (_fading == 0)
431 		_fading = _fadeSamples;
432 }
433 
readyToRemove()434 bool MusicInputStream::readyToRemove() {
435 	return _remove;
436 }
437 
getTimeRemaining()438 int32 MusicInputStream::getTimeRemaining() {
439 	// This is far from exact, but it doesn't have to be.
440 	return (_samplesLeft + BUFFER_SIZE) / getRate();
441 }
442 
443 // ----------------------------------------------------------------------------
444 // Main sound class
445 // ----------------------------------------------------------------------------
446 
447 // AudioStream API
448 
readBuffer(int16 * buffer,const int numSamples)449 int Sound::readBuffer(int16 *buffer, const int numSamples) {
450 	Common::StackLock lock(_mutex);
451 	int i;
452 
453 	if (_musicPaused)
454 		return 0;
455 
456 	for (i = 0; i < MAXMUS; i++) {
457 		if (_music[i] && _music[i]->readyToRemove()) {
458 			delete _music[i];
459 			_music[i] = NULL;
460 		}
461 	}
462 
463 	memset(buffer, 0, 2 * numSamples);
464 
465 	if (!_mixBuffer || numSamples > _mixBufferLen) {
466 		if (_mixBuffer) {
467 			int16 *newBuffer = (int16 *)realloc(_mixBuffer, 2 * numSamples);
468 			if (newBuffer) {
469 				_mixBuffer = newBuffer;
470 			} else {
471 				// We can't use the old buffer any more. It's too small.
472 				free(_mixBuffer);
473 				_mixBuffer = 0;
474 			}
475 		} else
476 			_mixBuffer = (int16 *)malloc(2 * numSamples);
477 
478 		_mixBufferLen = numSamples;
479 	}
480 
481 	if (!_mixBuffer)
482 		return 0;
483 
484 	for (i = 0; i < MAXMUS; i++) {
485 		if (!_music[i])
486 			continue;
487 
488 		int len = _music[i]->readBuffer(_mixBuffer, numSamples);
489 
490 		if (!_musicMuted) {
491 			for (int j = 0; j < len; j++) {
492 				Audio::clampedAdd(buffer[j], _mixBuffer[j]);
493 			}
494 		}
495 	}
496 
497 	bool inUse[MAXMUS];
498 
499 	for (i = 0; i < MAXMUS; i++)
500 		inUse[i] = false;
501 
502 	for (i = 0; i < MAXMUS; i++) {
503 		if (_music[i]) {
504 			if (_music[i]->getCD() == 1)
505 				inUse[0] = true;
506 			else
507 				inUse[1] = true;
508 		}
509 	}
510 
511 	for (i = 0; i < MAXMUS; i++) {
512 		if (!inUse[i] && !_musicFile[i].inUse && _musicFile[i].file.isOpen())
513 			_musicFile[i].file.close();
514 	}
515 
516 	return numSamples;
517 }
518 
endOfData() const519 bool Sound::endOfData() const {
520 	// The music never stops. It just goes quiet.
521 	return false;
522 }
523 
524 // ----------------------------------------------------------------------------
525 // MUSIC
526 // ----------------------------------------------------------------------------
527 
528 /**
529  * Stops the music dead in its tracks. Any music that is currently being
530  * streamed is paused.
531  */
532 
pauseMusic()533 void Sound::pauseMusic() {
534 	Common::StackLock lock(_mutex);
535 
536 	_musicPaused = true;
537 }
538 
539 /**
540  * Restarts the music from where it was stopped.
541  */
542 
unpauseMusic()543 void Sound::unpauseMusic() {
544 	Common::StackLock lock(_mutex);
545 
546 	_musicPaused = false;
547 }
548 
549 /**
550  * Fades out and stops the music.
551  */
552 
stopMusic(bool immediately)553 void Sound::stopMusic(bool immediately) {
554 	Common::StackLock lock(_mutex);
555 
556 	_loopingMusicId = 0;
557 
558 	for (int i = 0; i < MAXMUS; i++) {
559 		if (_music[i]) {
560 			if (immediately) {
561 				delete _music[i];
562 				_music[i] = NULL;
563 			} else
564 				_music[i]->fadeDown();
565 		}
566 	}
567 }
568 
569 /**
570  * Streams music from a cluster file.
571  * @param musicId the id of the music to stream
572  * @param loop true if the music is to loop back to the start
573  * @return RD_OK or an error code
574  */
streamCompMusic(uint32 musicId,bool loop)575 int32 Sound::streamCompMusic(uint32 musicId, bool loop) {
576 	Common::StackLock lock(_mutex);
577 
578 	int cd = _vm->_resman->getCD();
579 
580 	if (loop)
581 		_loopingMusicId = musicId;
582 	else
583 		_loopingMusicId = 0;
584 
585 	int primary = -1;
586 	int secondary = -1;
587 
588 	// If both music streams are active, one of them will have to go.
589 
590 	if (_music[0] && _music[1]) {
591 		int32 fade0 = _music[0]->isFading();
592 		int32 fade1 = _music[1]->isFading();
593 
594 		if (!fade0 && !fade1) {
595 			// Neither is fading. This shouldn't happen, so just
596 			// pick one and be done with it.
597 			primary = 0;
598 		} else if (fade0 && !fade1) {
599 			// Stream 0 is fading, so pick that one.
600 			primary = 0;
601 		} else if (!fade0 && fade1) {
602 			// Stream 1 is fading, so pick that one.
603 			primary = 1;
604 		} else {
605 			// Both streams are fading. Pick the one that is
606 			// closest to silent.
607 			if (ABS(fade0) < ABS(fade1))
608 				primary = 0;
609 			else
610 				primary = 1;
611 		}
612 
613 		delete _music[primary];
614 		_music[primary] = NULL;
615 	}
616 
617 	// Pick the available music stream. If no music is playing it doesn't
618 	// matter which we use.
619 
620 	if (_music[0] || _music[1]) {
621 		if (_music[0]) {
622 			primary = 1;
623 			secondary = 0;
624 		} else {
625 			primary = 0;
626 			secondary = 1;
627 		}
628 	} else
629 		primary = 0;
630 
631 	// Don't start streaming if the volume is off.
632 	if (isMusicMute()) {
633 		return RD_OK;
634 	}
635 
636 	if (secondary != -1)
637 		_music[secondary]->fadeDown();
638 	SoundFileHandle *fh = (cd == 1) ? &_musicFile[0] : &_musicFile[1];
639 	fh->inUse = true;
640 
641 	MusicInputStream *tmp = new MusicInputStream(cd, fh, musicId, loop);
642 
643 	if (tmp->isReady()) {
644 		_music[primary] = tmp;
645 		fh->inUse = false;
646 		return RD_OK;
647 	} else {
648 		fh->inUse = false;
649 		delete tmp;
650 		return RDERR_INVALIDFILENAME;
651 	}
652 }
653 
654 /**
655  * @return the time left for the current music, in seconds.
656  */
657 
musicTimeRemaining()658 int32 Sound::musicTimeRemaining() {
659 	Common::StackLock lock(_mutex);
660 
661 	for (int i = 0; i < MAXMUS; i++) {
662 		if (_music[i] && _music[i]->isFading() <= 0)
663 			return _music[i]->getTimeRemaining();
664 	}
665 
666 	return 0;
667 }
668 
669 // ----------------------------------------------------------------------------
670 // SPEECH
671 // ----------------------------------------------------------------------------
672 
673 /**
674  * Mutes/Unmutes the speech.
675  * @param mute If mute is false, restore the volume to the last set master
676  * level. Otherwise the speech is muted (volume 0).
677  */
678 
muteSpeech(bool mute)679 void Sound::muteSpeech(bool mute) {
680 	_speechMuted = mute;
681 
682 	if (_vm->_mixer->isSoundHandleActive(_soundHandleSpeech)) {
683 		uint volume = mute ? 0 : Audio::Mixer::kMaxChannelVolume;
684 
685 		_vm->_mixer->setChannelVolume(_soundHandleSpeech, volume);
686 	}
687 }
688 
689 /**
690  * Stops the speech dead in its tracks.
691  */
692 
pauseSpeech()693 void Sound::pauseSpeech() {
694 	if (!_speechPaused) {
695 		_speechPaused = true;
696 		_vm->_mixer->pauseHandle(_soundHandleSpeech, true);
697 	}
698 }
699 
700 /**
701  * Restarts the speech from where it was stopped.
702  */
703 
unpauseSpeech()704 void Sound::unpauseSpeech() {
705 	if (_speechPaused) {
706 		_speechPaused = false;
707 		_vm->_mixer->pauseHandle(_soundHandleSpeech, false);
708 	}
709 }
710 
711 /**
712  * Stops the speech from playing.
713  */
714 
stopSpeech()715 int32 Sound::stopSpeech() {
716 	if (_vm->_mixer->isSoundHandleActive(_soundHandleSpeech)) {
717 		_vm->_mixer->stopHandle(_soundHandleSpeech);
718 		return RD_OK;
719 	}
720 
721 	return RDERR_SPEECHNOTPLAYING;
722 }
723 
724 /**
725  * @return Either RDSE_SAMPLEPLAYING or RDSE_SAMPLEFINISHED
726  */
727 
getSpeechStatus()728 int32 Sound::getSpeechStatus() {
729 	return _vm->_mixer->isSoundHandleActive(_soundHandleSpeech) ? RDSE_SAMPLEPLAYING : RDSE_SAMPLEFINISHED;
730 }
731 
732 /**
733  * Returns either RDSE_QUIET or RDSE_SPEAKING
734  */
735 
amISpeaking()736 int32 Sound::amISpeaking() {
737 	if (!_speechMuted && !_speechPaused && _vm->_mixer->isSoundHandleActive(_soundHandleSpeech))
738 		return RDSE_SPEAKING;
739 
740 	return RDSE_QUIET;
741 }
742 
743 /**
744  * This function loads, decompresses and plays a line of speech. An error
745  * occurs if speech is already playing.
746  * @param speechId the text line id used to reference the speech
747  * @param vol volume, 0 (minimum) to 16 (maximum)
748  * @param pan panning, -16 (full left) to 16 (full right)
749  */
750 
playCompSpeech(uint32 speechId,uint8 vol,int8 pan)751 int32 Sound::playCompSpeech(uint32 speechId, uint8 vol, int8 pan) {
752 	if (_speechMuted)
753 		return RD_OK;
754 
755 	if (getSpeechStatus() == RDERR_SPEECHPLAYING)
756 		return RDERR_SPEECHPLAYING;
757 
758 	int cd = _vm->_resman->getCD();
759 	SoundFileHandle *fh = (cd == 1) ? &_speechFile[0] : &_speechFile[1];
760 
761 	Audio::AudioStream *input = getAudioStream(fh, "speech", cd, speechId, NULL);
762 
763 	if (!input)
764 		return RDERR_INVALIDID;
765 
766 	// Modify the volume according to the master volume
767 
768 	byte volume = _speechMuted ? 0 : vol * Audio::Mixer::kMaxChannelVolume / 16;
769 	int8 p = (pan * 127) / 16;
770 
771 	if (isReverseStereo())
772 		p = -p;
773 
774 	// Start the speech playing
775 	_vm->_mixer->playStream(Audio::Mixer::kSpeechSoundType, &_soundHandleSpeech, input, -1, volume, p);
776 	return RD_OK;
777 }
778 
779 // ----------------------------------------------------------------------------
780 // SOUND EFFECTS
781 // ----------------------------------------------------------------------------
782 
783 /**
784  * Mutes/Unmutes the sound effects.
785  * @param mute If mute is false, restore the volume to the last set master
786  * level. Otherwise the sound effects are muted (volume 0).
787  */
788 
muteFx(bool mute)789 void Sound::muteFx(bool mute) {
790 	_fxMuted = mute;
791 
792 	// Now update the volume of any fxs playing
793 	for (int i = 0; i < FXQ_LENGTH; i++) {
794 		if (_fxQueue[i].resource) {
795 			_vm->_mixer->setChannelVolume(_fxQueue[i].handle, mute ? 0 : _fxQueue[i].volume);
796 		}
797 	}
798 }
799 
800 /**
801  * Sets the volume and pan of the sample which is currently playing
802  * @param id the id of the sample
803  * @param vol volume
804  * @param pan panning
805  */
806 
setFxIdVolumePan(int32 id,int vol,int pan)807 int32 Sound::setFxIdVolumePan(int32 id, int vol, int pan) {
808 	if (!_fxQueue[id].resource)
809 		return RDERR_FXNOTOPEN;
810 
811 	if (vol > 16)
812 		vol = 16;
813 
814 	_fxQueue[id].volume = (vol * Audio::Mixer::kMaxChannelVolume) / 16;
815 
816 	if (pan != 255) {
817 		if (isReverseStereo())
818 			pan = -pan;
819 		_fxQueue[id].pan = (pan * 127) / 16;
820 	}
821 
822 	if (!_fxMuted && _vm->_mixer->isSoundHandleActive(_fxQueue[id].handle)) {
823 		_vm->_mixer->setChannelVolume(_fxQueue[id].handle, _fxQueue[id].volume);
824 		if (pan != -1)
825 			_vm->_mixer->setChannelBalance(_fxQueue[id].handle, _fxQueue[id].pan);
826 	}
827 
828 	return RD_OK;
829 }
830 
pauseFx()831 void Sound::pauseFx() {
832 	if (!_fxPaused) {
833 		for (int i = 0; i < FXQ_LENGTH; i++) {
834 			if (_fxQueue[i].resource)
835 				_vm->_mixer->pauseHandle(_fxQueue[i].handle, true);
836 		}
837 		_fxPaused = true;
838 	}
839 }
840 
unpauseFx()841 void Sound::unpauseFx() {
842 	if (_fxPaused) {
843 		for (int i = 0; i < FXQ_LENGTH; i++)
844 			if (_fxQueue[i].resource)
845 				_vm->_mixer->pauseHandle(_fxQueue[i].handle, false);
846 		_fxPaused = false;
847 	}
848 }
849 
850 } // End of namespace Sword2
851