mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-15 22:28:10 +00:00
236 lines
4.7 KiB
C++
236 lines
4.7 KiB
C++
/* 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 "prince/prince.h"
|
|
#include "prince/music.h"
|
|
#include "prince/musNum.h"
|
|
#include "prince/resource.h"
|
|
|
|
#include "common/archive.h"
|
|
#include "common/debug.h"
|
|
#include "audio/mididrv.h"
|
|
#include "audio/midiparser.h"
|
|
|
|
namespace Prince {
|
|
|
|
const char *MusicPlayer::_musTable[] = {
|
|
"",
|
|
"Battlfld.mid",
|
|
"Cave.mid",
|
|
"Cemetery.mid",
|
|
"Credits.mid",
|
|
"Fjord.mid",
|
|
"Guitar.mid",
|
|
"Hell.mid",
|
|
"Jingle.mid",
|
|
"Main.mid",
|
|
"Night.mid",
|
|
"Reality.mid",
|
|
"Sunlord.mid",
|
|
"Tavern.mid",
|
|
"Temple.mid",
|
|
"Boruta.mid",
|
|
"Intro.mid"
|
|
};
|
|
|
|
const uint8 MusicPlayer::_musRoomTable[] = {
|
|
0,
|
|
ROOM01MUS,
|
|
ROOM02MUS,
|
|
ROOM03MUS,
|
|
ROOM04MUS,
|
|
ROOM05MUS,
|
|
ROOM06MUS,
|
|
ROOM07MUS,
|
|
ROOM08MUS,
|
|
ROOM09MUS,
|
|
ROOM10MUS,
|
|
ROOM11MUS,
|
|
ROOM12MUS,
|
|
ROOM13MUS,
|
|
ROOM14MUS,
|
|
ROOM15MUS,
|
|
ROOM16MUS,
|
|
ROOM17MUS,
|
|
ROOM18MUS,
|
|
ROOM19MUS,
|
|
ROOM20MUS,
|
|
ROOM21MUS,
|
|
ROOM22MUS,
|
|
ROOM23MUS,
|
|
ROOM24MUS,
|
|
ROOM25MUS,
|
|
ROOM26MUS,
|
|
ROOM27MUS,
|
|
ROOM28MUS,
|
|
ROOM29MUS,
|
|
ROOM30MUS,
|
|
ROOM31MUS,
|
|
ROOM32MUS,
|
|
ROOM33MUS,
|
|
ROOM34MUS,
|
|
ROOM35MUS,
|
|
ROOM36MUS,
|
|
ROOM37MUS,
|
|
ROOM38MUS,
|
|
ROOM39MUS,
|
|
ROOM40MUS,
|
|
ROOM41MUS,
|
|
ROOM42MUS,
|
|
ROOM43MUS,
|
|
0,
|
|
0,
|
|
ROOM46MUS,
|
|
ROOM47MUS,
|
|
ROOM48MUS,
|
|
ROOM49MUS,
|
|
ROOM50MUS,
|
|
ROOM51MUS,
|
|
ROOM52MUS,
|
|
ROOM53MUS,
|
|
ROOM54MUS,
|
|
ROOM55MUS,
|
|
ROOM56MUS,
|
|
ROOM57MUS,
|
|
ROOM58MUS,
|
|
ROOM59MUS,
|
|
ROOM60MUS,
|
|
ROOM61MUS
|
|
};
|
|
|
|
|
|
MusicPlayer::MusicPlayer(PrinceEngine *vm) : _vm(vm) {
|
|
_data = nullptr;
|
|
_dataSize = 0;
|
|
_isGM = false;
|
|
|
|
MidiPlayer::createDriver();
|
|
|
|
int ret = _driver->open();
|
|
if (ret == 0) {
|
|
if (_nativeMT32)
|
|
_driver->sendMT32Reset();
|
|
else
|
|
_driver->sendGMReset();
|
|
|
|
_driver->setTimerCallback(this, &timerCallback);
|
|
}
|
|
}
|
|
|
|
MusicPlayer::~MusicPlayer() {
|
|
killMidi();
|
|
}
|
|
|
|
void MusicPlayer::killMidi() {
|
|
Audio::MidiPlayer::stop();
|
|
|
|
free(_data);
|
|
_data = nullptr;
|
|
}
|
|
|
|
void MusicPlayer::loadMidi(const char *name) {
|
|
Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(name);
|
|
if (!stream) {
|
|
warning("Can't load midi stream %s", name);
|
|
return;
|
|
}
|
|
|
|
stream = Resource::getDecompressedStream(stream);
|
|
|
|
// Stop any currently playing MIDI file
|
|
killMidi();
|
|
|
|
// Read in the data for the file
|
|
_dataSize = stream->size();
|
|
_data = (byte *)malloc(_dataSize);
|
|
stream->read(_data, _dataSize);
|
|
|
|
delete stream;
|
|
|
|
// Start playing the music
|
|
sndMidiStart();
|
|
}
|
|
|
|
void MusicPlayer::sndMidiStart() {
|
|
_isGM = true;
|
|
|
|
MidiParser *parser = MidiParser::createParser_SMF();
|
|
if (parser->loadMusic(_data, _dataSize)) {
|
|
parser->setTrack(0);
|
|
parser->setMidiDriver(this);
|
|
parser->setTimerRate(_driver->getBaseTempo());
|
|
parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
|
|
|
|
_parser = parser;
|
|
|
|
syncVolume();
|
|
|
|
// Al the tracks are supposed to loop
|
|
_isLooping = true;
|
|
_isPlaying = true;
|
|
}
|
|
}
|
|
|
|
void MusicPlayer::send(uint32 b) {
|
|
if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) {
|
|
b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
|
|
}
|
|
|
|
Audio::MidiPlayer::send(b);
|
|
}
|
|
|
|
void MusicPlayer::sendToChannel(byte channel, uint32 b) {
|
|
if (!_channelsTable[channel]) {
|
|
_channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
|
|
// If a new channel is allocated during the playback, make sure
|
|
// its volume is correctly initialized.
|
|
if (_channelsTable[channel])
|
|
_channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255);
|
|
}
|
|
|
|
if (_channelsTable[channel])
|
|
_channelsTable[channel]->send(b);
|
|
}
|
|
|
|
bool PrinceEngine::loadMusic(int musNumber) {
|
|
uint8 midiNumber = MusicPlayer::_musRoomTable[musNumber];
|
|
if (midiNumber) {
|
|
if (midiNumber != 100) {
|
|
if (_currentMidi != midiNumber) {
|
|
_currentMidi = midiNumber;
|
|
const char *musName = MusicPlayer::_musTable[_currentMidi];
|
|
_midiPlayer->loadMidi(musName);
|
|
}
|
|
}
|
|
} else {
|
|
stopMusic();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void PrinceEngine::stopMusic() {
|
|
if (_midiPlayer->isPlaying()) {
|
|
_midiPlayer->stop();
|
|
}
|
|
}
|
|
|
|
} // End of namespace Prince
|