2008-07-23 09:02:47 +00:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
|
|
|
*
|
|
|
|
* ScummVM is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* $URL$
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
// FIXME: This code is taken from MADE and may need more work (e.g. setVolume).
|
|
|
|
|
|
|
|
// MIDI and digital music class
|
|
|
|
|
|
|
|
#include "sound/audiostream.h"
|
|
|
|
#include "sound/mididrv.h"
|
|
|
|
#include "sound/midiparser.h"
|
|
|
|
#include "sound/audiocd.h"
|
|
|
|
#include "common/config-manager.h"
|
|
|
|
#include "common/file.h"
|
|
|
|
|
|
|
|
#include "tinsel/config.h"
|
|
|
|
#include "tinsel/sound.h"
|
|
|
|
#include "tinsel/music.h"
|
|
|
|
|
|
|
|
namespace Tinsel {
|
|
|
|
|
|
|
|
//--------------------------- Midi data -------------------------------------
|
|
|
|
|
|
|
|
// sound buffer structure used for MIDI data and samples
|
|
|
|
struct SOUND_BUFFER {
|
|
|
|
uint8 *pDat; // pointer to actual buffer
|
|
|
|
uint32 size; // size of the buffer
|
|
|
|
};
|
|
|
|
|
|
|
|
// get set when music driver is installed
|
|
|
|
//static MDI_DRIVER *mDriver;
|
|
|
|
//static HSEQUENCE mSeqHandle;
|
|
|
|
|
|
|
|
// if non-zero this is the index position of the next MIDI sequence to play
|
|
|
|
static uint32 dwMidiIndex = 0;
|
|
|
|
|
|
|
|
// MIDI buffer
|
|
|
|
static SOUND_BUFFER midiBuffer = { 0, 0 };
|
|
|
|
|
2008-07-24 10:31:37 +00:00
|
|
|
static SCNHANDLE currentMidi = 0;
|
|
|
|
static bool currentLoop = false;
|
2008-07-23 09:02:47 +00:00
|
|
|
|
|
|
|
const SCNHANDLE midiOffsetsGRAVersion[] = {
|
|
|
|
4, 4534, 14298, 18828, 23358, 38888, 54418, 57172, 59926, 62450,
|
|
|
|
62952, 67482, 72258, 74538, 79314, 87722, 103252, 115176, 127100, 127898,
|
|
|
|
130256, 132614, 134972, 137330, 139688, 150196, 152554, 154912, 167422, 174762,
|
|
|
|
182102, 194612, 198880, 199536, 206128, 206380, 216372, 226364, 235676, 244988,
|
|
|
|
249098, 249606, 251160, 252714, 263116, 268706, 274296, 283562, 297986, 304566,
|
|
|
|
312028, 313524, 319192, 324860, 331772, 336548, 336838, 339950, 343062, 346174,
|
|
|
|
349286, 356246, 359358, 360434, 361510, 369966, 374366, 382822, 384202, 394946,
|
|
|
|
396022, 396730, 399524, 401020, 403814, 418364, 419466, 420568, 425132, 433540,
|
|
|
|
434384, 441504, 452132, 462760, 472804, 486772, 491302, 497722, 501260, 507680,
|
|
|
|
509726, 521858, 524136, 525452, 533480, 538236, 549018, 559870, 564626, 565306,
|
|
|
|
566734, 567616, 570144, 574102, 574900, 582518, 586350, 600736, 604734, 613812,
|
|
|
|
616566, 619626, 623460, 627294, 631128, 634188, 648738, 663288, 667864, 681832,
|
|
|
|
682048, 683014, 688908, 689124, 698888, 708652, 718416, 728180, 737944, 747708,
|
|
|
|
752238, 765522, 766554, 772944, 774546, 776148, 776994, 781698, 786262, 789016,
|
|
|
|
794630, 796422, 798998
|
|
|
|
};
|
|
|
|
|
|
|
|
const SCNHANDLE midiOffsetsSCNVersion[] = {
|
|
|
|
4, 4504, 11762, 21532, 26070, 28754, 33254, 40512, 56310, 72108,
|
|
|
|
74864, 77620, 80152, 80662, 85200, 89982, 92268, 97050, 105466, 121264,
|
|
|
|
133194, 145124, 145928, 148294, 150660, 153026, 155392, 157758, 168272, 170638,
|
|
|
|
173004, 185522, 192866, 200210, 212728, 217000, 217662, 224254, 224756, 234754,
|
|
|
|
244752, 245256, 245950, 255256, 264562, 268678, 269192, 270752, 272312, 282712,
|
|
|
|
288312, 293912, 303186, 317624, 324210, 331680, 333208, 338884, 344560, 351478,
|
|
|
|
356262, 356552, 359670, 362788, 365906, 369024, 376014, 379132, 380214, 381296,
|
|
|
|
389758, 394164, 402626, 404012, 414762, 415844, 416552, 419352, 420880, 423680,
|
|
|
|
438236, 439338, 440440, 445010, 453426, 454276, 461398, 472032, 482666, 492716,
|
|
|
|
506690, 511226, 517654, 521198, 527626, 529676, 541814, 546210, 547532, 555562,
|
|
|
|
560316, 571104, 581962, 586716, 587402, 588836, 589718, 592246, 596212, 597016,
|
|
|
|
604636, 608474, 622862, 626860, 635944, 638700, 641456, 645298, 649140, 652982,
|
|
|
|
655738, 670294, 684850, 689432, 703628, 703850, 704816, 706350, 706572, 716342,
|
|
|
|
726112, 735882, 745652, 755422, 765192, 774962, 784732, 794502, 804272, 814042,
|
|
|
|
823812, 832996, 846286, 847324, 853714, 855324, 856934, 857786, 862496, 867066,
|
|
|
|
869822, 875436, 877234, 879818
|
|
|
|
};
|
|
|
|
|
|
|
|
// TODO: finish this (currently unmapped tracks are 0)
|
|
|
|
const int enhancedAudioSCNVersion[] = {
|
|
|
|
0, 0, 2, 0, 0, 0, 0, 3, 3, 4,
|
|
|
|
4, 0, 0, 0, 0, 0, 0, 10, 3, 11,
|
|
|
|
11, 0, 13, 13, 13, 13, 13, 0, 13, 13,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 24, 0, 0, 27, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 55, 56, 56, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, 0, 0, 0, 4, 4, 83, 83, 83, 4,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 2, 2,
|
|
|
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0, 52, 4,
|
|
|
|
0, 0, 0, 0
|
|
|
|
};
|
|
|
|
|
|
|
|
int GetTrackNumber(SCNHANDLE hMidi) {
|
|
|
|
if (_vm->getFeatures() & GF_SCNFILES) {
|
|
|
|
for (int i = 0; i < ARRAYSIZE(midiOffsetsSCNVersion); i++) {
|
|
|
|
if (midiOffsetsSCNVersion[i] == hMidi)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (int i = 0; i < ARRAYSIZE(midiOffsetsGRAVersion); i++) {
|
|
|
|
if (midiOffsetsGRAVersion[i] == hMidi)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
SCNHANDLE GetTrackOffset(int trackNumber) {
|
|
|
|
if (_vm->getFeatures() & GF_SCNFILES) {
|
|
|
|
assert(trackNumber < ARRAYSIZE(midiOffsetsSCNVersion));
|
|
|
|
return midiOffsetsSCNVersion[trackNumber];
|
|
|
|
} else {
|
|
|
|
assert(trackNumber < ARRAYSIZE(midiOffsetsGRAVersion));
|
|
|
|
return midiOffsetsGRAVersion[trackNumber];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Plays the specified MIDI sequence through the sound driver.
|
|
|
|
* @param dwFileOffset File offset of MIDI sequence data
|
|
|
|
* @param bLoop Whether to loop the sequence
|
|
|
|
*/
|
|
|
|
bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
|
|
|
|
currentMidi = dwFileOffset;
|
|
|
|
currentLoop = bLoop;
|
|
|
|
|
|
|
|
if (volMidi != 0) {
|
|
|
|
SetMidiVolume(volMidi);
|
|
|
|
// Support for compressed music from the music enhancement project
|
|
|
|
AudioCD.stop();
|
|
|
|
|
|
|
|
int trackNumber = GetTrackNumber(dwFileOffset);
|
|
|
|
if (trackNumber >= 0) {
|
|
|
|
#if 0
|
|
|
|
// TODO: GRA version
|
|
|
|
int track = enhancedAudioSCNVersion[trackNumber];
|
|
|
|
if (track > 0)
|
|
|
|
AudioCD.play(track, -1, 0, 0);
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
warning("Unknown MIDI offset %d", dwFileOffset);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (AudioCD.isPlaying())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set file offset for this sequence
|
|
|
|
dwMidiIndex = dwFileOffset;
|
|
|
|
|
|
|
|
// the index and length of the last tune loaded
|
|
|
|
static uint32 dwLastMidiIndex;
|
|
|
|
static uint32 dwLastSeqLen;
|
|
|
|
|
|
|
|
uint32 dwSeqLen = 0; // length of the sequence
|
|
|
|
|
|
|
|
if (dwMidiIndex == 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (dwMidiIndex != dwLastMidiIndex) {
|
|
|
|
Common::File midiStream;
|
|
|
|
|
|
|
|
// open MIDI sequence file in binary mode
|
|
|
|
if (!midiStream.open(MIDI_FILE))
|
|
|
|
error("Cannot find file %s", MIDI_FILE);
|
|
|
|
|
|
|
|
// update index of last tune loaded
|
|
|
|
dwLastMidiIndex = dwMidiIndex;
|
|
|
|
|
|
|
|
// move to correct position in the file
|
|
|
|
midiStream.seek(dwMidiIndex, SEEK_SET);
|
|
|
|
|
|
|
|
// read the length of the sequence
|
|
|
|
dwSeqLen = midiStream.readUint32LE();
|
|
|
|
|
|
|
|
// make sure buffer is large enough for this sequence
|
|
|
|
assert(dwSeqLen > 0 && dwSeqLen <= midiBuffer.size);
|
|
|
|
|
|
|
|
// stop any currently playing tune
|
|
|
|
_vm->_music->stop();
|
|
|
|
|
|
|
|
// read the sequence
|
|
|
|
if (midiStream.read(midiBuffer.pDat, dwSeqLen) != dwSeqLen)
|
|
|
|
error("File %s is corrupt", MIDI_FILE);
|
|
|
|
|
|
|
|
midiStream.close();
|
|
|
|
|
|
|
|
_vm->_music->playXMIDI(midiBuffer.pDat, dwSeqLen, bLoop);
|
|
|
|
|
|
|
|
// Store the length
|
|
|
|
dwLastSeqLen = dwSeqLen;
|
|
|
|
} else {
|
|
|
|
// dwMidiIndex == dwLastMidiIndex
|
|
|
|
_vm->_music->stop();
|
|
|
|
_vm->_music->playXMIDI(midiBuffer.pDat, dwSeqLen, bLoop);
|
|
|
|
}
|
|
|
|
|
|
|
|
// allow another sequence to play
|
|
|
|
dwMidiIndex = 0;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns TRUE if a Midi tune is currently playing.
|
|
|
|
*/
|
|
|
|
bool MidiPlaying(void) {
|
|
|
|
if (AudioCD.isPlaying()) return true;
|
|
|
|
return _vm->_music->isPlaying();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stops any currently playing midi.
|
|
|
|
*/
|
|
|
|
bool StopMidi(void) {
|
|
|
|
currentMidi = 0;
|
|
|
|
currentLoop = false;
|
|
|
|
|
|
|
|
AudioCD.stop();
|
|
|
|
_vm->_music->stop();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the volume of the MIDI music.
|
|
|
|
*/
|
|
|
|
int GetMidiVolume() {
|
|
|
|
return volMidi;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the volume of the MIDI music.
|
|
|
|
* @param vol New volume - 0..MAXMIDIVOL
|
|
|
|
*/
|
|
|
|
void SetMidiVolume(int vol) {
|
|
|
|
assert(vol >= 0 && vol <= MAXMIDIVOL);
|
|
|
|
|
|
|
|
if (vol == 0 && volMidi == 0) {
|
|
|
|
// Nothing to do
|
|
|
|
} else if (vol == 0 && volMidi != 0) {
|
|
|
|
// Stop current midi sequence
|
|
|
|
AudioCD.stop();
|
|
|
|
StopMidi();
|
|
|
|
} else if (vol != 0 && volMidi == 0) {
|
|
|
|
// Perhaps restart last midi sequence
|
|
|
|
if (currentLoop) {
|
|
|
|
PlayMidiSequence(currentMidi, true);
|
|
|
|
_vm->_music->setVolume(vol);
|
|
|
|
}
|
|
|
|
} else if (vol != 0 && volMidi != 0) {
|
|
|
|
// Alter current volume
|
|
|
|
_vm->_music->setVolume(vol);
|
|
|
|
}
|
|
|
|
|
|
|
|
volMidi = vol;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Opens and inits all MIDI sequence files.
|
|
|
|
*/
|
|
|
|
void OpenMidiFiles(void) {
|
|
|
|
Common::File midiStream;
|
|
|
|
|
|
|
|
// Demo version has no midi file
|
|
|
|
if (_vm->getFeatures() & GF_DEMO)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (midiBuffer.pDat)
|
|
|
|
// already allocated
|
|
|
|
return;
|
|
|
|
|
|
|
|
// open MIDI sequence file in binary mode
|
|
|
|
if (!midiStream.open(MIDI_FILE))
|
|
|
|
error("Cannot find file %s", MIDI_FILE);
|
|
|
|
|
|
|
|
// gen length of the largest sequence
|
|
|
|
midiBuffer.size = midiStream.readUint32LE();
|
|
|
|
if (midiStream.ioFailed())
|
|
|
|
error("File %s is corrupt", MIDI_FILE);
|
|
|
|
|
|
|
|
if (midiBuffer.size) {
|
|
|
|
// allocate a buffer big enough for the largest MIDI sequence
|
|
|
|
if ((midiBuffer.pDat = (uint8 *)malloc(midiBuffer.size)) != NULL) {
|
|
|
|
// clear out the buffer
|
|
|
|
memset(midiBuffer.pDat, 0, midiBuffer.size);
|
|
|
|
// VMM_lock(midiBuffer.pDat, midiBuffer.size);
|
|
|
|
} else {
|
|
|
|
//mSeqHandle = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
midiStream.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeleteMidiBuffer() {
|
|
|
|
free(midiBuffer.pDat);
|
|
|
|
midiBuffer.pDat = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
MusicPlayer::MusicPlayer(MidiDriver *driver) : _parser(0), _driver(driver), _looping(false), _isPlaying(false) {
|
|
|
|
memset(_channel, 0, sizeof(_channel));
|
|
|
|
_masterVolume = 0;
|
|
|
|
this->open();
|
|
|
|
_xmidiParser = MidiParser::createParser_XMIDI();
|
|
|
|
}
|
|
|
|
|
|
|
|
MusicPlayer::~MusicPlayer() {
|
|
|
|
_driver->setTimerCallback(NULL, NULL);
|
|
|
|
stop();
|
|
|
|
this->close();
|
|
|
|
_xmidiParser->setMidiDriver(NULL);
|
|
|
|
delete _xmidiParser;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MusicPlayer::setVolume(int volume) {
|
|
|
|
// FIXME: Could we simply change MAXMIDIVOL to match ScummVM's range?
|
|
|
|
volume = CLIP((255 * volume) / MAXMIDIVOL, 0, 255);
|
|
|
|
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
|
|
|
|
|
|
|
|
if (_masterVolume == volume)
|
|
|
|
return;
|
|
|
|
|
|
|
|
_masterVolume = volume;
|
|
|
|
|
2008-08-20 09:15:59 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
|
|
|
|
2008-07-23 09:02:47 +00:00
|
|
|
for (int i = 0; i < 16; ++i) {
|
|
|
|
if (_channel[i]) {
|
|
|
|
_channel[i]->volume(_channelVolume[i] * _masterVolume / 255);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int MusicPlayer::open() {
|
|
|
|
// Don't ever call open without first setting the output driver!
|
|
|
|
if (!_driver)
|
|
|
|
return 255;
|
|
|
|
|
|
|
|
int ret = _driver->open();
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
_driver->setTimerCallback(this, &onTimer);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MusicPlayer::close() {
|
|
|
|
stop();
|
|
|
|
if (_driver)
|
|
|
|
_driver->close();
|
|
|
|
_driver = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MusicPlayer::send(uint32 b) {
|
|
|
|
byte channel = (byte)(b & 0x0F);
|
|
|
|
if ((b & 0xFFF0) == 0x07B0) {
|
|
|
|
// Adjust volume changes by master volume
|
|
|
|
byte volume = (byte)((b >> 16) & 0x7F);
|
|
|
|
_channelVolume[channel] = volume;
|
|
|
|
volume = volume * _masterVolume / 255;
|
|
|
|
b = (b & 0xFF00FFFF) | (volume << 16);
|
|
|
|
} else if ((b & 0xFFF0) == 0x007BB0) {
|
|
|
|
//Only respond to All Notes Off if this channel
|
|
|
|
//has currently been allocated
|
|
|
|
if (_channel[b & 0x0F])
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!_channel[channel])
|
|
|
|
_channel[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
|
|
|
|
|
|
|
|
if (_channel[channel]) {
|
|
|
|
_channel[channel]->send(b);
|
|
|
|
|
|
|
|
if ((b & 0xFFF0) == 0x0079B0) {
|
|
|
|
// We've just Reset All Controllers, so we need to
|
|
|
|
// re-adjust the volume. Otherwise, volume is reset to
|
|
|
|
// default whenever the music changes.
|
|
|
|
_channel[channel]->send(0x000007B0 | (((_channelVolume[channel] * _masterVolume) / 255) << 16) | channel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) {
|
|
|
|
switch (type) {
|
|
|
|
case 0x2F: // End of Track
|
|
|
|
if (_looping)
|
|
|
|
_parser->jumpToTick(0);
|
|
|
|
else
|
|
|
|
stop();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
//warning("Unhandled meta event: %02x", type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MusicPlayer::onTimer(void *refCon) {
|
|
|
|
MusicPlayer *music = (MusicPlayer *)refCon;
|
|
|
|
Common::StackLock lock(music->_mutex);
|
|
|
|
|
|
|
|
if (music->_isPlaying)
|
|
|
|
music->_parser->onTimer();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) {
|
|
|
|
if (_isPlaying)
|
|
|
|
return;
|
|
|
|
|
|
|
|
stop();
|
|
|
|
|
|
|
|
// It seems like not all music (the main menu music, for instance) set
|
|
|
|
// all the instruments explicitly. That means the music will sound
|
|
|
|
// different, depending on which music played before it. This appears
|
|
|
|
// to be a genuine glitch in the original. For consistency, reset all
|
|
|
|
// instruments to the default one (piano).
|
|
|
|
|
|
|
|
for (int i = 0; i < 16; i++) {
|
|
|
|
_driver->send(0xC0 | i, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load XMID resource data
|
|
|
|
|
|
|
|
if (_xmidiParser->loadMusic(midiData, size)) {
|
|
|
|
MidiParser *parser = _xmidiParser;
|
|
|
|
parser->setTrack(0);
|
|
|
|
parser->setMidiDriver(this);
|
|
|
|
parser->setTimerRate(getBaseTempo());
|
|
|
|
parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
|
|
|
|
|
|
|
|
_parser = parser;
|
|
|
|
|
|
|
|
_looping = loop;
|
|
|
|
_isPlaying = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MusicPlayer::stop() {
|
|
|
|
Common::StackLock lock(_mutex);
|
|
|
|
|
|
|
|
_isPlaying = false;
|
|
|
|
if (_parser) {
|
|
|
|
_parser->unloadMusic();
|
|
|
|
_parser = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MusicPlayer::pause() {
|
|
|
|
setVolume(-1);
|
|
|
|
_isPlaying = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MusicPlayer::resume() {
|
|
|
|
setVolume(GetMidiVolume());
|
|
|
|
_isPlaying = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CurrentMidiFacts(SCNHANDLE *pMidi, bool *pLoop) {
|
|
|
|
*pMidi = currentMidi;
|
|
|
|
*pLoop = currentLoop;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RestoreMidiFacts(SCNHANDLE Midi, bool Loop) {
|
|
|
|
AudioCD.stop();
|
|
|
|
StopMidi();
|
|
|
|
|
|
|
|
currentMidi = Midi;
|
|
|
|
currentLoop = Loop;
|
|
|
|
|
|
|
|
if (volMidi != 0 && Loop) {
|
|
|
|
PlayMidiSequence(currentMidi, true);
|
|
|
|
SetMidiVolume(volMidi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// Dumps all of the game's music in external XMIDI *.xmi files
|
|
|
|
void dumpMusic() {
|
|
|
|
Common::File midiFile;
|
2008-07-29 16:09:10 +00:00
|
|
|
Common::DumpFile outFile;
|
2008-07-23 09:02:47 +00:00
|
|
|
char outName[20];
|
|
|
|
midiFile.open(MIDI_FILE);
|
|
|
|
int outFileSize = 0;
|
|
|
|
char buffer[20000];
|
|
|
|
|
|
|
|
int total = (_vm->getFeatures() & GF_SCNFILES) ?
|
|
|
|
ARRAYSIZE(midiOffsetsSCNVersion) :
|
|
|
|
ARRAYSIZE(midiOffsetsGRAVersion);
|
|
|
|
|
|
|
|
for (int i = 0; i < total; i++) {
|
|
|
|
sprintf(outName, "track%03d.xmi", i + 1);
|
2008-07-29 16:09:10 +00:00
|
|
|
outFile.open(outName);
|
2008-07-23 09:02:47 +00:00
|
|
|
|
|
|
|
if (_vm->getFeatures() & GF_SCNFILES) {
|
|
|
|
if (i < total - 1)
|
|
|
|
outFileSize = midiOffsetsSCNVersion[i + 1] - midiOffsetsSCNVersion[i] - 4;
|
|
|
|
else
|
|
|
|
outFileSize = midiFile.size() - midiOffsetsSCNVersion[i] - 4;
|
|
|
|
|
|
|
|
midiFile.seek(midiOffsetsSCNVersion[i] + 4, SEEK_SET);
|
|
|
|
} else {
|
|
|
|
if (i < total - 1)
|
|
|
|
outFileSize = midiOffsetsGRAVersion[i + 1] - midiOffsetsGRAVersion[i] - 4;
|
|
|
|
else
|
|
|
|
outFileSize = midiFile.size() - midiOffsetsGRAVersion[i] - 4;
|
|
|
|
|
|
|
|
midiFile.seek(midiOffsetsGRAVersion[i] + 4, SEEK_SET);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(outFileSize < 20000);
|
|
|
|
midiFile.read(buffer, outFileSize);
|
|
|
|
outFile.write(buffer, outFileSize);
|
|
|
|
|
|
|
|
outFile.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
midiFile.close();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
} // End of namespace Made
|