From 445e9451cb9cc284f98b5be73c89017e24b9ba86 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 21 Feb 2018 02:02:29 +0100 Subject: [PATCH] - Added the long event handler for Timidity++. This will be hard to test because there's basically no material out there using the features this implements. --- .../music_timiditypp_mididevice.cpp | 19 ++-- src/sound/timiditypp/playmidi.cpp | 105 +++++++++++++++++- src/sound/timiditypp/playmidi.h | 18 +-- src/sound/timiditypp/readmidic.cpp | 87 ++------------- 4 files changed, 130 insertions(+), 99 deletions(-) diff --git a/src/sound/mididevices/music_timiditypp_mididevice.cpp b/src/sound/mididevices/music_timiditypp_mididevice.cpp index ac1233c97..55cedb34b 100644 --- a/src/sound/mididevices/music_timiditypp_mididevice.cpp +++ b/src/sound/mididevices/music_timiditypp_mididevice.cpp @@ -112,6 +112,7 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args) { if (args == NULL || *args == 0) args = timidity_config; + Renderer = nullptr; if (instruments != nullptr && !instruments->checkConfig(args)) { delete instruments; @@ -152,14 +153,14 @@ TimidityPPMIDIDevice::~TimidityPPMIDIDevice () int TimidityPPMIDIDevice::Open(MidiCallback callback, void *userdata) { - // No instruments loaded means we cannot play... - if (instruments == nullptr) return 0; int ret = OpenStream(2, 0, callback, userdata); - if (ret == 0) + if (ret == 0 && Renderer != nullptr) { Renderer->playmidi_stream_init(); } + // No instruments loaded means we cannot play... + if (instruments == nullptr) return 0; return ret; } @@ -176,7 +177,8 @@ int TimidityPPMIDIDevice::Open(MidiCallback callback, void *userdata) void TimidityPPMIDIDevice::PrecacheInstruments(const uint16_t *instrumentlist, int count) { - instruments->PrecacheInstruments(instrumentlist, count); + if (instruments != nullptr) + instruments->PrecacheInstruments(instrumentlist, count); } //========================================================================== @@ -187,7 +189,8 @@ void TimidityPPMIDIDevice::PrecacheInstruments(const uint16_t *instrumentlist, i void TimidityPPMIDIDevice::HandleEvent(int status, int parm1, int parm2) { - Renderer->send_event(sampletime, status, parm1, parm2); + if (Renderer != nullptr) + Renderer->send_event(sampletime, status, parm1, parm2); } //========================================================================== @@ -198,7 +201,8 @@ void TimidityPPMIDIDevice::HandleEvent(int status, int parm1, int parm2) void TimidityPPMIDIDevice::HandleLongEvent(const uint8_t *data, int len) { - //Renderer->HandleLongMessage(data, len); + if (Renderer != nullptr) + Renderer->send_long_event(sampletime, data, len); } //========================================================================== @@ -209,7 +213,8 @@ void TimidityPPMIDIDevice::HandleLongEvent(const uint8_t *data, int len) void TimidityPPMIDIDevice::ComputeOutput(float *buffer, int len) { - Renderer->get_output(buffer, len); + if (Renderer != nullptr) + Renderer->get_output(buffer, len); sampletime += len; } diff --git a/src/sound/timiditypp/playmidi.cpp b/src/sound/timiditypp/playmidi.cpp index a3c39ab39..e821787c5 100644 --- a/src/sound/timiditypp/playmidi.cpp +++ b/src/sound/timiditypp/playmidi.cpp @@ -5046,8 +5046,6 @@ int Player::compute_data(int32_t count) while ((count + buffered_count) >= AUDIO_BUFFER_SIZE) { - int i; - do_compute_data(AUDIO_BUFFER_SIZE - buffered_count); count -= AUDIO_BUFFER_SIZE - buffered_count; @@ -5864,6 +5862,7 @@ void Player::playmidi_stream_init(void) reuse_mblock(&playmidi_pool); /* Fill in current_file_info */ + current_file_info = get_midi_file_info("", 0); current_file_info->readflag = 1; current_file_info->seq_name = safe_strdup("TiMidity server"); current_file_info->karaoke_title = current_file_info->first_text = NULL; @@ -6070,6 +6069,72 @@ void Player::get_output(float *buffer, int len) //compute_data(len); } + +static const struct ctl_chg_types { + unsigned char mtype; + int ttype; +} ctl_chg_list[] = { + { 0, ME_TONE_BANK_MSB }, +{ 1, ME_MODULATION_WHEEL }, +{ 2, ME_BREATH }, +{ 4, ME_FOOT }, +{ 5, ME_PORTAMENTO_TIME_MSB }, +{ 6, ME_DATA_ENTRY_MSB }, +{ 7, ME_MAINVOLUME }, +{ 8, ME_BALANCE }, +{ 10, ME_PAN }, +{ 11, ME_EXPRESSION }, +{ 32, ME_TONE_BANK_LSB }, +{ 37, ME_PORTAMENTO_TIME_LSB }, +{ 38, ME_DATA_ENTRY_LSB }, +{ 64, ME_SUSTAIN }, +{ 65, ME_PORTAMENTO }, +{ 66, ME_SOSTENUTO }, +{ 67, ME_SOFT_PEDAL }, +{ 68, ME_LEGATO_FOOTSWITCH }, +{ 69, ME_HOLD2 }, +{ 71, ME_HARMONIC_CONTENT }, +{ 72, ME_RELEASE_TIME }, +{ 73, ME_ATTACK_TIME }, +{ 74, ME_BRIGHTNESS }, +{ 84, ME_PORTAMENTO_CONTROL }, +{ 91, ME_REVERB_EFFECT }, +{ 92, ME_TREMOLO_EFFECT }, +{ 93, ME_CHORUS_EFFECT }, +{ 94, ME_CELESTE_EFFECT }, +{ 95, ME_PHASER_EFFECT }, +{ 96, ME_RPN_INC }, +{ 97, ME_RPN_DEC }, +{ 98, ME_NRPN_LSB }, +{ 99, ME_NRPN_MSB }, +{ 100, ME_RPN_LSB }, +{ 101, ME_RPN_MSB }, +{ 120, ME_ALL_SOUNDS_OFF }, +{ 121, ME_RESET_CONTROLLERS }, +{ 123, ME_ALL_NOTES_OFF }, +{ 126, ME_MONO }, +{ 127, ME_POLY }, +}; + +int Player::convert_midi_control_change(int chn, int type, int val, MidiEvent *ev_ret) +{ + int etype = -1; + for (auto &t : ctl_chg_list) + { + if (t.mtype == type) + { + if (val > 127) val = 127; + ev_ret->type = t.ttype; + ev_ret->channel = chn; + ev_ret->a = val; + ev_ret->b = 0; + return 1; + } + } + return 0; +} + + int Player::send_event(int sampletime, int status, int parm1, int parm2) { MidiEvent ev; @@ -6122,4 +6187,40 @@ int Player::send_event(int sampletime, int status, int parm1, int parm2) return 0; } +void Player::send_long_event(int sampletime, const uint8_t *sysexbuffer, int exlen) +{ + int i, ne; + MidiEvent ev; + MidiEvent evm[260]; + SysexConvert sc; + + if ((sysexbuffer[0] != '\xf0') && (sysexbuffer[0] != '\xf7')) return; + + if (sc.parse_sysex_event(sysexbuffer + 1, exlen - 1, &ev, instruments)) + { + if (ev.type == ME_RESET) + { + kill_all_voices(); + for (int i = 0; i < MAX_CHANNELS; i++) + init_channel_layer(i); + + /* initialize effect status */ + reverb->init_effect_status(play_system_mode); + instruments->init_userdrum(); + instruments->init_userinst(); + playmidi_stream_init(); + } + play_event(&ev); + } + if (ne = sc.parse_sysex_event_multi(sysexbuffer + 1, exlen - 1, evm, instruments)) + { + for (i = 0; i < ne; i++) + { + play_event(&evm[i]); + } + } +} + + + } \ No newline at end of file diff --git a/src/sound/timiditypp/playmidi.h b/src/sound/timiditypp/playmidi.h index 4145c4780..5342540b3 100644 --- a/src/sound/timiditypp/playmidi.h +++ b/src/sound/timiditypp/playmidi.h @@ -707,6 +707,7 @@ private: void init_rx_drum(struct DrumParts *); void set_rx_drum(struct DrumParts *, int32_t, int); int32_t get_rx_drum(struct DrumParts *, int32_t); + int convert_midi_control_change(int chn, int type, int val, MidiEvent *ev_ret); public: @@ -741,15 +742,7 @@ public: void init_channel_layer(int ch); void get_output(float *buffer, int len); int send_event(int time, int status, int parm1, int parm2); - - // Only until streaming works. - void skip_to(int32_t until_time, MidiEvent *evt_start); - int start_midi(MidiEvent *eventlist, int32_t samples); - void run_midi(int); - int play_midi(MidiEvent *eventlist, int32_t samples); - friend MidiEvent *groom_list(int32_t divisions, int32_t *eventsp, int32_t *samplesp); - - + void send_long_event(int sampletime, const uint8_t *sysexbuffer, int exlen); }; class SysexConvert @@ -759,13 +752,10 @@ class SysexConvert uint8_t drum_setup_xg[16] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; /* for XG */ public: - int parse_sysex_event_multi(uint8_t *val, int32_t len, MidiEvent *evm, Instruments *instruments); - int parse_sysex_event(uint8_t *val, int32_t len, MidiEvent *ev, Instruments *instruments); + int parse_sysex_event_multi(const uint8_t *val, int32_t len, MidiEvent *evm, Instruments *instruments); + int parse_sysex_event(const uint8_t *val, int32_t len, MidiEvent *ev, Instruments *instruments); }; -// really extern! -int convert_midi_control_change(int chn, int type, int val, MidiEvent *ev_ret); - } diff --git a/src/sound/timiditypp/readmidic.cpp b/src/sound/timiditypp/readmidic.cpp index 70136f529..88fa73027 100644 --- a/src/sound/timiditypp/readmidic.cpp +++ b/src/sound/timiditypp/readmidic.cpp @@ -43,71 +43,6 @@ inline void SETMIDIEVENT(MidiEvent &e, int32_t at, uint32_t t, uint32_t ch, uint #define MERGE_CHANNEL_PORT(ch) ((int)(ch) | (midi_port_number << 4)) #define MERGE_CHANNEL_PORT2(ch, port) ((int)(ch) | ((int)port << 4)) - -static const struct ctl_chg_types { - unsigned char mtype; - int ttype; -} ctl_chg_list[] = { - { 0, ME_TONE_BANK_MSB }, -{ 1, ME_MODULATION_WHEEL }, -{ 2, ME_BREATH }, -{ 4, ME_FOOT }, -{ 5, ME_PORTAMENTO_TIME_MSB }, -{ 6, ME_DATA_ENTRY_MSB }, -{ 7, ME_MAINVOLUME }, -{ 8, ME_BALANCE }, -{ 10, ME_PAN }, -{ 11, ME_EXPRESSION }, -{ 32, ME_TONE_BANK_LSB }, -{ 37, ME_PORTAMENTO_TIME_LSB }, -{ 38, ME_DATA_ENTRY_LSB }, -{ 64, ME_SUSTAIN }, -{ 65, ME_PORTAMENTO }, -{ 66, ME_SOSTENUTO }, -{ 67, ME_SOFT_PEDAL }, -{ 68, ME_LEGATO_FOOTSWITCH }, -{ 69, ME_HOLD2 }, -{ 71, ME_HARMONIC_CONTENT }, -{ 72, ME_RELEASE_TIME }, -{ 73, ME_ATTACK_TIME }, -{ 74, ME_BRIGHTNESS }, -{ 84, ME_PORTAMENTO_CONTROL }, -{ 91, ME_REVERB_EFFECT }, -{ 92, ME_TREMOLO_EFFECT }, -{ 93, ME_CHORUS_EFFECT }, -{ 94, ME_CELESTE_EFFECT }, -{ 95, ME_PHASER_EFFECT }, -{ 96, ME_RPN_INC }, -{ 97, ME_RPN_DEC }, -{ 98, ME_NRPN_LSB }, -{ 99, ME_NRPN_MSB }, -{ 100, ME_RPN_LSB }, -{ 101, ME_RPN_MSB }, -{ 120, ME_ALL_SOUNDS_OFF }, -{ 121, ME_RESET_CONTROLLERS }, -{ 123, ME_ALL_NOTES_OFF }, -{ 126, ME_MONO }, -{ 127, ME_POLY }, -}; - -int convert_midi_control_change(int chn, int type, int val, MidiEvent *ev_ret) -{ - int etype = -1; - for (auto &t : ctl_chg_list) - { - if (t.mtype == type) - { - if (val > 127) val = 127; - ev_ret->type = t.ttype; - ev_ret->channel = chn; - ev_ret->a = val; - ev_ret->b = 0; - return 1; - } - } - return 0; -} - /* Map XG types onto GS types. XG should eventually have its own tables */ static int set_xg_reverb_type(int msb, int lsb) { @@ -272,7 +207,7 @@ static uint16_t gm_convert_master_vol(uint16_t v1, uint16_t v2) * This function provides basic support for XG Bulk Dump and Parameter * Change SysEx events */ -int SysexConvert::parse_sysex_event_multi(uint8_t *val, int32_t len, MidiEvent *evm, Instruments *instruments) +int SysexConvert::parse_sysex_event_multi(const uint8_t *val, int32_t len, MidiEvent *evm, Instruments *instruments) { int num_events = 0; /* Number of events added */ @@ -289,9 +224,9 @@ int SysexConvert::parse_sysex_event_multi(uint8_t *val, int32_t len, MidiEvent * (val[1] >= 0x10 && val[3] == 0x02))) /* Parameter Change */ { uint8_t addhigh, addmid, addlow; /* Addresses */ - uint8_t *body; /* SysEx body */ + const uint8_t *body; /* SysEx body */ int ent, v; /* Entry # of sub-event */ - uint8_t *body_end; /* End of SysEx body */ + const uint8_t *body_end; /* End of SysEx body */ if (val[1] < 0x10) /* Bulk Dump */ { @@ -484,9 +419,9 @@ int SysexConvert::parse_sysex_event_multi(uint8_t *val, int32_t len, MidiEvent * (val[1] >= 0x10 && val[3] == 0x03))) /* Parameter Change */ { uint8_t addhigh, addmid, addlow; /* Addresses */ - uint8_t *body; /* SysEx body */ + const uint8_t *body; /* SysEx body */ int ent; /* Entry # of sub-event */ - uint8_t *body_end; /* End of SysEx body */ + const uint8_t *body_end; /* End of SysEx body */ if (val[1] < 0x10) /* Bulk Dump */ { @@ -524,10 +459,10 @@ int SysexConvert::parse_sysex_event_multi(uint8_t *val, int32_t len, MidiEvent * (val[1] >= 0x10 && val[3] == 0x08))) /* Parameter Change */ { uint8_t addhigh, addmid, addlow; /* Addresses */ - uint8_t *body; /* SysEx body */ + const uint8_t *body; /* SysEx body */ uint8_t p; /* Channel part number [0..15] */ int ent; /* Entry # of sub-event */ - uint8_t *body_end; /* End of SysEx body */ + const uint8_t *body_end; /* End of SysEx body */ if (val[1] < 0x10) /* Bulk Dump */ { @@ -1094,10 +1029,10 @@ int SysexConvert::parse_sysex_event_multi(uint8_t *val, int32_t len, MidiEvent * (val[1] >= 0x10 && (val[3] & 0xF0) == 0x30))) /* Parameter Change */ { uint8_t addhigh, addmid, addlow; /* Addresses */ - uint8_t *body; /* SysEx body */ + const uint8_t *body; /* SysEx body */ uint8_t dp, note; /* Channel part number [0..15] */ int ent; /* Entry # of sub-event */ - uint8_t *body_end; /* End of SysEx body */ + const uint8_t *body_end; /* End of SysEx body */ if (val[1] < 0x10) /* Bulk Dump */ { @@ -2410,7 +2345,7 @@ int SysexConvert::parse_sysex_event_multi(uint8_t *val, int32_t len, MidiEvent * } -int SysexConvert::parse_sysex_event(uint8_t *val, int32_t len, MidiEvent *ev, Instruments *instruments) +int SysexConvert::parse_sysex_event(const uint8_t *val, int32_t len, MidiEvent *ev, Instruments *instruments) { uint16_t vol; @@ -2430,7 +2365,7 @@ int SysexConvert::parse_sysex_event(uint8_t *val, int32_t len, MidiEvent *ev, In */ int32_t addr, checksum, i; /* SysEx address */ - uint8_t *body; /* SysEx body */ + const uint8_t *body; /* SysEx body */ uint8_t p, gslen; /* Channel part number [0..15] */ /* check Checksum */