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