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 /*
24  * This code is based on Labyrinth of Time code with assistance of
25  *
26  * Copyright (c) 1993 Terra Nova Development
27  * Copyright (c) 2004 The Wyrmkeep Entertainment Co.
28  *
29  */
30 
31 #include "common/file.h"
32 #include "audio/audiostream.h"
33 #include "audio/decoders/raw.h"
34 
35 #include "lab/lab.h"
36 
37 #include "lab/anim.h"
38 #include "lab/eventman.h"
39 #include "lab/music.h"
40 #include "lab/resource.h"
41 
42 namespace Lab {
43 
44 #define CLOWNROOM           123
45 #define DIMROOM              80
46 
Music(LabEngine * vm)47 Music::Music(LabEngine *vm) : _vm(vm) {
48 	_musicFile = nullptr;
49 	_storedPos = 0;
50 }
51 
getSoundFlags()52 byte Music::getSoundFlags() {
53 	byte soundFlags = Audio::FLAG_LITTLE_ENDIAN;
54 	if (_vm->getPlatform() == Common::kPlatformWindows)
55 		soundFlags |= Audio::FLAG_16BITS;
56 	else if (_vm->getPlatform() == Common::kPlatformDOS)
57 		soundFlags |= Audio::FLAG_UNSIGNED;
58 
59 	return soundFlags;
60 }
61 
loadSoundEffect(const Common::String filename,bool loop,bool waitTillFinished)62 void Music::loadSoundEffect(const Common::String filename, bool loop, bool waitTillFinished) {
63 	stopSoundEffect();
64 
65 	Common::File *file = _vm->_resource->openDataFile(filename, MKTAG('D', 'I', 'F', 'F'));
66 	if (!file)
67 		return;
68 
69 	_vm->_anim->_doBlack = false;
70 
71 	uint32 magicBytes = file->readUint32LE();
72 	if (magicBytes != 1219009121) {
73 		warning("readSound: Bad signature, skipping");
74 		return;
75 	}
76 	uint32 soundTag = file->readUint32LE();
77 	uint32 soundSize = file->readUint32LE();
78 
79 	if (soundTag != 0)
80 		return;
81 
82 	file->skip(soundSize);	// skip the header
83 
84 	while (soundTag != 65535) {
85 		_vm->updateEvents();
86 		soundTag = file->readUint32LE();
87 		soundSize = file->readUint32LE() - 8;
88 
89 		if ((soundTag == 30) || (soundTag == 31)) {
90 			if (waitTillFinished) {
91 				while (isSoundEffectActive()) {
92 					_vm->updateEvents();
93 					_vm->waitTOF();
94 				}
95 			}
96 
97 			file->skip(4);
98 
99 			uint16 sampleRate = file->readUint16LE();
100 			file->skip(2);
101 			playSoundEffect(sampleRate, soundSize, loop, file);
102 		} else if (soundTag == 65535) {
103 			if (waitTillFinished) {
104 				while (isSoundEffectActive()) {
105 					_vm->updateEvents();
106 					_vm->waitTOF();
107 				}
108 			}
109 		} else
110 			file->skip(soundSize);
111 	}
112 }
113 
playSoundEffect(uint16 sampleSpeed,uint32 length,bool loop,Common::File * dataFile)114 void Music::playSoundEffect(uint16 sampleSpeed, uint32 length, bool loop, Common::File *dataFile) {
115 	stopSoundEffect();
116 
117 	// NOTE: We need to use malloc(), cause this will be freed with free()
118 	// by the music code
119 	byte *soundData = (byte *)malloc(length);
120 	dataFile->read(soundData, length);
121 
122 	Audio::SeekableAudioStream *audioStream = Audio::makeRawStream((const byte *)soundData, length, MAX<uint16>(sampleSpeed, 4000), getSoundFlags());
123 	_vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, new Audio::LoopingAudioStream(audioStream, (loop) ? 0 : 1));
124 }
125 
stopSoundEffect()126 void Music::stopSoundEffect() {
127 	if (isSoundEffectActive())
128 		_vm->_mixer->stopHandle(_sfxHandle);
129 }
130 
isSoundEffectActive() const131 bool Music::isSoundEffectActive() const {
132 	return _vm->_mixer->isSoundHandleActive(_sfxHandle);
133 }
134 
changeMusic(const Common::String filename,bool storeCurPos,bool seektoStoredPos)135 void Music::changeMusic(const Common::String filename, bool storeCurPos, bool seektoStoredPos) {
136 	if (storeCurPos)
137 		_storedPos = _musicFile->pos();
138 
139 	stopSoundEffect();
140 	freeMusic();
141 	_musicFile = _vm->_resource->openDataFile(filename);
142 	if (seektoStoredPos)
143 		_musicFile->seek(_storedPos);
144 
145 	Audio::SeekableAudioStream *audioStream = Audio::makeRawStream(_musicFile, 15000, getSoundFlags());
146 	_vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, new Audio::LoopingAudioStream(audioStream, 0));
147 }
148 
resetMusic(bool seektoStoredPos)149 void Music::resetMusic(bool seektoStoredPos) {
150 	if (_vm->getPlatform() != Common::kPlatformAmiga)
151 		changeMusic("Music:BackGrou", false, seektoStoredPos);
152 	else
153 		changeMusic("Music:BackGround", false, seektoStoredPos);
154 }
155 
checkRoomMusic(uint16 prevRoom,uint16 newRoom)156 void Music::checkRoomMusic(uint16 prevRoom, uint16 newRoom) {
157 	if (newRoom == CLOWNROOM)
158 		changeMusic("Music:Laugh", true, false);
159 	else if (newRoom == DIMROOM)
160 		changeMusic("Music:Rm81", true, false);
161 	else if (prevRoom == CLOWNROOM || prevRoom == DIMROOM)
162 		resetMusic(true);
163 }
164 
freeMusic()165 void Music::freeMusic() {
166 	_vm->_mixer->stopHandle(_musicHandle);
167 	_vm->_mixer->stopHandle(_sfxHandle);
168 	_musicFile = nullptr;
169 }
170 
171 } // End of namespace Lab
172