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 // FIXME: This code is taken from MADE and may need more work (e.g. setVolume).
24 
25 // MIDI and digital music class
26 
27 #include "audio/audiostream.h"
28 #include "audio/mididrv.h"
29 #include "audio/midiparser.h"
30 // Miles Audio for Discworld 1
31 #include "audio/miles.h"
32 // Discworld Noir
33 #include "audio/decoders/mp3.h"
34 
35 #include "backends/audiocd/audiocd.h"
36 
37 #include "common/config-manager.h"
38 #include "common/file.h"
39 #include "common/memstream.h"
40 
41 #include "tinsel/adpcm.h"
42 #include "tinsel/config.h"
43 #include "tinsel/sound.h"
44 #include "tinsel/music.h"
45 #include "tinsel/handle.h"
46 #include "tinsel/sysvar.h"
47 
48 enum {
49 	MUSIC_JUMP = -1,
50 	MUSIC_END = -2,
51 
52 	BLMAGIC  = -3458,
53 
54 	DIM_SPEED = 8
55 };
56 
57 namespace Tinsel {
58 
59 static const int enhancedAudioGRAVersion[] = {
60 	 1,   2,   1,   1,   3,   3,   4,   4,   5,   6, //   1-10
61 	 1,   7,   8,   9,  10,   3,  11,  11,  12,  13, //  11-20
62 	13,  13,  13,  13,  14,  13,  13,  15,  16,  17, //  21-30
63 	15,  18,  19,  20, 338,  21,  21,  22,  22,  23, //  31-40
64 	24,  25,  26,  27,  28,  29,  30,  31,  32,  33, //  41-50
65 	34,  35,  35,  36,  37,  38,  39,  39,  39,  39, //  51-60
66 	40,  39,  41,  41,  42,  43,  42,  44,  45,  41, //  61-70
67 	46,  48,  47,  48,  49,  50,  51,  52,  53,  54, //  71-80
68 	55,  56,  57,  58,  59,  60,  61,  62,  63,  61, //  81-90
69 	64,  65,  66,  67,  68,  69,  70,  68,  71,  72, //  91-100
70 	73,  74,  75,  12,  76,  77,  78,  79,  80,   4, // 101-110
71 	81,  82,  83,  82,  81,  84,  85,  86,  87,  88, // 111-120
72 	89,  90,  88,   2,   2,   2,   2,   2,   2,  60, // 121-130
73 	91,  92,  93,  94,  94,  95,  96,  52,   4,  97, // 131-140
74 	98,  99,  99                                     // 141-143
75 };
76 
77 static const int enhancedAudioSCNVersion[] = {
78 	 301, 302,   2,    1,   1, 301, 302,   3,   3,   4, //   1-10
79 	   4,   5,   6,    1,   7,   8,   9,  10,   8,  11, //  11-20
80 	  11,  12,  13,   13,  13,  13,  13,  14,  13,  13, //  21-30
81 	  15,  16,  17,   15,  18,  19,  20, 338,  21,  21, //  31-40
82 	 341, 342,  22,   22,  23,  24,  25,  26,  27,  28, //  41-50
83 	  29,  30,  31,   32,  33,  34,  35,  35,  36,  37, //  51-60
84 	  38,  39,  39,   39,  39,  40,  39,  41,  41,  42, //  61-70
85 	  43,  42,  44,   45,  41,  46,  48,  47,  48,  49, //  71-80
86 	  50,  51,  52,   53,  54,  55,  56,  57,  58,  59, //  81-90
87 	  60,  61,  62,   63,  61,  64,  65,  66,  67,  68, //  91-100
88 	  69,  70,  68,   71,  72,  73,  74,  75,  12,  76, // 101-110
89 	  77,  78,  79,   80,   4,   4,  82,  83,  77,   4, // 111-120
90 	  84,  85,  86, 3124,  88,  89,  90,  88,   2,   2, // 121-130
91 	   2,   2,   2,    2,   2,   2,   2,   2,   2,   2, // 131-140
92 	3142,  91,  92,   93,  94,  94,  95,  96,  52,   4, // 141-150
93 	  97,  98,  99,   99                                // 151-154
94 };
95 
GetTrackNumber(SCNHANDLE hMidi)96 int Music::GetTrackNumber(SCNHANDLE hMidi) {
97 	for (int i = 0; i < ARRAYSIZE(_midiOffsets); i++) {
98 		if (_midiOffsets[i] == hMidi)
99 			return i;
100 	}
101 
102 	return -1;
103 }
104 
GetTrackOffset(int trackNumber)105 SCNHANDLE Music::GetTrackOffset(int trackNumber) {
106 	assert(trackNumber < ARRAYSIZE(_midiOffsets));
107 	return _midiOffsets[trackNumber];
108 }
109 
110 /**
111  * Plays the specified MIDI sequence through the sound driver.
112  * @param dwFileOffset		File offset of MIDI sequence data
113  * @param bLoop				Whether to loop the sequence
114  */
PlayMidiSequence(uint32 dwFileOffset,bool bLoop)115 bool Music::PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
116 	_currentMidi = dwFileOffset;
117 	_currentLoop = bLoop;
118 
119 	bool mute = false;
120 	if (ConfMan.hasKey("mute"))
121 		mute = ConfMan.getBool("mute");
122 
123 	SetMidiVolume(mute ? 0 : _vm->_config->_musicVolume);
124 
125 	// the index and length of the last tune loaded
126 	uint32 dwSeqLen = 0;	// length of the sequence
127 
128 	// Support for external music from the music enhancement project
129 	if (_vm->getFeatures() & GF_ENHANCED_AUDIO_SUPPORT) {
130 		int trackNumber = GetTrackNumber(dwFileOffset);
131 		// Track 8 has been removed in the German CD re-release "Neon Edition"
132 		if ((_vm->getFeatures() & GF_ALT_MIDI) && trackNumber >= 8)
133 			trackNumber++;
134 
135 		int track = 0;
136 		if (trackNumber >= 0) {
137 			if (_vm->getFeatures() & GF_SCNFILES)
138 				track = enhancedAudioSCNVersion[trackNumber];
139 			else
140 				track = enhancedAudioGRAVersion[trackNumber];
141 
142 			if (track > 0) {
143 				StopMidi();
144 
145 				// StopMidi resets these fields, so set them again
146 				_currentMidi = dwFileOffset;
147 				_currentLoop = bLoop;
148 
149 				// try to play track, but don't fall back to a true CD
150 				g_system->getAudioCDManager()->play(track, bLoop ? -1 : 1, 0, 0, true);
151 
152 				// Check if an enhanced audio track is being played.
153 				// If it is, stop here and don't load a MIDI track
154 				if (g_system->getAudioCDManager()->isPlaying()) {
155 					return true;
156 				}
157 			}
158 		} else {
159 			warning("Unknown MIDI offset %d", dwFileOffset);
160 		}
161 	}
162 
163 	if (dwFileOffset == 0)
164 		return true;
165 
166 	Common::File midiStream;
167 
168 	// open MIDI sequence file in binary mode
169 	if (!midiStream.open(MIDI_FILE))
170 		error(CANNOT_FIND_FILE, MIDI_FILE);
171 
172 	// move to correct position in the file
173 	midiStream.seek(dwFileOffset, SEEK_SET);
174 
175 	if (TinselV1Mac) {
176 		// The Macintosh version of DW1 uses raw PCM for music
177 		dwSeqLen = midiStream.readUint32BE();
178 		_vm->_sound->playDW1MacMusic(midiStream, dwSeqLen);
179 	} else {
180 		dwSeqLen = midiStream.readUint32LE();
181 
182 		// make sure buffer is large enough for this sequence
183 		assert(dwSeqLen > 0 && dwSeqLen <= _midiBuffer.size);
184 
185 		// stop any currently playing tune
186 		_vm->_midiMusic->stop();
187 
188 		// read the sequence. This needs to be read again before playSEQ() is
189 		// called even if the music is restarting, as playSEQ() reads the file
190 		// name off the buffer itself. However, that function adds SMF headers
191 		// to the buffer, thus if it's read again, the SMF headers will be read
192 		// and the filename will always be 'MThd'.
193 		if (midiStream.read(_midiBuffer.pDat, dwSeqLen) != dwSeqLen)
194 			error(FILE_IS_CORRUPT, MIDI_FILE);
195 
196 		// WORKAROUND for bug #4393 "DW1: No intro music at first start on Wii",
197 		// which actually affects all ports, since it's specific to the GRA version.
198 		//
199 		// The GRA version does not seem to set the channel volume at all for the first
200 		// intro track, thus we need to do that here. We only initialize the channels
201 		// used in that sequence. And we are using 127 as default channel volume.
202 		//
203 		// Only in the GRA version dwFileOffset can be "38888", just to be sure, we
204 		// check for the SCN files feature flag not being set though.
205 		if (_vm->getGameID() == GID_DW1 && dwFileOffset == 38888 && !(_vm->getFeatures() & GF_SCNFILES)) {
206 			_vm->_midiMusic->send(0x7F07B0 |  3);
207 			_vm->_midiMusic->send(0x7F07B0 |  5);
208 			_vm->_midiMusic->send(0x7F07B0 |  8);
209 			_vm->_midiMusic->send(0x7F07B0 | 10);
210 			_vm->_midiMusic->send(0x7F07B0 | 13);
211 		}
212 
213 		_vm->_midiMusic->playMIDI(dwSeqLen, bLoop);
214 	}
215 
216 	midiStream.close();
217 
218 	return true;
219 }
220 
221 /**
222  * Returns TRUE if a Midi tune is currently playing.
223  */
MidiPlaying()224 bool Music::MidiPlaying() {
225 	if (_vm->getFeatures() & GF_ENHANCED_AUDIO_SUPPORT) {
226 		if (g_system->getAudioCDManager()->isPlaying())
227 			return true;
228 	}
229 	return _vm->_midiMusic->isPlaying();
230 }
231 
232 /**
233  * Stops any currently playing midi.
234  */
StopMidi()235 bool Music::StopMidi() {
236 	_currentMidi = 0;
237 	_currentLoop = false;
238 
239 	if (_vm->getFeatures() & GF_ENHANCED_AUDIO_SUPPORT) {
240 		g_system->getAudioCDManager()->stop();
241 	}
242 
243 	_vm->_midiMusic->stop();
244 	return true;
245 }
246 
247 
248 /**
249  * Gets the volume of the MIDI music.
250  */
GetMidiVolume()251 int Music::GetMidiVolume() {
252 	return _vm->_config->_musicVolume;
253 }
254 
255 /**
256  * Sets the volume of the MIDI music.
257  * @param vol			New volume - 0..MAXMIDIVOL
258  */
SetMidiVolume(int vol)259 void Music::SetMidiVolume(int vol) {
260 	assert(vol >= 0 && vol <= Audio::Mixer::kMaxChannelVolume);
261 	_vm->_midiMusic->setVolume(vol);
262 }
263 
264 /**
265  * Opens and inits all MIDI sequence files.
266  */
OpenMidiFiles()267 void Music::OpenMidiFiles() {
268 	Common::File midiStream;
269 
270 	if (TinselV0) {
271 		// The early demo version of DW1 doesn't have MIDI
272 	} else if (TinselV2) {
273 		// DW2 uses a different music mechanism
274 	} else if (TinselV1Mac) {
275 		// open MIDI sequence file in binary mode
276 		if (!midiStream.open(MIDI_FILE))
277 			error(CANNOT_FIND_FILE, MIDI_FILE);
278 
279 		uint32 curTrack = 1;
280 		uint32 songLength = 0;
281 		int32 fileSize = midiStream.size();
282 
283 		// Init
284 		for (int i = 0; i < ARRAYSIZE(_midiOffsets); i++)
285 			_midiOffsets[i] = 0;
286 
287 		midiStream.skip(4);	// skip file header
288 
289 		while (!midiStream.eos() && !midiStream.err() && midiStream.pos() != fileSize) {
290 			assert(curTrack < ARRAYSIZE(_midiOffsets));
291 			_midiOffsets[curTrack] = midiStream.pos();
292 			//debug("%d: %d", curTrack, g_midiOffsets[curTrack]);
293 
294 			songLength = midiStream.readUint32BE();
295 			midiStream.skip(songLength);
296 
297 			curTrack++;
298 		}
299 
300 		midiStream.close();
301 	} else {
302 		if (_midiBuffer.pDat)
303 			// already allocated
304 			return;
305 
306 		// open MIDI sequence file in binary mode
307 		if (!midiStream.open(MIDI_FILE))
308 			error(CANNOT_FIND_FILE, MIDI_FILE);
309 
310 		// get length of the largest sequence
311 		_midiBuffer.size = midiStream.readUint32LE();
312 		if (midiStream.eos() || midiStream.err())
313 			error(FILE_IS_CORRUPT, MIDI_FILE);
314 
315 		if (_midiBuffer.size) {
316 			// allocate a buffer big enough for the largest MIDI sequence
317 			if ((_midiBuffer.pDat = (uint8 *)malloc(_midiBuffer.size)) != NULL) {
318 				// clear out the buffer
319 				memset(_midiBuffer.pDat, 0, _midiBuffer.size);
320 			}
321 		}
322 
323 		// Now scan through the contents of the MIDI file to find the offset
324 		// of each individual track, in order to create a mapping from MIDI
325 		// offset to track number, for the enhanced MIDI soundtrack.
326 		// The first song is always at position 4. The subsequent ones are
327 		// calculated dynamically.
328 		uint32 curOffset = 4;
329 		uint32 curTrack = 0;
330 		uint32 songLength = 0;
331 
332 		// Init
333 		for (int i = 0; i < ARRAYSIZE(_midiOffsets); i++)
334 			_midiOffsets[i] = 0;
335 
336 		while (!midiStream.eos() && !midiStream.err()) {
337 			if (curOffset + (4 * curTrack) >= (uint32)midiStream.size())
338 				break;
339 
340 			assert(curTrack < ARRAYSIZE(_midiOffsets));
341 			_midiOffsets[curTrack] = curOffset + (4 * curTrack);
342 			//debug("%d: %d", curTrack, midiOffsets[curTrack]);
343 
344 			songLength = midiStream.readUint32LE();
345 			curOffset += songLength;
346 			midiStream.skip(songLength);
347 
348 			curTrack++;
349 		}
350 
351 		midiStream.close();
352 	}
353 }
354 
DeleteMidiBuffer()355 void Music::DeleteMidiBuffer() {
356 	free(_midiBuffer.pDat);
357 	_midiBuffer.pDat = nullptr;
358 }
359 
CurrentMidiFacts(SCNHANDLE * pMidi,bool * pLoop)360 void Music::CurrentMidiFacts(SCNHANDLE* pMidi, bool* pLoop) {
361 	*pMidi = _currentMidi;
362 	*pLoop = _currentLoop;
363 }
364 
RestoreMidiFacts(SCNHANDLE Midi,bool Loop)365 void Music::RestoreMidiFacts(SCNHANDLE	Midi, bool Loop) {
366 	StopMidi();
367 
368 	_currentMidi = Midi;
369 	_currentLoop = Loop;
370 
371 	bool mute = false;
372 	if (ConfMan.hasKey("mute"))
373 		mute = ConfMan.getBool("mute");
374 
375 	PlayMidiSequence(_currentMidi, true);
376 	SetMidiVolume(mute ? 0 : _vm->_config->_musicVolume);
377 }
378 
379 #if 0
380 // Dumps all of the game's music in external XMIDI *.xmi files
381 void dumpMusic() {
382 	Common::File midiFile;
383 	Common::DumpFile outFile;
384 	char outName[20];
385 	midiFile.open(MIDI_FILE);
386 	int outFileSize = 0;
387 	char buffer[20000];
388 
389 	const int total = 155;	// maximum (SCN version)
390 
391 	for (int i = 0; i < total; i++) {
392 		if (midiOffsets[i] == 0)
393 			break;
394 
395 		sprintf(outName, "track%03d.xmi", i + 1);
396 		outFile.open(outName);
397 
398 		if (i < total - 1)
399 			outFileSize = midiOffsets[i + 1] - midiOffsets[i] - 4;
400 		else
401 			outFileSize = midiFile.size() - midiOffsets[i] - 4;
402 
403 		midiFile.seek(midiOffsets[i] + 4, SEEK_SET);
404 
405 		assert(outFileSize < 20000);
406 		midiFile.read(buffer, outFileSize);
407 		outFile.write(buffer, outFileSize);
408 
409 		outFile.close();
410 	}
411 
412 	midiFile.close();
413 }
414 #endif
415 
MidiMusicPlayer(TinselEngine * vm)416 MidiMusicPlayer::MidiMusicPlayer(TinselEngine *vm) {
417 	_driver = nullptr;
418 	_milesAudioMode = false;
419 	bool milesAudioEnabled = false;
420 
421 	if (vm->getPlatform() == Common::kPlatformDOS) {
422 		// Enable Miles Audio for DOS platform only...
423 		switch (vm->getGameID()) {
424 		case GID_DW1:
425 			if (!vm->getIsADGFDemo()) {
426 				// ...for Discworld 1
427 				milesAudioEnabled = true;
428 			} else {
429 				if (vm->isV1CD()) {
430 					// ...and for Discworld 1 CD Demo
431 					milesAudioEnabled = true;
432 				}
433 			}
434 			break;
435 		default:
436 			break;
437 		}
438 	}
439 
440 	if (milesAudioEnabled) {
441 		// Discworld 1 (DOS) uses Miles Audio 3
442 		// use our own Miles Audio drivers
443 		//
444 		// It seems that there are multiple versions of Discworld 1
445 		//
446 		// Version 1:
447 		// Has SAMPLE.AD for AdLib and SAMPLE.OPL for OPL-3
448 		// Timbre files are inside a subdirectory of the CD called "/drivers". Main game files are in
449 		// another subdirectory, which means the user has to copy those files over.
450 		// Installer script copies all drivers directly to harddrive without name changes
451 		//
452 		// Version 2:
453 		// Has FAT.OPL only (gets copied by the installer into MIDPAK.AD or MIDPAK.OPL)
454 		// Timbre file is inside subdirectory "drivers" right in the main game directory.
455 		// Installer copies FAT.OPL to MIDPAK.AD all the time, even when user selected AWE32
456 		//
457 		// Neither have timbre data for MT32
458 
459 		::MidiDriver::DeviceHandle dev = ::MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
460 		::MusicType musicType = ::MidiDriver::getMusicType(dev);
461 		Common::File fileClass;
462 
463 		switch (musicType) {
464 		case MT_ADLIB:
465 			if (fileClass.exists("FAT.OPL")) {
466 				// Version 2: fat.opl, may be in drivers-subdirectory
467 				_driver = Audio::MidiDriver_Miles_AdLib_create("", "FAT.OPL");
468 			} else {
469 				if (fileClass.exists("MIDPAK.AD")) {
470 					// Version 2: drivers got installed and fat.opl got copied over by the user
471 					_driver = Audio::MidiDriver_Miles_AdLib_create("MIDPAK.AD", "");
472 				} else {
473 					if ((fileClass.exists("SAMPLE.AD")) || (fileClass.exists("SAMPLE.OPL"))) {
474 						// Version 1: sample.ad / sample.opl, have to be copied over by the user for this version
475 						_driver = Audio::MidiDriver_Miles_AdLib_create("SAMPLE.AD", "SAMPLE.OPL");
476 					} else {
477 						error("MILES-ADLIB: timbre file not found (may be called FAT.OPL, MIDPAK.AD, SAMPLE.AD or SAMPLE.OPL, may be in a subdirectory)");
478 					}
479 				}
480 			}
481 			break;
482 		case MT_MT32:
483 			// Discworld 1 doesn't have a MT32 timbre file
484 			_driver = Audio::MidiDriver_Miles_MT32_create("");
485 			break;
486 		case MT_GM:
487 			if (ConfMan.getBool("native_mt32")) {
488 				_driver = Audio::MidiDriver_Miles_MT32_create("");
489 				musicType = MT_MT32;
490 			}
491 			break;
492 		default:
493 			break;
494 		}
495 		if (!_driver) {
496 			// nothing got created yet? -> create default driver
497 			MidiPlayer::createDriver();
498 		} else {
499 			_milesAudioMode = true;
500 		}
501 
502 	} else {
503 		MidiPlayer::createDriver();
504 	}
505 
506 	int ret = _driver->open();
507 	if (ret == 0) {
508 		if (_nativeMT32)
509 			_driver->sendMT32Reset();
510 		else
511 			_driver->sendGMReset();
512 
513 		_driver->setTimerCallback(this, &timerCallback);
514 	}
515 }
516 
setVolume(int volume)517 void MidiMusicPlayer::setVolume(int volume) {
518 	_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
519 
520 	Audio::MidiPlayer::setVolume(volume);
521 }
522 
send(uint32 b)523 void MidiMusicPlayer::send(uint32 b) {
524 	if (_milesAudioMode) {
525 		_driver->send(b);
526 		return;
527 	}
528 
529 	Audio::MidiPlayer::send(b);
530 
531 	byte channel = (byte)(b & 0x0F);
532 	if (_channelsTable[channel]) {
533 		if ((b & 0xFFF0) == 0x0079B0) {
534 			// We've just Reset All Controllers, so we need to
535 			// re-adjust the volume. Otherwise, volume is reset to
536 			// default whenever the music changes.
537 			_channelsTable[channel]->send(0x000007B0 | (((_channelsVolume[channel] * _masterVolume) / 255) << 16) | channel);
538 		}
539 	}
540 }
541 
playMIDI(uint32 size,bool loop)542 void MidiMusicPlayer::playMIDI(uint32 size, bool loop) {
543 	Common::StackLock lock(_mutex);
544 
545 	if (_isPlaying)
546 		return;
547 
548 	stop();
549 
550 	if (TinselV1PSX)
551 		playSEQ(size, loop);
552 	else
553 		playXMIDI(size, loop);
554 }
555 
playXMIDI(uint32 size,bool loop)556 void MidiMusicPlayer::playXMIDI(uint32 size, bool loop) {
557 	// It seems like not all music (the main menu music, for instance) set
558 	// all the instruments explicitly. That means the music will sound
559 	// different, depending on which music played before it. This appears
560 	// to be a genuine glitch in the original. For consistency, reset all
561 	// instruments to the default one (piano).
562 
563 	for (int i = 0; i < 16; i++) {
564 		_driver->send(0xC0 | i, 0, 0);
565 	}
566 
567 	// Load XMID resource data
568 
569 	MidiParser *parser = MidiParser::createParser_XMIDI();
570 	if (parser->loadMusic(_vm->_music->GetMidiBuffer(), size)) {
571 		parser->setTrack(0);
572 		parser->setMidiDriver(this);
573 		parser->setTimerRate(getBaseTempo());
574 		parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
575 		parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);
576 
577 		_parser = parser;
578 
579 		_isLooping = loop;
580 		_isPlaying = true;
581 	} else {
582 		delete parser;
583 	}
584 }
585 
playSEQ(uint32 size,bool loop)586 void MidiMusicPlayer::playSEQ(uint32 size, bool loop) {
587 	uint8 *midiData = _vm->_music->GetMidiBuffer();
588 	// MIDI.DAT holds the file names in DW1 PSX
589 	Common::String baseName((char *)midiData, size);
590 	Common::String seqName = baseName + ".SEQ";
591 
592 	// TODO: Load the instrument bank (<baseName>.VB and <baseName>.VH)
593 
594 	Common::File seqFile;
595 	if (!seqFile.open(seqName))
596 		error("Failed to open SEQ file '%s'", seqName.c_str());
597 
598 	if (seqFile.readUint32LE() != MKTAG('S', 'E', 'Q', 'p'))
599 		error("Failed to find SEQp tag");
600 
601 	// Make sure we don't have a SEP file (with multiple SEQ's inside)
602 	if (seqFile.readUint32BE() != 1)
603 		error("Can only play SEQ files, not SEP");
604 
605 	uint16 ppqn = seqFile.readUint16BE();
606 	uint32 tempo = seqFile.readUint16BE() << 8;
607 	tempo |= seqFile.readByte();
608 	/* uint16 beat = */ seqFile.readUint16BE();
609 
610 	// SEQ is directly based on SMF and we'll use that to our advantage here
611 	// and convert to SMF and then use the SMF MidiParser.
612 
613 	// Calculate the SMF size we'll need
614 	uint32 dataSize = seqFile.size() - 15;
615 	uint32 actualSize = dataSize + 7 + 22;
616 
617 	// Resize the buffer if necessary
618 	midiData = _vm->_music->ResizeMidiBuffer(actualSize);
619 
620 	// Now construct the header
621 	WRITE_BE_UINT32(midiData, MKTAG('M', 'T', 'h', 'd'));
622 	WRITE_BE_UINT32(midiData + 4, 6); // header size
623 	WRITE_BE_UINT16(midiData + 8, 0); // type 0
624 	WRITE_BE_UINT16(midiData + 10, 1); // one track
625 	WRITE_BE_UINT16(midiData + 12, ppqn);
626 	WRITE_BE_UINT32(midiData + 14, MKTAG('M', 'T', 'r', 'k'));
627 	WRITE_BE_UINT32(midiData + 18, dataSize + 7); // SEQ data size + tempo change event size
628 
629 	// Add in a fake tempo change event
630 	WRITE_BE_UINT32(midiData + 22, 0x00FF5103); // no delta, meta event, tempo change, param size = 3
631 	WRITE_BE_UINT16(midiData + 26, tempo >> 8);
632 	midiData[28] = tempo & 0xFF;
633 
634 	// Now copy in the rest of the events
635 	seqFile.read(midiData + 29, dataSize);
636 	seqFile.close();
637 
638 	MidiParser *parser = MidiParser::createParser_SMF();
639 	if (parser->loadMusic(midiData, actualSize)) {
640 		parser->setTrack(0);
641 		parser->setMidiDriver(this);
642 		parser->setTimerRate(getBaseTempo());
643 		parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
644 		parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);
645 
646 		_parser = parser;
647 
648 		_isLooping = loop;
649 		_isPlaying = true;
650 	} else {
651 		delete parser;
652 	}
653 }
654 
pause()655 void MidiMusicPlayer::pause() {
656 	setVolume(-1);
657 	_isPlaying = false;
658 }
659 
resume()660 void MidiMusicPlayer::resume() {
661 	setVolume(_vm->_music->GetMidiVolume());
662 	_isPlaying = true;
663 }
664 
PCMMusicPlayer()665 PCMMusicPlayer::PCMMusicPlayer() {
666 	_silenceSamples = 0;
667 
668 	_curChunk = 0;
669 	_state = S_IDLE;
670 	_mState = S_IDLE;
671 	_scriptNum = -1;
672 	_scriptIndex = 0;
673 	_forcePlay = false;
674 
675 	_volume = 255;
676 	_dimmed = false;
677 	_dimmedTinsel = false;
678 	_dimIteration = 0;
679 	_dimmedVolume = 0;
680 	_dimPosition = 0;
681 
682 	_fadeOutVolume = 0;
683 	_fadeOutIteration = 0;
684 
685 	_hScript = _hSegment = 0;
686 
687 	_end = true;
688 
689 	_vm->_mixer->playStream(Audio::Mixer::kMusicSoundType,
690 			&_handle, this, -1, _volume, 0, DisposeAfterUse::NO, true);
691 }
692 
~PCMMusicPlayer()693 PCMMusicPlayer::~PCMMusicPlayer() {
694 	_vm->_mixer->stopHandle(_handle);
695 	delete _curChunk;
696 }
697 
startPlay(int id)698 void PCMMusicPlayer::startPlay(int id) {
699 	if (_filename.empty())
700 		return;
701 
702 	debugC(DEBUG_DETAILED, kTinselDebugMusic, "Playing PCM music %s, index %d", _filename.c_str(), id);
703 
704 	Common::StackLock slock(_mutex);
705 
706 	stop();
707 
708 	_scriptNum = id;
709 	_scriptIndex = 1;
710 	_state = S_NEW;
711 
712 	play();
713 }
714 
stopPlay()715 void PCMMusicPlayer::stopPlay() {
716 	Common::StackLock slock(_mutex);
717 
718 	stop();
719 }
720 
readBuffer(int16 * buffer,const int numSamples)721 int PCMMusicPlayer::readBuffer(int16 *buffer, const int numSamples) {
722 	Common::StackLock slock(_mutex);
723 
724 	if (!_curChunk && ((_state == S_IDLE) || (_state == S_STOP)))
725 		return 0;
726 
727 	int samplesLeft = numSamples;
728 
729 	while (samplesLeft > 0) {
730 		if (_silenceSamples > 0) {
731 			int n = MIN(_silenceSamples, samplesLeft);
732 
733 			memset(buffer, 0, n);
734 
735 			buffer += n;
736 			_silenceSamples -= n;
737 			samplesLeft -= n;
738 
739 		} else if (_curChunk &&
740 		          ((_state == S_MID) || (_state == S_NEXT) || (_state == S_NEW))) {
741 			int n = _curChunk->readBuffer(buffer, samplesLeft);
742 
743 			buffer += n;
744 			samplesLeft -= n;
745 
746 			if (_curChunk->endOfData()) {
747 				_state = S_END1;
748 
749 				delete _curChunk;
750 				_curChunk = 0;
751 			}
752 		} else {
753 
754 			if (!getNextChunk())
755 				break;
756 		}
757 	}
758 
759 	return (numSamples - samplesLeft);
760 }
761 
isStereo() const762 bool PCMMusicPlayer::isStereo() const {
763 	if (TinselV3) {
764 		return true;
765 	} else {
766 		return false;
767 	}
768 }
769 
getRate() const770 int PCMMusicPlayer::getRate() const {
771 	if (TinselV3) {
772 		if (_curChunk) {
773 			return _curChunk->getRate();
774 		} else {
775 			return 0;
776 		}
777 	} else {
778 		return 22050;
779 	}
780 }
781 
isPlaying() const782 bool PCMMusicPlayer::isPlaying() const {
783 	return ((_state != S_IDLE) && (_state != S_STOP));
784 }
785 
isDimmed() const786 bool PCMMusicPlayer::isDimmed() const {
787 	return _dimmed;
788 }
789 
getTunePlaying(void * voidPtr,int length)790 void PCMMusicPlayer::getTunePlaying(void *voidPtr, int length) {
791 	Common::StackLock lock(_mutex);
792 
793 	debugC(DEBUG_DETAILED, kTinselDebugMusic, "getTunePlaying");
794 
795 	assert(length == (3 * sizeof(int32)));
796 
797 	int32 *p = (int32 *) voidPtr;
798 
799 	_mState = _state;
800 
801 	p[0] = (int32) _mState;
802 	p[1] = _scriptNum;
803 	p[2] = _scriptIndex;
804 }
805 
restoreThatTune(void * voidPtr)806 void PCMMusicPlayer::restoreThatTune(void *voidPtr) {
807 	Common::StackLock lock(_mutex);
808 
809 	debugC(DEBUG_DETAILED, kTinselDebugMusic, "restoreThatTune");
810 
811 	int32 *p = (int32 *) voidPtr;
812 
813 	_mState = (State) p[0];
814 	_scriptNum = p[1];
815 	_scriptIndex = p[2];
816 
817 	if (_mState != S_IDLE)
818 		_state = S_NEW;
819 
820 	delete _curChunk;
821 	_curChunk = 0;
822 
823 	_end = false;
824 }
825 
setMusicSceneDetails(SCNHANDLE hScript,SCNHANDLE hSegment,const char * fileName)826 void PCMMusicPlayer::setMusicSceneDetails(SCNHANDLE hScript,
827 		SCNHANDLE hSegment, const char *fileName) {
828 
829 	Common::StackLock lock(_mutex);
830 
831 	stop();
832 
833 	debugC(DEBUG_INTERMEDIATE, kTinselDebugMusic, "Setting music scene details: %s", fileName);
834 
835 	_hScript = hScript;
836 	_hSegment = hSegment;
837 	_filename = fileName;
838 
839 	// Start scene with music not dimmed
840 	_dimmed = false;
841 	_dimmedTinsel = false;
842 	_dimIteration = 0;
843 	setVol(255);
844 }
845 
setVolume(int volume)846 void PCMMusicPlayer::setVolume(int volume) {
847 	assert((volume >= 0) && (volume <= 100));
848 
849 	_dimmed = false;
850 	setVol((volume * 255) / 100);
851 }
852 
setVol(uint8 volume)853 void PCMMusicPlayer::setVol(uint8 volume) {
854 	_volume = volume;
855 
856 	_vm->_mixer->setChannelVolume(_handle, _volume);
857 }
858 
getMusicTinselDimmed() const859 bool PCMMusicPlayer::getMusicTinselDimmed() const {
860 	return _dimmedTinsel;
861 }
862 
dim(bool bTinselDim)863 void PCMMusicPlayer::dim(bool bTinselDim) {
864 	if (_dimmed || (_volume == 0) ||
865 			(_state == S_IDLE) || !_curChunk || (SysVar(SV_MUSICDIMFACTOR) == 0))
866 		return;
867 
868 	_dimmed = true;
869 	if (bTinselDim)
870 		_dimmedTinsel = true;
871 
872 	_dimmedVolume = _volume - (_volume / SysVar(SV_MUSICDIMFACTOR));
873 
874 	// Iterate down, negative iteration
875 	if (!_dimIteration)
876 		_dimPosition = _volume;
877 	_dimIteration = (_dimmedVolume - _volume)/DIM_SPEED;
878 
879 	debugC(DEBUG_DETAILED, kTinselDebugMusic, "Dimming music from %d to %d, steps %d", _dimPosition, _dimmedVolume, _dimIteration);
880 
881 	// And SFX
882 	if (SysVar(SYS_SceneFxDimFactor))
883 		_vm->_sound->setSFXVolumes(255 - 255/SysVar(SYS_SceneFxDimFactor));
884 }
885 
unDim(bool bTinselUnDim)886 void PCMMusicPlayer::unDim(bool bTinselUnDim) {
887 	if (!_dimmed || (_dimmedTinsel && !bTinselUnDim))
888 		return; // not dimmed
889 
890 	_dimmed = _dimmedTinsel = false;
891 
892 	if ((_volume == 0) || (_state == S_IDLE) || !_curChunk)
893 		return;
894 
895 	// Iterate up, positive iteration
896 	if (!_dimIteration)
897 		_dimPosition = _dimmedVolume;
898 	_dimIteration = (_volume - _dimmedVolume)/DIM_SPEED;
899 
900 	debugC(DEBUG_DETAILED, kTinselDebugMusic, "UnDimming music from %d to %d, steps %d", _dimPosition, _volume, _dimIteration);
901 
902 	// And SFX
903 	_vm->_sound->setSFXVolumes(255);
904 }
905 
dimIteration()906 void PCMMusicPlayer::dimIteration() {
907 	if (_dimIteration != 0)
908 	{
909 		_dimPosition += _dimIteration;
910 		if (_dimPosition >= _volume)
911 		{
912 			_dimPosition = _volume;
913 			_dimIteration = 0;
914 		}
915 		else if (_dimPosition <= _dimmedVolume)
916 		{
917 			_dimPosition = _dimmedVolume;
918 			_dimIteration = 0;
919 		}
920 
921 		_vm->_mixer->setChannelVolume(_handle, _dimPosition);
922 	}
923 }
924 
startFadeOut(int ticks)925 void PCMMusicPlayer::startFadeOut(int ticks) {
926 	if ((_volume == 0) || (_state == S_IDLE) || !_curChunk)
927 		return;
928 
929 	debugC(DEBUG_INTERMEDIATE, kTinselDebugMusic, "Fading out music...");
930 
931 	if (_dimmed) {
932 		// Start from dimmed volume and go from there
933 		_dimmed = false;
934 		_fadeOutVolume = _volume - _volume/SysVar(SV_MUSICDIMFACTOR);
935 	} else
936 		_fadeOutVolume = _volume;
937 
938 	assert(ticks != 0);
939 	_fadeOutIteration = _fadeOutVolume / ticks;
940 
941 	fadeOutIteration();
942 }
943 
fadeOutIteration()944 void PCMMusicPlayer::fadeOutIteration() {
945 	if ((_volume == 0) || (_state == S_IDLE) || !_curChunk)
946 		return;
947 
948 	_fadeOutVolume = CLIP<int>(_fadeOutVolume -= _fadeOutIteration, 0, 255);
949 
950 	_vm->_mixer->setChannelVolume(_handle, _fadeOutVolume);
951 }
952 
readSampleData(const Common::String & filename,uint32 sampleOffset,uint32 sampleLength)953 Common::MemoryReadStream *readSampleData(const Common::String &filename, uint32 sampleOffset, uint32 sampleLength) {
954 	Common::File file;
955 	if (!file.open(filename))
956 		error(CANNOT_FIND_FILE, filename.c_str());
957 
958 	file.seek(sampleOffset);
959 	if (file.eos() || file.err() || (uint32)file.pos() != sampleOffset)
960 		error(FILE_IS_CORRUPT, filename.c_str());
961 
962 	byte *buffer = (byte *) malloc(sampleLength);
963 	assert(buffer);
964 
965 	// read all of the sample
966 	if (file.read(buffer, sampleLength) != sampleLength)
967 		error(FILE_IS_CORRUPT, filename.c_str());
968 
969 	return new Common::MemoryReadStream(buffer, sampleLength, DisposeAfterUse::YES);
970 }
971 
972 struct MusicSegment {
973 	uint32 numChannels;
974 	uint32 bitsPerSec;
975 	uint32 bitsPerSample;
976 	uint32 sampleLength;
977 	uint32 sampleOffset;
978 };
979 
loadADPCMMusicFromSegment(int segmentNum)980 void PCMMusicPlayer::loadADPCMMusicFromSegment(int segmentNum) {
981 	MusicSegment *musicSegments = (MusicSegment *)_vm->_handle->LockMem(_hSegment);
982 
983 	assert(FROM_32(musicSegments[segmentNum].numChannels) == 1);
984 	assert(FROM_32(musicSegments[segmentNum].bitsPerSample) == 16);
985 
986 	uint32 sampleOffset = FROM_32(musicSegments[segmentNum].sampleOffset);
987 	uint32 sampleLength = FROM_32(musicSegments[segmentNum].sampleLength);
988 	uint32 sampleCLength = (((sampleLength + 63) & ~63)*33)/64;
989 
990 	debugC(DEBUG_DETAILED, kTinselDebugMusic, "Creating ADPCM music chunk with size %d, "
991 			"offset %d (script %d.%d)",
992 			sampleCLength, sampleOffset, _scriptNum, _scriptIndex - 1);
993 
994 	Common::SeekableReadStream *sampleStream = readSampleData(_filename, sampleOffset, sampleCLength);
995 
996 	delete _curChunk;
997 	_curChunk = new Tinsel8_ADPCMStream(sampleStream, DisposeAfterUse::YES, sampleCLength, 22050, 1, 32);
998 }
999 
1000 struct MusicSegmentNoir {
1001 	uint32 sampleLength;
1002 	uint32 sampleOffset;
1003 };
1004 
loadMP3MusicFromSegment(int segmentNum)1005 void PCMMusicPlayer::loadMP3MusicFromSegment(int segmentNum) {
1006 #ifdef USE_MAD
1007 	MusicSegmentNoir *musicSegments = (MusicSegmentNoir *)_vm->_handle->LockMem(_hSegment);
1008 
1009 	Common::SeekableReadStream *sampleStream = readSampleData(_filename, musicSegments[segmentNum].sampleOffset,
1010 			musicSegments[segmentNum].sampleLength);
1011 
1012 	delete _curChunk;
1013 	_curChunk = Audio::makeMP3Stream(sampleStream, DisposeAfterUse::YES);
1014 #else
1015 	delete _curChunk;
1016 	_curChunk = 0;
1017 #endif
1018 }
1019 
loadMusicFromSegment(int segmentNum)1020 void PCMMusicPlayer::loadMusicFromSegment(int segmentNum) {
1021 	if (TinselV3) {
1022 		loadMP3MusicFromSegment(segmentNum);
1023 	} else {
1024 		loadADPCMMusicFromSegment(segmentNum);
1025 	}
1026 }
1027 
getNextChunk()1028 bool PCMMusicPlayer::getNextChunk() {
1029 	int32 *script, *scriptBuffer;
1030 	int id;
1031 	int snum;
1032 
1033 	switch (_state) {
1034 	case S_NEW:
1035 	case S_NEXT:
1036 		_forcePlay = false;
1037 
1038 		script = scriptBuffer = (int32 *)_vm->_handle->LockMem(_hScript);
1039 
1040 		// Set parameters for this chunk of music
1041 		id = _scriptNum;
1042 		while (id--)
1043 			script = scriptBuffer + READ_32(script);
1044 		snum = FROM_32(script[_scriptIndex++]);
1045 
1046 		if (snum == MUSIC_JUMP || snum == MUSIC_END) {
1047 			// Let usual code sort it out!
1048 			_scriptIndex--;    // Undo increment
1049 			_forcePlay = true; // Force a Play
1050 			_state = S_END1;   // 'Goto' S_END1
1051 			break;
1052 		}
1053 
1054 		loadMusicFromSegment(snum);
1055 
1056 		_state = S_MID;
1057 		return true;
1058 
1059 	case S_END1:
1060 		debugC(DEBUG_DETAILED, kTinselDebugMusic, "Music reached state S_END1 (script %d.%d)",
1061 				_scriptNum, _scriptIndex);
1062 
1063 		script = scriptBuffer = (int32 *)_vm->_handle->LockMem(_hScript);
1064 
1065 		id = _scriptNum;
1066 		while (id--)
1067 			script = scriptBuffer + READ_32(script);
1068 		snum = FROM_32(script[_scriptIndex]);
1069 
1070 		if (snum == MUSIC_END) {
1071 			_state = S_END2;
1072 		} else {
1073 			if (snum == MUSIC_JUMP)
1074 				_scriptIndex = FROM_32(script[_scriptIndex+1]);
1075 
1076 			_state = _forcePlay ? S_NEW : S_NEXT;
1077 			_forcePlay = false;
1078 		}
1079 
1080 		return true;
1081 
1082 	case S_END2:
1083 		debugC(DEBUG_DETAILED, kTinselDebugMusic, "Music reached state S_END2 (script %d.%d)",
1084 				_scriptNum, _scriptIndex);
1085 
1086 		_silenceSamples = 11025; // Half a second of silence
1087 		return true;
1088 
1089 	case S_END3:
1090 		debugC(DEBUG_DETAILED, kTinselDebugMusic, "Music reached state S_END3 (script %d.%d)",
1091 				_scriptNum, _scriptIndex);
1092 
1093 		stop();
1094 		_state = S_IDLE;
1095 		return false;
1096 
1097 	case S_IDLE:
1098 		return false;
1099 
1100 	default:
1101 		break;
1102 	}
1103 
1104 	return true;
1105 }
1106 
play()1107 void PCMMusicPlayer::play() {
1108 	if (_curChunk)
1109 		return;
1110 	if (_scriptNum == -1)
1111 		return;
1112 
1113 	_end = false;
1114 
1115 	getNextChunk();
1116 }
1117 
stop()1118 void PCMMusicPlayer::stop() {
1119 	delete _curChunk;
1120 	_curChunk = 0;
1121 	_scriptNum = -1;
1122 	_state = S_IDLE;
1123 	_mState = S_IDLE;
1124 
1125 	_end = true;
1126 }
1127 
1128 } // End of namespace Tinsel
1129