mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-13 21:31:53 +00:00
SAGA: Change Sage to use Audio::MidiPlayer
This commit is contained in:
parent
baeb28d0e1
commit
9e65daef3b
@ -44,15 +44,14 @@ namespace Saga {
|
||||
#define MUSIC_SUNSPOT 26
|
||||
|
||||
MusicDriver::MusicDriver() : _isGM(false) {
|
||||
memset(_channelsTable, 0, sizeof(_channelsTable));
|
||||
_masterVolume = 0;
|
||||
_nativeMT32 = ConfMan.getBool("native_mt32");
|
||||
|
||||
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
|
||||
_nativeMT32 = ((MidiDriver::getMusicType(dev) == MT_MT32) || ConfMan.getBool("native_mt32"));
|
||||
|
||||
_driver = MidiDriver::createMidi(dev);
|
||||
assert(_driver);
|
||||
_driverType = MidiDriver::getMusicType(dev);
|
||||
if (isMT32())
|
||||
if (_nativeMT32)
|
||||
_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
|
||||
|
||||
int retValue = _driver->open();
|
||||
@ -61,62 +60,76 @@ MusicDriver::MusicDriver() : _isGM(false) {
|
||||
_driver->sendMT32Reset();
|
||||
else
|
||||
_driver->sendGMReset();
|
||||
}
|
||||
}
|
||||
|
||||
MusicDriver::~MusicDriver() {
|
||||
_driver->close();
|
||||
delete _driver;
|
||||
}
|
||||
|
||||
void MusicDriver::setVolume(int volume) {
|
||||
volume = CLIP(volume, 0, 255);
|
||||
|
||||
if (_masterVolume == volume)
|
||||
return;
|
||||
|
||||
_masterVolume = volume;
|
||||
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (_channelsTable[i]) {
|
||||
_channelsTable[i]->volume(_channelsVolume[i] * _masterVolume / 255);
|
||||
}
|
||||
_driver->setTimerCallback(this, &timerCallback);
|
||||
}
|
||||
}
|
||||
|
||||
void MusicDriver::send(uint32 b) {
|
||||
byte channel = (byte)(b & 0x0F);
|
||||
if ((b & 0xFFF0) == 0x07B0) {
|
||||
// Adjust volume changes by master volume
|
||||
byte volume = (byte)((b >> 16) & 0x7F);
|
||||
_channelsVolume[channel] = volume;
|
||||
volume = volume * _masterVolume / 255;
|
||||
b = (b & 0xFF00FFFF) | (volume << 16);
|
||||
} else if ((b & 0xF0) == 0xC0 && !_isGM && !isMT32()) {
|
||||
if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) {
|
||||
// Remap MT32 instruments to General Midi
|
||||
b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
|
||||
} else if ((b & 0xFFF0) == 0x007BB0) {
|
||||
// Only respond to All Notes Off if this channel
|
||||
// has currently been allocated
|
||||
if (!_channelsTable[channel])
|
||||
return;
|
||||
}
|
||||
Audio::MidiPlayer::send(b);
|
||||
}
|
||||
|
||||
void MusicDriver::metaEvent(byte type, byte *data, uint16 length) {
|
||||
// TODO: Seems SAGA does not want / need to handle end-of-track events?
|
||||
}
|
||||
|
||||
void MusicDriver::play(SagaEngine *vm, ByteArray *buffer, bool loop) {
|
||||
if (buffer->size() < 4) {
|
||||
error("Music::play() wrong music resource size");
|
||||
}
|
||||
|
||||
if (!_channelsTable[channel])
|
||||
_channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
|
||||
else
|
||||
_channelsTable[channel]->send(b);
|
||||
// Check if the game is using XMIDI or SMF music
|
||||
if (vm->getGameId() == GID_IHNM && vm->isMacResources()) {
|
||||
// Just set an XMIDI parser for Mac IHNM for now
|
||||
_parser = MidiParser::createParser_XMIDI();
|
||||
} else {
|
||||
if (!memcmp(buffer->getBuffer(), "FORM", 4)) {
|
||||
_parser = MidiParser::createParser_XMIDI();
|
||||
// ITE had MT32 mapped instruments
|
||||
_isGM = (vm->getGameId() != GID_ITE);
|
||||
} else {
|
||||
_parser = MidiParser::createParser_SMF();
|
||||
// ITE with standalone MIDI files is General MIDI
|
||||
_isGM = (vm->getGameId() == GID_ITE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_parser->loadMusic(buffer->getBuffer(), buffer->size()))
|
||||
error("Music::play() wrong music resource");
|
||||
|
||||
_parser->setTrack(0);
|
||||
_parser->setMidiDriver(this);
|
||||
_parser->setTimerRate(_driver->getBaseTempo());
|
||||
_parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
|
||||
_parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);
|
||||
|
||||
// Handle music looping
|
||||
_parser->property(MidiParser::mpAutoLoop, loop);
|
||||
// _isLooping = loop;
|
||||
|
||||
_isPlaying = true;
|
||||
}
|
||||
|
||||
void MusicDriver::pause() {
|
||||
_isPlaying = false;
|
||||
}
|
||||
|
||||
void MusicDriver::resume() {
|
||||
_isPlaying = true;
|
||||
}
|
||||
|
||||
|
||||
Music::Music(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
|
||||
_currentVolume = 0;
|
||||
_currentMusicBuffer = NULL;
|
||||
_driver = new MusicDriver();
|
||||
_player = new MusicDriver();
|
||||
|
||||
_digitalMusicContext = _vm->_resource->getContext(GAME_DIGITALMUSICFILE);
|
||||
if (!_driver->isAdlib())
|
||||
if (!_player->isAdlib())
|
||||
_musicContext = _vm->_resource->getContext(GAME_MUSICFILE_GM);
|
||||
else
|
||||
_musicContext = _vm->_resource->getContext(GAME_MUSICFILE_FM);
|
||||
@ -153,55 +166,19 @@ Music::Music(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the game is using XMIDI or SMF music
|
||||
if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) {
|
||||
// Just set an XMIDI parser for Mac IHNM for now
|
||||
_parser = MidiParser::createParser_XMIDI();
|
||||
} else {
|
||||
ByteArray resourceData;
|
||||
int resourceId = (_vm->getGameId() == GID_ITE ? 9 : 0);
|
||||
_vm->_resource->loadResource(_musicContext, resourceId, resourceData);
|
||||
if (resourceData.size() < 4) {
|
||||
error("Music::Music Unable to load midi resource data");
|
||||
}
|
||||
if (!memcmp(resourceData.getBuffer(), "FORM", 4)) {
|
||||
_parser = MidiParser::createParser_XMIDI();
|
||||
// ITE had MT32 mapped instruments
|
||||
_driver->setGM(_vm->getGameId() != GID_ITE);
|
||||
} else {
|
||||
_parser = MidiParser::createParser_SMF();
|
||||
// ITE with standalone MIDI files is General MIDI
|
||||
_driver->setGM(_vm->getGameId() == GID_ITE);
|
||||
}
|
||||
}
|
||||
|
||||
_parser->setMidiDriver(_driver);
|
||||
_parser->setTimerRate(_driver->getBaseTempo());
|
||||
_parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
|
||||
_parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);
|
||||
|
||||
_digitalMusic = false;
|
||||
}
|
||||
|
||||
Music::~Music() {
|
||||
_vm->getTimerManager()->removeTimerProc(&musicVolumeGaugeCallback);
|
||||
_mixer->stopHandle(_musicHandle);
|
||||
_driver->setTimerCallback(NULL, NULL);
|
||||
delete _driver;
|
||||
_parser->setMidiDriver(NULL);
|
||||
delete _parser;
|
||||
delete _player;
|
||||
}
|
||||
|
||||
void Music::musicVolumeGaugeCallback(void *refCon) {
|
||||
((Music *)refCon)->musicVolumeGauge();
|
||||
}
|
||||
|
||||
void Music::onTimer(void *refCon) {
|
||||
Music *music = (Music *)refCon;
|
||||
Common::StackLock lock(music->_driver->_mutex);
|
||||
music->_parser->onTimer();
|
||||
}
|
||||
|
||||
void Music::musicVolumeGauge() {
|
||||
int volume;
|
||||
|
||||
@ -217,7 +194,7 @@ void Music::musicVolumeGauge() {
|
||||
volume = 1;
|
||||
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
|
||||
_driver->setVolume(volume);
|
||||
_player->setVolume(volume);
|
||||
|
||||
if (_currentVolumePercent == 100) {
|
||||
_vm->getTimerManager()->removeTimerProc(&musicVolumeGaugeCallback);
|
||||
@ -237,7 +214,7 @@ void Music::setVolume(int volume, int time) {
|
||||
volume = 0;
|
||||
|
||||
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
|
||||
_driver->setVolume(volume);
|
||||
_player->setVolume(volume);
|
||||
_vm->getTimerManager()->removeTimerProc(&musicVolumeGaugeCallback);
|
||||
_currentVolume = volume;
|
||||
return;
|
||||
@ -247,7 +224,7 @@ void Music::setVolume(int volume, int time) {
|
||||
}
|
||||
|
||||
bool Music::isPlaying() {
|
||||
return _mixer->isSoundHandleActive(_musicHandle) || _parser->isPlaying();
|
||||
return _mixer->isSoundHandleActive(_musicHandle) || _player->isPlaying();
|
||||
}
|
||||
|
||||
void Music::play(uint32 resourceId, MusicFlags flags) {
|
||||
@ -262,7 +239,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
|
||||
|
||||
_trackNumber = resourceId;
|
||||
_mixer->stopHandle(_musicHandle);
|
||||
_parser->unloadMusic();
|
||||
_player->stop();
|
||||
|
||||
int realTrackNumber;
|
||||
|
||||
@ -392,33 +369,20 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
|
||||
_vm->_resource->loadResource(_musicContext, resourceId, *_currentMusicBuffer);
|
||||
}
|
||||
|
||||
if (_currentMusicBuffer->size() < 4) {
|
||||
error("Music::play() wrong music resource size");
|
||||
}
|
||||
|
||||
if (!_parser->loadMusic(_currentMusicBuffer->getBuffer(), _currentMusicBuffer->size()))
|
||||
error("Music::play() wrong music resource");
|
||||
|
||||
_parser->setTrack(0);
|
||||
_driver->setTimerCallback(this, &onTimer);
|
||||
|
||||
_player->play(_vm, _currentMusicBuffer, (flags & MUSIC_LOOP));
|
||||
setVolume(_vm->_musicVolume);
|
||||
|
||||
// Handle music looping
|
||||
_parser->property(MidiParser::mpAutoLoop, (flags & MUSIC_LOOP) ? 1 : 0);
|
||||
}
|
||||
|
||||
void Music::pause() {
|
||||
_driver->setTimerCallback(NULL, NULL);
|
||||
_player->pause();
|
||||
}
|
||||
|
||||
void Music::resume() {
|
||||
_driver->setTimerCallback(this, &onTimer);
|
||||
_player->resume();
|
||||
}
|
||||
|
||||
void Music::stop() {
|
||||
_driver->setTimerCallback(NULL, NULL);
|
||||
_parser->unloadMusic();
|
||||
_player->stop();
|
||||
}
|
||||
|
||||
} // End of namespace Saga
|
||||
|
@ -28,8 +28,7 @@
|
||||
#ifndef SAGA_MUSIC_H
|
||||
#define SAGA_MUSIC_H
|
||||
|
||||
#include "audio/mididrv.h"
|
||||
#include "audio/midiparser.h"
|
||||
#include "audio/midiplayer.h"
|
||||
#include "audio/mixer.h"
|
||||
#include "audio/decoders/mp3.h"
|
||||
#include "audio/decoders/vorbis.h"
|
||||
@ -44,41 +43,26 @@ enum MusicFlags {
|
||||
MUSIC_DEFAULT = 0xffff
|
||||
};
|
||||
|
||||
class MusicDriver : public MidiDriver_BASE {
|
||||
class MusicDriver : public Audio::MidiPlayer {
|
||||
public:
|
||||
MusicDriver();
|
||||
~MusicDriver();
|
||||
|
||||
void setVolume(int volume);
|
||||
int getVolume() { return _masterVolume; }
|
||||
void play(SagaEngine *vm, ByteArray *buffer, bool loop);
|
||||
virtual void pause();
|
||||
virtual void resume();
|
||||
|
||||
bool isAdlib() { return _driverType == MT_ADLIB; }
|
||||
bool isMT32() { return _driverType == MT_MT32 || _nativeMT32; }
|
||||
void setGM(bool isGM) { _isGM = isGM; }
|
||||
|
||||
// FIXME
|
||||
bool isPlaying() const { return _parser && _parser->isPlaying(); }
|
||||
|
||||
// MidiDriver_BASE interface implementation
|
||||
virtual void send(uint32 b);
|
||||
virtual void metaEvent(byte type, byte *data, uint16 length) {}
|
||||
|
||||
void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { _driver->setTimerCallback(timerParam, timerProc); }
|
||||
uint32 getBaseTempo() { return _driver->getBaseTempo(); }
|
||||
|
||||
Common::Mutex _mutex; // FIXME: Make _mutex protected
|
||||
virtual void metaEvent(byte type, byte *data, uint16 length);
|
||||
|
||||
protected:
|
||||
|
||||
MidiChannel *_channelsTable[16];
|
||||
MidiDriver *_driver;
|
||||
MusicType _driverType;
|
||||
byte _channelsVolume[16];
|
||||
bool _isGM;
|
||||
bool _nativeMT32;
|
||||
|
||||
byte _masterVolume;
|
||||
|
||||
byte *_musicData;
|
||||
uint16 *_buf;
|
||||
size_t _musicDataSize;
|
||||
};
|
||||
|
||||
class Music {
|
||||
@ -103,7 +87,7 @@ private:
|
||||
SagaEngine *_vm;
|
||||
Audio::Mixer *_mixer;
|
||||
|
||||
MusicDriver *_driver;
|
||||
MusicDriver *_player;
|
||||
Audio::SoundHandle _musicHandle;
|
||||
uint32 _trackNumber;
|
||||
|
||||
@ -114,7 +98,6 @@ private:
|
||||
|
||||
ResourceContext *_musicContext;
|
||||
ResourceContext *_digitalMusicContext;
|
||||
MidiParser *_parser;
|
||||
|
||||
|
||||
static void musicVolumeGaugeCallback(void *refCon);
|
||||
|
Loading…
Reference in New Issue
Block a user