PARALLACTION: Change MidiPlayer impls to derive from Audio::MidiPlayer

This commit is contained in:
Max Horn 2011-03-24 16:41:23 +01:00
parent 84d68f31e8
commit 7cc04f25ff
2 changed files with 25 additions and 150 deletions

View File

@ -27,8 +27,8 @@
#include "common/util.h"
#include "audio/mixer.h"
#include "audio/mididrv.h"
#include "audio/midiparser.h"
#include "audio/midiplayer.h"
#include "audio/mods/protracker.h"
#include "audio/decoders/raw.h"
@ -201,13 +201,9 @@ MidiParser *createParser_MSC() {
}
class MidiPlayer_MSC : public MidiDriver_BASE {
class MidiPlayer_MSC : public Audio::MidiPlayer {
public:
enum {
NUM_CHANNELS = 16
};
MidiPlayer_MSC(MidiDriver *driver);
~MidiPlayer_MSC();
@ -215,42 +211,26 @@ public:
void stop();
void pause(bool p);
void updateTimer();
void adjustVolume(int diff);
void setVolume(int volume);
int getVolume() const { return _masterVolume; }
void setLooping(bool loop) { _isLooping = loop; }
// MidiDriver_BASE interface
virtual void send(uint32 b);
virtual void metaEvent(byte type, byte *data, uint16 length);
private:
static void timerCallback(void *p);
void setVolumeInternal(int volume);
Common::Mutex _mutex;
MidiDriver *_driver;
MidiParser *_parser;
uint8 *_midiData;
bool _isLooping;
bool _isPlaying;
bool _paused;
int _masterVolume;
MidiChannel *_channels[NUM_CHANNELS];
uint8 _volume[NUM_CHANNELS];
};
MidiPlayer_MSC::MidiPlayer_MSC(MidiDriver *driver)
: _driver(driver), _parser(0), _midiData(0), _isLooping(false), _isPlaying(false), _paused(false), _masterVolume(0) {
: _midiData(0), _paused(false) {
_driver = driver;
assert(_driver);
memset(_channels, 0, sizeof(_channels));
for (int i = 0; i < NUM_CHANNELS; i++) {
_volume[i] = 127;
}
int ret = _driver->open();
if (ret == 0) {
@ -295,13 +275,9 @@ void MidiPlayer_MSC::play(Common::SeekableReadStream *stream) {
}
void MidiPlayer_MSC::stop() {
Common::StackLock lock(_mutex);
if (_isPlaying) {
_isPlaying = false;
_parser->unloadMusic();
free(_midiData);
_midiData = 0;
}
Audio::MidiPlayer::stop();
free(_midiData);
_midiData = 0;
}
void MidiPlayer_MSC::pause(bool p) {
@ -320,10 +296,6 @@ void MidiPlayer_MSC::updateTimer() {
}
}
void MidiPlayer_MSC::adjustVolume(int diff) {
setVolume(_masterVolume + diff);
}
void MidiPlayer_MSC::setVolume(int volume) {
_masterVolume = CLIP(volume, 0, 255);
setVolumeInternal(_masterVolume);
@ -331,43 +303,28 @@ void MidiPlayer_MSC::setVolume(int volume) {
void MidiPlayer_MSC::setVolumeInternal(int volume) {
Common::StackLock lock(_mutex);
for (int i = 0; i < NUM_CHANNELS; ++i) {
if (_channels[i]) {
_channels[i]->volume(_volume[i] * volume / 255);
for (int i = 0; i < kNumChannels; ++i) {
if (_channelsTable[i]) {
_channelsTable[i]->volume(_channelsVolume[i] * volume / 255);
}
}
}
void MidiPlayer_MSC::send(uint32 b) {
// FIXME/TODO: Unlike Audio::MidiPlayer::send(), this code
// does not handle All Note Off. Is this on purpose?
// If not, we could simply remove this method, and use the
// inherited one.
const byte ch = b & 0x0F;
byte param2 = (b >> 16) & 0xFF;
switch (b & 0xFFF0) {
case 0x07B0: // volume change
_volume[ch] = param2;
_channelsVolume[ch] = param2;
break;
}
if (!_channels[ch]) {
_channels[ch] = (ch == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
}
if (_channels[ch]) {
_channels[ch]->send(b);
}
}
void MidiPlayer_MSC::metaEvent(byte type, byte *data, uint16 length) {
switch (type) {
case 0x2F: // end of Track
if (_isLooping) {
_parser->jumpToTick(0);
} else {
stop();
}
break;
default:
break;
}
sendToChannel(ch, b);
}
void MidiPlayer_MSC::timerCallback(void *p) {

View File

@ -29,6 +29,7 @@
#include "audio/mixer.h"
#include "audio/midiparser.h"
#include "audio/midiplayer.h"
#include "audio/mods/protracker.h"
#include "audio/decoders/raw.h"
@ -38,13 +39,9 @@
namespace Parallaction {
class MidiPlayer : public MidiDriver_BASE {
class MidiPlayer : public Audio::MidiPlayer {
public:
enum {
NUM_CHANNELS = 16
};
MidiPlayer(MidiDriver *driver);
~MidiPlayer();
@ -52,38 +49,18 @@ public:
void stop();
void pause(bool p);
void updateTimer();
void adjustVolume(int diff);
void setVolume(int volume);
int getVolume() const { return _masterVolume; }
void setLooping(bool loop) { _isLooping = loop; }
// MidiDriver_BASE interface
virtual void send(uint32 b);
virtual void metaEvent(byte type, byte *data, uint16 length);
private:
static void timerCallback(void *p);
MidiDriver *_driver;
MidiParser *_parser;
uint8 *_midiData;
bool _isLooping;
bool _isPlaying;
bool _paused;
int _masterVolume;
MidiChannel *_channelsTable[NUM_CHANNELS];
uint8 _channelsVolume[NUM_CHANNELS];
Common::Mutex _mutex;
};
MidiPlayer::MidiPlayer(MidiDriver *driver)
: _driver(driver), _parser(0), _midiData(0), _isLooping(false), _isPlaying(false), _paused(false), _masterVolume(0) {
assert(_driver);
memset(_channelsTable, 0, sizeof(_channelsTable));
for (int i = 0; i < NUM_CHANNELS; i++) {
_channelsVolume[i] = 127;
}
: _midiData(0), _paused(false) {
assert(driver);
_driver = driver;
int ret = _driver->open();
if (ret == 0) {
@ -128,19 +105,15 @@ void MidiPlayer::play(Common::SeekableReadStream *stream) {
}
void MidiPlayer::stop() {
Common::StackLock lock(_mutex);
if (_isPlaying) {
_isPlaying = false;
_parser->unloadMusic();
free(_midiData);
_midiData = 0;
}
Audio::MidiPlayer::stop();
free(_midiData);
_midiData = 0;
}
void MidiPlayer::pause(bool p) {
_paused = p;
for (int i = 0; i < NUM_CHANNELS; ++i) {
for (int i = 0; i < kNumChannels; ++i) {
if (_channelsTable[i]) {
_channelsTable[i]->volume(_paused ? 0 : _channelsVolume[i] * _masterVolume / 255);
}
@ -158,61 +131,6 @@ void MidiPlayer::updateTimer() {
}
}
void MidiPlayer::adjustVolume(int diff) {
setVolume(_masterVolume + diff);
}
void MidiPlayer::setVolume(int volume) {
_masterVolume = CLIP(volume, 0, 255);
Common::StackLock lock(_mutex);
for (int i = 0; i < NUM_CHANNELS; ++i) {
if (_channelsTable[i]) {
_channelsTable[i]->volume(_channelsVolume[i] * _masterVolume / 255);
}
}
}
void MidiPlayer::send(uint32 b) {
byte volume, ch = (byte)(b & 0xF);
switch (b & 0xFFF0) {
case 0x07B0: // volume change
volume = (byte)((b >> 16) & 0x7F);
_channelsVolume[ch] = volume;
volume = volume * _masterVolume / 255;
b = (b & 0xFF00FFFF) | (volume << 16);
break;
case 0x7BB0: // all notes off
if (!_channelsTable[ch]) {
// channel not yet allocated, no need to send the event
return;
}
break;
}
if (!_channelsTable[ch]) {
_channelsTable[ch] = (ch == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
}
if (_channelsTable[ch]) {
_channelsTable[ch]->send(b);
}
}
void MidiPlayer::metaEvent(byte type, byte *data, uint16 length) {
switch (type) {
case 0x2F: // end of Track
if (_isLooping) {
_parser->jumpToTick(0);
} else {
stop();
}
break;
default:
// warning("Unhandled meta event: %02x", type);
break;
}
}
void MidiPlayer::timerCallback(void *p) {
MidiPlayer *player = (MidiPlayer *)p;