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 "audio/mididrv.h"
24 #include "audio/mixer.h"
25 
26 #include "groovie/music.h"
27 #include "groovie/groovie.h"
28 #include "groovie/resource.h"
29 
30 #include "backends/audiocd/audiocd.h"
31 #include "common/config-manager.h"
32 #include "common/debug.h"
33 #include "common/file.h"
34 #include "common/macresman.h"
35 #include "common/memstream.h"
36 #include "common/textconsole.h"
37 #include "audio/audiostream.h"
38 #include "audio/midiparser.h"
39 #include "audio/miles.h"
40 
41 namespace Groovie {
42 
43 // MusicPlayer
44 
MusicPlayer(GroovieEngine * vm)45 MusicPlayer::MusicPlayer(GroovieEngine *vm) :
46 	_vm(vm), _isPlaying(false), _backgroundFileRef(0), _gameVolume(100),
47 	_prevCDtrack(0), _backgroundDelay(0), _fadingStartTime(0), _fadingStartVolume(0),
48 	_fadingEndVolume(0), _fadingDuration(0), _userVolume(0) {
49 }
50 
~MusicPlayer()51 MusicPlayer::~MusicPlayer() {
52 	g_system->getAudioCDManager()->stop();
53 }
54 
playSong(uint32 fileref)55 void MusicPlayer::playSong(uint32 fileref) {
56 	Common::StackLock lock(_mutex);
57 
58 	// Set the volumes
59 	_fadingEndVolume = 100;
60 	_gameVolume = 100;
61 
62 	// Play the referenced file once
63 	play(fileref, false);
64 }
65 
setBackgroundSong(uint32 fileref)66 void MusicPlayer::setBackgroundSong(uint32 fileref) {
67 	Common::StackLock lock(_mutex);
68 
69 	debugC(1, kDebugMIDI, "Groovie::Music: Changing the background song: %04X", fileref);
70 	_backgroundFileRef = fileref;
71 }
72 
frameTick()73 void MusicPlayer::frameTick() {
74 	if (_backgroundDelay > 0) {
75 		_backgroundDelay--;
76 		if (_backgroundDelay == 0)
77 			playSong(_backgroundFileRef);
78 	}
79 }
80 
setBackgroundDelay(uint16 delay)81 void MusicPlayer::setBackgroundDelay(uint16 delay) {
82 	_backgroundDelay = delay;
83 }
84 
playCD(uint8 track)85 void MusicPlayer::playCD(uint8 track) {
86 	int startms = 0;
87 
88 	// Stop the MIDI playback
89 	unload();
90 
91 	debugC(1, kDebugMIDI, "Groovie::Music: Playing CD track %d", track);
92 
93 	if (track == 3) {
94 		// This is the credits song, start at 23:20
95 		startms = 1400000;
96 		// TODO: If we want to play it directly from the CD, we should decrement
97 		// the song number (it's track 2 on the 2nd CD)
98 	} else if ((track == 98) && (_prevCDtrack == 3)) {
99 		// Track 98 is used as a hack to stop the credits song
100 		g_system->getAudioCDManager()->stop();
101 		stopCreditsIOS();
102 		return;
103 	}
104 
105 	// Save the playing track in order to be able to stop the credits song
106 	_prevCDtrack = track;
107 
108 	// Wait until the CD stops playing the current song
109 	// It was in the original interpreter, but it introduces a big delay
110 	// in the middle of the introduction, so it's disabled right now
111 	/*
112 	g_system->getAudioCDManager()->updateCD();
113 	while (g_system->getAudioCDManager()->isPlaying()) {
114 		// Wait a bit and try again
115 		_vm->_system->delayMillis(100);
116 		g_system->getAudioCDManager()->updateCD();
117 	}
118 	*/
119 
120 	// Play the track starting at the requested offset (1000ms = 75 frames)
121 	g_system->getAudioCDManager()->play(track - 1, 1, startms * 75 / 1000, 0);
122 
123 	// If the audio is not playing from the CD, play the "fallback" MIDI.
124 	// The Mac version has no CD tracks, so it will always use the MIDI.
125 	if (!g_system->getAudioCDManager()->isPlaying()) {
126 		if (track == 2) {
127 			// Intro MIDI fallback
128 			if (_vm->getPlatform() == Common::kPlatformMacintosh)
129 				playSong(70);
130 			else
131 				playSong((19 << 10) | 36); // XMI.GJD, file 36
132 		} else if (track == 3) {
133 			// TODO: Credits MIDI fallback
134 			if (_vm->getPlatform() == Common::kPlatformIOS)
135 				playCreditsIOS();
136 		}
137 	}
138 }
139 
startBackground()140 void MusicPlayer::startBackground() {
141 	debugC(3, kDebugMIDI, "Groovie::Music: startBackground()");
142 	if (!_isPlaying && _backgroundFileRef) {
143 		debugC(3, kDebugMIDI, "Groovie::Music: Starting the background song (0x%4X)", _backgroundFileRef);
144 		play(_backgroundFileRef, true);
145 	}
146 }
147 
setUserVolume(uint16 volume)148 void MusicPlayer::setUserVolume(uint16 volume) {
149 	Common::StackLock lock(_mutex);
150 
151 	// Save the new user volume
152 	_userVolume = volume;
153 	if (_userVolume > 0x100)
154 		_userVolume = 0x100;
155 
156 	// Apply it
157 	updateVolume();
158 }
159 
setGameVolume(uint16 volume,uint16 time)160 void MusicPlayer::setGameVolume(uint16 volume, uint16 time) {
161 	Common::StackLock lock(_mutex);
162 
163 	debugC(1, kDebugMIDI, "Groovie::Music: Setting game volume from %d to %d in %dms", _gameVolume, volume, time);
164 
165 	// Save the start parameters of the fade
166 	_fadingStartTime = _vm->_system->getMillis();
167 	_fadingStartVolume = _gameVolume;
168 	_fadingDuration = time;
169 
170 	// Save the new game volume
171 	_fadingEndVolume = volume;
172 	if (_fadingEndVolume > 100)
173 		_fadingEndVolume = 100;
174 }
175 
play(uint32 fileref,bool loop)176 bool MusicPlayer::play(uint32 fileref, bool loop) {
177 	// Unload the previous song
178 	unload();
179 
180 	// Set the new state
181 	_isPlaying = true;
182 
183 	// Load the new file
184 	return load(fileref, loop);
185 }
186 
applyFading()187 void MusicPlayer::applyFading() {
188 	debugC(6, kDebugMIDI, "Groovie::Music: applyFading() _fadingStartTime = %d, _fadingDuration = %d, _fadingStartVolume = %d, _fadingEndVolume = %d", _fadingStartTime, _fadingDuration, _fadingStartVolume, _fadingEndVolume);
189 	Common::StackLock lock(_mutex);
190 
191 	// Calculate the passed time
192 	uint32 time = _vm->_system->getMillis() - _fadingStartTime;
193 	debugC(6, kDebugMIDI, "Groovie::Music: time = %d, _gameVolume = %d", time, _gameVolume);
194 	if (time >= _fadingDuration) {
195 		// Set the end volume
196 		_gameVolume = _fadingEndVolume;
197 	} else {
198 		// Calculate the interpolated volume for the current time
199 		_gameVolume = (_fadingStartVolume * (_fadingDuration - time) +
200 			_fadingEndVolume * time) / _fadingDuration;
201 	}
202 	if (_gameVolume == _fadingEndVolume) {
203 		// If we were fading to 0, stop the playback and restore the volume
204 		if (_fadingEndVolume == 0) {
205 			debugC(1, kDebugMIDI, "Groovie::Music: Faded to zero: end of song. _fadingEndVolume set to 100");
206 			unload();
207 		}
208 	}
209 
210 	// Apply it
211 	updateVolume();
212 }
213 
onTimer(void * refCon)214 void MusicPlayer::onTimer(void *refCon) {
215 	debugC(9, kDebugMIDI, "Groovie::Music: onTimer()");
216 	MusicPlayer *music = (MusicPlayer *)refCon;
217 	Common::StackLock lock(music->_mutex);
218 
219 	// Apply the game volume fading
220 	if (music->_gameVolume != music->_fadingEndVolume) {
221 		// Apply the next step of the fading
222 		music->applyFading();
223 	}
224 
225 	// Handle internal timed events
226 	music->onTimerInternal();
227 }
228 
unload()229 void MusicPlayer::unload() {
230 	debugC(1, kDebugMIDI, "Groovie::Music: Stopping the playback");
231 
232 	// Set the new state
233 	_isPlaying = false;
234 }
235 
playCreditsIOS()236 void MusicPlayer::playCreditsIOS() {
237 	Audio::AudioStream *stream = Audio::SeekableAudioStream::openStreamFile("7th_Guest_Dolls_from_Hell_OC_ReMix");
238 
239 	if (!stream) {
240 		warning("Could not find '7th_Guest_Dolls_from_Hell_OC_ReMix' audio file");
241 		return;
242 	}
243 
244 	_vm->_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, &_handleCreditsIOS, stream);
245 }
246 
stopCreditsIOS()247 void MusicPlayer::stopCreditsIOS() {
248 	_vm->_system->getMixer()->stopHandle(_handleCreditsIOS);
249 }
250 
251 // MusicPlayerMidi
252 
MusicPlayerMidi(GroovieEngine * vm)253 MusicPlayerMidi::MusicPlayerMidi(GroovieEngine *vm) :
254 	MusicPlayer(vm), _midiParser(NULL), _data(NULL), _driver(NULL) {
255 	// Initialize the channel volumes
256 	for (int i = 0; i < 0x10; i++) {
257 		_chanVolumes[i] = 0x7F;
258 	}
259 }
260 
~MusicPlayerMidi()261 MusicPlayerMidi::~MusicPlayerMidi() {
262 	// Stop the callback
263 	if (_driver)
264 		_driver->setTimerCallback(NULL, NULL);
265 
266 	Common::StackLock lock(_mutex);
267 
268 	// Unload the parser
269 	unload();
270 	delete _midiParser;
271 
272 	// Unload the MIDI Driver
273 	if (_driver) {
274 		_driver->close();
275 		delete _driver;
276 	}
277 }
278 
send(uint32 b)279 void MusicPlayerMidi::send(uint32 b) {
280 	if ((b & 0xFFF0) == 0x07B0) { // Volume change
281 		// Save the specific channel volume
282 		byte chan = b & 0xF;
283 		_chanVolumes[chan] = (b >> 16) & 0x7F;
284 
285 		// Send the updated value
286 		updateChanVolume(chan);
287 
288 		return;
289 	}
290 	if (_driver)
291 		_driver->send(b);
292 }
293 
metaEvent(byte type,byte * data,uint16 length)294 void MusicPlayerMidi::metaEvent(byte type, byte *data, uint16 length) {
295 	switch (type) {
296 	case 0x2F:
297 		// End of Track, play the background song
298 		endTrack();
299 		break;
300 	default:
301 		if (_driver)
302 			_driver->metaEvent(type, data, length);
303 		break;
304 	}
305 }
306 
updateChanVolume(byte channel)307 void MusicPlayerMidi::updateChanVolume(byte channel) {
308 	// Generate a MIDI Control change message for the volume
309 	uint32 b = 0x7B0;
310 
311 	// Specify the channel
312 	b |= (channel & 0xF);
313 
314 	// Scale by the user and game volumes
315 	uint32 val = (_chanVolumes[channel] * _userVolume * _gameVolume) / 0x100 / 100;
316 	val &= 0x7F;
317 
318 	// Send it to the driver
319 	if (_driver)
320 		_driver->send(b | (val << 16));
321 }
322 
endTrack()323 void MusicPlayerMidi::endTrack() {
324 	debugC(3, kDebugMIDI, "Groovie::Music: endTrack()");
325 	unload();
326 }
327 
onTimerInternal()328 void MusicPlayerMidi::onTimerInternal() {
329 	// TODO: We really only need to call this while music is playing.
330 	if (_midiParser)
331 		_midiParser->onTimer();
332 }
333 
updateVolume()334 void MusicPlayerMidi::updateVolume() {
335 	// Apply it to all the channels
336 	for (int i = 0; i < 0x10; i++) {
337 		updateChanVolume(i);
338 	}
339 }
340 
unload()341 void MusicPlayerMidi::unload() {
342 	MusicPlayer::unload();
343 
344 	// Unload the parser data
345 	if (_midiParser)
346 		_midiParser->unloadMusic();
347 
348 	// Unload the data
349 	delete[] _data;
350 	_data = NULL;
351 }
352 
loadParser(Common::SeekableReadStream * stream,bool loop)353 bool MusicPlayerMidi::loadParser(Common::SeekableReadStream *stream, bool loop) {
354 	if (!_midiParser)
355 		return false;
356 
357 	// Read the whole file to memory
358 	int length = stream->size();
359 	_data = new byte[length];
360 	stream->read(_data, length);
361 	delete stream;
362 
363 	// Set the looping option
364 	_midiParser->property(MidiParser::mpAutoLoop, loop);
365 
366 	// Start parsing the data
367 	if (!_midiParser->loadMusic(_data, length)) {
368 		error("Groovie::Music: Couldn't parse the data");
369 		return false;
370 	}
371 
372 	// Activate the timer source
373 	if (_driver)
374 		_driver->setTimerCallback(this, &onTimer);
375 
376 	return true;
377 }
378 
379 
380 // MusicPlayerXMI
381 
MusicPlayerXMI(GroovieEngine * vm,const Common::String & gtlName)382 MusicPlayerXMI::MusicPlayerXMI(GroovieEngine *vm, const Common::String &gtlName) :
383 	MusicPlayerMidi(vm) {
384 
385 	// Create the driver
386 	MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
387 	MusicType musicType = MidiDriver::getMusicType(dev);
388 	_driver = NULL;
389 
390 	// new Miles Audio support, to disable set milesAudioEnabled to false
391 	_milesAudioMode = false;
392 	bool milesAudioEnabled = true;
393 	MidiParser::XMidiNewTimbreListProc newTimbreListProc = NULL;
394 
395 	_musicType = 0;
396 
397 	if (milesAudioEnabled) {
398 		// 7th Guest uses FAT.AD/FAT.OPL/FAT.MT
399 		// 11th Hour uses SAMPLE.AD/SAMPLE.OPL/SAMPLE.MT
400 		switch (musicType) {
401 		case MT_ADLIB:
402 			_driver = Audio::MidiDriver_Miles_AdLib_create(gtlName + ".AD", gtlName + ".OPL");
403 			break;
404 		case MT_MT32:
405 			_driver = Audio::MidiDriver_Miles_MT32_create(gtlName + ".MT");
406 			break;
407 		case MT_GM:
408 			if (ConfMan.getBool("native_mt32")) {
409 				_driver = Audio::MidiDriver_Miles_MT32_create(gtlName + ".MT");
410 				musicType = MT_MT32;
411 			}
412 			break;
413 		default:
414 			break;
415 		}
416 
417 		if (musicType == MT_MT32) {
418 			newTimbreListProc = Audio::MidiDriver_Miles_MT32_processXMIDITimbreChunk;
419 		}
420 	}
421 
422 	if (_driver) {
423 		_milesAudioMode = true;
424 	}
425 
426 	if (!_driver) {
427 		// No driver yet? create a generic one
428 		_driver = MidiDriver::createMidi(dev);
429 	}
430 
431 	assert(_driver);
432 
433 	// Create the parser
434 	_midiParser = MidiParser::createParser_XMIDI(NULL, NULL, newTimbreListProc, _driver);
435 
436 	_driver->open();	// TODO: Handle return value != 0 (indicating an error)
437 
438 	// Set the parser's driver
439 	_midiParser->setMidiDriver(this);
440 
441 	// Set the timer rate
442 	_midiParser->setTimerRate(_driver->getBaseTempo());
443 
444 	// Initialize the channel banks
445 	for (int i = 0; i < 0x10; i++) {
446 		_chanBanks[i] = 0;
447 	}
448 
449 	if (_milesAudioMode)
450 		return;
451 
452 	// Load the Global Timbre Library
453 	if (MidiDriver::getMusicType(dev) == MT_ADLIB) {
454 		// MIDI through AdLib
455 		_musicType = MT_ADLIB;
456 		loadTimbres(gtlName + ".ad");
457 
458 		// Setup the percussion channel
459 		for (uint i = 0; i < _timbres.size(); i++) {
460 			if (_timbres[i].bank == 0x7F)
461 				setTimbreAD(9, _timbres[i]);
462 		}
463 	} else if ((MidiDriver::getMusicType(dev) == MT_MT32) || ConfMan.getBool("native_mt32")) {
464 		_driver->sendMT32Reset();
465 
466 		// MT-32
467 		_musicType = MT_MT32;
468 		loadTimbres(gtlName + ".mt");
469 	} else {
470 		_driver->sendGMReset();
471 
472 		// GM
473 		_musicType = 0;
474 	}
475 }
476 
~MusicPlayerXMI()477 MusicPlayerXMI::~MusicPlayerXMI() {
478 	//~MusicPlayer();
479 
480 	// Unload the timbres
481 	clearTimbres();
482 }
483 
send(uint32 b)484 void MusicPlayerXMI::send(uint32 b) {
485 	if (_milesAudioMode) {
486 		MusicPlayerMidi::send(b);
487 		return;
488 	}
489 
490 	if ((b & 0xFFF0) == 0x72B0) { // XMIDI Patch Bank Select 114
491 		// From AIL2's documentation: XMIDI Patch Bank Select controller (114)
492 		// selects a bank to be used when searching the next patches
493 		byte chan = b & 0xF;
494 		byte bank = (b >> 16) & 0xFF;
495 
496 		debugC(5, kDebugMIDI, "Groovie::Music: Selecting bank %X for channel %X", bank, chan);
497 		_chanBanks[chan] = bank;
498 		return;
499 	} else if ((b & 0xF0) == 0xC0) { // Program change
500 		// We intercept the program change when using AdLib or MT32 drivers,
501 		// since we have custom timbres for them.  The command is sent
502 		// unchanged to GM drivers.
503 		if (_musicType != 0) {
504 			byte chan = b & 0xF;
505 			byte patch = (b >> 8) & 0xFF;
506 
507 			debugC(5, kDebugMIDI, "Groovie::Music: Setting custom patch %X from bank %X to channel %X", patch, _chanBanks[chan], chan);
508 
509 			// Try to find the requested patch from the previously
510 			// specified bank
511 			int numTimbres = _timbres.size();
512 			for (int i = 0; i < numTimbres; i++) {
513 				if ((_timbres[i].bank == _chanBanks[chan]) &&
514 					(_timbres[i].patch == patch)) {
515 					if (_musicType == MT_ADLIB) {
516 						setTimbreAD(chan, _timbres[i]);
517 					} else if (_musicType == MT_MT32) {
518 						setTimbreMT(chan, _timbres[i]);
519 					}
520 					return;
521 				}
522 			}
523 
524 			// If we got here we couldn't find the patch, and the
525 			// received message will be sent unchanged.
526 		}
527 	}
528 	MusicPlayerMidi::send(b);
529 }
530 
load(uint32 fileref,bool loop)531 bool MusicPlayerXMI::load(uint32 fileref, bool loop) {
532 	debugC(1, kDebugMIDI, "Groovie::Music: Starting the playback of song: %04X", fileref);
533 
534 	// Open the song resource
535 	Common::SeekableReadStream *file = _vm->_resMan->open(fileref);
536 	if (!file) {
537 		error("Groovie::Music: Couldn't find resource 0x%04X", fileref);
538 		return false;
539 	}
540 
541 	return loadParser(file, loop);
542 }
543 
loadTimbres(const Common::String & filename)544 void MusicPlayerXMI::loadTimbres(const Common::String &filename) {
545 	// Load the Global Timbre Library format as documented in AIL2
546 	debugC(1, kDebugMIDI, "Groovie::Music: Loading the GTL file %s", filename.c_str());
547 
548 	// Does it exist?
549 	if (!Common::File::exists(filename)) {
550 		error("Groovie::Music: %s not found", filename.c_str());
551 		return;
552 	}
553 
554 	// Open the GTL
555 	Common::File *gtl = new Common::File();
556 	if (!gtl->open(filename.c_str())) {
557 		delete gtl;
558 		error("Groovie::Music: Couldn't open %s", filename.c_str());
559 		return;
560 	}
561 
562 	// Clear the old timbres before loading the new ones
563 	clearTimbres();
564 
565 	// Get the list of timbres
566 	while (true) {
567 		Timbre t;
568 		t.patch = gtl->readByte();
569 		t.bank = gtl->readByte();
570 		if ((t.patch == 0xFF) && (t.bank == 0xFF)) {
571 			// End of list
572 			break;
573 		}
574 		// We temporarily use the size field to store the offset
575 		t.size = gtl->readUint32LE();
576 
577 		// Add it to the list
578 		_timbres.push_back(t);
579 	}
580 
581 	// Read the timbres
582 	for (unsigned int i = 0; i < _timbres.size(); i++) {
583 		// Seek to the start of the timbre
584 		gtl->seek(_timbres[i].size);
585 
586 		// Read the size
587 		_timbres[i].size = gtl->readUint16LE() - 2;
588 
589 		// Allocate memory for the timbre data
590 		_timbres[i].data = new byte[_timbres[i].size];
591 
592 		// Read the timbre data
593 		gtl->read(_timbres[i].data, _timbres[i].size);
594 		debugC(5, kDebugMIDI, "Groovie::Music: Loaded patch %x in bank %x with size %d",
595 			_timbres[i].patch, _timbres[i].bank, _timbres[i].size);
596 	}
597 
598 	// Close the file
599 	delete gtl;
600 }
601 
clearTimbres()602 void MusicPlayerXMI::clearTimbres() {
603 	// Delete the allocated data
604 	int num = _timbres.size();
605 	for (int i = 0; i < num; i++) {
606 		delete[] _timbres[i].data;
607 	}
608 
609 	// Erase the array entries
610 	_timbres.clear();
611 }
612 
setTimbreAD(byte channel,const Timbre & timbre)613 void MusicPlayerXMI::setTimbreAD(byte channel, const Timbre &timbre) {
614 	// Verify the timbre size
615 	if (timbre.size != 12) {
616 		error("Groovie::Music: Invalid size for an AdLib timbre: %d", timbre.size);
617 	}
618 
619 	// Prepare the AdLib Instrument array from the GTL entry
620 	//
621 	// struct AdLibInstrument used by our AdLib MIDI synth is 30 bytes.
622 	// Since we pass data + 2 for non percussion instruments we need to
623 	// have a buffer of size 32, so there are no invalid memory reads,
624 	// when setting up an AdLib instrument.
625 	byte data[32];
626 	memset(data, 0, sizeof(data));
627 
628 	data[2] = timbre.data[1];        // mod_characteristic
629 	data[3] = timbre.data[2] ^ 0x3F; // mod_scalingOutputLevel
630 	data[4] = ~timbre.data[3];       // mod_attackDecay
631 	data[5] = ~timbre.data[4];       // mod_sustainRelease
632 	data[6] = timbre.data[5];        // mod_waveformSelect
633 	data[7] = timbre.data[7];        // car_characteristic
634 	data[8] = timbre.data[8] ^ 0x3F; // car_scalingOutputLevel
635 	data[9] = ~timbre.data[9];       // car_attackDecay
636 	data[10] = ~timbre.data[10];     // car_sustainRelease
637 	data[11] = timbre.data[11];      // car_waveformSelect
638 	data[12] = timbre.data[6];       // feedback
639 
640 	// Send the instrument to the driver
641 	if (timbre.bank == 0x7F) {
642 		// This is a Percussion instrument, this will always be set on the same note
643 		data[0] = timbre.patch;
644 
645 		// From AIL2's documentation: If the instrument is to be played in MIDI
646 		// channel 10, num specifies its desired absolute MIDI note number.
647 		data[1] = timbre.data[0];
648 
649 		_driver->getPercussionChannel()->sysEx_customInstrument('ADLP', data);
650 	} else {
651 		// Some tweaks for non-percussion instruments
652 		byte mult1 = timbre.data[1] & 0xF;
653 		if (mult1 < 4)
654 			mult1 = 1 << mult1;
655 		data[2] = (timbre.data[1] & 0xF0) + (mult1 & 0xF);
656 		byte mult2 = timbre.data[7] & 0xF;
657 		if (mult2 < 4)
658 			mult2 = 1 << mult2;
659 		data[7] = (timbre.data[7] & 0xF0) + (mult2 & 0xF);
660 		// TODO: Fix CHARACTERISTIC: 0xF0: pitch_vib, amp_vib, sustain_sound, env_scaling  0xF: freq_mult
661 		// TODO: Fix KSL_TL: 0xC: key_scale_lvl  0x3F: out_lvl
662 
663 		// From AIL2's documentation: num specifies the number of semitones
664 		// by which to transpose notes played with the instrument.
665 		if (timbre.data[0] != 0)
666 			warning("Groovie::Music: AdLib instrument's transposing not supported");
667 
668 		_driver->sysEx_customInstrument(channel, 'ADL ', data + 2);
669 	}
670 }
671 
672 
673 #include "common/pack-start.h"	// START STRUCT PACKING
674 
675 struct RolandInstrumentSysex {
676 	byte roland_id;
677 	byte device_id;
678 	byte model_id;
679 	byte command;
680 	byte address[3];
681 	byte instrument[0xF6];
682 	byte checksum;
683 } PACKED_STRUCT;
684 
685 #include "common/pack-end.h"	// END STRUCT PACKING
686 
setRolandInstrument(MidiDriver * drv,byte channel,byte * instrument)687 void setRolandInstrument(MidiDriver *drv, byte channel, byte *instrument) {
688 	RolandInstrumentSysex sysex;
689 	memcpy(&sysex.instrument, instrument, 0xF6);
690 
691 	// Show the timbre name as extra debug information
692 	Common::String name((char *)instrument, 10);
693 	debugC(5, kDebugMIDI, "Groovie::Music: Setting MT32 timbre '%s' to channel %d", name.c_str(), channel);
694 
695 	sysex.roland_id = 0x41;
696 	sysex.device_id = channel; // Unit#
697 	sysex.model_id = 0x16; // MT32
698 	sysex.command = 0x12; // Data set
699 
700 	// Remap instrument to appropriate address space.
701 	int address = 0x008000;
702 	sysex.address[0] = (address >> 14) & 0x7F;
703 	sysex.address[1] = (address >>  7) & 0x7F;
704 	sysex.address[2] = (address      ) & 0x7F;
705 
706 	// Compute the checksum.
707 	byte checksum = 0;
708 	byte *ptr = sysex.address;
709 	for (int i = 4; i < (int)sizeof(RolandInstrumentSysex) - 1; ++i)
710 		checksum -= *ptr++;
711 	sysex.checksum = checksum & 0x7F;
712 
713 	// Send sysex
714 	drv->sysEx((byte *)&sysex, sizeof(RolandInstrumentSysex));
715 
716 
717 	// Wait the time it takes to send the SysEx data
718 	uint32 delay = (sizeof(RolandInstrumentSysex) + 2) * 1000 / 3125;
719 
720 	// Plus an additional delay for the MT-32 rev00
721 	delay += 40;
722 
723 	g_system->delayMillis(delay);
724 }
725 
setTimbreMT(byte channel,const Timbre & timbre)726 void MusicPlayerXMI::setTimbreMT(byte channel, const Timbre &timbre) {
727 	// Verify the timbre size
728 	if (timbre.size != 0xF6)
729 		error("Groovie::Music: Invalid size for an MT-32 timbre: %d", timbre.size);
730 
731 	setRolandInstrument(_driver, channel, timbre.data);
732 }
733 
734 
735 // MusicPlayerMac_t7g
736 
MusicPlayerMac_t7g(GroovieEngine * vm)737 MusicPlayerMac_t7g::MusicPlayerMac_t7g(GroovieEngine *vm) : MusicPlayerMidi(vm) {
738 	// Create the parser
739 	_midiParser = MidiParser::createParser_SMF();
740 
741 	// Create the driver
742 	MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
743 	_driver = MidiDriver::createMidi(dev);
744 	assert(_driver);
745 
746 	_driver->open();	// TODO: Handle return value != 0 (indicating an error)
747 
748 	// Set the parser's driver
749 	_midiParser->setMidiDriver(this);
750 
751 	// Set the timer rate
752 	_midiParser->setTimerRate(_driver->getBaseTempo());
753 
754 	// Sanity check
755 	assert(_vm->_macResFork);
756 }
757 
load(uint32 fileref,bool loop)758 bool MusicPlayerMac_t7g::load(uint32 fileref, bool loop) {
759 	debugC(1, kDebugMIDI, "Groovie::Music: Starting the playback of song: %04X", fileref);
760 
761 	// First try for compressed MIDI
762 	Common::SeekableReadStream *file = _vm->_macResFork->getResource(MKTAG('c','m','i','d'), fileref & 0x3FF);
763 
764 	if (file) {
765 		// Found the resource, decompress it
766 		Common::SeekableReadStream *tmp = decompressMidi(file);
767 		delete file;
768 		file = tmp;
769 	} else {
770 		// Otherwise, it's uncompressed
771 		file = _vm->_macResFork->getResource(MKTAG('M','i','d','i'), fileref & 0x3FF);
772 		if (!file)
773 			error("Groovie::Music: Couldn't find resource 0x%04X", fileref);
774 	}
775 
776 	return loadParser(file, loop);
777 }
778 
decompressMidi(Common::SeekableReadStream * stream)779 Common::SeekableReadStream *MusicPlayerMac_t7g::decompressMidi(Common::SeekableReadStream *stream) {
780 	// Initialize an output buffer of the given size
781 	uint32 size = stream->readUint32BE();
782 	byte *output = (byte *)malloc(size);
783 
784 	byte *current = output;
785 	uint32 decompBytes = 0;
786 	while ((decompBytes < size) && !stream->eos()) {
787 		// 8 flags
788 		byte flags = stream->readByte();
789 
790 		for (byte i = 0; (i < 8) && !stream->eos(); i++) {
791 			if (flags & 1) {
792 				// 1: Next byte is a literal
793 				*(current++) = stream->readByte();
794 				if (stream->eos())
795 					continue;
796 				decompBytes++;
797 			} else {
798 				// 0: It's a reference to part of the history
799 				uint16 args = stream->readUint16BE();
800 				if (stream->eos())
801 					continue;
802 
803 				// Length = 4bit unsigned (3 minimal)
804 				uint8 length = (args >> 12) + 3;
805 
806 				// Offset = 12bit signed (all values are negative)
807 				int16 offset = (args & 0xFFF) | 0xF000;
808 
809 				// Copy from the past decompressed bytes
810 				decompBytes += length;
811 				while (length > 0) {
812 					*(current) = *(current + offset);
813 					current++;
814 					length--;
815 				}
816 			}
817 			flags = flags >> 1;
818 		}
819 	}
820 
821 	// Return the output buffer wrapped in a MemoryReadStream
822 	return new Common::MemoryReadStream(output, size, DisposeAfterUse::YES);
823 }
824 
825 // MusicPlayerMac_v2
826 
MusicPlayerMac_v2(GroovieEngine * vm)827 MusicPlayerMac_v2::MusicPlayerMac_v2(GroovieEngine *vm) : MusicPlayerMidi(vm) {
828 	// Create the parser
829 	_midiParser = MidiParser::createParser_QT();
830 
831 	// Create the driver
832 	MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
833 	_driver = MidiDriver::createMidi(dev);
834 	assert(_driver);
835 
836 	_driver->open();	// TODO: Handle return value != 0 (indicating an error)
837 
838 	// Set the parser's driver
839 	_midiParser->setMidiDriver(this);
840 
841 	// Set the timer rate
842 	_midiParser->setTimerRate(_driver->getBaseTempo());
843 }
844 
load(uint32 fileref,bool loop)845 bool MusicPlayerMac_v2::load(uint32 fileref, bool loop) {
846 	debugC(1, kDebugMIDI, "Groovie::Music: Starting the playback of song: %04X", fileref);
847 
848 	// Find correct filename
849 	ResInfo info;
850 	_vm->_resMan->getResInfo(fileref, info);
851 	uint len = info.filename.size();
852 	if (len < 4)
853 		return false;	// This shouldn't actually occur
854 
855 	// Remove the extension and add ".mov"
856 	info.filename.deleteLastChar();
857 	info.filename.deleteLastChar();
858 	info.filename.deleteLastChar();
859 	info.filename += "mov";
860 
861 	Common::SeekableReadStream *file = SearchMan.createReadStreamForMember(info.filename);
862 
863 	if (!file) {
864 		warning("Could not find file '%s'", info.filename.c_str());
865 		return false;
866 	}
867 
868 	return loadParser(file, loop);
869 }
870 
MusicPlayerIOS(GroovieEngine * vm)871 MusicPlayerIOS::MusicPlayerIOS(GroovieEngine *vm) : MusicPlayer(vm) {
872 	vm->getTimerManager()->installTimerProc(&onTimer, 50 * 1000, this, "groovieMusic");
873 }
874 
~MusicPlayerIOS()875 MusicPlayerIOS::~MusicPlayerIOS() {
876 	_vm->getTimerManager()->removeTimerProc(&onTimer);
877 }
878 
updateVolume()879 void MusicPlayerIOS::updateVolume() {
880 	// Just set the mixer volume for the music sound type
881 	_vm->_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, _userVolume * _gameVolume / 100);
882 }
883 
unload()884 void MusicPlayerIOS::unload() {
885 	MusicPlayer::unload();
886 
887 	_vm->_system->getMixer()->stopHandle(_handle);
888 }
889 
load(uint32 fileref,bool loop)890 bool MusicPlayerIOS::load(uint32 fileref, bool loop) {
891 	// Find correct filename
892 	ResInfo info;
893 	_vm->_resMan->getResInfo(fileref, info);
894 	uint len = info.filename.size();
895 	if (len < 4)
896 		return false;	// This shouldn't actually occur
897 	/*
898 	19462 door
899 	19463 ??
900 	19464 ??
901 	19465 puzzle?
902 	19466 cake
903 	19467 maze
904 	19468 ambient  (but not 69, amb b.  odd)
905 	19470 puzzle
906 	19471
907 	19473
908 	19475 coffins or blood pump
909 	19476 blood pump or coffins
910 	19493
911 	19499 chapel
912 	19509 downstair ambient
913 	19510 bedroom 'skip 3 and 5' puzzle (should loop from partway?)
914 	19514
915 	19515 bathroom drain teeth
916 	*/
917 	if ((fileref >= 19462 && fileref <= 19468) ||
918 		fileref == 19470 || fileref == 19471 ||
919 		fileref == 19473 || fileref == 19475 ||
920 		fileref == 19476 || fileref == 19493 ||
921 		fileref == 19499 || fileref == 19509 ||
922 		fileref == 19510 || fileref == 19514 ||
923 		fileref == 19515)
924 		loop = true; // XMIs for these refs self-loop
925 
926 	// iOS port provides alternative intro sequence music
927 	if (info.filename == "gu39.xmi") {
928 		info.filename = "intro";
929 	} else if (info.filename == "gu32.xmi") {
930 		info.filename = "foyer";
931 	} else {
932 		// Remove the extension
933 		info.filename.deleteLastChar();
934 		info.filename.deleteLastChar();
935 		info.filename.deleteLastChar();
936 		info.filename.deleteLastChar();
937 	}
938 
939 	// Create the audio stream
940 	Audio::SeekableAudioStream *seekStream = Audio::SeekableAudioStream::openStreamFile(info.filename);
941 
942 	if (!seekStream) {
943 		warning("Could not play audio file '%s'", info.filename.c_str());
944 		return false;
945 	}
946 
947 	Audio::AudioStream *audStream = seekStream;
948 
949 	// Loop if requested
950 	if (loop)
951 		audStream = Audio::makeLoopingAudioStream(seekStream, 0);
952 
953 	// MIDI player handles volume reset on load, IOS player doesn't - force update here
954 	updateVolume();
955 
956 	// Play!
957 	_vm->_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, &_handle, audStream);
958 	return true;
959 }
960 
961 } // End of Groovie namespace
962