diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/mididrv.cpp | 75 | ||||
-rw-r--r-- | sound/mididrv.h | 8 | ||||
-rw-r--r-- | sound/midistreamer.cpp | 34 |
3 files changed, 101 insertions, 16 deletions
diff --git a/sound/mididrv.cpp b/sound/mididrv.cpp index 9b9b8fe416..baf3427cfb 100644 --- a/sound/mididrv.cpp +++ b/sound/mididrv.cpp @@ -35,6 +35,67 @@ #include "common/engine.h" // for warning/error/debug #include "common/util.h" + + +//////////////////////////////////////// +// +// Common MPU401 implementation methods +// +//////////////////////////////////////// + +typedef void TimerCallback (void *); + +class MidiDriver_MPU401 : public MidiDriver { +private: + bool _started_thread; + TimerCallback *_timer_proc; + void *_timer_param; + + static int midi_driver_thread (void *param); + +public: + virtual void setTimerCallback (void *timer_param, void (*timer_proc) (void *)); + virtual uint32 getBaseTempo (void) { return 0x4A0000; } +}; + +void MidiDriver_MPU401::setTimerCallback (void *timer_param, void (*timer_proc) (void *)) +{ + if (!_timer_proc || !timer_proc) { + _timer_proc = (TimerCallback *) timer_proc; + _timer_param = timer_param; + if (!_started_thread && timer_proc) + g_system->create_thread (midi_driver_thread, this); + _started_thread = true; + } +} + +int MidiDriver_MPU401::midi_driver_thread(void *param) +{ + MidiDriver_MPU401 *mid = (MidiDriver_MPU401 *)param; + int old_time, cur_time; + + old_time = g_system->get_msecs(); + + for (;;) { + g_system->delay_msecs(10); + + cur_time = g_system->get_msecs(); + while (old_time < cur_time) { + old_time += 10; + // Don't use mid->_se_on_timer() + // We must come in through IMuseMonitor to protect + // against conflicts with script access to IMuse. + if (mid->_timer_proc) + (*(mid->_timer_proc)) (mid->_timer_param); + } + } + + return 0; +} + + + + // FIXME - the following disables reverb support in the QuickTime / CoreAudio // midi backends. For some reasons, reverb will suck away a *lot* of CPU time. // Until we know for sure what is causing this and if there is a better way to @@ -44,7 +105,7 @@ #if defined(WIN32) && !defined(_WIN32_WCE) /* Windows MIDI driver */ -class MidiDriver_WIN : public MidiDriver { +class MidiDriver_WIN : public MidiDriver_MPU401 { public: int open(int mode); void close(); @@ -304,7 +365,7 @@ MidiDriver *MidiDriver_WIN_create() #include "morphos_sound.h" /* MorphOS MIDI driver */ -class MidiDriver_ETUDE:public MidiDriver { +class MidiDriver_ETUDE:public MidiDriver_MPU401 { public: int open(int mode); void close(); @@ -515,7 +576,7 @@ MidiDriver *MidiDriver_ETUDE_create() #define SEQ_MIDIPUTC 5 #define SPECIAL_CHANNEL 9 -class MidiDriver_SEQ:public MidiDriver { +class MidiDriver_SEQ:public MidiDriver_MPU401 { public: MidiDriver_SEQ(); int open(int mode); @@ -655,7 +716,7 @@ MidiDriver *MidiDriver_SEQ_create() /* QuickTime MIDI driver */ -class MidiDriver_QT:public MidiDriver { +class MidiDriver_QT:public MidiDriver_MPU401 { public: int open(int mode); void close(); @@ -872,7 +933,7 @@ MidiDriver *MidiDriver_QT_create() /* CoreAudio MIDI driver */ /* Based on code by Benjamin W. Zale */ -class MidiDriver_CORE:public MidiDriver { +class MidiDriver_CORE:public MidiDriver_MPU401 { public: MidiDriver_CORE():au_MusicDevice(NULL), au_output(NULL) { } int open(int mode); @@ -979,7 +1040,7 @@ MidiDriver *MidiDriver_CORE_create() #endif // __APPLE__ /* NULL driver */ -class MidiDriver_NULL:public MidiDriver { +class MidiDriver_NULL:public MidiDriver_MPU401 { public: int open(int mode); void close() { } @@ -1051,7 +1112,7 @@ const char *MidiDriver::get_error_name(int error_code) #define ADDR_DELIM ".:" -class MidiDriver_ALSA:public MidiDriver { +class MidiDriver_ALSA:public MidiDriver_MPU401 { public: MidiDriver_ALSA(); int open(int mode); diff --git a/sound/mididrv.h b/sound/mididrv.h index 6544f7f885..49fff19fd5 100644 --- a/sound/mididrv.h +++ b/sound/mididrv.h @@ -106,6 +106,12 @@ public: send((range << 16) | ( 6 << 8) | (0xB0 | channel)); send(( 0 << 16) | ( 38 << 8) | (0xB0 | channel)); } + + virtual void sysEx_customInstrument (byte channel, uint32 type, byte *instr) { } + + // Timing functions - MidiDriver now operates timers + virtual void setTimerCallback (void *timer_param, void (*timer_proc) (void *)) = 0; + virtual uint32 getBaseTempo (void) = 0; }; @@ -122,12 +128,14 @@ enum { MD_COREAUDIO = 7, MD_MIDIEMU = 8, MD_ALSA = 9, + MD_ADLIB = 10 }; /* Factory functions => no need to include the specific classes * in this header => faster compile */ extern MidiDriver *MidiDriver_NULL_create(); +extern MidiDriver *MidiDriver_ADLIB_create(); extern MidiDriver *MidiDriver_WIN_create(); extern MidiDriver *MidiDriver_TIMIDITY_create(); extern MidiDriver *MidiDriver_SEQ_create(); diff --git a/sound/midistreamer.cpp b/sound/midistreamer.cpp index fcd4109c81..724b0852c5 100644 --- a/sound/midistreamer.cpp +++ b/sound/midistreamer.cpp @@ -37,6 +37,7 @@ private: int _event_count; int _event_index; + long _driver_tempo; long _tempo; uint16 _ticks_per_beat; long _delay; @@ -44,8 +45,8 @@ private: volatile bool _active; uint32 property(int prop, uint32 param); - static int timer_thread (void *param); - void on_timer (void); + static void timer_thread (void *param); + void on_timer(); public: MidiStreamer (MidiDriver *target); @@ -56,6 +57,9 @@ public: void pause(bool p) { _paused = p; } void set_stream_callback(void *param, StreamCallback *sc); void setPitchBendRange (byte channel, uint range) { _target->setPitchBendRange (channel, range); } + + void setTimerCallback (void *timer_param, void (*timer_proc) (void *)) { } + uint32 getBaseTempo (void) { return _target->getBaseTempo(); } }; MidiStreamer::MidiStreamer (MidiDriver *target) : @@ -82,7 +86,7 @@ void MidiStreamer::set_stream_callback (void *param, StreamCallback *sc) _event_index = 0; } } - +/* int MidiStreamer::timer_thread (void *param) { MidiStreamer *mid = (MidiStreamer *) param; int old_time, cur_time; @@ -109,10 +113,14 @@ int MidiStreamer::timer_thread (void *param) { mid->_active = false; return 0; } +*/ +void MidiStreamer::timer_thread (void *param) { + ((MidiStreamer *) param)->on_timer(); +} void MidiStreamer::on_timer() { - _delay += 10000; + _delay += _driver_tempo; // 10000; while (true) { if (_event_index >= _event_count) { _event_count = _stream_proc (_stream_param, _events, ARRAYSIZE (_events)); @@ -145,18 +153,17 @@ int MidiStreamer::open (int mode) if (res && res != MERR_ALREADY_OPEN) return res; - // Wait for existing timer thread to shut down. - while (_active); - _event_index = _event_count = _delay = 0; _mode = mode; _paused = false; - _active = true; if (mode == MO_SIMPLE) return 0; - g_system->create_thread (timer_thread, this); +// g_system->create_thread (timer_thread, this); + _driver_tempo = _target->getBaseTempo() / 500; + + _target->setTimerCallback (this, &timer_thread); return 0; } @@ -164,6 +171,15 @@ void MidiStreamer::close() { if (!_mode) return; + + _target->setTimerCallback (NULL, NULL); + + // Turn off all notes on all channels, + // just to catch anything still playing. + int i; + for (i = 0; i < 16; ++i) + _target->send ((0x7B << 8) | 0xB0 | i); + _mode = 0; _paused = true; } |