- 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.
This commit is contained in:
Christoph Oelckers 2018-02-21 02:02:29 +01:00
parent 4813eeeb85
commit 445e9451cb
4 changed files with 130 additions and 99 deletions

View file

@ -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;
}

View file

@ -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]);
}
}
}
}

View file

@ -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);
}

View file

@ -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 */