Added support for volume and pause control to Simon music.

Note that MidiStreamer is now used as a streaming wrapper
for ALL MidiDriver types, even those that natively support
streaming. This is because MidiStreamer supports a hybrid
of streamed and non-streamed MIDI, which is necessary to
support interactive events.

svn-id: r5596
This commit is contained in:
Jamieson Christian 2002-11-18 09:08:45 +00:00
parent 713f11d99e
commit 5214cb3463
3 changed files with 64 additions and 33 deletions

View File

@ -31,6 +31,13 @@
// FIXME: This is a horrible place to put this, but for now....
#include "sound/midistreamer.cpp"
MidiPlayer::MidiPlayer() {
// Since initialize() is called every time the music changes,
// this is where we'll initialize stuff that must persist
// between songs.
_masterVolume = 255;
}
void MidiPlayer::read_all_songs(File *in, uint music)
{
uint i, num;
@ -178,21 +185,16 @@ void MidiPlayer::initialize()
int i;
for (i = 0; i != 16; i++)
_volumeTable[i] = 100;
_volumeTable[i] = 127;
_midiDriver->property(MidiDriver::PROP_TIMEDIV, _songs[0].ppqn);
res = _midiDriver->open(MidiDriver::MO_STREAMING);
if (res == MidiDriver::MERR_STREAMING_NOT_AVAILABLE) {
// No direct streaming, slap a front-end on.
_midiDriver = new MidiStreamer (_midiDriver);
_midiDriver->property (MidiDriver::PROP_TIMEDIV, _songs[0].ppqn);
_midiDriver->set_stream_callback (this, on_fill);
res = _midiDriver->open (MidiDriver::MO_STREAMING);
}
if (res != 0)
error("MidiPlayer::initializer, got %s", MidiDriver::get_error_name(res));
if (_paused)
_midiDriver->pause (true);
}
int MidiPlayer::fill(MidiEvent *me, int num_event)
@ -261,8 +263,8 @@ bool MidiPlayer::fill_helper(NoteRec *nr, MidiEvent *me)
if ((nr->cmd & 0xF0) == 0xB0 && nr->param_1 == 7) {
_volumeTable[nr->cmd & 0xF] = nr->param_2;
nr->param_1 = 0x76;
me->event = nr->cmd | (nr->param_1 << 8) | (nr->param_2 << 16) /* | MEVT_F_CALLBACK */ ;
// nr->param_1 = 0x76;
me->event = nr->cmd | (nr->param_1 << 8) | ((nr->param_2 * _masterVolume / 255) << 16) /* | MEVT_F_CALLBACK */ ;
}
return true;
@ -414,27 +416,52 @@ void MidiPlayer::unload()
void MidiPlayer::play()
{
_midiDriver->pause(false);
if (!_paused)
_midiDriver->pause(false);
}
void MidiPlayer::pause(bool b)
void MidiPlayer::pause (bool b)
{
if (_paused == b)
return;
_paused = b;
_midiDriver->pause(b);
for (int i = ARRAYSIZE (_volumeTable); i; --i) {
_midiDriver->send (((_paused ? 0 : (_volumeTable[i-1] * _masterVolume / 255)) << 16) | (7 << 8) | 0xB0 | i);
}
}
uint MidiPlayer::get_volume()
int MidiPlayer::get_volume()
{
// TODO: implement me
return 0;
return _masterVolume;
}
void MidiPlayer::set_volume(uint volume)
void MidiPlayer::set_volume (int volume)
{
// TODO: implement me
if (volume < 0)
volume = 0;
else if (volume > 255)
volume = 255;
if (_masterVolume == volume)
return;
_masterVolume = volume;
// Now tell all the channels this.
if (_midiDriver && !_paused) {
for (int i = ARRAYSIZE (_volumeTable); i; --i) {
_midiDriver->send (((_volumeTable[i-1] * _masterVolume / 255) << 16) | (7 << 8) | 0xB0 | i);
}
}
}
void MidiPlayer::set_driver(MidiDriver *md)
{
_midiDriver = md;
// We must always use the MidiStreamer front-end
// so we can support user-initiated MIDI events (like volume).
_midiDriver = new MidiStreamer (md);
_midiDriver->set_stream_callback(this, on_fill);
}

View File

@ -28,15 +28,17 @@ struct MidiEvent;
class MidiPlayer {
public:
void read_all_songs(File *in, uint music);
void read_all_songs_old(File *in, uint music);
MidiPlayer();
void read_all_songs (File *in, uint music);
void read_all_songs_old (File *in, uint music);
void initialize();
void shutdown();
void play();
void pause(bool b);
uint get_volume();
void set_volume(uint volume);
void set_driver(MidiDriver *md);
void pause (bool b);
int get_volume();
void set_volume (int volume);
void set_driver (MidiDriver *md);
private:
struct Track {
@ -69,8 +71,9 @@ private:
uint _lastDelay;
Song *_currentSong;
Song _songs[8];
uint32 _volumeTable[16];
byte _volumeTable[16]; // 0-127
byte _masterVolume; // 0-255
bool _paused;
void read_mthd(File *in, Song *s, bool old, uint music);
@ -79,8 +82,8 @@ private:
static uint32 track_read_gamma(Track *t);
static byte track_read_byte(Track *t);
int fill(MidiEvent *me, int num_event);
bool fill_helper(NoteRec *nr, MidiEvent *me);
int fill (MidiEvent *me, int num_event);
bool fill_helper (NoteRec *nr, MidiEvent *me);
void reset_tracks();
void read_next_note(Track *t, NoteRec *nr);

View File

@ -30,8 +30,8 @@ private:
MidiDriver *_target;
StreamCallback *_stream_proc;
void *_stream_param;
int _mode;
bool _paused;
volatile int _mode;
volatile bool _paused;
MidiEvent _events [64];
int _event_count;
@ -52,7 +52,7 @@ public:
int open(int mode);
void close();
void send(uint32 b) { _target->send (b); }
void send(uint32 b) { if (_mode) _target->send (b); }
void pause(bool p) { _paused = p; }
void set_stream_callback(void *param, StreamCallback *sc);
void setPitchBendRange (byte channel, uint range) { _target->setPitchBendRange (channel, range); }
@ -87,6 +87,7 @@ int MidiStreamer::timer_thread (void *param) {
MidiStreamer *mid = (MidiStreamer *) param;
int old_time, cur_time;
while (mid->_mode) {
g_system->delay_msecs (100);
while (!mid->_stream_proc);
old_time = g_system->get_msecs();
while (!mid->_paused) {
@ -104,7 +105,7 @@ int MidiStreamer::timer_thread (void *param) {
// just to catch anything still playing.
int i;
for (i = 0; i < 16; ++i)
mid->send ((0x7B << 8) | 0xB0 | i);
mid->_target->send ((0x7B << 8) | 0xB0 | i);
mid->_active = false;
return 0;
}