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 #include "audio/soundfont/rawfile.h"
23 #include "audio/soundfont/vab/vab.h"
24 #include "audio/soundfont/vgmcoll.h"
25 #include "audio/mixer.h"
26 #include "audio/audiostream.h"
27 #include "audio/decoders/raw.h"
28 #include "audio/decoders/xa.h"
29 #include "common/config-manager.h"
30 #include "common/file.h"
31 #include "common/memstream.h"
32 #include "dragons/dragons.h"
33 #include "dragons/sound.h"
34 #include "dragons/bigfile.h"
35 #include "dragons/dragonrms.h"
36 #include "dragons/vabsound.h"
37 
38 #define RAW_CD_SECTOR_SIZE 2352
39 
40 #define CDXA_TYPE_MASK     0x0E
41 #define CDXA_TYPE_DATA     0x08
42 #define CDXA_TYPE_AUDIO    0x04
43 
44 namespace Dragons {
45 
46 struct SpeechLocation {
47 	uint32 talkId;
48 	uint16 sectorStart;
49 	int8 startOffset;
50 	uint16 sectorEnd;
51 } SpeechLocation;
52 
CdIntToPos_0(uint32 param_1)53 void CdIntToPos_0(uint32 param_1) { //, byte *param_2)
54 	int iVar1;
55 	int iVar2;
56 	int iVar3;
57 	uint8 minute;
58 	uint8 second;
59 	uint8 sector;
60 
61 	iVar3 = (param_1 + 0x96) / 0x4b;
62 	iVar2 = (param_1 + 0x96) % 0x4b;
63 	iVar1 = iVar3 / 0x3c;
64 	iVar3 = iVar3 % 0x3c;
65 	second = (char)iVar3 + (char)(iVar3 / 10) * 6;
66 	sector = (char)iVar2 + (char)(iVar2 / 10) * 6;
67 	minute = (char)iVar1 + (char)(iVar1 / 10) * 6;
68 
69 
70 	uint32 out =          (((uint)(minute >> 4) * 10 + ((uint)minute & 0xf)) * 0x3c +
71 						   (uint)(second >> 4) * 10 + ((uint)second & 0xf)) * 0x4b +
72 						  (uint)(sector >> 4) * 10 + ((uint)sector & 0xf) + -0x96;
73 
74 	debug(3, "Seek Audio %2X:%2X:%2X  in: %d out %d", minute, second, sector, param_1, out);
75 
76 	return;
77 }
78 
playSpeech(uint32 textIndex)79 void SoundManager::playSpeech(uint32 textIndex) {
80 	if (isSpeechPlaying()) {
81 		_vm->_mixer->stopHandle(_speechHandle);
82 	}
83 
84 	// Reduce music volume while playing dialog.
85 	_midiPlayer->setVolume(_musicVolume / 2);
86 
87 	struct SpeechLocation speechLocation;
88 	if (!getSpeechLocation(textIndex, &speechLocation)) {
89 		return;
90 	}
91 
92 	Common::File *fd = new Common::File();
93 	if (!fd->open("dtspeech.xa")) {
94 		error("Failed to open dtspeech.xa");
95 	}
96 	CdIntToPos_0(speechLocation.sectorStart * 32);
97 	PSXAudioTrack *_audioTrack = new PSXAudioTrack();
98 
99 	_vm->setFlags(ENGINE_FLAG_8000);
100 	_vm->_mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, _audioTrack->createNewAudioStream(fd, speechLocation.sectorStart, speechLocation.startOffset, speechLocation.sectorEnd), -1, _speechVolume);
101 	fd->close();
102 	delete fd;
103 	delete _audioTrack;
104 }
105 
isSpeechPlaying()106 bool SoundManager::isSpeechPlaying() {
107 	return _vm->_mixer->isSoundHandleActive(_speechHandle);
108 }
109 
getSpeechLocation(uint32 talkId,struct SpeechLocation * location)110 bool SoundManager::getSpeechLocation(uint32 talkId, struct SpeechLocation *location) {
111 	Common::File *fd = new Common::File();
112 	if (!fd->open("dragon.exe")) {
113 		error("Failed to open dragon.exe");
114 	}
115 	fd->seek(_vm->getSpeechTblOffsetFromDragonEXE());
116 	bool foundId = false;
117 	for (int i = 0; i < 2272; i++) { //TODO check that the number of speech audio tracks is the same across game variants
118 		uint32 id = (fd->readUint32LE() & 0xffffff);
119 		fd->seek(-1, SEEK_CUR);
120 		int8 startOffset = fd->readSByte();
121 		uint16 start = fd->readUint16LE();
122 		uint16 end = fd->readUint16LE();
123 		if (id == talkId) {
124 			location->talkId = id;
125 			location->sectorStart = start;
126 			location->startOffset = startOffset;
127 			location->sectorEnd = end;
128 			foundId = true;
129 			debug(3, "sectors [%d-%d] unk byte = %d", start * 32, end * 32, startOffset);
130 			break;
131 		}
132 	}
133 
134 	fd->close();
135 	delete fd;
136 
137 	return foundId;
138 }
139 
resumeMusic()140 void SoundManager::resumeMusic() {
141 	if (isSpeechPlaying()) {
142 		_vm->_mixer->stopHandle(_speechHandle);
143 		_vm->clearFlags(ENGINE_FLAG_8000);
144 	}
145 	if (_currentSong != -1) {
146 		_midiPlayer->resume();
147 	}
148 }
149 
PSXAudioTrack()150 SoundManager::PSXAudioTrack::PSXAudioTrack() {
151 	memset(&_adpcmStatus, 0, sizeof(_adpcmStatus));
152 }
153 
154 // Ha! It's palindromic!
155 #define AUDIO_DATA_CHUNK_SIZE   2304
156 #define AUDIO_DATA_SAMPLE_COUNT 4032
157 
158 static const int s_xaTable[5][2] = {
159 	{   0,   0 },
160 	{  60,   0 },
161 	{ 115, -52 },
162 	{  98, -55 },
163 	{ 122, -60 }
164 };
165 
queueAudioFromSector(Audio::QueuingAudioStream * audStream,Common::SeekableReadStream * sector)166 void SoundManager::PSXAudioTrack::queueAudioFromSector(Audio::QueuingAudioStream *audStream, Common::SeekableReadStream *sector) {
167 	sector->skip(24);
168 
169 	// This XA audio is different (yet similar) from normal XA audio! Watch out!
170 	// TODO: It's probably similar enough to normal XA that we can merge it somehow...
171 	// TODO: RTZ PSX needs the same audio code in a regular AudioStream class. Probably
172 	// will do something similar to QuickTime and creating a base class 'ISOMode2Parser'
173 	// or something similar.
174 	byte *buf = new byte[AUDIO_DATA_CHUNK_SIZE];
175 	sector->read(buf, AUDIO_DATA_CHUNK_SIZE);
176 
177 	int channels = audStream->isStereo() ? 2 : 1;
178 	int16 *dst = new int16[AUDIO_DATA_SAMPLE_COUNT];
179 	int16 *leftChannel = dst;
180 	int16 *rightChannel = dst + 1;
181 
182 	for (byte *src = buf; src < buf + AUDIO_DATA_CHUNK_SIZE; src += 128) {
183 		for (int i = 0; i < 4; i++) {
184 			int shift = 12 - (src[4 + i * 2] & 0xf);
185 			int filter = src[4 + i * 2] >> 4;
186 			int f0 = s_xaTable[filter][0];
187 			int f1 = s_xaTable[filter][1];
188 			int16 s_1 = _adpcmStatus[0].sample[0];
189 			int16 s_2 = _adpcmStatus[0].sample[1];
190 
191 			for (int j = 0; j < 28; j++) {
192 				byte d = src[16 + i + j * 4];
193 				int t = (int8)(d << 4) >> 4;
194 				int s = (t << shift) + ((s_1 * f0 + s_2 * f1 + 32) >> 6);
195 				s_2 = s_1;
196 				s_1 = CLIP<int>(s, -32768, 32767);
197 				*leftChannel = s_1;
198 				leftChannel += channels;
199 			}
200 
201 			if (channels == 2) {
202 				_adpcmStatus[0].sample[0] = s_1;
203 				_adpcmStatus[0].sample[1] = s_2;
204 				s_1 = _adpcmStatus[1].sample[0];
205 				s_2 = _adpcmStatus[1].sample[1];
206 			}
207 
208 			shift = 12 - (src[5 + i * 2] & 0xf);
209 			filter = src[5 + i * 2] >> 4;
210 			f0 = s_xaTable[filter][0];
211 			f1 = s_xaTable[filter][1];
212 
213 			for (int j = 0; j < 28; j++) {
214 				byte d = src[16 + i + j * 4];
215 				int t = (int8)d >> 4;
216 				int s = (t << shift) + ((s_1 * f0 + s_2 * f1 + 32) >> 6);
217 				s_2 = s_1;
218 				s_1 = CLIP<int>(s, -32768, 32767);
219 
220 				if (channels == 2) {
221 					*rightChannel = s_1;
222 					rightChannel += 2;
223 				} else {
224 					*leftChannel++ = s_1;
225 				}
226 			}
227 
228 			if (channels == 2) {
229 				_adpcmStatus[1].sample[0] = s_1;
230 				_adpcmStatus[1].sample[1] = s_2;
231 			} else {
232 				_adpcmStatus[0].sample[0] = s_1;
233 				_adpcmStatus[0].sample[1] = s_2;
234 			}
235 		}
236 	}
237 
238 	int flags = Audio::FLAG_16BITS;
239 
240 	if (audStream->isStereo())
241 		flags |= Audio::FLAG_STEREO;
242 
243 #ifdef SCUMM_LITTLE_ENDIAN
244 	flags |= Audio::FLAG_LITTLE_ENDIAN;
245 #endif
246 
247 	audStream->queueBuffer((byte *)dst, AUDIO_DATA_SAMPLE_COUNT * 2, DisposeAfterUse::YES, flags);
248 	delete[] buf;
249 }
250 
createNewAudioStream(Common::File * fd,uint16 sectorStart,int8 startOffset,uint16 sectorEnd)251 Audio::QueuingAudioStream *SoundManager::PSXAudioTrack::createNewAudioStream(Common::File *fd, uint16 sectorStart, int8 startOffset, uint16 sectorEnd) {
252 	fd->seek(((sectorStart * 32) + startOffset) * RAW_CD_SECTOR_SIZE);
253 	fd->skip(19);
254 	byte format = fd->readByte();
255 	bool stereo = (format & (1 << 0)) != 0;
256 	uint rate = (format & (1 << 2)) ? 18900 : 37800;
257 
258 	Audio::QueuingAudioStream *audStream = Audio::makeQueuingAudioStream(rate, stereo);
259 	for (int i = 0x0; i < sectorEnd - sectorStart; i++) {
260 		fd->seek(((sectorStart * 32) + startOffset + i * 32) * RAW_CD_SECTOR_SIZE);
261 		queueAudioFromSector(audStream, fd);
262 	}
263 	audStream->finish();
264 	return audStream;
265 }
266 
SoundManager(DragonsEngine * vm,BigfileArchive * bigFileArchive,DragonRMS * dragonRMS)267 SoundManager::SoundManager(DragonsEngine *vm, BigfileArchive *bigFileArchive, DragonRMS *dragonRMS)
268 		: _vm(vm),
269 		  _sfxVolume(0),
270 		  _musicVolume(0),
271 		  _speechVolume(0),
272 		  _bigFileArchive(bigFileArchive),
273 		  _dragonRMS(dragonRMS) {
274 	_dat_8006bb60_sound_related = 0;
275 	_currentSong = -1;
276 
277 	bool allSoundIsMuted = false;
278 	if (ConfMan.hasKey("mute")) {
279 		allSoundIsMuted = ConfMan.getBool("mute");
280 	}
281 
282 	if (ConfMan.hasKey("speech_mute") && !allSoundIsMuted) {
283 		_vm->_mixer->muteSoundType(_vm->_mixer->kSpeechSoundType, ConfMan.getBool("speech_mute"));
284 	}
285 
286 	if (ConfMan.hasKey("sfx_mute") && !allSoundIsMuted) {
287 		_vm->_mixer->muteSoundType(_vm->_mixer->kSFXSoundType, ConfMan.getBool("sfx_mute"));
288 	}
289 
290 	if (ConfMan.hasKey("music_mute") && !allSoundIsMuted) {
291 		_vm->_mixer->muteSoundType(_vm->_mixer->kMusicSoundType, ConfMan.getBool("music_mute"));
292 	}
293 
294 	SomeInitSound_FUN_8003f64c();
295 	initVabData();
296 	_midiPlayer = new MidiMusicPlayer(_bigFileArchive);
297 
298 	syncSoundSettings();
299 }
300 
~SoundManager()301 SoundManager::~SoundManager() {
302 	if (isSpeechPlaying()) {
303 		_vm->_mixer->stopHandle(_speechHandle);
304 	}
305 
306 	stopAllVoices();
307 
308 	_midiPlayer->stop();
309 
310 	delete _midiPlayer;
311 	delete _vabMusx;
312 	delete _vabMsf;
313 	delete _vabGlob;
314 }
315 
SomeInitSound_FUN_8003f64c()316 void SoundManager::SomeInitSound_FUN_8003f64c() {
317 	// TODO: Check if this changes on different game versions?
318 	memset(_sfxVolumeTbl, 0x10, sizeof(_sfxVolumeTbl));
319 
320 	_sfxVolumeTbl[192] = 0x0b;
321 	_sfxVolumeTbl[193] = 0x0b;
322 	_sfxVolumeTbl[226] = _sfxVolumeTbl[226] | 0x80u;
323 	_sfxVolumeTbl[229] = 0x0b;
324 	_sfxVolumeTbl[230] = 0x0b;
325 	_sfxVolumeTbl[450] = 0x0b;
326 	_sfxVolumeTbl[451] = 0x0b;
327 	_sfxVolumeTbl[514] = 0x8b;
328 	_sfxVolumeTbl[515] = 0x0b;
329 	_sfxVolumeTbl[516] = 0x0b;
330 	_sfxVolumeTbl[578] = 0x0b;
331 	_sfxVolumeTbl[579] = 0x0b;
332 	_sfxVolumeTbl[580] = 0x0b;
333 	_sfxVolumeTbl[611] = 0x0b;
334 	_sfxVolumeTbl[674] = 0x8b;
335 	_sfxVolumeTbl[675] = 0x88;
336 	_sfxVolumeTbl[711] = 0x08;
337 	_sfxVolumeTbl[866] = 0x0b;
338 	_sfxVolumeTbl[896] = 0x0b;
339 	_sfxVolumeTbl[897] = _sfxVolumeTbl[897] | 0x80u;
340 	_sfxVolumeTbl[930] = _sfxVolumeTbl[930] | 0x80u;
341 	_sfxVolumeTbl[934] = 0x8b;
342 	_sfxVolumeTbl[935] = 0x8b;
343 	_sfxVolumeTbl[936] = 0x0b;
344 	_sfxVolumeTbl[937] = 0x88;
345 	_sfxVolumeTbl[941] = 0x0b;
346 	_sfxVolumeTbl[964] = 0x0b;
347 	_sfxVolumeTbl[995] = _sfxVolumeTbl[995] | 0x80u;
348 	_sfxVolumeTbl[1027] = 0x08;
349 	_sfxVolumeTbl[1056] = 0x8b;
350 	_sfxVolumeTbl[1059] = _sfxVolumeTbl[1059] | 0x80u;
351 	_sfxVolumeTbl[1122] = 0x0b;
352 	_sfxVolumeTbl[1250] = 0x08;
353 	_sfxVolumeTbl[1252] = 0x0b;
354 	_sfxVolumeTbl[1256] = 0x0b;
355 	_sfxVolumeTbl[1257] = 0x08;
356 	_sfxVolumeTbl[1258] = 0x0b;
357 	_sfxVolumeTbl[1284] = 0x0b;
358 	_sfxVolumeTbl[1378] = 0x0b;
359 	_sfxVolumeTbl[1379] = _sfxVolumeTbl[1379] | 0x80u;
360 	_sfxVolumeTbl[1380] = 0x0b;
361 	_sfxVolumeTbl[1385] = 0x0b;
362 	_sfxVolumeTbl[1443] = 0x8b;
363 	_sfxVolumeTbl[1444] = _sfxVolumeTbl[1444] | 0x80u;
364 	_sfxVolumeTbl[1445] = _sfxVolumeTbl[1445] | 0x80u;
365 	_sfxVolumeTbl[1446] = 0x8b;
366 	_sfxVolumeTbl[1472] = 0x8b;
367 	_sfxVolumeTbl[1508] = _sfxVolumeTbl[1508] | 0x80u;
368 	_sfxVolumeTbl[1575] = 0x08;
369 	_sfxVolumeTbl[1576] = 0x08;
370 	_sfxVolumeTbl[1577] = 0x08;
371 	_sfxVolumeTbl[1604] = 0x08;
372 	_sfxVolumeTbl[1605] = 0x08;
373 	_sfxVolumeTbl[1610] = 0x0b;
374 	_sfxVolumeTbl[1611] = 0x0b;
375 	_sfxVolumeTbl[1612] = 0x0b;
376 }
377 
initVabData()378 void SoundManager::initVabData() {
379 	_vabMusx = loadVab("musx.vh", "musx.vb");
380 	_vabMsf = loadVab("musx.vh", "musx.vb");
381 	_vabGlob = loadVab("glob.vh", "glob.vb");
382 }
383 
loadVab(const char * headerFilename,const char * bodyFilename)384 VabSound * SoundManager::loadVab(const char *headerFilename, const char *bodyFilename) {
385 	uint32 headSize, bodySize;
386 
387 	byte *headData = _bigFileArchive->load(headerFilename, headSize);
388 	byte *bodyData = _bigFileArchive->load(bodyFilename, bodySize);
389 
390 	Common::SeekableReadStream *headStream = new Common::MemoryReadStream(headData, headSize, DisposeAfterUse::YES);
391 	Common::SeekableReadStream *bodyStream = new Common::MemoryReadStream(bodyData, bodySize, DisposeAfterUse::YES);
392 
393 	return new VabSound(headStream, bodyStream);
394 }
395 
396 /**
397  *
398  * @param soundId Bit 0x4000 set indicates STOP SOUND, bit 0x8000 set indicates SOUND IS GLOBAL (comes from glob.v[hb])
399  */
playOrStopSound(uint16 soundId)400 void SoundManager::playOrStopSound(uint16 soundId) {
401 	uint16 volumeId;
402 	if ((soundId & 0x8000u) == 0) {
403 		volumeId = (soundId & ~0x4000u) + _vm->getCurrentSceneId() * 0x20;
404 	} else {
405 		volumeId = soundId & ~(0x4000u | 0x8000u);
406 	}
407 
408 	if ((soundId & 0x4000u) == 0) {
409 		playSound(soundId, volumeId);
410 	} else {
411 		stopSound(soundId, volumeId);
412 	}
413 }
414 
playSound(uint16 soundId,uint16 volumeId)415 void SoundManager::playSound(uint16 soundId, uint16 volumeId) {
416 	byte volume = 0;
417 
418 	volume = _sfxVolumeTbl[volumeId] & 0x1fu;
419 	_sfxVolumeTbl[volumeId] = _sfxVolumeTbl[volumeId] | 0x40u;      // Set bit 0x40
420 
421 	VabSound *vabSound = ((soundId & 0x8000u) != 0) ? _vabGlob : _vabMsf;
422 
423 	uint16 realId = soundId & 0x7fffu;
424 
425 	uint16 program = realId >> 4u;
426 	uint16 key = ((realId & 0xfu) << 1u | 0x40u);
427 
428 	if (isVoicePlaying(soundId)) {
429 		stopVoicePlaying(soundId);
430 	}
431 
432 	if (vabSound->hasSound(program, key)) {
433 		Audio::SoundHandle *handle = getVoiceHandle(soundId);
434 		if (handle) {
435 			uint8 adjustedVolume = (uint8)((float)_sfxVolume * ((float)volume / 31));
436 			debug(3, "Playing SFX: Master Volume %d  Adjusted Volume %d diff %f%%", _sfxVolume, adjustedVolume, 100 * ((float)volume / 31));
437 			Audio::AudioStream *audioStream = vabSound->getAudioStream(program, key);
438 			if (audioStream) {
439 				_vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, handle, audioStream, -1, adjustedVolume);
440 			}
441 		}
442 	} else {
443 		warning("Sound not found Program: %d, key %d", program, key);
444 	}
445 }
446 
stopSound(uint16 soundId,uint16 volumeId)447 void SoundManager::stopSound(uint16 soundId, uint16 volumeId) {
448 	_sfxVolumeTbl[volumeId] = _sfxVolumeTbl[volumeId] & 0xbfu;      // Clear bit 0x40
449 
450 //	uint16 vabId = getVabFromSoundId(soundId);
451 
452 	stopVoicePlaying(soundId & ~0x4000u);
453 }
454 
getVabFromSoundId(uint16 soundId)455 uint16 SoundManager::getVabFromSoundId(uint16 soundId) {
456 	// TODO
457 	return 0;
458 }
459 
loadMsf(uint32 sceneId)460 void SoundManager::loadMsf(uint32 sceneId) {
461 	char msfFileName[] = "XXXX.MSF";
462 	memcpy(msfFileName, _dragonRMS->getSceneName(sceneId), 4);
463 
464 	debug(3, "Loading SFX file %s", msfFileName);
465 
466 	if (_bigFileArchive->doesFileExist(msfFileName)) {
467 		uint32 msfSize;
468 		byte *msfData = _bigFileArchive->load(msfFileName, msfSize);
469 
470 		Common::SeekableReadStream *msfStream = new Common::MemoryReadStream(msfData, msfSize, DisposeAfterUse::YES);
471 
472 		stopAllVoices();
473 
474 		delete _vabMsf;
475 		_vabMsf = new VabSound(msfStream, _vm);
476 	}
477 }
478 
isVoicePlaying(uint16 soundID)479 bool SoundManager::isVoicePlaying(uint16 soundID) {
480 	for (int i = 0; i < NUM_VOICES; i++) {
481 		if (_voice[i].soundID == soundID && _vm->_mixer->isSoundHandleActive(_voice[i].handle)) {
482 			return true;
483 		}
484 	}
485 	return false;
486 }
487 
getVoiceHandle(uint16 soundID)488 Audio::SoundHandle *SoundManager::getVoiceHandle(uint16 soundID) {
489 	for (int i = 0; i < NUM_VOICES; i++) {
490 		if (!_vm->_mixer->isSoundHandleActive(_voice[i].handle)) {
491 			_voice[i].soundID = soundID & ~0x4000u;
492 			return &_voice[i].handle;
493 		}
494 	}
495 	return nullptr;
496 }
497 
stopVoicePlaying(uint16 soundID)498 void SoundManager::stopVoicePlaying(uint16 soundID) {
499 	for (int i = 0; i < NUM_VOICES; i++) {
500 		if (_voice[i].soundID == soundID) {
501 			_vm->_mixer->stopHandle(_voice[i].handle);
502 			return;
503 		}
504 	}
505 }
506 
stopAllVoices()507 void SoundManager::stopAllVoices() {
508 	for (int i = 0; i < NUM_VOICES; i++) {
509 		_vm->_mixer->stopHandle(_voice[i].handle);
510 	}
511 }
512 
playMusic(int16 song)513 void SoundManager::playMusic(int16 song) {
514 	char sceneName[5] = "nnnn";
515 	char filename[12] = "xxxxznn.msq";
516 
517 	if (_currentSong == song) {
518 		return;
519 	}
520 
521 	_currentSong = song;
522 
523 	memcpy(sceneName, _vm->_dragonRMS->getSceneName(_vm->getCurrentSceneId()), 4);
524 	snprintf(filename, 12, "%sz%02d.msq", sceneName, song);
525 	debug(1, "Load music file %s", filename);
526 
527 	if (!_bigFileArchive->doesFileExist(filename)) {
528 		warning("Could not find music file %s", filename);
529 		return;
530 	}
531 
532 	uint32 dataSize;
533 	byte *seqData = _bigFileArchive->load(filename, dataSize);
534 	Common::MemoryReadStream *seq = new Common::MemoryReadStream(seqData, dataSize, DisposeAfterUse::YES);
535 	_midiPlayer->playSong(seq);
536 	delete seq;
537 }
538 
syncSoundSettings()539 void SoundManager::syncSoundSettings() {
540 	_musicVolume = CLIP<int>(ConfMan.getInt("music_volume"), 0, 255);
541 	_sfxVolume = CLIP<int>(ConfMan.getInt("sfx_volume"), 0, 255);
542 	_speechVolume = CLIP<int>(ConfMan.getInt("speech_volume"), 0, 255);
543 
544 	_midiPlayer->setVolume(_musicVolume);
545 }
546 
547 } // End of namespace Dragons
548