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