Initial commit
This commit is contained in:
633
engines/sherlock/music.cpp
Normal file
633
engines/sherlock/music.cpp
Normal file
@@ -0,0 +1,633 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/algorithm.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/mutex.h"
|
||||
#include "sherlock/sherlock.h"
|
||||
#include "sherlock/music.h"
|
||||
#include "sherlock/scalpel/drivers/mididriver.h"
|
||||
#include "audio/audiostream.h"
|
||||
// for Miles Audio (Sherlock Holmes 2)
|
||||
#include "audio/miles.h"
|
||||
// for 3DO digital music
|
||||
#include "audio/decoders/aiff.h"
|
||||
|
||||
namespace Sherlock {
|
||||
|
||||
#define NUM_SONGS 45
|
||||
|
||||
/* This tells which song to play in each room, 0 = no song played */
|
||||
static const char ROOM_SONG[62] = {
|
||||
0, 20, 43, 6, 11, 2, 8, 15, 6, 28,
|
||||
6, 38, 7, 32, 16, 5, 8, 41, 9, 22,
|
||||
10, 23, 4, 39, 19, 24, 13, 27, 0, 30,
|
||||
3, 21, 26, 25, 16, 29, 1, 1, 18, 12,
|
||||
1, 17, 17, 31, 17, 34, 36, 7, 20, 20,
|
||||
33, 8, 44, 40, 42, 35, 0, 0, 0, 12,
|
||||
12
|
||||
};
|
||||
|
||||
static const char *const SONG_NAMES[NUM_SONGS] = {
|
||||
"SINGERF", "CHEMIST", "TOBAC", "EQUEST", "MORTUARY", "DOCKS", "LSTUDY",
|
||||
"LORD", "BOY", "PERFUM1", "BAKER1", "BAKER2", "OPERA1", "HOLMES",
|
||||
"FFLAT", "OP1FLAT", "ZOO", "SROOM", "FLOWERS", "YARD", "TAXID",
|
||||
"PUB1", "VICTIM", "RUGBY", "DORM", "SHERMAN", "LAWYER", "THEATRE",
|
||||
"DETECT", "OPERA4", "POOL", "SOOTH", "ANNA1", "ANNA2", "PROLOG3",
|
||||
"PAWNSHOP", "MUSICBOX", "MOZART1", "ROBHUNT", "PANCRAS1", "PANCRAS2", "LORDKILL",
|
||||
"BLACKWEL", "RESCUE", "MAP"
|
||||
};
|
||||
|
||||
MidiParser_SH::MidiParser_SH() {
|
||||
_ppqn = 1;
|
||||
setTempo(16667);
|
||||
_data = nullptr;
|
||||
_beats = 0;
|
||||
_lastEvent = 0;
|
||||
_trackEnd = nullptr;
|
||||
|
||||
_musData = nullptr;
|
||||
_musDataSize = 0;
|
||||
}
|
||||
|
||||
MidiParser_SH::~MidiParser_SH() {
|
||||
Common::StackLock lock(_mutex);
|
||||
unloadMusic();
|
||||
_driver = nullptr;
|
||||
}
|
||||
|
||||
void MidiParser_SH::parseNextEvent(EventInfo &info) {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
// warning("parseNextEvent");
|
||||
|
||||
const byte *playPos = _position._subtracks[0]._playPos;
|
||||
|
||||
// there is no delta right at the start of the music data
|
||||
// this order is essential, otherwise notes will get delayed or even go missing
|
||||
if (playPos != _tracks[0][0]) {
|
||||
info.delta = *(playPos++);
|
||||
} else {
|
||||
info.delta = 0;
|
||||
}
|
||||
|
||||
info.start = playPos;
|
||||
|
||||
info.event = *(playPos++);
|
||||
//warning("Event %x", info.event);
|
||||
_position._subtracks[0]._runningStatus = info.event;
|
||||
|
||||
switch (info.command()) {
|
||||
case 0xC: { // program change
|
||||
int idx = *playPos++;
|
||||
info.basic.param1 = idx & 0x7f;
|
||||
info.basic.param2 = 0;
|
||||
}
|
||||
break;
|
||||
case 0xD:
|
||||
info.basic.param1 = *(playPos++);
|
||||
info.basic.param2 = 0;
|
||||
break;
|
||||
|
||||
case 0xB:
|
||||
info.basic.param1 = *(playPos++);
|
||||
info.basic.param2 = *(playPos++);
|
||||
info.length = 0;
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
case 0x9:
|
||||
case 0xA:
|
||||
case 0xE:
|
||||
info.basic.param1 = *(playPos++);
|
||||
info.basic.param2 = *(playPos++);
|
||||
if (info.command() == 0x9 && info.basic.param2 == 0) {
|
||||
// NoteOn with param2==0 is a NoteOff
|
||||
info.event = info.channel() | 0x80;
|
||||
}
|
||||
info.length = 0;
|
||||
break;
|
||||
case 0xF:
|
||||
if (info.event == 0xFF) {
|
||||
error("SysEx META event 0xFF");
|
||||
|
||||
byte type = *(playPos++);
|
||||
switch(type) {
|
||||
case 0x2F:
|
||||
// End of Track
|
||||
allNotesOff();
|
||||
stopPlaying();
|
||||
unloadMusic();
|
||||
return;
|
||||
case 0x51:
|
||||
warning("TODO: 0xFF / 0x51");
|
||||
break;
|
||||
default:
|
||||
warning("TODO: 0xFF / %x Unknown", type);
|
||||
break;
|
||||
}
|
||||
} else if (info.event == 0xFC) {
|
||||
// Official End-Of-Track signal
|
||||
debugC(kDebugLevelMusic, "Music: System META event 0xFC");
|
||||
|
||||
byte type = *(playPos++);
|
||||
switch (type) {
|
||||
case 0x80: // end of track, triggers looping
|
||||
debugC(kDebugLevelMusic, "Music: META event triggered looping");
|
||||
jumpToTick(0, true, true, false);
|
||||
return;
|
||||
case 0x81: // end of track, stop playing
|
||||
debugC(kDebugLevelMusic, "Music: META event triggered music stop");
|
||||
stopPlaying();
|
||||
unloadMusic();
|
||||
return;
|
||||
default:
|
||||
error("MidiParser_SH::parseNextEvent: Unknown META event 0xFC type %x", type);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
warning("TODO: %x / Unknown", info.event);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
warning("MidiParser_SH::parseNextEvent: Unsupported event code %x", info.event);
|
||||
break;
|
||||
}// switch (info.command())
|
||||
|
||||
_position._subtracks[0]._playPos = playPos;
|
||||
}
|
||||
|
||||
bool MidiParser_SH::loadMusic(const byte *musData, uint32 musDataSize) {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
debugC(kDebugLevelMusic, "Music: loadMusic()");
|
||||
unloadMusic();
|
||||
|
||||
_musData = musData;
|
||||
_musDataSize = musDataSize;
|
||||
|
||||
const byte *headerPtr = _musData + 12; // skip over the already checked SPACE header
|
||||
const byte *pos = headerPtr;
|
||||
|
||||
uint16 headerSize = READ_LE_UINT16(headerPtr);
|
||||
assert(headerSize == 0x7F); // Security check
|
||||
|
||||
// Skip over header
|
||||
pos += headerSize;
|
||||
|
||||
_lastEvent = 0;
|
||||
_trackEnd = _musData + _musDataSize;
|
||||
|
||||
_numTracks = 1;
|
||||
_numSubtracks[0] = 1;
|
||||
_tracks[0][0] = pos;
|
||||
|
||||
_ppqn = 1;
|
||||
setTempo(16667);
|
||||
setTrack(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MidiParser_SH::unloadMusic() {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
if (_musData) {
|
||||
delete[] _musData;
|
||||
_musData = nullptr;
|
||||
_musDataSize = 0;
|
||||
}
|
||||
|
||||
MidiParser::unloadMusic();
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
Music::Music(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
|
||||
_midiDriver = nullptr;
|
||||
_midiParser = nullptr;
|
||||
_musicType = MT_NULL;
|
||||
_musicPlaying = false;
|
||||
_midiOption = false;
|
||||
_midiMusicData = nullptr;
|
||||
_musicVolume = ConfMan.hasKey("music_volume") ? ConfMan.getInt("music_volume") : 255;
|
||||
_musicOn = false;
|
||||
|
||||
if (IS_3DO) {
|
||||
// 3DO - uses digital samples for music
|
||||
_musicOn = ConfMan.hasKey("music_mute") ? !ConfMan.getBool("music_mute") : true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_vm->_interactiveFl)
|
||||
_vm->_res->addToCache("MUSIC.LIB");
|
||||
|
||||
MidiDriver::DeviceHandle dev;
|
||||
|
||||
if (IS_SERRATED_SCALPEL) {
|
||||
// Serrated Scalpel: used an internal Electronic Arts .MUS music engine
|
||||
_midiParser = new MidiParser_SH();
|
||||
dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MT32);
|
||||
_musicType = MidiDriver::getMusicType(dev);
|
||||
|
||||
switch (_musicType) {
|
||||
case MT_ADLIB:
|
||||
_midiDriver = MidiDriver_SH_AdLib_create();
|
||||
break;
|
||||
case MT_MT32:
|
||||
_midiDriver = MidiDriver_MT32_create();
|
||||
break;
|
||||
case MT_GM:
|
||||
if (ConfMan.getBool("native_mt32")) {
|
||||
_midiDriver = MidiDriver_MT32_create();
|
||||
_musicType = MT_MT32;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Create default one
|
||||
// I guess we shouldn't do this anymore
|
||||
//_midiDriver = MidiDriver::createMidi(dev);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Rose Tattooo: seems to use Miles Audio 3
|
||||
_midiParser = MidiParser::createParser_XMIDI();
|
||||
dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
|
||||
_musicType = MidiDriver::getMusicType(dev);
|
||||
|
||||
switch (_musicType) {
|
||||
case MT_ADLIB:
|
||||
// SAMPLE.AD -> regular AdLib instrument data
|
||||
// SAMPLE.OPL -> OPL-3 instrument data
|
||||
// although in case of Rose Tattoo both files are exactly the same
|
||||
_midiDriver = Audio::MidiDriver_Miles_AdLib_create("SAMPLE.AD", "SAMPLE.OPL");
|
||||
break;
|
||||
case MT_MT32:
|
||||
// Sherlock Holmes 2 does not have a MT32 timbre file
|
||||
_midiDriver = Audio::MidiDriver_Miles_MT32_create("");
|
||||
break;
|
||||
case MT_GM:
|
||||
if (ConfMan.getBool("native_mt32")) {
|
||||
_midiDriver = Audio::MidiDriver_Miles_MT32_create("");
|
||||
_musicType = MT_MT32;
|
||||
} else {
|
||||
_midiDriver = MidiDriver::createMidi(dev);
|
||||
_musicType = MT_GM;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Do not create anything
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_midiDriver) {
|
||||
int ret = _midiDriver->open();
|
||||
if (ret == 0) {
|
||||
// Reset is done inside our MIDI driver
|
||||
_midiDriver->setTimerCallback(_midiParser, &_midiParser->timerCallback);
|
||||
}
|
||||
_midiParser->setMidiDriver(_midiDriver);
|
||||
_midiParser->setTimerRate(_midiDriver->getBaseTempo());
|
||||
|
||||
if (IS_SERRATED_SCALPEL) {
|
||||
if (_musicType == MT_MT32) {
|
||||
// Upload patches
|
||||
Common::SeekableReadStream *MT32driverStream = _vm->_res->load("MTHOM.DRV", "MUSIC.LIB");
|
||||
|
||||
if (!MT32driverStream)
|
||||
error("Music: could not load MTHOM.DRV, critical");
|
||||
|
||||
byte *MT32driverData = new byte[MT32driverStream->size()];
|
||||
int32 MT32driverDataSize = MT32driverStream->size();
|
||||
assert(MT32driverData);
|
||||
|
||||
MT32driverStream->read(MT32driverData, MT32driverDataSize);
|
||||
delete MT32driverStream;
|
||||
|
||||
assert(MT32driverDataSize > 12);
|
||||
byte *MT32driverDataPtr = MT32driverData + 12;
|
||||
MT32driverDataSize -= 12;
|
||||
|
||||
MidiDriver_MT32_uploadPatches(_midiDriver, MT32driverDataPtr, MT32driverDataSize);
|
||||
delete[] MT32driverData;
|
||||
}
|
||||
}
|
||||
|
||||
_musicOn = ConfMan.hasKey("music_mute") ? !ConfMan.getBool("music_mute") : true;
|
||||
}
|
||||
}
|
||||
|
||||
Music::~Music() {
|
||||
stopMusic();
|
||||
if (_midiDriver) {
|
||||
_midiDriver->setTimerCallback(this, nullptr);
|
||||
}
|
||||
if (_midiParser) {
|
||||
_midiParser->stopPlaying();
|
||||
delete _midiParser;
|
||||
_midiParser = nullptr;
|
||||
}
|
||||
if (_midiDriver) {
|
||||
_midiDriver->close();
|
||||
delete _midiDriver;
|
||||
}
|
||||
}
|
||||
|
||||
bool Music::loadSong(int songNumber) {
|
||||
debugC(kDebugLevelMusic, "Music: loadSong()");
|
||||
|
||||
if(songNumber == 100)
|
||||
songNumber = 55;
|
||||
else if(songNumber == 70)
|
||||
songNumber = 54;
|
||||
|
||||
if((songNumber > 60) || (songNumber < 1))
|
||||
return false;
|
||||
|
||||
songNumber = ROOM_SONG[songNumber];
|
||||
|
||||
if(songNumber == 0)
|
||||
songNumber = 12;
|
||||
|
||||
if((songNumber > NUM_SONGS) || (songNumber < 1))
|
||||
return false;
|
||||
|
||||
Common::String songName = Common::String(SONG_NAMES[songNumber - 1]);
|
||||
|
||||
freeSong(); // free any song that is currently loaded
|
||||
stopMusic();
|
||||
|
||||
if (!playMusic(songName))
|
||||
return false;
|
||||
|
||||
startSong();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Music::loadSong(const Common::String &songName) {
|
||||
freeSong(); // free any song that is currently loaded
|
||||
stopMusic();
|
||||
|
||||
if (!playMusic(songName))
|
||||
return false;
|
||||
|
||||
startSong();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Music::syncMusicSettings() {
|
||||
_musicOn = !ConfMan.getBool("mute") && !ConfMan.getBool("music_mute");
|
||||
}
|
||||
|
||||
bool Music::playMusic(const Common::String &name) {
|
||||
if (!_musicOn)
|
||||
return false;
|
||||
|
||||
_nextSongName = _currentSongName = name;
|
||||
debugC(kDebugLevelMusic, "Music: playMusic('%s')", name.c_str());
|
||||
|
||||
if (!IS_3DO) {
|
||||
// MIDI based
|
||||
if (!_midiDriver)
|
||||
return false;
|
||||
|
||||
Common::String midiMusicName = (IS_SERRATED_SCALPEL) ? name + ".MUS" : name + ".XMI";
|
||||
Common::SeekableReadStream *stream = _vm->_res->load(Common::Path(midiMusicName), "MUSIC.LIB");
|
||||
|
||||
byte *midiMusicData = new byte[stream->size()];
|
||||
int32 midiMusicDataSize = stream->size();
|
||||
|
||||
stream->read(midiMusicData, midiMusicDataSize);
|
||||
delete stream;
|
||||
|
||||
if (midiMusicDataSize < 14) {
|
||||
warning("Music: not enough data in music file");
|
||||
delete[] midiMusicData;
|
||||
return false;
|
||||
}
|
||||
|
||||
byte *dataPos = midiMusicData;
|
||||
uint32 dataSize = midiMusicDataSize;
|
||||
|
||||
if (IS_SERRATED_SCALPEL) {
|
||||
if (memcmp(" ", dataPos, 12)) {
|
||||
warning("Music: expected header not found in music file");
|
||||
delete[] midiMusicData;
|
||||
return false;
|
||||
}
|
||||
dataPos += 12;
|
||||
dataSize -= 12;
|
||||
|
||||
if (dataSize < 0x7F) {
|
||||
warning("Music: expected music header not found in music file");
|
||||
delete[] midiMusicData;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16 headerSize = READ_LE_UINT16(dataPos);
|
||||
if (headerSize != 0x7F) {
|
||||
warning("Music: header is not as expected");
|
||||
delete[] midiMusicData;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (memcmp("FORM", dataPos, 4)) {
|
||||
warning("Music: expected header not found in music file");
|
||||
delete[] midiMusicData;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_SERRATED_SCALPEL) {
|
||||
// Pass the music data to the driver as well
|
||||
// because channel mapping and a few other things inside the header
|
||||
switch (_musicType) {
|
||||
case MT_ADLIB:
|
||||
MidiDriver_SH_AdLib_newMusicData(_midiDriver, dataPos, dataSize);
|
||||
break;
|
||||
|
||||
case MT_MT32:
|
||||
MidiDriver_MT32_newMusicData(_midiDriver, dataPos, dataSize);
|
||||
break;
|
||||
|
||||
default:
|
||||
// should never happen
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_midiMusicData = midiMusicData;
|
||||
_midiParser->loadMusic(midiMusicData, midiMusicDataSize);
|
||||
} else {
|
||||
// 3DO: sample based
|
||||
Audio::AudioStream *musicStream;
|
||||
Common::Path digitalMusicName("music/");
|
||||
digitalMusicName.appendInPlace(name + "_MW22.aifc");
|
||||
|
||||
if (isPlaying()) {
|
||||
_mixer->stopHandle(_digitalMusicHandle);
|
||||
}
|
||||
|
||||
Common::File *digitalMusicFile = new Common::File();
|
||||
if (!digitalMusicFile->open(digitalMusicName)) {
|
||||
warning("playMusic: can not open 3DO music '%s'", digitalMusicName.toString().c_str());
|
||||
delete digitalMusicFile;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to load the given file as AIFF/AIFC
|
||||
musicStream = Audio::makeAIFFStream(digitalMusicFile, DisposeAfterUse::YES);
|
||||
if (!musicStream) {
|
||||
warning("playMusic: can not load 3DO music '%s'", digitalMusicName.toString().c_str());
|
||||
return false;
|
||||
}
|
||||
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_digitalMusicHandle, musicStream);
|
||||
}
|
||||
|
||||
_musicPlaying = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Music::stopMusic() {
|
||||
freeSong();
|
||||
}
|
||||
|
||||
void Music::startSong() {
|
||||
// No implementation needed for ScummVM
|
||||
}
|
||||
|
||||
void Music::freeSong() {
|
||||
if (!IS_3DO) {
|
||||
if (_midiParser->isPlaying())
|
||||
_midiParser->stopPlaying();
|
||||
|
||||
// Free the MIDI MUS data buffer
|
||||
_midiParser->unloadMusic();
|
||||
}
|
||||
|
||||
_midiMusicData = nullptr;
|
||||
_musicPlaying = false;
|
||||
}
|
||||
|
||||
bool Music::isPlaying() {
|
||||
if (!IS_3DO) {
|
||||
// MIDI based
|
||||
return _midiParser->isPlaying();
|
||||
} else {
|
||||
// 3DO: sample based
|
||||
return _mixer->isSoundHandleActive(_digitalMusicHandle);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the current music position in milliseconds
|
||||
uint32 Music::getCurrentPosition() {
|
||||
if (!IS_3DO) {
|
||||
// MIDI based
|
||||
return (_midiParser->getTick() * 1000) / 60; // translate tick to millisecond
|
||||
} else {
|
||||
// 3DO: sample based
|
||||
return _mixer->getSoundElapsedTime(_digitalMusicHandle);
|
||||
}
|
||||
}
|
||||
|
||||
// This is used to wait for the music in certain situations like especially the intro
|
||||
// Note: the original game didn't do this, instead it just waited for certain amounts of time
|
||||
// We do this, so that the intro graphics + music work together even on faster/slower hardware.
|
||||
bool Music::waitUntilMSec(uint32 msecTarget, uint32 msecMax, uint32 additionalDelay, uint32 noMusicDelay) {
|
||||
uint32 msecCurrent = 0;
|
||||
|
||||
if (!isPlaying()) {
|
||||
return _vm->_events->delay(noMusicDelay, true);
|
||||
}
|
||||
while (1) {
|
||||
if (!isPlaying()) { // Music is not playing anymore -> we are done
|
||||
if (additionalDelay > 0) {
|
||||
if (!_vm->_events->delay(additionalDelay, true))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
msecCurrent = getCurrentPosition();
|
||||
//warning("waitUntilMSec: %lx", msecCurrent);
|
||||
|
||||
if ((!msecMax) || (msecCurrent <= msecMax)) {
|
||||
if (msecCurrent >= msecTarget) {
|
||||
if (additionalDelay > 0) {
|
||||
if (!_vm->_events->delay(additionalDelay, true))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!_vm->_events->delay(10, true))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Music::setMusicVolume(int volume) {
|
||||
_musicVolume = volume;
|
||||
_musicOn = volume > 0;
|
||||
_vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
|
||||
}
|
||||
|
||||
void Music::getSongNames(Common::StringArray &songs) {
|
||||
songs.clear();
|
||||
if (IS_SERRATED_SCALPEL) {
|
||||
if (IS_3DO) {
|
||||
Common::FSDirectory gameDirectory(ConfMan.getPath("path"));
|
||||
Common::FSDirectory *musicDirectory = gameDirectory.getSubDirectory("music");
|
||||
Common::ArchiveMemberList files;
|
||||
|
||||
musicDirectory->listMatchingMembers(files, "*_mw22.aifc");
|
||||
|
||||
for (Common::ArchiveMemberList::iterator i = files.begin(); i != files.end(); ++i) {
|
||||
Common::String name = (*i)->getName();
|
||||
name.erase(name.size() - 10);
|
||||
songs.push_back(name);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < ARRAYSIZE(SONG_NAMES); i++) {
|
||||
songs.push_back(SONG_NAMES[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Common::StringArray fileList;
|
||||
_vm->_res->getResourceNames("music.lib", fileList);
|
||||
for (Common::StringArray::iterator i = fileList.begin(); i != fileList.end(); ++i) {
|
||||
if ((*i).matchString("*.XMI", true)) {
|
||||
(*i).erase((*i).size() - 4);
|
||||
songs.push_back(*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
Common::sort(songs.begin(), songs.end());
|
||||
}
|
||||
|
||||
void Music::checkSongProgress() {
|
||||
if (!isPlaying()) {
|
||||
playMusic(_nextSongName);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Sherlock
|
||||
Reference in New Issue
Block a user