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/stream.h"
24 #include "common/textconsole.h"
25 
26 #include "gob/sound/musplayer.h"
27 
28 namespace Gob {
29 
MUSPlayer()30 MUSPlayer::MUSPlayer() : AdLib(60),
31 	_songData(0), _songDataSize(0), _playPos(0), _songID(0) {
32 
33 }
34 
~MUSPlayer()35 MUSPlayer::~MUSPlayer() {
36 	unload();
37 }
38 
unload()39 void MUSPlayer::unload() {
40 	stopPlay();
41 
42 	unloadSND();
43 	unloadMUS();
44 }
45 
skipToTiming()46 void MUSPlayer::skipToTiming() {
47 	while (*_playPos < 0x80)
48 		_playPos++;
49 
50 	if (*_playPos != 0xF8)
51 		_playPos--;
52 }
53 
pollMusic(bool first)54 uint32 MUSPlayer::pollMusic(bool first) {
55 	if (_timbres.empty() || !_songData || !_playPos || (_playPos >= (_songData + _songDataSize))) {
56 		end();
57 		return 0;
58 	}
59 
60 	if (first) {
61 		// Set the timer frequency on first run.
62 		// Do not set it in rewind() for thread safety reasons.
63 		setTimerFrequency((_ticksPerBeat * _tempo) / 60);
64 		return *_playPos++;
65 	}
66 
67 	uint16 delay = 0;
68 	while (delay == 0) {
69 		byte cmd = *_playPos;
70 
71 		// Delay overflow
72 		if (cmd == 0xF8) {
73 			_playPos++;
74 			delay = 0xF8;
75 			break;
76 		}
77 
78 		// Song end marker
79 		if (cmd == 0xFC) {
80 			end();
81 			return 0;
82 		}
83 
84 		// Global command
85 		if (cmd == 0xF0) {
86 			_playPos++;
87 
88 			byte type1 = *_playPos++;
89 			byte type2 = *_playPos++;
90 
91 			if ((type1 == 0x7F) && (type2 == 0)) {
92 				// Tempo change, as a fraction of the base tempo
93 
94 				uint32 num   = *_playPos++;
95 				uint32 denom = *_playPos++;
96 
97 				_tempo = _baseTempo * num + ((_baseTempo * denom) >> 7);
98 				setTimerFrequency((_ticksPerBeat * _tempo) / 60);
99 
100 				_playPos++;
101 			} else {
102 
103 				// Unsupported global command, skip it
104 				_playPos -= 2;
105 				while(*_playPos++ != 0xF7)
106 					;
107 			}
108 
109 			delay = *_playPos++;
110 			break;
111 		}
112 
113 		// Voice command
114 
115 		if (cmd >= 0x80) {
116 			_playPos++;
117 
118 			_lastCommand = cmd;
119 		} else
120 			cmd = _lastCommand;
121 
122 		uint8 voice = cmd & 0x0F;
123 		uint8 note, volume;
124 		uint16 pitch;
125 
126 		switch (cmd & 0xF0) {
127 		case 0x80: // Note off
128 			_playPos += 2;
129 			noteOff(voice);
130 			break;
131 
132 		case 0x90: // Note on
133 			note   = *_playPos++;
134 			volume = *_playPos++;
135 
136 			if (volume) {
137 				setVoiceVolume(voice, volume);
138 				noteOn(voice, note);
139 			} else
140 				noteOff(voice);
141 			break;
142 
143 		case 0xA0: // Set volume
144 			setVoiceVolume(voice, *_playPos++);
145 			break;
146 
147 		case 0xB0:
148 			_playPos += 2;
149 			break;
150 
151 		case 0xC0: // Set instrument
152 			setInstrument(voice, *_playPos++);
153 			break;
154 
155 		case 0xD0:
156 			_playPos++;
157 			break;
158 
159 		case 0xE0: // Pitch bend
160 			pitch  = *_playPos++;
161 			pitch += *_playPos++ << 7;
162 			bendVoicePitch(voice, pitch);
163 			break;
164 
165 		default:
166 			warning("MUSPlayer: Unsupported command: 0x%02X", cmd);
167 			skipToTiming();
168 			break;
169 		}
170 
171 		delay = *_playPos++;
172 	}
173 
174 	if (delay == 0xF8) {
175 		delay = 240;
176 
177 		if (*_playPos != 0xF8)
178 			delay += *_playPos++;
179 	}
180 
181 	return delay;
182 }
183 
rewind()184 void MUSPlayer::rewind() {
185 	_playPos = _songData;
186 	_tempo   = _baseTempo;
187 
188 	_lastCommand = 0;
189 
190 	setPercussionMode(_soundMode != 0);
191 	setPitchRange(_pitchBendRange);
192 }
193 
loadSND(Common::SeekableReadStream & snd)194 bool MUSPlayer::loadSND(Common::SeekableReadStream &snd) {
195 	unloadSND();
196 
197 	int timbreCount, timbrePos;
198 	if (!readSNDHeader(snd, timbreCount, timbrePos))
199 		return false;
200 
201 	if (!readSNDTimbres(snd, timbreCount, timbrePos) || snd.err()) {
202 		unloadSND();
203 		return false;
204 	}
205 
206 	return true;
207 }
208 
readString(Common::SeekableReadStream & stream,Common::String & string,byte * buffer,uint size)209 bool MUSPlayer::readString(Common::SeekableReadStream &stream, Common::String &string, byte *buffer, uint size) {
210 	if (stream.read(buffer, size) != size)
211 		return false;
212 
213 	buffer[size] = '\0';
214 
215 	string = (char *) buffer;
216 
217 	return true;
218 }
219 
readSNDHeader(Common::SeekableReadStream & snd,int & timbreCount,int & timbrePos)220 bool MUSPlayer::readSNDHeader(Common::SeekableReadStream &snd, int &timbreCount, int &timbrePos) {
221 	// Sanity check
222 	if (snd.size() <= 6) {
223 		warning("MUSPlayer::readSNDHeader(): File too small (%d)", (int)snd.size());
224 		return false;
225 	}
226 
227 	// Version
228 	const uint8 versionMajor = snd.readByte();
229 	const uint8 versionMinor = snd.readByte();
230 
231 	if ((versionMajor != 1) && (versionMinor != 0)) {
232 		warning("MUSPlayer::readSNDHeader(): Unsupported version %d.%d", versionMajor, versionMinor);
233 		return false;
234 	}
235 
236 	// Number of timbres and where they start
237 	timbreCount = snd.readUint16LE();
238 	timbrePos   = snd.readUint16LE();
239 
240 	const uint16 minTimbrePos = 6 + timbreCount * 9;
241 
242 	// Sanity check
243 	if (timbrePos < minTimbrePos) {
244 		warning("MUSPlayer::readSNDHeader(): Timbre offset too small: %d < %d", timbrePos, minTimbrePos);
245 		return false;
246 	}
247 
248 	const uint32 timbreParametersSize = snd.size() - timbrePos;
249 	const uint32 paramSize            = kOperatorsPerVoice * kParamCount * sizeof(uint16);
250 
251 	// Sanity check
252 	if (timbreParametersSize != (timbreCount * paramSize)) {
253 		warning("MUSPlayer::loadSND(): Timbre parameters size mismatch: %d != %d",
254 		        timbreParametersSize, timbreCount * paramSize);
255 		return false;
256 	}
257 
258 	return true;
259 }
260 
readSNDTimbres(Common::SeekableReadStream & snd,int timbreCount,int timbrePos)261 bool MUSPlayer::readSNDTimbres(Common::SeekableReadStream &snd, int timbreCount, int timbrePos) {
262 	_timbres.resize(timbreCount);
263 
264 	// Read names
265 	byte nameBuffer[10];
266 	for (Common::Array<Timbre>::iterator t = _timbres.begin(); t != _timbres.end(); ++t) {
267 		if (!readString(snd, t->name, nameBuffer, 9)) {
268 			warning("MUSPlayer::readMUSTimbres(): Failed to read timbre name");
269 			return false;
270 		}
271 	}
272 
273 	if (!snd.seek(timbrePos)) {
274 		warning("MUSPlayer::readMUSTimbres(): Failed to seek to timbres");
275 		return false;
276 	}
277 
278 	// Read parameters
279 	for (Common::Array<Timbre>::iterator t = _timbres.begin(); t != _timbres.end(); ++t) {
280 		for (int i = 0; i < (kOperatorsPerVoice * kParamCount); i++)
281 			t->params[i] = snd.readUint16LE();
282 	}
283 
284 	return true;
285 }
286 
loadMUS(Common::SeekableReadStream & mus)287 bool MUSPlayer::loadMUS(Common::SeekableReadStream &mus) {
288 	unloadMUS();
289 
290 	if (!readMUSHeader(mus) || !readMUSSong(mus) || mus.err()) {
291 		unloadMUS();
292 		return false;
293 	}
294 
295 	rewind();
296 
297 	return true;
298 }
299 
readMUSHeader(Common::SeekableReadStream & mus)300 bool MUSPlayer::readMUSHeader(Common::SeekableReadStream &mus) {
301 	// Sanity check
302 	if (mus.size() <= 6)
303 		return false;
304 
305 	// Version
306 	const uint8 versionMajor = mus.readByte();
307 	const uint8 versionMinor = mus.readByte();
308 
309 	if ((versionMajor != 1) && (versionMinor != 0)) {
310 		warning("MUSPlayer::readMUSHeader(): Unsupported version %d.%d", versionMajor, versionMinor);
311 		return false;
312 	}
313 
314 	_songID = mus.readUint32LE();
315 
316 	byte nameBuffer[31];
317 	if (!readString(mus, _songName, nameBuffer, 30)) {
318 		warning("MUSPlayer::readMUSHeader(): Failed to read the song name");
319 		return false;
320 	}
321 
322 	_ticksPerBeat    = mus.readByte();
323 	_beatsPerMeasure = mus.readByte();
324 
325 	mus.skip(4); // Length of song in ticks
326 
327 	_songDataSize = mus.readUint32LE();
328 
329 	mus.skip(4); // Number of commands
330 	mus.skip(8); // Unused
331 
332 	_soundMode      = mus.readByte();
333 	_pitchBendRange = mus.readByte();
334 	_baseTempo      = mus.readUint16LE();
335 
336 	mus.skip(8); // Unused
337 
338 	return true;
339 }
340 
readMUSSong(Common::SeekableReadStream & mus)341 bool MUSPlayer::readMUSSong(Common::SeekableReadStream &mus) {
342 	const uint32 realSongDataSize = mus.size() - mus.pos();
343 
344 	if (realSongDataSize < _songDataSize) {
345 		warning("MUSPlayer::readMUSSong(): File too small for the song data: %d < %d", realSongDataSize, _songDataSize);
346 		return false;
347 	}
348 
349 	_songData = new byte[_songDataSize];
350 
351 	if (mus.read(_songData, _songDataSize) != _songDataSize) {
352 		warning("MUSPlayer::readMUSSong(): Read failed");
353 		return false;
354 	}
355 
356 	return true;
357 }
358 
unloadSND()359 void MUSPlayer::unloadSND() {
360 	_timbres.clear();
361 }
362 
unloadMUS()363 void MUSPlayer::unloadMUS() {
364 	delete[] _songData;
365 
366 	_songData     = 0;
367 	_songDataSize = 0;
368 
369 	_playPos = 0;
370 }
371 
getSongID() const372 uint32 MUSPlayer::getSongID() const {
373 	return _songID;
374 }
375 
getSongName() const376 const Common::String &MUSPlayer::getSongName() const {
377 	return _songName;
378 }
379 
setInstrument(uint8 voice,uint8 instrument)380 void MUSPlayer::setInstrument(uint8 voice, uint8 instrument) {
381 	if (instrument >= _timbres.size())
382 		return;
383 
384 	setVoiceTimbre(voice, _timbres[instrument].params);
385 }
386 
387 } // End of namespace Gob
388