/* TiMidity++ -- MIDI to WAVE converter and player Copyright (C) 1999-2009 Masanao Izumo Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA playmidi.c -- random stuff in need of rearrangement */ #include #include #include #include #include #include "timidity.h" #include "common.h" #include "instrum.h" #include "playmidi.h" #include "mix.h" #include "recache.h" #include "reverb.h" #include "freq.h" #include "quantity.h" #include "tables.h" #include "effect.h" namespace TimidityPlus { std::mutex CvarCritSec; bool timidity_modulation_wheel = true; bool timidity_portamento = false; int timidity_reverb = 0; int timidity_chorus = 0; bool timidity_surround_chorus = false; // requires restart! bool timidity_channel_pressure = false; int timidity_lpf_def = true; bool timidity_temper_control = true; bool timidity_modulation_envelope = true; bool timidity_overlap_voice_allow = true; bool timidity_drum_effect = false; bool timidity_pan_delay = false; float timidity_drum_power = 1.f; int timidity_key_adjust = 0; float timidity_tempo_adjust = 1.f; float min_sustain_time = 5000; // The following options have no generic use and are only meaningful for some SYSEX events not normally found in common MIDIs. // For now they are kept as unchanging global variables static bool opt_eq_control = false; static bool op_nrpn_vibrato = true; static bool opt_tva_attack = false; static bool opt_tva_decay = false; static bool opt_tva_release = false; static bool opt_insertion_effect = false; static bool opt_delay_control = false; // These two variables need to remain global or things will get messy because they get accessed from non-class code. int32_t control_ratio = 22; int32_t playback_rate = 22050; #define PLAY_INTERLEAVE_SEC 1.0 #define PORTAMENTO_TIME_TUNING (1.0 / 5000.0) #define PORTAMENTO_CONTROL_RATIO 256 /* controls per sec */ #define DEFAULT_CHORUS_DELAY1 0.02 #define DEFAULT_CHORUS_DELAY2 0.003 #define CHORUS_OPPOSITE_THRESHOLD 32 #define EOT_PRESEARCH_LEN 32 #define SPEED_CHANGE_RATE 1.0594630943592953 /* 2^(1/12) */ #define DEFAULT_AMPLIFICATION 70 #define VIBRATO_DEPTH_MAX 384 /* 600 cent */ void set_playback_rate(int freq) { const int CONTROLS_PER_SECOND = 1000; const int MAX_CONTROL_RATIO = 255; playback_rate = freq; control_ratio = playback_rate / CONTROLS_PER_SECOND; if (control_ratio < 1) control_ratio = 1; else if (control_ratio > MAX_CONTROL_RATIO) control_ratio = MAX_CONTROL_RATIO; } Player::Player(Instruments *instr) { last_reverb_setting = timidity_reverb; memset(this, 0, sizeof(*this)); // init one-time global stuff - this should go to the device class once it exists. instruments = instr; initialize_resampler_coeffs(); init_tables(); new_midi_file_info(); init_mblock(&playmidi_pool); reverb = new Reverb; reverb->init_effect_status(play_system_mode); effect = new Effect(reverb); mixer = new Mixer(this); recache = new Recache(this); for (int i = 0; i < MAX_CHANNELS; i++) init_channel_layer(i); instruments->init_userdrum(); instruments->init_userinst(); master_volume_ratio = 0xFFFF; vol_table = def_vol_table; play_system_mode = DEFAULT_SYSTEM_MODE; midi_streaming = 0; stream_max_compute = 500; /* compute time limit (in msec) when streaming */ current_keysig = 0; current_temper_keysig = 0; temper_adj = 0; current_play_tempo = 500000; opt_realtime_playing = 0; check_eot_flag; playmidi_seek_flag = 0; opt_pure_intonation = 0; current_freq_table = 0; current_temper_freq_table = 0; master_tuning = 0; make_rvid_flag = 0; /* For reverb optimization */ voices = DEFAULT_VOICES; amplification = DEFAULT_AMPLIFICATION; static const int drums[] = { 10, -1 }; CLEAR_CHANNELMASK(default_drumchannels); for (int i = 0; drums[i] > 0; i++) { SET_CHANNELMASK(default_drumchannels, drums[i] - 1); } for (int i = 16; i < MAX_CHANNELS; i++) { if (IS_SET_CHANNELMASK(default_drumchannels, i & 0xF)) SET_CHANNELMASK(default_drumchannels, i); } COPY_CHANNELMASK(drumchannels, default_drumchannels); COPY_CHANNELMASK(drumchannel_mask, default_drumchannel_mask); } Player::~Player() { reuse_mblock(&playmidi_pool); if (reverb_buffer != nullptr) free(reverb_buffer); for (int i = 0; i < MAX_CHANNELS; i++) free_drum_effect(i); delete mixer; delete recache; delete effect; delete reverb; } bool Player::IS_SYSEX_EVENT_TYPE(MidiEvent *event) { return ((event)->type == ME_NONE || (event)->type >= ME_RANDOM_PAN || (event)->b == SYSEX_TAG); } void Player::init_freq_table_user(void) { int p, i, j, k, l; double f; for (p = 0; p < 4; p++) for (i = 0; i < 12; i++) for (j = -1; j < 11; j++) { f = 440 * pow(2.0, (i - 9) / 12.0 + j - 5); for (k = 0; k < 12; k++) { l = i + j * 12 + k; if (l < 0 || l >= 128) continue; freq_table_user[p][i][l] = f * 1000 + 0.5; freq_table_user[p][i + 12][l] = f * 1000 + 0.5; freq_table_user[p][i + 24][l] = f * 1000 + 0.5; freq_table_user[p][i + 36][l] = f * 1000 + 0.5; } } } /*! convert Hz to internal vibrato control ratio. */ double Player::cnv_Hz_to_vib_ratio(double freq) { return ((double)(playback_rate) / (freq * 2.0f * VIBRATO_SAMPLE_INCREMENTS)); } void Player::adjust_amplification(void) { static const double compensation_ratio = 1.0; /* compensate master volume */ master_volume = (double)(amplification) / 100.0 * ((double)master_volume_ratio * (compensation_ratio/0xFFFF)); } int Player::new_vidq(int ch, int note) { int i; if(timidity_overlap_voice_allow) { i = ch * 128 + note; return vidq_head[i]++; } return 0; } int Player::last_vidq(int ch, int note) { int i; if(timidity_overlap_voice_allow) { i = ch * 128 + note; if(vidq_head[i] == vidq_tail[i]) { return -1; } return vidq_tail[i]++; } return 0; } void Player::reset_voices(void) { int i; for(i = 0; i < max_voices; i++) { voice[i].status = VOICE_FREE; voice[i].temper_instant = 0; voice[i].chorus_link = i; } upper_voices = 0; memset(vidq_head, 0, sizeof(vidq_head)); memset(vidq_tail, 0, sizeof(vidq_tail)); } void Player::kill_note(int i) { voice[i].status = VOICE_DIE; } void Player::kill_all_voices(void) { int i, uv = upper_voices; for(i = 0; i < uv; i++) if(voice[i].status & ~(VOICE_FREE | VOICE_DIE)) kill_note(i); memset(vidq_head, 0, sizeof(vidq_head)); memset(vidq_tail, 0, sizeof(vidq_tail)); } void Player::reset_drum_controllers(struct DrumParts *d[], int note) { int i, j; if (note == -1) { for (i = 0; i < 128; i++) if (d[i] != NULL) { d[i]->drum_panning = NO_PANNING; for (j = 0; j < 6; j++) { d[i]->drum_envelope_rate[j] = -1; } d[i]->pan_random = 0; d[i]->drum_level = 1.0f; d[i]->coarse = 0; d[i]->fine = 0; d[i]->delay_level = -1; d[i]->chorus_level = -1; d[i]->reverb_level = -1; d[i]->play_note = -1; d[i]->drum_cutoff_freq = 0; d[i]->drum_resonance = 0; init_rx_drum(d[i]); } } else { d[note]->drum_panning = NO_PANNING; for (j = 0; j < 6; j++) { d[note]->drum_envelope_rate[j] = -1; } d[note]->pan_random = 0; d[note]->drum_level = 1.0f; d[note]->coarse = 0; d[note]->fine = 0; d[note]->delay_level = -1; d[note]->chorus_level = -1; d[note]->reverb_level = -1; d[note]->play_note = -1; d[note]->drum_cutoff_freq = 0; d[note]->drum_resonance = 0; init_rx_drum(d[note]); } } void Player::reset_nrpn_controllers(int c) { int i; /* NRPN */ reset_drum_controllers(channel[c].drums, -1); channel[c].vibrato_ratio = 1.0; channel[c].vibrato_depth = 0; channel[c].vibrato_delay = 0; channel[c].param_cutoff_freq = 0; channel[c].param_resonance = 0; channel[c].cutoff_freq_coef = 1.0; channel[c].resonance_dB = 0; /* System Exclusive */ channel[c].dry_level = 127; channel[c].eq_gs = 1; channel[c].insertion_effect = 0; channel[c].velocity_sense_depth = 0x40; channel[c].velocity_sense_offset = 0x40; channel[c].pitch_offset_fine = 0; if (play_system_mode == GS_SYSTEM_MODE) { channel[c].assign_mode = 1; } else { if (ISDRUMCHANNEL(c)) { channel[c].assign_mode = 1; } else { channel[c].assign_mode = 2; } } for (i = 0; i < 12; i++) channel[c].scale_tuning[i] = 0; channel[c].prev_scale_tuning = 0; channel[c].temper_type = 0; init_channel_layer(c); init_part_eq_xg(&(channel[c].eq_xg)); /* channel pressure & polyphonic key pressure control */ init_midi_controller(&(channel[c].mod)); init_midi_controller(&(channel[c].bend)); init_midi_controller(&(channel[c].caf)); init_midi_controller(&(channel[c].paf)); init_midi_controller(&(channel[c].cc1)); init_midi_controller(&(channel[c].cc2)); channel[c].bend.pitch = 2; init_rx(c); channel[c].note_limit_high = 127; channel[c].note_limit_low = 0; channel[c].vel_limit_high = 127; channel[c].vel_limit_low = 0; free_drum_effect(c); channel[c].legato = 0; channel[c].damper_mode = 0; channel[c].loop_timeout = 0; channel[c].sysex_gs_msb_addr = channel[c].sysex_gs_msb_val = channel[c].sysex_xg_msb_addr = channel[c].sysex_xg_msb_val = channel[c].sysex_msb_addr = channel[c].sysex_msb_val = 0; } /* Process the Reset All Controllers event */ void Player::reset_controllers(int c) { int j; /* Some standard says, although the SCC docs say 0. */ if (play_system_mode == XG_SYSTEM_MODE) channel[c].volume = 100; else channel[c].volume = 90; channel[c].expression = 127; /* SCC-1 does this. */ channel[c].sustain = 0; channel[c].sostenuto = 0; channel[c].pitchbend = 0x2000; channel[c].pitchfactor = 0; /* to be computed */ channel[c].mod.val = 0; channel[c].bend.val = 0; channel[c].caf.val = 0; channel[c].paf.val = 0; channel[c].cc1.val = 0; channel[c].cc2.val = 0; channel[c].portamento_time_lsb = 0; channel[c].portamento_time_msb = 0; channel[c].porta_control_ratio = 0; channel[c].portamento = 0; channel[c].last_note_fine = -1; for (j = 0; j < 6; j++) { channel[c].envelope_rate[j] = -1; } update_portamento_controls(c); set_reverb_level(c, -1); if (timidity_chorus == 1) channel[c].chorus_level = 0; else channel[c].chorus_level = -timidity_chorus; channel[c].mono = 0; channel[c].delay_level = 0; } int Player::get_default_mapID(int ch) { if (play_system_mode == XG_SYSTEM_MODE) return ISDRUMCHANNEL(ch) ? XG_DRUM_MAP : XG_NORMAL_MAP; return INST_NO_MAP; } void Player::reset_midi(int playing) { int i; for (i = 0; i < MAX_CHANNELS; i++) { reset_controllers(i); reset_nrpn_controllers(i); channel[i].tone_map0_number = 0; channel[i].mod.lfo1_pitch_depth = 50; /* The rest of these are unaffected * by the Reset All Controllers event */ channel[i].program = instruments->defaultProgram(i); channel[i].panning = NO_PANNING; channel[i].pan_random = 0; /* tone bank or drum set */ if (ISDRUMCHANNEL(i)) { channel[i].bank = 0; channel[i].altassign = instruments->drumSet(0)->alt; } else { if (special_tonebank >= 0) channel[i].bank = special_tonebank; else channel[i].bank = default_tonebank; } channel[i].bank_lsb = channel[i].bank_msb = 0; if (play_system_mode == XG_SYSTEM_MODE && i % 16 == 9) channel[i].bank_msb = 127; /* Use MSB=127 for XG */ update_rpn_map(i, RPN_ADDR_FFFF, 0); channel[i].special_sample = 0; channel[i].key_shift = 0; channel[i].mapID = get_default_mapID(i); channel[i].lasttime = 0; } if (playing) { kill_all_voices(); if (temper_type_mute) { if (temper_type_mute & 1) FILL_CHANNELMASK(channel_mute); else CLEAR_CHANNELMASK(channel_mute); } } else reset_voices(); master_volume_ratio = 0xffff; adjust_amplification(); master_tuning = 0; if (current_file_info) { COPY_CHANNELMASK(drumchannels, current_file_info->drumchannels); COPY_CHANNELMASK(drumchannel_mask, current_file_info->drumchannel_mask); } else { COPY_CHANNELMASK(drumchannels, default_drumchannels); COPY_CHANNELMASK(drumchannel_mask, default_drumchannel_mask); } } void Player::recompute_freq(int v) { int i; int ch = voice[v].channel; int note = voice[v].note; int32_t tuning = 0; int8_t st = channel[ch].scale_tuning[note % 12]; int8_t tt = channel[ch].temper_type; uint8_t tp = channel[ch].rpnmap[RPN_ADDR_0003]; int32_t f; int pb = channel[ch].pitchbend; int32_t tmp; double pf, root_freq; int32_t a; Voice *vp = &(voice[v]); if (! voice[v].sample->sample_rate) return; if (! timidity_modulation_wheel) channel[ch].mod.val = 0; if (! timidity_portamento) voice[v].porta_control_ratio = 0; voice[v].vibrato_control_ratio = voice[v].orig_vibrato_control_ratio; if (voice[v].vibrato_control_ratio || channel[ch].mod.val > 0) { /* This instrument has vibrato. Invalidate any precomputed * sample_increments. */ /* MIDI controllers LFO pitch depth */ if (timidity_channel_pressure || timidity_modulation_wheel) { vp->vibrato_depth = vp->sample->vibrato_depth + channel[ch].vibrato_depth; vp->vibrato_depth += get_midi_controller_pitch_depth(&(channel[ch].mod)) + get_midi_controller_pitch_depth(&(channel[ch].bend)) + get_midi_controller_pitch_depth(&(channel[ch].caf)) + get_midi_controller_pitch_depth(&(channel[ch].paf)) + get_midi_controller_pitch_depth(&(channel[ch].cc1)) + get_midi_controller_pitch_depth(&(channel[ch].cc2)); if (vp->vibrato_depth > VIBRATO_DEPTH_MAX) {vp->vibrato_depth = VIBRATO_DEPTH_MAX;} else if (vp->vibrato_depth < 1) {vp->vibrato_depth = 1;} if (vp->sample->vibrato_depth < 0) { /* in opposite phase */ vp->vibrato_depth = -vp->vibrato_depth; } } /* fill parameters for modulation wheel */ if (channel[ch].mod.val > 0) { if(vp->vibrato_control_ratio == 0) { vp->vibrato_control_ratio = vp->orig_vibrato_control_ratio = (int)(cnv_Hz_to_vib_ratio(5.0) * channel[ch].vibrato_ratio); } vp->vibrato_delay = 0; } for (i = 0; i < VIBRATO_SAMPLE_INCREMENTS; i++) vp->vibrato_sample_increment[i] = 0; vp->cache = NULL; } /* At least for GM2, it's recommended not to apply master_tuning for drum channels */ tuning = ISDRUMCHANNEL(ch) ? 0 : master_tuning; /* fine: [0..128] => [-256..256] * 1 coarse = 256 fine (= 1 note) * 1 fine = 2^5 tuning */ tuning += (channel[ch].rpnmap[RPN_ADDR_0001] - 0x40 + (channel[ch].rpnmap[RPN_ADDR_0002] - 0x40) * 64) << 7; /* for NRPN Coarse Pitch of Drum (GS) & Fine Pitch of Drum (XG) */ if (ISDRUMCHANNEL(ch) && channel[ch].drums[note] != NULL && (channel[ch].drums[note]->fine || channel[ch].drums[note]->coarse)) { tuning += (channel[ch].drums[note]->fine + channel[ch].drums[note]->coarse * 64) << 7; } /* MIDI controllers pitch control */ if (timidity_channel_pressure) { tuning += get_midi_controller_pitch(&(channel[ch].mod)) + get_midi_controller_pitch(&(channel[ch].bend)) + get_midi_controller_pitch(&(channel[ch].caf)) + get_midi_controller_pitch(&(channel[ch].paf)) + get_midi_controller_pitch(&(channel[ch].cc1)) + get_midi_controller_pitch(&(channel[ch].cc2)); } if (timidity_modulation_envelope) { if (voice[v].sample->tremolo_to_pitch) { tuning += lookup_triangular(voice[v].tremolo_phase >> RATE_SHIFT) * (voice[v].sample->tremolo_to_pitch << 13) / 100.0 + 0.5; channel[ch].pitchfactor = 0; } if (voice[v].sample->modenv_to_pitch) { tuning += voice[v].last_modenv_volume * (voice[v].sample->modenv_to_pitch << 13) / 100.0 + 0.5; channel[ch].pitchfactor = 0; } } /* GS/XG - Scale Tuning */ if (! ISDRUMCHANNEL(ch)) { tuning += ((st << 13) + 50) / 100; if (st != channel[ch].prev_scale_tuning) { channel[ch].pitchfactor = 0; channel[ch].prev_scale_tuning = st; } } if (! opt_pure_intonation && timidity_temper_control && voice[v].temper_instant) { switch (tt) { case 0: f = freq_table_tuning[tp][note]; break; case 1: if (current_temper_keysig < 8) f = freq_table_pytha[current_temper_freq_table][note]; else f = freq_table_pytha[current_temper_freq_table + 12][note]; break; case 2: if (current_temper_keysig < 8) f = freq_table_meantone[current_temper_freq_table + ((temper_adj) ? 36 : 0)][note]; else f = freq_table_meantone[current_temper_freq_table + ((temper_adj) ? 24 : 12)][note]; break; case 3: if (current_temper_keysig < 8) f = freq_table_pureint[current_temper_freq_table + ((temper_adj) ? 36 : 0)][note]; else f = freq_table_pureint[current_temper_freq_table + ((temper_adj) ? 24 : 12)][note]; break; default: /* user-defined temperament */ if ((tt -= 0x40) >= 0 && tt < 4) { if (current_temper_keysig < 8) f = freq_table_user[tt][current_temper_freq_table + ((temper_adj) ? 36 : 0)][note]; else f = freq_table_user[tt][current_temper_freq_table + ((temper_adj) ? 24 : 12)][note]; } else f = freq_table[note]; break; } voice[v].orig_frequency = f; } if (! voice[v].porta_control_ratio) { if (tuning == 0 && pb == 0x2000) voice[v].frequency = voice[v].orig_frequency; else { pb -= 0x2000; if (! channel[ch].pitchfactor) { /* Damn. Somebody bent the pitch. */ tmp = pb * channel[ch].rpnmap[RPN_ADDR_0000] + tuning; if (tmp >= 0) channel[ch].pitchfactor = bend_fine[tmp >> 5 & 0xff] * bend_coarse[tmp >> 13 & 0x7f]; else channel[ch].pitchfactor = 1.0 / (bend_fine[-tmp >> 5 & 0xff] * bend_coarse[-tmp >> 13 & 0x7f]); } voice[v].frequency = voice[v].orig_frequency * channel[ch].pitchfactor; if (voice[v].frequency != voice[v].orig_frequency) voice[v].cache = NULL; } } else { /* Portamento */ pb -= 0x2000; tmp = pb * channel[ch].rpnmap[RPN_ADDR_0000] + (voice[v].porta_pb << 5) + tuning; if (tmp >= 0) pf = bend_fine[tmp >> 5 & 0xff] * bend_coarse[tmp >> 13 & 0x7f]; else pf = 1.0 / (bend_fine[-tmp >> 5 & 0xff] * bend_coarse[-tmp >> 13 & 0x7f]); voice[v].frequency = voice[v].orig_frequency * pf; voice[v].cache = NULL; } root_freq = voice[v].sample->root_freq; a = TIM_FSCALE(((double) voice[v].sample->sample_rate * ((double)voice[v].frequency + channel[ch].pitch_offset_fine)) / (root_freq * playback_rate), FRACTION_BITS) + 0.5; /* need to preserve the loop direction */ voice[v].sample_increment = (voice[v].sample_increment >= 0) ? a : -a; } int32_t Player::calc_velocity(int32_t ch,int32_t vel) { int32_t velocity; velocity = channel[ch].velocity_sense_depth * vel / 64 + (channel[ch].velocity_sense_offset - 64) * 2; if(velocity > 127) {velocity = 127;} return velocity; } void Player::recompute_voice_tremolo(int v) { Voice *vp = &(voice[v]); int ch = vp->channel; int32_t depth = vp->sample->tremolo_depth; depth += get_midi_controller_amp_depth(&(channel[ch].mod)) + get_midi_controller_amp_depth(&(channel[ch].bend)) + get_midi_controller_amp_depth(&(channel[ch].caf)) + get_midi_controller_amp_depth(&(channel[ch].paf)) + get_midi_controller_amp_depth(&(channel[ch].cc1)) + get_midi_controller_amp_depth(&(channel[ch].cc2)); if(depth > 256) {depth = 256;} vp->tremolo_depth = depth; } void Player::recompute_amp(int v) { double tempamp; int ch = voice[v].channel; /* master_volume and sample->volume are percentages, used to scale * amplitude directly, NOT perceived volume * * all other MIDI volumes are linear in perceived volume, 0-127 * use a lookup table for the non-linear scalings */ if (play_system_mode == GM2_SYSTEM_MODE) { tempamp = master_volume * voice[v].sample->volume * gm2_vol_table[calc_velocity(ch, voice[v].velocity)] * /* velocity: not in GM2 standard */ gm2_vol_table[channel[ch].volume] * gm2_vol_table[channel[ch].expression]; /* 21 bits */ } else if (play_system_mode == GS_SYSTEM_MODE) { /* use measured curve */ tempamp = master_volume * voice[v].sample->volume * sc_vel_table[calc_velocity(ch, voice[v].velocity)] * sc_vol_table[channel[ch].volume] * sc_vol_table[channel[ch].expression]; /* 21 bits */ } else { /* use generic exponential curve */ tempamp = master_volume * voice[v].sample->volume * perceived_vol_table[calc_velocity(ch, voice[v].velocity)] * perceived_vol_table[channel[ch].volume] * perceived_vol_table[channel[ch].expression]; /* 21 bits */ } /* every digital effect increases amplitude, * so that it must be reduced in advance. */ if ( (timidity_reverb || timidity_chorus || opt_delay_control || (opt_eq_control && (reverb->eq_status_gs.low_gain != 0x40 || reverb->eq_status_gs.high_gain != 0x40)) || opt_insertion_effect)) tempamp *= 1.35f * 0.55f; else tempamp *= 1.35f; /* Reduce amplitude for chorus partners. * 2x voices -> 2x power -> sqrt(2)x amplitude. * 1 / sqrt(2) = ~0.7071, which is very close to the old * CHORUS_VELOCITY_TUNING1 value of 0.7. * * The previous amp scaling for the various digital effects should * really be redone to split them into separate scalings for each * effect, rather than a single scaling if any one of them is used * (which is NOT correct). As it is now, if partner chorus is the * only effect in use, then it is reduced in volume twice and winds * up too quiet. Compare the output of "-EFreverb=0 -EFchorus=0", * "-EFreverb=0 -EFchorus=2", "-EFreverb=4 -EFchorus=2", and * "-EFreverb=4 -EFchorus=0" to see how the digital effect volumes * are not scaled properly. Idealy, all the resulting output should * have the same volume, regardless of effects used. This will * require empirically determining the amount to scale for each * individual effect. */ if (voice[v].chorus_link != v) tempamp *= 0.7071067811865f; /* NRPN - drum instrument tva level */ if (ISDRUMCHANNEL(ch)) { if (channel[ch].drums[voice[v].note] != NULL) { tempamp *= channel[ch].drums[voice[v].note]->drum_level; } tempamp *= (double)timidity_drum_power; /* global drum power */ } /* MIDI controllers amplitude control */ if (timidity_channel_pressure) { tempamp *= get_midi_controller_amp(&(channel[ch].mod)) * get_midi_controller_amp(&(channel[ch].bend)) * get_midi_controller_amp(&(channel[ch].caf)) * get_midi_controller_amp(&(channel[ch].paf)) * get_midi_controller_amp(&(channel[ch].cc1)) * get_midi_controller_amp(&(channel[ch].cc2)); recompute_voice_tremolo(v); } if (voice[v].fc.type != 0) { tempamp *= voice[v].fc.gain; /* filter gain */ } /* applying panning to amplitude */ if (true) { if (voice[v].panning == 64) { voice[v].panned = PANNED_CENTER; voice[v].left_amp = voice[v].right_amp = TIM_FSCALENEG(tempamp * pan_table[64], 27); } else if (voice[v].panning < 2) { voice[v].panned = PANNED_LEFT; voice[v].left_amp = TIM_FSCALENEG(tempamp, 20); voice[v].right_amp = 0; } else if (voice[v].panning == 127) { if (voice[v].panned == PANNED_MYSTERY) { voice[v].old_left_mix = voice[v].old_right_mix; voice[v].old_right_mix = 0; } voice[v].panned = PANNED_RIGHT; voice[v].left_amp = TIM_FSCALENEG(tempamp, 20); voice[v].right_amp = 0; } else { if (voice[v].panned == PANNED_RIGHT) { voice[v].old_right_mix = voice[v].old_left_mix; voice[v].old_left_mix = 0; } voice[v].panned = PANNED_MYSTERY; voice[v].left_amp = TIM_FSCALENEG(tempamp * pan_table[128 - voice[v].panning], 27); voice[v].right_amp = TIM_FSCALENEG(tempamp * pan_table[voice[v].panning], 27); } } else { voice[v].panned = PANNED_CENTER; voice[v].left_amp = TIM_FSCALENEG(tempamp, 21); } } #define RESONANCE_COEFF 0.2393 void Player::recompute_channel_filter(int ch, int note) { double coef = 1.0f, reso = 0; if(channel[ch].special_sample > 0) {return;} /* Soft Pedal */ if(channel[ch].soft_pedal != 0) { if(note > 49) { /* tre corde */ coef *= 1.0 - 0.20 * ((double)channel[ch].soft_pedal) / 127.0f; } else { /* una corda (due corde) */ coef *= 1.0 - 0.25 * ((double)channel[ch].soft_pedal) / 127.0f; } } if(!ISDRUMCHANNEL(ch)) { /* NRPN Filter Cutoff */ coef *= pow(1.26, (double)(channel[ch].param_cutoff_freq) / 8.0f); /* NRPN Resonance */ reso = (double)channel[ch].param_resonance * RESONANCE_COEFF; } channel[ch].cutoff_freq_coef = coef; channel[ch].resonance_dB = reso; } void Player::init_voice_filter(int i) { memset(&(voice[i].fc), 0, sizeof(FilterCoefficients)); if(timidity_lpf_def && voice[i].sample->cutoff_freq) { voice[i].fc.orig_freq = voice[i].sample->cutoff_freq; voice[i].fc.orig_reso_dB = (double)voice[i].sample->resonance / 10.0f - 3.01f; if (voice[i].fc.orig_reso_dB < 0.0f) {voice[i].fc.orig_reso_dB = 0.0f;} if (timidity_lpf_def == 2) { voice[i].fc.gain = 1.0; voice[i].fc.type = 2; } else if(timidity_lpf_def == 1) { voice[i].fc.gain = pow(10.0f, -voice[i].fc.orig_reso_dB / 2.0f / 20.0f); voice[i].fc.type = 1; } voice[i].fc.start_flag = 0; } else { voice[i].fc.type = 0; } } #define CHAMBERLIN_RESONANCE_MAX 24.0 void Player::recompute_voice_filter(int v) { int ch = voice[v].channel, note = voice[v].note; double coef = 1.0, reso = 0, cent = 0, depth_cent = 0, freq; FilterCoefficients *fc = &(voice[v].fc); Sample *sp = (Sample *) &voice[v].sample; if(fc->type == 0) {return;} coef = channel[ch].cutoff_freq_coef; if(ISDRUMCHANNEL(ch) && channel[ch].drums[note] != NULL) { /* NRPN Drum Instrument Filter Cutoff */ coef *= pow(1.26, (double)(channel[ch].drums[note]->drum_cutoff_freq) / 8.0f); /* NRPN Drum Instrument Filter Resonance */ reso += (double)channel[ch].drums[note]->drum_resonance * RESONANCE_COEFF; } /* MIDI controllers filter cutoff control and LFO filter depth */ if(timidity_channel_pressure) { cent += get_midi_controller_filter_cutoff(&(channel[ch].mod)) + get_midi_controller_filter_cutoff(&(channel[ch].bend)) + get_midi_controller_filter_cutoff(&(channel[ch].caf)) + get_midi_controller_filter_cutoff(&(channel[ch].paf)) + get_midi_controller_filter_cutoff(&(channel[ch].cc1)) + get_midi_controller_filter_cutoff(&(channel[ch].cc2)); depth_cent += get_midi_controller_filter_depth(&(channel[ch].mod)) + get_midi_controller_filter_depth(&(channel[ch].bend)) + get_midi_controller_filter_depth(&(channel[ch].caf)) + get_midi_controller_filter_depth(&(channel[ch].paf)) + get_midi_controller_filter_depth(&(channel[ch].cc1)) + get_midi_controller_filter_depth(&(channel[ch].cc2)); } if(sp->vel_to_fc) { /* velocity to filter cutoff frequency */ if(voice[v].velocity > sp->vel_to_fc_threshold) cent += sp->vel_to_fc * (double)(127 - voice[v].velocity) / 127.0f; else coef += sp->vel_to_fc * (double)(127 - sp->vel_to_fc_threshold) / 127.0f; } if(sp->vel_to_resonance) { /* velocity to filter resonance */ reso += (double)voice[v].velocity * sp->vel_to_resonance / 127.0f / 10.0f; } if(sp->key_to_fc) { /* filter cutoff key-follow */ cent += sp->key_to_fc * (double)(voice[v].note - sp->key_to_fc_bpo); } if(timidity_modulation_envelope) { if(voice[v].sample->tremolo_to_fc + (int16_t)depth_cent) { cent += ((double)voice[v].sample->tremolo_to_fc + depth_cent) * lookup_triangular(voice[v].tremolo_phase >> RATE_SHIFT); } if(voice[v].sample->modenv_to_fc) { cent += (double)voice[v].sample->modenv_to_fc * voice[v].last_modenv_volume; } } if(cent != 0) {coef *= pow(2.0, cent / 1200.0f);} freq = (double)fc->orig_freq * coef; if (freq > playback_rate / 2) {freq = playback_rate / 2;} else if(freq < 5) {freq = 5;} fc->freq = (int32_t)freq; fc->reso_dB = fc->orig_reso_dB + channel[ch].resonance_dB + reso; if(fc->reso_dB < 0.0f) {fc->reso_dB = 0.0f;} else if(fc->reso_dB > 96.0f) {fc->reso_dB = 96.0f;} if(fc->type == 1) { /* Chamberlin filter */ if(fc->freq > playback_rate / 6) { if (fc->start_flag == 0) {fc->type = 0;} /* turn off. */ else {fc->freq = playback_rate / 6;} } if(fc->reso_dB > CHAMBERLIN_RESONANCE_MAX) {fc->reso_dB = CHAMBERLIN_RESONANCE_MAX;} } else if(fc->type == 2) { /* Moog VCF */ if(fc->reso_dB > fc->orig_reso_dB / 2) { fc->gain = pow(10.0f, (fc->reso_dB - fc->orig_reso_dB / 2) / 20.0f); } } fc->start_flag = 1; /* filter is started. */ } float Player::calc_drum_tva_level(int ch, int note, int level) { int def_level, nbank, nprog; const ToneBank *bank; if(channel[ch].special_sample > 0) {return 1.0;} nbank = channel[ch].bank; nprog = note; instruments->instrument_map(channel[ch].mapID, &nbank, &nprog); if(ISDRUMCHANNEL(ch)) { bank = instruments->drumSet(nbank); if(bank == NULL) {bank = instruments->drumSet(0);} } else { return 1.0; } def_level = bank->tone[nprog].tva_level; if(def_level == -1 || def_level == 0) {def_level = 127;} else if(def_level > 127) {def_level = 127;} return (sc_drum_level_table[level] / sc_drum_level_table[def_level]); } int32_t Player::calc_random_delay(int ch, int note) { int nbank, nprog; const ToneBank *bank; if(channel[ch].special_sample > 0) {return 0;} nbank = channel[ch].bank; if(ISDRUMCHANNEL(ch)) { nprog = note; instruments->instrument_map(channel[ch].mapID, &nbank, &nprog); bank = instruments->drumSet(nbank); if (bank == NULL) {bank = instruments->drumSet(0);} } else { nprog = channel[ch].program; if(nprog == SPECIAL_PROGRAM) {return 0;} instruments->instrument_map(channel[ch].mapID, &nbank, &nprog); bank = instruments->toneBank(nbank); if(bank == NULL) {bank = instruments->toneBank(0);} } if (bank->tone[nprog].rnddelay == 0) {return 0;} else {return (int32_t)((double)bank->tone[nprog].rnddelay * playback_rate / 1000.0 * (reverb->get_pink_noise_light(&reverb->global_pink_noise_light) + 1.0f) * 0.5);} } void Player::recompute_bank_parameter(int ch, int note) { int nbank, nprog; const ToneBank *bank; struct DrumParts *drum; if(channel[ch].special_sample > 0) {return;} nbank = channel[ch].bank; if(ISDRUMCHANNEL(ch)) { nprog = note; instruments->instrument_map(channel[ch].mapID, &nbank, &nprog); bank = instruments->drumSet(nbank); if (bank == NULL) {bank = instruments->drumSet(0);} if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); drum = channel[ch].drums[note]; if (drum->reverb_level == -1 && bank->tone[nprog].reverb_send != -1) { drum->reverb_level = bank->tone[nprog].reverb_send; } if (drum->chorus_level == -1 && bank->tone[nprog].chorus_send != -1) { drum->chorus_level = bank->tone[nprog].chorus_send; } if (drum->delay_level == -1 && bank->tone[nprog].delay_send != -1) { drum->delay_level = bank->tone[nprog].delay_send; } } else { nprog = channel[ch].program; if (nprog == SPECIAL_PROGRAM) {return;} instruments->instrument_map(channel[ch].mapID, &nbank, &nprog); bank = instruments->toneBank(nbank); if (bank == NULL) {bank = instruments->toneBank(0);} channel[ch].legato = bank->tone[nprog].legato; channel[ch].damper_mode = bank->tone[nprog].damper_mode; channel[ch].loop_timeout = bank->tone[nprog].loop_timeout; } } /* this reduces voices while maintaining sound quality */ int Player::reduce_voice(void) { int32_t lv, v; int i, j, lowest=-0x7FFFFFFF; i = upper_voices; lv = 0x7FFFFFFF; /* Look for the decaying note with the smallest volume */ /* Protect drum decays. Truncating them early sounds bad, especially on snares and cymbals */ for(j = 0; j < i; j++) { if(voice[j].status & VOICE_FREE || (voice[j].sample->note_to_use && ISDRUMCHANNEL(voice[j].channel))) continue; if(voice[j].status & ~(VOICE_ON | VOICE_DIE | VOICE_SUSTAINED)) { /* find lowest volume */ v = voice[j].left_mix; if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v) v = voice[j].right_mix; if(v < lv) { lv = v; lowest = j; } } } if(lowest != -0x7FFFFFFF) { /* This can still cause a click, but if we had a free voice to spare for ramping down this note, we wouldn't need to kill it in the first place... Still, this needs to be fixed. Perhaps we could use a reserve of voices to play dying notes only. */ cut_notes++; free_voice(lowest); return lowest; } /* try to remove VOICE_DIE before VOICE_ON */ lv = 0x7FFFFFFF; lowest = -1; for(j = 0; j < i; j++) { if(voice[j].status & VOICE_FREE) continue; if(voice[j].status & ~(VOICE_ON | VOICE_SUSTAINED)) { /* continue protecting drum decays */ if (voice[j].status & ~(VOICE_DIE) && (voice[j].sample->note_to_use && ISDRUMCHANNEL(voice[j].channel))) continue; /* find lowest volume */ v = voice[j].left_mix; if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v) v = voice[j].right_mix; if(v < lv) { lv = v; lowest = j; } } } if(lowest != -1) { cut_notes++; free_voice(lowest); return lowest; } /* try to remove VOICE_SUSTAINED before VOICE_ON */ lv = 0x7FFFFFFF; lowest = -0x7FFFFFFF; for(j = 0; j < i; j++) { if(voice[j].status & VOICE_FREE) continue; if(voice[j].status & VOICE_SUSTAINED) { /* find lowest volume */ v = voice[j].left_mix; if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v) v = voice[j].right_mix; if(v < lv) { lv = v; lowest = j; } } } if(lowest != -0x7FFFFFFF) { cut_notes++; free_voice(lowest); return lowest; } /* try to remove chorus before VOICE_ON */ lv = 0x7FFFFFFF; lowest = -0x7FFFFFFF; for(j = 0; j < i; j++) { if(voice[j].status & VOICE_FREE) continue; if(voice[j].chorus_link < j) { /* find lowest volume */ v = voice[j].left_mix; if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v) v = voice[j].right_mix; if(v < lv) { lv = v; lowest = j; } } } if(lowest != -0x7FFFFFFF) { cut_notes++; /* fix pan */ j = voice[lowest].chorus_link; voice[j].panning = channel[voice[lowest].channel].panning; recompute_amp(j); mixer->apply_envelope_to_amp(j); free_voice(lowest); return lowest; } lost_notes++; /* remove non-drum VOICE_ON */ lv = 0x7FFFFFFF; lowest = -0x7FFFFFFF; for(j = 0; j < i; j++) { if(voice[j].status & VOICE_FREE || (voice[j].sample->note_to_use && ISDRUMCHANNEL(voice[j].channel))) continue; /* find lowest volume */ v = voice[j].left_mix; if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v) v = voice[j].right_mix; if(v < lv) { lv = v; lowest = j; } } if(lowest != -0x7FFFFFFF) { free_voice(lowest); return lowest; } /* remove all other types of notes */ lv = 0x7FFFFFFF; lowest = 0; for(j = 0; j < i; j++) { if(voice[j].status & VOICE_FREE) continue; /* find lowest volume */ v = voice[j].left_mix; if(voice[j].panned == PANNED_MYSTERY && voice[j].right_mix > v) v = voice[j].right_mix; if(v < lv) { lv = v; lowest = j; } } free_voice(lowest); return lowest; } void Player::free_voice(int v1) { int v2; #ifdef ENABLE_PAN_DELAY if (voice[v1].pan_delay_buf != NULL) { free(voice[v1].pan_delay_buf); voice[v1].pan_delay_buf = NULL; } #endif /* ENABLE_PAN_DELAY */ v2 = voice[v1].chorus_link; if(v1 != v2) { /* Unlink chorus link */ voice[v1].chorus_link = v1; voice[v2].chorus_link = v2; } voice[v1].status = VOICE_FREE; voice[v1].temper_instant = 0; } int Player::find_free_voice(void) { int i, nv = voices, lowest; int32_t lv, v; for(i = 0; i < nv; i++) if(voice[i].status == VOICE_FREE) { if(upper_voices <= i) upper_voices = i + 1; return i; } upper_voices = voices; /* Look for the decaying note with the lowest volume */ lv = 0x7FFFFFFF; lowest = -1; for(i = 0; i < nv; i++) { if(voice[i].status & ~(VOICE_ON | VOICE_DIE) && !(voice[i].sample && voice[i].sample->note_to_use && ISDRUMCHANNEL(voice[i].channel))) { v = voice[i].left_mix; if((voice[i].panned==PANNED_MYSTERY) && (voice[i].right_mix>v)) v = voice[i].right_mix; if(vchannel; if (channel[ch].special_sample > 0) { if ((s = instruments->specialPatch(channel[ch].special_sample)) == NULL) { return 0; } note = e->a + channel[ch].key_shift + note_key_offset; note = (note < 0) ? 0 : ((note > 127) ? 127 : note); return select_play_sample(s->sample, s->samples, ¬e, vlist, e); } bank = channel[ch].bank; if (ISDRUMCHANNEL(ch)) { note = e->a & 0x7f; instruments->instrument_map(channel[ch].mapID, &bank, ¬e); if (! (ip = play_midi_load_instrument(1, bank, note))) return 0; /* No instrument? Then we can't play. */ /* "keynum" of SF2, and patch option "note=" */ if (ip->sample->note_to_use) note = ip->sample->note_to_use; } else { if ((prog = channel[ch].program) == SPECIAL_PROGRAM) ip = instruments->defaultInstrument(); else { instruments->instrument_map(channel[ch].mapID, &bank, &prog); if (! (ip = play_midi_load_instrument(0, bank, prog))) return 0; /* No instrument? Then we can't play. */ } note = ((ip->sample->note_to_use) ? ip->sample->note_to_use : e->a) + channel[ch].key_shift + note_key_offset; note = (note < 0) ? 0 : ((note > 127) ? 127 : note); } nv = select_play_sample(ip->sample, ip->samples, ¬e, vlist, e); /* Replace the sample if the sample is cached. */ if (ip->sample->note_to_use) note = MIDI_EVENT_NOTE(e); for (i = 0; i < nv; i++) { j = vlist[i]; if (! opt_realtime_playing && allocate_cache_size > 0 && ! channel[ch].portamento) { voice[j].cache = recache->resamp_cache_fetch(voice[j].sample, note); if (voice[j].cache) /* cache hit */ voice[j].sample = voice[j].cache->resampled; } else voice[j].cache = NULL; } return nv; } int Player::select_play_sample(Sample *splist, int nsp, int *note, int *vlist, MidiEvent *e) { int ch = e->channel, kn = e->a & 0x7f, vel = e->b; int32_t f, fs, ft, fst, fc, fr, cdiff, diff, sample_link; int8_t tt = channel[ch].temper_type; uint8_t tp = channel[ch].rpnmap[RPN_ADDR_0003]; Sample *sp, *spc, *spr; int16_t sf, sn; double ratio; int i, j, k, nv, nvc; if (ISDRUMCHANNEL(ch)) f = fs = freq_table[*note]; else { if (opt_pure_intonation) { if (current_keysig < 8) f = freq_table_pureint[current_freq_table][*note]; else f = freq_table_pureint[current_freq_table + 12][*note]; } else if (timidity_temper_control) switch (tt) { case 0: f = freq_table_tuning[tp][*note]; break; case 1: if (current_temper_keysig < 8) f = freq_table_pytha[ current_temper_freq_table][*note]; else f = freq_table_pytha[ current_temper_freq_table + 12][*note]; break; case 2: if (current_temper_keysig < 8) f = freq_table_meantone[current_temper_freq_table + ((temper_adj) ? 36 : 0)][*note]; else f = freq_table_meantone[current_temper_freq_table + ((temper_adj) ? 24 : 12)][*note]; break; case 3: if (current_temper_keysig < 8) f = freq_table_pureint[current_temper_freq_table + ((temper_adj) ? 36 : 0)][*note]; else f = freq_table_pureint[current_temper_freq_table + ((temper_adj) ? 24 : 12)][*note]; break; default: /* user-defined temperament */ if ((tt -= 0x40) >= 0 && tt < 4) { if (current_temper_keysig < 8) f = freq_table_user[tt][current_temper_freq_table + ((temper_adj) ? 36 : 0)][*note]; else f = freq_table_user[tt][current_temper_freq_table + ((temper_adj) ? 24 : 12)][*note]; } else f = freq_table[*note]; break; } else f = freq_table[*note]; if (! opt_pure_intonation && timidity_temper_control && tt == 0 && f != freq_table[*note]) { *note = log(f / 440000.0) / log(2) * 12 + 69.5; *note = (*note < 0) ? 0 : ((*note > 127) ? 127 : *note); fs = freq_table[*note]; } else fs = freq_table[*note]; } nv = 0; for (i = 0, sp = splist; i < nsp; i++, sp++) { /* GUS/SF2 - Scale Tuning */ if ((sf = sp->scale_factor) != 1024) { sn = sp->scale_freq; ratio = pow(2.0, (*note - sn) * (sf - 1024) / 12288.0); ft = f * ratio + 0.5, fst = fs * ratio + 0.5; } else ft = f, fst = fs; if (ISDRUMCHANNEL(ch) && channel[ch].drums[kn] != NULL) if ((ratio = get_play_note_ratio(ch, kn)) != 1.0) ft = ft * ratio + 0.5, fst = fst * ratio + 0.5; if (sp->low_freq <= fst && sp->high_freq >= fst && sp->low_vel <= vel && sp->high_vel >= vel && ! (sp->inst_type == INST_SF2 && sp->sample_type == SF_SAMPLETYPE_RIGHT)) { j = vlist[nv] = find_voice(e); voice[j].orig_frequency = ft; voice[j].sample = sp; voice[j].status = VOICE_ON; nv++; } } if (nv == 0) { /* we must select at least one sample. */ fr = fc = 0; spc = spr = NULL; cdiff = 0x7fffffff; for (i = 0, sp = splist; i < nsp; i++, sp++) { /* GUS/SF2 - Scale Tuning */ if ((sf = sp->scale_factor) != 1024) { sn = sp->scale_freq; ratio = pow(2.0, (*note - sn) * (sf - 1024) / 12288.0); ft = f * ratio + 0.5, fst = fs * ratio + 0.5; } else ft = f, fst = fs; if (ISDRUMCHANNEL(ch) && channel[ch].drums[kn] != NULL) if ((ratio = get_play_note_ratio(ch, kn)) != 1.0) ft = ft * ratio + 0.5, fst = fst * ratio + 0.5; diff = abs(sp->root_freq - fst); if (diff < cdiff) { if (sp->inst_type == INST_SF2 && sp->sample_type == SF_SAMPLETYPE_RIGHT) { fr = ft; /* reserve */ spr = sp; /* reserve */ } else { fc = ft; spc = sp; cdiff = diff; } } } /* If spc is not NULL, a makeshift sample is found. */ /* Otherwise, it's a lonely right sample, but better than nothing. */ j = vlist[nv] = find_voice(e); voice[j].orig_frequency = (spc) ? fc : fr; voice[j].sample = (spc) ? spc : spr; voice[j].status = VOICE_ON; nv++; } nvc = nv; for (i = 0; i < nvc; i++) { spc = voice[vlist[i]].sample; /* If it's left sample, there must be right sample. */ if (spc->inst_type == INST_SF2 && spc->sample_type == SF_SAMPLETYPE_LEFT) { sample_link = spc->sf_sample_link; for (j = 0, sp = splist; j < nsp; j++, sp++) if (sp->inst_type == INST_SF2 && sp->sample_type == SF_SAMPLETYPE_RIGHT && sp->sf_sample_index == sample_link) { /* right sample is found. */ /* GUS/SF2 - Scale Tuning */ if ((sf = sp->scale_factor) != 1024) { sn = sp->scale_freq; ratio = pow(2.0, (*note - sn) * (sf - 1024) / 12288.0); ft = f * ratio + 0.5; } else ft = f; if (ISDRUMCHANNEL(ch) && channel[ch].drums[kn] != NULL) if ((ratio = get_play_note_ratio(ch, kn)) != 1.0) ft = ft * ratio + 0.5; k = vlist[nv] = find_voice(e); voice[k].orig_frequency = ft; voice[k].sample = sp; voice[k].status = VOICE_ON; nv++; break; } } } return nv; } double Player::get_play_note_ratio(int ch, int note) { int play_note = channel[ch].drums[note]->play_note; int bank = channel[ch].bank; const ToneBank *dbank; int def_play_note; if (play_note == -1) return 1.0; instruments->instrument_map(channel[ch].mapID, &bank, ¬e); dbank = (instruments->drumSet(bank)) ? instruments->drumSet(bank) : instruments->drumSet(0); if ((def_play_note = dbank->tone[note].play_note) == -1) return 1.0; if (play_note >= def_play_note) return bend_coarse[(play_note - def_play_note) & 0x7f]; else return 1 / bend_coarse[(def_play_note - play_note) & 0x7f]; } /* Only one instance of a note can be playing on a single channel. */ int Player::find_voice(MidiEvent *e) { int ch = e->channel; int note = MIDI_EVENT_NOTE(e); int status_check, mono_check; AlternateAssign *altassign; int i, lowest = -1; status_check = (timidity_overlap_voice_allow) ? (VOICE_OFF | VOICE_SUSTAINED) : 0xff; mono_check = channel[ch].mono; altassign = instruments->find_altassign(channel[ch].altassign, note); for (i = 0; i < upper_voices; i++) if (voice[i].status == VOICE_FREE) { lowest = i; /* lower volume */ break; } for (i = 0; i < upper_voices; i++) if (voice[i].status != VOICE_FREE && voice[i].channel == ch) { if (voice[i].note == note && (voice[i].status & status_check)) kill_note(i); else if (mono_check) kill_note(i); else if (altassign && instruments->find_altassign(altassign, voice[i].note)) kill_note(i); else if (voice[i].note == note && (channel[ch].assign_mode == 0 || (channel[ch].assign_mode == 1 && voice[i].proximate_flag == 0))) kill_note(i); } for (i = 0; i < upper_voices; i++) if (voice[i].channel == ch && voice[i].note == note) voice[i].proximate_flag = 0; if (lowest != -1) /* Found a free voice. */ return lowest; if (upper_voices < voices) return upper_voices++; return reduce_voice(); } int Player::get_panning(int ch, int note,int v) { int pan; if(channel[ch].panning != NO_PANNING) {pan = (int)channel[ch].panning - 64;} else {pan = 0;} if(ISDRUMCHANNEL(ch) && channel[ch].drums[note] != NULL && channel[ch].drums[note]->drum_panning != NO_PANNING) { pan += channel[ch].drums[note]->drum_panning; } else { pan += voice[v].sample->panning; } if (pan > 127) pan = 127; else if (pan < 0) pan = 0; return pan; } /*! initialize vibrato parameters for a voice. */ void Player::init_voice_vibrato(int v) { Voice *vp = &(voice[v]); int ch = vp->channel, j, nrpn_vib_flag; double ratio; /* if NRPN vibrato is set, it's believed that there must be vibrato. */ nrpn_vib_flag = op_nrpn_vibrato && (channel[ch].vibrato_ratio != 1.0 || channel[ch].vibrato_depth != 0); /* vibrato sweep */ vp->vibrato_sweep = vp->sample->vibrato_sweep_increment; vp->vibrato_sweep_position = 0; /* vibrato rate */ if (nrpn_vib_flag) { if(vp->sample->vibrato_control_ratio == 0) { ratio = cnv_Hz_to_vib_ratio(5.0) * channel[ch].vibrato_ratio; } else { ratio = (double)vp->sample->vibrato_control_ratio * channel[ch].vibrato_ratio; } if (ratio < 0) {ratio = 0;} vp->vibrato_control_ratio = (int)ratio; } else { vp->vibrato_control_ratio = vp->sample->vibrato_control_ratio; } /* vibrato depth */ if (nrpn_vib_flag) { vp->vibrato_depth = vp->sample->vibrato_depth + channel[ch].vibrato_depth; if (vp->vibrato_depth > VIBRATO_DEPTH_MAX) {vp->vibrato_depth = VIBRATO_DEPTH_MAX;} else if (vp->vibrato_depth < 1) {vp->vibrato_depth = 1;} if (vp->sample->vibrato_depth < 0) { /* in opposite phase */ vp->vibrato_depth = -vp->vibrato_depth; } } else { vp->vibrato_depth = vp->sample->vibrato_depth; } /* vibrato delay */ vp->vibrato_delay = vp->sample->vibrato_delay + channel[ch].vibrato_delay; /* internal parameters */ vp->orig_vibrato_control_ratio = vp->vibrato_control_ratio; vp->vibrato_control_counter = vp->vibrato_phase = 0; for (j = 0; j < VIBRATO_SAMPLE_INCREMENTS; j++) { vp->vibrato_sample_increment[j] = 0; } } /*! initialize panning-delay for a voice. */ void Player::init_voice_pan_delay(int v) { #ifdef ENABLE_PAN_DELAY Voice *vp = &(voice[v]); int ch = vp->channel; double pan_delay_diff; if (vp->pan_delay_buf != NULL) { free(vp->pan_delay_buf); vp->pan_delay_buf = NULL; } vp->pan_delay_rpt = 0; if (timidity_pan_delay && channel[ch].insertion_effect == 0 && !timidity_surround_chorus) { if (vp->panning == 64) {vp->delay += pan_delay_table[64] * playback_rate / 1000;} else { if(pan_delay_table[vp->panning] > pan_delay_table[127 - vp->panning]) { pan_delay_diff = pan_delay_table[vp->panning] - pan_delay_table[127 - vp->panning]; vp->delay += (pan_delay_table[vp->panning] - pan_delay_diff) * playback_rate / 1000; } else { pan_delay_diff = pan_delay_table[127 - vp->panning] - pan_delay_table[vp->panning]; vp->delay += (pan_delay_table[127 - vp->panning] - pan_delay_diff) * playback_rate / 1000; } vp->pan_delay_rpt = pan_delay_diff * playback_rate / 1000; } if(vp->pan_delay_rpt < 1) {vp->pan_delay_rpt = 0;} vp->pan_delay_wpt = 0; vp->pan_delay_spt = vp->pan_delay_wpt - vp->pan_delay_rpt; if (vp->pan_delay_spt < 0) {vp->pan_delay_spt += PAN_DELAY_BUF_MAX;} vp->pan_delay_buf = (int32_t *)safe_malloc(sizeof(int32_t) * PAN_DELAY_BUF_MAX); memset(vp->pan_delay_buf, 0, sizeof(int32_t) * PAN_DELAY_BUF_MAX); } #endif /* ENABLE_PAN_DELAY */ } /*! initialize portamento or legato for a voice. */ void Player::init_voice_portamento(int v) { Voice *vp = &(voice[v]); int ch = vp->channel; vp->porta_control_counter = 0; if (channel[ch].legato && channel[ch].legato_flag) { update_legato_controls(ch); } else if (channel[ch].portamento && !channel[ch].porta_control_ratio) { update_portamento_controls(ch); } vp->porta_control_ratio = 0; if (channel[ch].porta_control_ratio) { if (channel[ch].last_note_fine == -1) { /* first on */ channel[ch].last_note_fine = vp->note * 256; channel[ch].porta_control_ratio = 0; } else { vp->porta_control_ratio = channel[ch].porta_control_ratio; vp->porta_dpb = channel[ch].porta_dpb; vp->porta_pb = channel[ch].last_note_fine - vp->note * 256; if (vp->porta_pb == 0) { vp->porta_control_ratio = 0; } } } } /*! initialize tremolo for a voice. */ void Player::init_voice_tremolo(int v) { Voice *vp = &(voice[v]); vp->tremolo_delay = vp->sample->tremolo_delay; vp->tremolo_phase = 0; vp->tremolo_phase_increment = vp->sample->tremolo_phase_increment; vp->tremolo_sweep = vp->sample->tremolo_sweep_increment; vp->tremolo_sweep_position = 0; vp->tremolo_depth = vp->sample->tremolo_depth; } void Player::start_note(MidiEvent *e, int i, int vid, int cnt) { int j, ch, note; ch = e->channel; note = MIDI_EVENT_NOTE(e); voice[i].status = VOICE_ON; voice[i].channel = ch; voice[i].note = note; voice[i].velocity = e->b; voice[i].chorus_link = i; /* No link */ voice[i].proximate_flag = 1; j = channel[ch].special_sample; if (j == 0 || instruments->specialPatch(j) == NULL) voice[i].sample_offset = 0; else { voice[i].sample_offset = instruments->specialPatch(j)->sample_offset << FRACTION_BITS; if (voice[i].sample->modes & MODES_LOOPING) { if (voice[i].sample_offset > voice[i].sample->loop_end) voice[i].sample_offset = voice[i].sample->loop_start; } else if (voice[i].sample_offset > voice[i].sample->data_length) { free_voice(i); return; } } voice[i].sample_increment = 0; /* make sure it isn't negative */ voice[i].vid = vid; voice[i].delay = voice[i].sample->envelope_delay; voice[i].modenv_delay = voice[i].sample->modenv_delay; voice[i].delay_counter = 0; init_voice_tremolo(i); /* tremolo */ init_voice_filter(i); /* resonant lowpass filter */ init_voice_vibrato(i); /* vibrato */ voice[i].panning = get_panning(ch, note, i); /* pan */ init_voice_pan_delay(i); /* panning-delay */ init_voice_portamento(i); /* portamento or legato */ if (cnt == 0) channel[ch].last_note_fine = voice[i].note * 256; /* initialize modulation envelope */ if (voice[i].sample->modes & MODES_ENVELOPE) { voice[i].modenv_stage = EG_GUS_ATTACK; voice[i].modenv_volume = 0; mixer->recompute_modulation_envelope(i); mixer->apply_modulation_envelope(i); } else { voice[i].modenv_increment = 0; mixer->apply_modulation_envelope(i); } recompute_freq(i); recompute_voice_filter(i); recompute_amp(i); /* initialize volume envelope */ if (voice[i].sample->modes & MODES_ENVELOPE) { /* Ramp up from 0 */ voice[i].envelope_stage = EG_GUS_ATTACK; voice[i].envelope_volume = 0; voice[i].control_counter = 0; mixer->recompute_envelope(i); mixer->apply_envelope_to_amp(i); } else { voice[i].envelope_increment = 0; mixer->apply_envelope_to_amp(i); } voice[i].timeout = -1; } void Player::finish_note(int i) { if (voice[i].sample->modes & MODES_ENVELOPE) { /* We need to get the envelope out of Sustain stage. */ /* Note that voice[i].envelope_stage < EG_GUS_RELEASE1 */ voice[i].status = VOICE_OFF; voice[i].envelope_stage = EG_GUS_RELEASE1; mixer->recompute_envelope(i); voice[i].modenv_stage = EG_GUS_RELEASE1; mixer->recompute_modulation_envelope(i); mixer->apply_modulation_envelope(i); mixer->apply_envelope_to_amp(i); } else { /* Set status to OFF so resample_voice() will let this voice out of its loop, if any. In any case, this voice dies when it hits the end of its data (ofs>=data_length). */ if(voice[i].status != VOICE_OFF) { voice[i].status = VOICE_OFF; } } } void Player::set_envelope_time(int ch, int val, int stage) { val = val & 0x7F; #if 0 switch(stage) { case EG_ATTACK: /* Attack */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Attack Time (CH:%d VALUE:%d)", ch, val); break; case EG_DECAY: /* Decay */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Decay Time (CH:%d VALUE:%d)", ch, val); break; case EG_RELEASE: /* Release */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Release Time (CH:%d VALUE:%d)", ch, val); break; default: //ctl_cmsg(CMSG_INFO,VERB_NOISY,"? Time (CH:%d VALUE:%d)", ch, val); } #endif channel[ch].envelope_rate[stage] = val; } /* Yet another chorus implementation * by Eric A. Welsh . */ void Player::new_chorus_voice_alternate(int v1, int level) { int v2, ch, panlevel; uint8_t pan; double delay; double freq, frac; int note_adjusted; if((v2 = find_free_voice()) == -1) return; ch = voice[v1].channel; voice[v2] = voice[v1]; /* NRPN Chorus Send Level of Drum */ if(ISDRUMCHANNEL(ch) && channel[ch].drums[voice[v1].note] != NULL) { level *= (double)channel[ch].drums[voice[v1].note]->chorus_level / 127.0; } /* for our purposes, hard left will be equal to 1 instead of 0 */ pan = voice[v1].panning; if (!pan) pan = 1; /* Choose lower voice index for base voice (v1) */ if(v1 > v2) { v1 ^= v2; v2 ^= v1; v1 ^= v2; } /* Make doubled link v1 and v2 */ voice[v1].chorus_link = v2; voice[v2].chorus_link = v1; /* detune notes for chorus effect */ level >>= 2; /* scale to a "better" value */ if (level) { if(channel[ch].pitchbend + level < 0x2000) voice[v2].orig_frequency *= bend_fine[level]; else voice[v2].orig_frequency /= bend_fine[level]; voice[v2].cache = NULL; } delay = 0.003; /* Try to keep the delayed voice from cancelling out the other voice */ /* Pitch detection is used to find the real pitches for drums and MODs */ note_adjusted = voice[v1].note + voice[v1].sample->transpose_detected; if (note_adjusted > 127) note_adjusted = 127; else if (note_adjusted < 0) note_adjusted = 0; freq = pitch_freq_table[note_adjusted]; delay *= freq; frac = delay - floor(delay); /* force the delay away from 0.5 period */ if (frac < 0.5 && frac > 0.40) { delay = (floor(delay) + 0.40) / freq; delay += (0.5 - frac) * (1.0 - labs(64 - pan) / 63.0) / freq; } else if (frac >= 0.5 && frac < 0.60) { delay = (floor(delay) + 0.60) / freq; delay += (0.5 - frac) * (1.0 - labs(64 - pan) / 63.0) / freq; } else delay = 0.003; /* set panning & delay for pseudo-surround effect */ { panlevel = 63; if (pan - panlevel < 1) panlevel = pan - 1; if (pan + panlevel > 127) panlevel = 127 - pan; voice[v1].panning -= panlevel; voice[v2].panning += panlevel; /* choose which voice is delayed based on panning */ if (voice[v1].panned == PANNED_CENTER) { /* randomly choose which voice is delayed */ if (int_rand(2)) voice[v1].delay += (int)(playback_rate * delay); else voice[v2].delay += (int)(playback_rate * delay); } else if (pan - 64 < 0) { voice[v2].delay += (int)(playback_rate * delay); } else { voice[v1].delay += (int)(playback_rate * delay); } } /* check for similar drums playing simultaneously with center pans */ if (ISDRUMCHANNEL(ch) && voice[v1].panned == PANNED_CENTER) { int i, j; /* force Rimshot (37), Snare1 (38), Snare2 (40), and XG #34 to have * the same delay, otherwise there will be bad voice cancellation. */ if (voice[v1].note == 37 || voice[v1].note == 38 || voice[v1].note == 40 || (voice[v1].note == 34 && play_system_mode == XG_SYSTEM_MODE)) { for (i = 0; i < upper_voices; i++) { if (voice[i].status & (VOICE_DIE | VOICE_FREE)) continue; if (!ISDRUMCHANNEL(voice[i].channel)) continue; if (i == v1 || i == v2) continue; if (voice[i].note == 37 || voice[i].note == 38 || voice[i].note == 40 || (voice[i].note == 34 && play_system_mode == XG_SYSTEM_MODE)) { j = voice[i].chorus_link; if (voice[i].panned == PANNED_LEFT && voice[j].panned == PANNED_RIGHT) { voice[v1].delay = voice[i].delay; voice[v2].delay = voice[j].delay; break; } } } } /* force Kick1 (35), Kick2 (36), and XG Kick #33 to have the same * delay, otherwise there will be bad voice cancellation. */ if (voice[v1].note == 35 || voice[v1].note == 36 || (voice[v1].note == 33 && play_system_mode == XG_SYSTEM_MODE)) { for (i = 0; i < upper_voices; i++) { if (voice[i].status & (VOICE_DIE | VOICE_FREE)) continue; if (!ISDRUMCHANNEL(voice[i].channel)) continue; if (i == v1 || i == v2) continue; if (voice[i].note == 35 || voice[i].note == 36 || (voice[i].note == 33 && play_system_mode == XG_SYSTEM_MODE)) { j = voice[i].chorus_link; if (voice[i].panned == PANNED_LEFT && voice[j].panned == PANNED_RIGHT) { voice[v1].delay = voice[i].delay; voice[v2].delay = voice[j].delay; break; } } } } } init_voice_pan_delay(v1); init_voice_pan_delay(v2); recompute_amp(v1); mixer->apply_envelope_to_amp(v1); recompute_amp(v2); mixer->apply_envelope_to_amp(v2); if (level) recompute_freq(v2); } void Player::note_on(MidiEvent *e) { int i, nv, v, ch, note; int vlist[32]; int vid; int32_t random_delay = 0; ch = e->channel; note = MIDI_EVENT_NOTE(e); if(ISDRUMCHANNEL(ch) && channel[ch].drums[note] != NULL && !get_rx_drum(channel[ch].drums[note], RX_NOTE_ON)) { /* Rx. Note On */ return; } if(channel[ch].note_limit_low > note || channel[ch].note_limit_high < note || channel[ch].vel_limit_low > e->b || channel[ch].vel_limit_high < e->b) { return; } if((nv = find_samples(e, vlist)) == 0) return; vid = new_vidq(e->channel, note); recompute_bank_parameter(ch, note); recompute_channel_filter(ch, note); random_delay = calc_random_delay(ch, note); for(i = 0; i < nv; i++) { v = vlist[i]; if(ISDRUMCHANNEL(ch) && channel[ch].drums[note] != NULL && channel[ch].drums[note]->pan_random) channel[ch].drums[note]->drum_panning = int_rand(128); else if(channel[ch].pan_random) { channel[ch].panning = int_rand(128); } start_note(e, v, vid, nv - i - 1); voice[v].delay += random_delay; voice[v].modenv_delay += random_delay; voice[v].old_left_mix = voice[v].old_right_mix = voice[v].left_mix_inc = voice[v].left_mix_offset = voice[v].right_mix_inc = voice[v].right_mix_offset = 0; if(timidity_surround_chorus) new_chorus_voice_alternate(v, 0); } channel[ch].legato_flag = 1; } /*! sostenuto is now implemented as an instant sustain */ void Player::update_sostenuto_controls(int ch) { int uv = upper_voices, i; if(ISDRUMCHANNEL(ch) || channel[ch].sostenuto == 0) {return;} for(i = 0; i < uv; i++) { if ((voice[i].status & (VOICE_ON | VOICE_OFF)) && voice[i].channel == ch) { voice[i].status = VOICE_SUSTAINED; voice[i].envelope_stage = EG_GUS_RELEASE1; mixer->recompute_envelope(i); } } } /*! redamper effect for piano instruments */ void Player::update_redamper_controls(int ch) { int uv = upper_voices, i; if(ISDRUMCHANNEL(ch) || channel[ch].damper_mode == 0) {return;} for(i = 0; i < uv; i++) { if ((voice[i].status & (VOICE_ON | VOICE_OFF)) && voice[i].channel == ch) { voice[i].status = VOICE_SUSTAINED; voice[i].envelope_stage = EG_GUS_RELEASE1; mixer->recompute_envelope(i); } } } void Player::note_off(MidiEvent *e) { int uv = upper_voices, i; int ch, note, vid, sustain; ch = e->channel; note = MIDI_EVENT_NOTE(e); if(ISDRUMCHANNEL(ch)) { int nbank, nprog; nbank = channel[ch].bank; nprog = note; instruments->instrument_map(channel[ch].mapID, &nbank, &nprog); if (channel[ch].drums[nprog] != NULL && get_rx_drum(channel[ch].drums[nprog], RX_NOTE_OFF)) { auto bank = instruments->drumSet(nbank); if(bank == NULL) bank = instruments->drumSet(0); /* uh oh, this drum doesn't have an instrument loaded yet */ if (bank->tone[nprog].instrument == NULL) return; /* this drum is not loaded for some reason (error occured?) */ if (IS_MAGIC_INSTRUMENT(bank->tone[nprog].instrument)) return; /* only disallow Note Off if the drum sample is not looped */ if (!(bank->tone[nprog].instrument->sample->modes & MODES_LOOPING)) return; /* Note Off is not allowed. */ } } if ((vid = last_vidq(ch, note)) == -1) return; sustain = channel[ch].sustain; for (i = 0; i < uv; i++) { if(voice[i].status == VOICE_ON && voice[i].channel == ch && voice[i].note == note && voice[i].vid == vid) { if(sustain) { voice[i].status = VOICE_SUSTAINED; } else finish_note(i); } } channel[ch].legato_flag = 0; } /* Process the All Notes Off event */ void Player::all_notes_off(int c) { int i, uv = upper_voices; ctl_cmsg(CMSG_INFO, VERB_DEBUG, "All notes off on channel %d", c); for(i = 0; i < uv; i++) if (voice[i].status==VOICE_ON && voice[i].channel==c) { if (channel[c].sustain) { voice[i].status=VOICE_SUSTAINED; } else finish_note(i); } for(i = 0; i < 128; i++) vidq_head[c * 128 + i] = vidq_tail[c * 128 + i] = 0; } /* Process the All Sounds Off event */ void Player::all_sounds_off(int c) { int i, uv = upper_voices; for(i = 0; i < uv; i++) if (voice[i].channel==c && (voice[i].status & ~(VOICE_FREE | VOICE_DIE))) { kill_note(i); } for(i = 0; i < 128; i++) vidq_head[c * 128 + i] = vidq_tail[c * 128 + i] = 0; } /*! adjust polyphonic key pressure (PAf, PAT) */ void Player::adjust_pressure(MidiEvent *e) { int i, uv = upper_voices; int note, ch; if(timidity_channel_pressure) { ch = e->channel; note = MIDI_EVENT_NOTE(e); channel[ch].paf.val = e->b; if(channel[ch].paf.pitch != 0) {channel[ch].pitchfactor = 0;} for(i = 0; i < uv; i++) if(voice[i].status == VOICE_ON && voice[i].channel == ch && voice[i].note == note) { recompute_amp(i); mixer->apply_envelope_to_amp(i); recompute_freq(i); recompute_voice_filter(i); } } } /*! adjust channel pressure (channel aftertouch, CAf, CAT) */ void Player::adjust_channel_pressure(MidiEvent *e) { if(timidity_channel_pressure) { int i, uv = upper_voices; int ch; ch = e->channel; channel[ch].caf.val = e->a; if(channel[ch].caf.pitch != 0) {channel[ch].pitchfactor = 0;} for(i = 0; i < uv; i++) { if(voice[i].status == VOICE_ON && voice[i].channel == ch) { recompute_amp(i); mixer->apply_envelope_to_amp(i); recompute_freq(i); recompute_voice_filter(i); } } } } void Player::adjust_panning(int c) { int i, uv = upper_voices, pan = channel[c].panning; for(i = 0; i < uv; i++) { if ((voice[i].channel==c) && (voice[i].status & (VOICE_ON | VOICE_SUSTAINED))) { /* adjust pan to include drum/sample pan offsets */ pan = get_panning(c, voice[i].note, i); /* Hack to handle -EFchorus=2 in a "reasonable" way */ if(timidity_surround_chorus && voice[i].chorus_link != i) { int v1, v2; if(i >= voice[i].chorus_link) /* `i' is not base chorus voice. * This sub voice is already updated. */ continue; v1 = i; /* base voice */ v2 = voice[i].chorus_link; /* sub voice (detuned) */ if(timidity_surround_chorus) /* Surround chorus mode by Eric. */ { int panlevel; if (!pan) pan = 1; /* make hard left be 1 instead of 0 */ panlevel = 63; if (pan - panlevel < 1) panlevel = pan - 1; if (pan + panlevel > 127) panlevel = 127 - pan; voice[v1].panning = pan - panlevel; voice[v2].panning = pan + panlevel; } else { voice[v1].panning = pan; if(pan > 60 && pan < 68) /* PANNED_CENTER */ voice[v2].panning = 64 + int_rand(40) - 20; /* 64 +- rand(20) */ else if(pan < CHORUS_OPPOSITE_THRESHOLD) voice[v2].panning = 127; else if(pan > 127 - CHORUS_OPPOSITE_THRESHOLD) voice[v2].panning = 0; else voice[v2].panning = (pan < 64 ? 0 : 127); } recompute_amp(v2); mixer->apply_envelope_to_amp(v2); /* v1 == i, so v1 will be updated next */ } else voice[i].panning = pan; recompute_amp(i); mixer->apply_envelope_to_amp(i); } } } void Player::play_midi_setup_drums(int ch, int note) { channel[ch].drums[note] = (struct DrumParts *) new_segment(&playmidi_pool, sizeof(struct DrumParts)); reset_drum_controllers(channel[ch].drums, note); } void Player::adjust_drum_panning(int ch, int note) { int i, uv = upper_voices; for(i = 0; i < uv; i++) { if(voice[i].channel == ch && voice[i].note == note && (voice[i].status & (VOICE_ON | VOICE_SUSTAINED))) { voice[i].panning = get_panning(ch, note, i); recompute_amp(i); mixer->apply_envelope_to_amp(i); } } } void Player::drop_sustain(int c) { int i, uv = upper_voices; for(i = 0; i < uv; i++) if (voice[i].status == VOICE_SUSTAINED && voice[i].channel == c) finish_note(i); } void Player::adjust_all_pitch(void) { int ch, i, uv = upper_voices; for (ch = 0; ch < MAX_CHANNELS; ch++) channel[ch].pitchfactor = 0; for (i = 0; i < uv; i++) if (voice[i].status != VOICE_FREE) recompute_freq(i); } void Player::adjust_pitch(int c) { int i, uv = upper_voices; for(i = 0; i < uv; i++) if (voice[i].status != VOICE_FREE && voice[i].channel == c) recompute_freq(i); } void Player::adjust_volume(int c) { int i, uv = upper_voices; for(i = 0; i < uv; i++) if (voice[i].channel == c && (voice[i].status & (VOICE_ON | VOICE_SUSTAINED))) { recompute_amp(i); mixer->apply_envelope_to_amp(i); } } void Player::set_reverb_level(int ch, int level) { if (level == -1) { channel[ch].reverb_level = channel[ch].reverb_id = (timidity_reverb < 0) ? -timidity_reverb & 0x7f : DEFAULT_REVERB_SEND_LEVEL; make_rvid_flag = 1; return; } channel[ch].reverb_level = level; make_rvid_flag = 0; /* to update reverb_id */ } int Player::get_reverb_level(int ch) { if (channel[ch].reverb_level == -1) return (timidity_reverb < 0) ? -timidity_reverb & 0x7f : DEFAULT_REVERB_SEND_LEVEL; return channel[ch].reverb_level; } int Player::get_chorus_level(int ch) { #ifdef DISALLOW_DRUM_BENDS if(ISDRUMCHANNEL(ch)) return 0; /* Not supported drum channel chorus */ #endif if(timidity_chorus == 1) return channel[ch].chorus_level; return -timidity_chorus; } void Player::free_drum_effect(int ch) { int i; if (channel[ch].drum_effect != NULL) { for (i = 0; i < channel[ch].drum_effect_num; i++) { if (channel[ch].drum_effect[i].buf != NULL) { free(channel[ch].drum_effect[i].buf); channel[ch].drum_effect[i].buf = NULL; } } free(channel[ch].drum_effect); channel[ch].drum_effect = NULL; } channel[ch].drum_effect_num = 0; channel[ch].drum_effect_flag = 0; } void Player::make_drum_effect(int ch) { int i, note, num = 0; int8_t note_table[128]; struct DrumParts *drum; struct DrumPartEffect *de; if (channel[ch].drum_effect_flag == 0) { free_drum_effect(ch); memset(note_table, 0, sizeof(int8_t) * 128); for(i = 0; i < 128; i++) { if ((drum = channel[ch].drums[i]) != NULL) { if (drum->reverb_level != -1 || drum->chorus_level != -1 || drum->delay_level != -1) { note_table[num++] = i; } } } channel[ch].drum_effect = (struct DrumPartEffect *)safe_malloc(sizeof(struct DrumPartEffect) * num); for(i = 0; i < num; i++) { de = &(channel[ch].drum_effect[i]); de->note = note = note_table[i]; drum = channel[ch].drums[note]; de->reverb_send = (int32_t)drum->reverb_level * (int32_t)get_reverb_level(ch) / 127; de->chorus_send = (int32_t)drum->chorus_level * (int32_t)channel[ch].chorus_level / 127; de->delay_send = (int32_t)drum->delay_level * (int32_t)channel[ch].delay_level / 127; de->buf = (int32_t *)safe_malloc(AUDIO_BUFFER_SIZE * 8); memset(de->buf, 0, AUDIO_BUFFER_SIZE * 8); } channel[ch].drum_effect_num = num; channel[ch].drum_effect_flag = 1; } } void Player::adjust_master_volume(void) { int i, uv = upper_voices; adjust_amplification(); for(i = 0; i < uv; i++) if(voice[i].status & (VOICE_ON | VOICE_SUSTAINED)) { recompute_amp(i); mixer->apply_envelope_to_amp(i); } } int Player::midi_drumpart_change(int ch, int isdrum) { if (IS_SET_CHANNELMASK(drumchannel_mask, ch)) return 0; if (isdrum) { SET_CHANNELMASK(drumchannels, ch); SET_CHANNELMASK(current_file_info->drumchannels, ch); } else { UNSET_CHANNELMASK(drumchannels, ch); UNSET_CHANNELMASK(current_file_info->drumchannels, ch); } return 1; } void Player::midi_program_change(int ch, int prog) { int dr = ISDRUMCHANNEL(ch); int newbank, b, p, map; switch (play_system_mode) { case GS_SYSTEM_MODE: /* GS */ if ((map = channel[ch].bank_lsb) == 0) { map = channel[ch].tone_map0_number; } switch (map) { case 0: /* No change */ break; case 1: channel[ch].mapID = (dr) ? SC_55_DRUM_MAP : SC_55_TONE_MAP; break; case 2: channel[ch].mapID = (dr) ? SC_88_DRUM_MAP : SC_88_TONE_MAP; break; case 3: channel[ch].mapID = (dr) ? SC_88PRO_DRUM_MAP : SC_88PRO_TONE_MAP; break; case 4: channel[ch].mapID = (dr) ? SC_8850_DRUM_MAP : SC_8850_TONE_MAP; break; default: break; } newbank = channel[ch].bank_msb; break; case XG_SYSTEM_MODE: /* XG */ switch (channel[ch].bank_msb) { case 0: /* Normal */ #if 0 if (ch == 9 && channel[ch].bank_lsb == 127 && channel[ch].mapID == XG_DRUM_MAP) /* FIXME: Why this part is drum? Is this correct? */ break; #endif /* Eric's explanation for the FIXME (March 2004): * * I don't have the original email from my archived inbox, but I found a * reply I made in my archived sent-mail from 1999. A September 5th message * to Masanao Izumo is discussing a problem with a "reapxg.mid", a file which * I still have, and how it issues an MSB=0 with a program change on ch 9, * thus turning it into a melodic channel. The strange thing is, this doesn't * happen on XG hardware, nor on the XG softsynth. It continues to play as a * normal drum. The author of the midi file obviously intended it to be * drumset 16 too. The original fix was to detect LSB == -1, then break so * as to not set it to a melodic channel. I'm guessing that this somehow got * mutated into checking for 127 instead, and the current FIXME is related to * the original hack from Sept 1999. The Sept 5th email discusses patches * being applied to version 2.5.1 to get XG drums to work properly, and a * Sept 7th email to someone else discusses the fixes being part of the * latest 2.6.0-beta3. A September 23rd email to Masanao Izumo specifically * mentions the LSB == -1 hack (and reapxg.mid not playing "correctly" * anymore), as well as new changes in 2.6.0 that broke a lot of other XG * files (XG drum support was extremely buggy in 1999 and we were still trying * to figure out how to initialize things to reproduce hardware behavior). An * October 5th email says that 2.5.1 was correct, 2.6.0 had very broken XG * drum changes, and 2.6.1 still has problems. Further discussions ensued * over what was "correct": to follow the XG spec, or to reproduce * "features" / bugs in the hardware. I can't find the rest of the * discussions, but I think it ended with us agreeing to just follow the spec * and not try to reproduce the hardware strangeness. I don't know how the * current FIXME wound up the way it is now. I'm still going to guess it is * related to the old reapxg.mid hack. * * Now that reset_midi() initializes channel[ch].bank_lsb to 0 instead of -1, * checking for LSB == -1 won't do anything anymore, so changing the above * FIXME to the original == -1 won't do any good. It is best to just #if 0 * it out and leave it here as a reminder that there is at least one XG * hardware / softsynth "bug" that is not reproduced by timidity at the * moment. * * If the current FIXME actually reproduces some other XG hadware bug that * I don't know about, then it may have a valid purpose. I just don't know * what that purpose is at the moment. Perhaps someone else does? I still * have src going back to 2.10.4, and the FIXME comment was already there by * then. I don't see any entries in the Changelog that could explain it * either. If someone has src from 2.5.1 through 2.10.3 and wants to * investigate this further, go for it :) */ midi_drumpart_change(ch, 0); channel[ch].mapID = XG_NORMAL_MAP; dr = ISDRUMCHANNEL(ch); break; case 64: /* SFX voice */ midi_drumpart_change(ch, 0); channel[ch].mapID = XG_SFX64_MAP; dr = ISDRUMCHANNEL(ch); break; case 126: /* SFX kit */ midi_drumpart_change(ch, 1); channel[ch].mapID = XG_SFX126_MAP; dr = ISDRUMCHANNEL(ch); break; case 127: /* Drum kit */ midi_drumpart_change(ch, 1); channel[ch].mapID = XG_DRUM_MAP; dr = ISDRUMCHANNEL(ch); break; default: break; } newbank = channel[ch].bank_lsb; break; case GM2_SYSTEM_MODE: /* GM2 */ if ((channel[ch].bank_msb & 0xfe) == 0x78) { /* 0x78/0x79 */ midi_drumpart_change(ch, channel[ch].bank_msb == 0x78); dr = ISDRUMCHANNEL(ch); } channel[ch].mapID = (dr) ? GM2_DRUM_MAP : GM2_TONE_MAP; newbank = channel[ch].bank_lsb; break; default: newbank = channel[ch].bank_msb; break; } if (dr) { channel[ch].bank = prog; /* newbank is ignored */ channel[ch].program = prog; if (instruments->drumSet(prog) == NULL || instruments->drumSet(prog)->alt == NULL) channel[ch].altassign = instruments->drumSet(0)->alt; else channel[ch].altassign = instruments->drumSet(prog)->alt; } else { channel[ch].bank = (special_tonebank >= 0) ? special_tonebank : newbank; channel[ch].program = (instruments->defaultProgram(ch) == SPECIAL_PROGRAM) ? SPECIAL_PROGRAM : prog; channel[ch].altassign = NULL; if (opt_realtime_playing) { b = channel[ch].bank, p = prog; instruments->instrument_map(channel[ch].mapID, &b, &p); play_midi_load_instrument(0, b, p); } } } /*! add a new layer. */ void Player::add_channel_layer(int to_ch, int from_ch) { if (to_ch >= MAX_CHANNELS || from_ch >= MAX_CHANNELS) return; /* add a channel layer */ UNSET_CHANNELMASK(channel[to_ch].channel_layer, to_ch); SET_CHANNELMASK(channel[to_ch].channel_layer, from_ch); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Channel Layer (CH:%d -> CH:%d)", from_ch, to_ch); } /*! remove all layers for this channel. */ void Player::remove_channel_layer(int ch) { int i, offset; if (ch >= MAX_CHANNELS) return; /* remove channel layers */ offset = ch & ~0xf; for (i = offset; i < offset + REDUCE_CHANNELS; i++) UNSET_CHANNELMASK(channel[i].channel_layer, ch); SET_CHANNELMASK(channel[ch].channel_layer, ch); } /*! process system exclusive sent from parse_sysex_event_multi(). */ void Player::process_sysex_event(int ev, int ch, int val, int b) { int temp, msb, note; if (ch >= MAX_CHANNELS) return; if (ev == ME_SYSEX_MSB) { channel[ch].sysex_msb_addr = b; channel[ch].sysex_msb_val = val; } else if(ev == ME_SYSEX_GS_MSB) { channel[ch].sysex_gs_msb_addr = b; channel[ch].sysex_gs_msb_val = val; } else if(ev == ME_SYSEX_XG_MSB) { channel[ch].sysex_xg_msb_addr = b; channel[ch].sysex_xg_msb_val = val; } else if(ev == ME_SYSEX_LSB) { /* Universal system exclusive message */ msb = channel[ch].sysex_msb_addr; note = channel[ch].sysex_msb_val; channel[ch].sysex_msb_addr = channel[ch].sysex_msb_val = 0; switch(b) { case 0x00: /* CAf Pitch Control */ if(val > 0x58) {val = 0x58;} else if(val < 0x28) {val = 0x28;} channel[ch].caf.pitch = val - 64; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CAf Pitch Control (CH:%d %d semitones)", ch, channel[ch].caf.pitch); break; case 0x01: /* CAf Filter Cutoff Control */ channel[ch].caf.cutoff = (val - 64) * 150; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CAf Filter Cutoff Control (CH:%d %d cents)", ch, channel[ch].caf.cutoff); break; case 0x02: /* CAf Amplitude Control */ channel[ch].caf.amp = (float)val / 64.0f - 1.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CAf Amplitude Control (CH:%d %.2f)", ch, channel[ch].caf.amp); break; case 0x03: /* CAf LFO1 Rate Control */ channel[ch].caf.lfo1_rate = (float)(val - 64) / 6.4f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CAf LFO1 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].caf.lfo1_rate); break; case 0x04: /* CAf LFO1 Pitch Depth */ channel[ch].caf.lfo1_pitch_depth = conv_lfo_pitch_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CAf LFO1 Pitch Depth (CH:%d %d cents)", ch, channel[ch].caf.lfo1_pitch_depth); break; case 0x05: /* CAf LFO1 Filter Depth */ channel[ch].caf.lfo1_tvf_depth = conv_lfo_filter_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CAf LFO1 Filter Depth (CH:%d %d cents)", ch, channel[ch].caf.lfo1_tvf_depth); break; case 0x06: /* CAf LFO1 Amplitude Depth */ channel[ch].caf.lfo1_tva_depth = (float)val / 127.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CAf LFO1 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].caf.lfo1_tva_depth); break; case 0x07: /* CAf LFO2 Rate Control */ channel[ch].caf.lfo2_rate = (float)(val - 64) / 6.4f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CAf LFO2 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].caf.lfo2_rate); break; case 0x08: /* CAf LFO2 Pitch Depth */ channel[ch].caf.lfo2_pitch_depth = conv_lfo_pitch_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CAf LFO2 Pitch Depth (CH:%d %d cents)", ch, channel[ch].caf.lfo2_pitch_depth); break; case 0x09: /* CAf LFO2 Filter Depth */ channel[ch].caf.lfo2_tvf_depth = conv_lfo_filter_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CAf LFO2 Filter Depth (CH:%d %d cents)", ch, channel[ch].caf.lfo2_tvf_depth); break; case 0x0A: /* CAf LFO2 Amplitude Depth */ channel[ch].caf.lfo2_tva_depth = (float)val / 127.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CAf LFO2 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].caf.lfo2_tva_depth); break; case 0x0B: /* PAf Pitch Control */ if(val > 0x58) {val = 0x58;} else if(val < 0x28) {val = 0x28;} channel[ch].paf.pitch = val - 64; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"PAf Pitch Control (CH:%d %d semitones)", ch, channel[ch].paf.pitch); break; case 0x0C: /* PAf Filter Cutoff Control */ channel[ch].paf.cutoff = (val - 64) * 150; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"PAf Filter Cutoff Control (CH:%d %d cents)", ch, channel[ch].paf.cutoff); break; case 0x0D: /* PAf Amplitude Control */ channel[ch].paf.amp = (float)val / 64.0f - 1.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"PAf Amplitude Control (CH:%d %.2f)", ch, channel[ch].paf.amp); break; case 0x0E: /* PAf LFO1 Rate Control */ channel[ch].paf.lfo1_rate = (float)(val - 64) / 6.4f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"PAf LFO1 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].paf.lfo1_rate); break; case 0x0F: /* PAf LFO1 Pitch Depth */ channel[ch].paf.lfo1_pitch_depth = conv_lfo_pitch_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"PAf LFO1 Pitch Depth (CH:%d %d cents)", ch, channel[ch].paf.lfo1_pitch_depth); break; case 0x10: /* PAf LFO1 Filter Depth */ channel[ch].paf.lfo1_tvf_depth = conv_lfo_filter_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"PAf LFO1 Filter Depth (CH:%d %d cents)", ch, channel[ch].paf.lfo1_tvf_depth); break; case 0x11: /* PAf LFO1 Amplitude Depth */ channel[ch].paf.lfo1_tva_depth = (float)val / 127.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"PAf LFO1 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].paf.lfo1_tva_depth); break; case 0x12: /* PAf LFO2 Rate Control */ channel[ch].paf.lfo2_rate = (float)(val - 64) / 6.4f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"PAf LFO2 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].paf.lfo2_rate); break; case 0x13: /* PAf LFO2 Pitch Depth */ channel[ch].paf.lfo2_pitch_depth = conv_lfo_pitch_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"PAf LFO2 Pitch Depth (CH:%d %d cents)", ch, channel[ch].paf.lfo2_pitch_depth); break; case 0x14: /* PAf LFO2 Filter Depth */ channel[ch].paf.lfo2_tvf_depth = conv_lfo_filter_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"PAf LFO2 Filter Depth (CH:%d %d cents)", ch, channel[ch].paf.lfo2_tvf_depth); break; case 0x15: /* PAf LFO2 Amplitude Depth */ channel[ch].paf.lfo2_tva_depth = (float)val / 127.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"PAf LFO2 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].paf.lfo2_tva_depth); break; case 0x16: /* MOD Pitch Control */ if(val > 0x58) {val = 0x58;} else if(val < 0x28) {val = 0x28;} channel[ch].mod.pitch = val - 64; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"MOD Pitch Control (CH:%d %d semitones)", ch, channel[ch].mod.pitch); break; case 0x17: /* MOD Filter Cutoff Control */ channel[ch].mod.cutoff = (val - 64) * 150; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"MOD Filter Cutoff Control (CH:%d %d cents)", ch, channel[ch].mod.cutoff); break; case 0x18: /* MOD Amplitude Control */ channel[ch].mod.amp = (float)val / 64.0f - 1.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"MOD Amplitude Control (CH:%d %.2f)", ch, channel[ch].mod.amp); break; case 0x19: /* MOD LFO1 Rate Control */ channel[ch].mod.lfo1_rate = (float)(val - 64) / 6.4f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"MOD LFO1 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].mod.lfo1_rate); break; case 0x1A: /* MOD LFO1 Pitch Depth */ channel[ch].mod.lfo1_pitch_depth = conv_lfo_pitch_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"MOD LFO1 Pitch Depth (CH:%d %d cents)", ch, channel[ch].mod.lfo1_pitch_depth); break; case 0x1B: /* MOD LFO1 Filter Depth */ channel[ch].mod.lfo1_tvf_depth = conv_lfo_filter_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"MOD LFO1 Filter Depth (CH:%d %d cents)", ch, channel[ch].mod.lfo1_tvf_depth); break; case 0x1C: /* MOD LFO1 Amplitude Depth */ channel[ch].mod.lfo1_tva_depth = (float)val / 127.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"MOD LFO1 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].mod.lfo1_tva_depth); break; case 0x1D: /* MOD LFO2 Rate Control */ channel[ch].mod.lfo2_rate = (float)(val - 64) / 6.4f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"MOD LFO2 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].mod.lfo2_rate); break; case 0x1E: /* MOD LFO2 Pitch Depth */ channel[ch].mod.lfo2_pitch_depth = conv_lfo_pitch_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"MOD LFO2 Pitch Depth (CH:%d %d cents)", ch, channel[ch].mod.lfo2_pitch_depth); break; case 0x1F: /* MOD LFO2 Filter Depth */ channel[ch].mod.lfo2_tvf_depth = conv_lfo_filter_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"MOD LFO2 Filter Depth (CH:%d %d cents)", ch, channel[ch].mod.lfo2_tvf_depth); break; case 0x20: /* MOD LFO2 Amplitude Depth */ channel[ch].mod.lfo2_tva_depth = (float)val / 127.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"MOD LFO2 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].mod.lfo2_tva_depth); break; case 0x21: /* BEND Pitch Control */ if(val > 0x58) {val = 0x58;} else if(val < 0x28) {val = 0x28;} channel[ch].bend.pitch = val - 64; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"BEND Pitch Control (CH:%d %d semitones)", ch, channel[ch].bend.pitch); break; case 0x22: /* BEND Filter Cutoff Control */ channel[ch].bend.cutoff = (val - 64) * 150; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"BEND Filter Cutoff Control (CH:%d %d cents)", ch, channel[ch].bend.cutoff); break; case 0x23: /* BEND Amplitude Control */ channel[ch].bend.amp = (float)val / 64.0f - 1.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"BEND Amplitude Control (CH:%d %.2f)", ch, channel[ch].bend.amp); break; case 0x24: /* BEND LFO1 Rate Control */ channel[ch].bend.lfo1_rate = (float)(val - 64) / 6.4f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"BEND LFO1 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].bend.lfo1_rate); break; case 0x25: /* BEND LFO1 Pitch Depth */ channel[ch].bend.lfo1_pitch_depth = conv_lfo_pitch_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"BEND LFO1 Pitch Depth (CH:%d %d cents)", ch, channel[ch].bend.lfo1_pitch_depth); break; case 0x26: /* BEND LFO1 Filter Depth */ channel[ch].bend.lfo1_tvf_depth = conv_lfo_filter_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"BEND LFO1 Filter Depth (CH:%d %d cents)", ch, channel[ch].bend.lfo1_tvf_depth); break; case 0x27: /* BEND LFO1 Amplitude Depth */ channel[ch].bend.lfo1_tva_depth = (float)val / 127.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"BEND LFO1 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].bend.lfo1_tva_depth); break; case 0x28: /* BEND LFO2 Rate Control */ channel[ch].bend.lfo2_rate = (float)(val - 64) / 6.4f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"BEND LFO2 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].bend.lfo2_rate); break; case 0x29: /* BEND LFO2 Pitch Depth */ channel[ch].bend.lfo2_pitch_depth = conv_lfo_pitch_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"BEND LFO2 Pitch Depth (CH:%d %d cents)", ch, channel[ch].bend.lfo2_pitch_depth); break; case 0x2A: /* BEND LFO2 Filter Depth */ channel[ch].bend.lfo2_tvf_depth = conv_lfo_filter_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"BEND LFO2 Filter Depth (CH:%d %d cents)", ch, channel[ch].bend.lfo2_tvf_depth); break; case 0x2B: /* BEND LFO2 Amplitude Depth */ channel[ch].bend.lfo2_tva_depth = (float)val / 127.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"BEND LFO2 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].bend.lfo2_tva_depth); break; case 0x2C: /* CC1 Pitch Control */ if(val > 0x58) {val = 0x58;} else if(val < 0x28) {val = 0x28;} channel[ch].cc1.pitch = val - 64; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC1 Pitch Control (CH:%d %d semitones)", ch, channel[ch].cc1.pitch); break; case 0x2D: /* CC1 Filter Cutoff Control */ channel[ch].cc1.cutoff = (val - 64) * 150; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC1 Filter Cutoff Control (CH:%d %d cents)", ch, channel[ch].cc1.cutoff); break; case 0x2E: /* CC1 Amplitude Control */ channel[ch].cc1.amp = (float)val / 64.0f - 1.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC1 Amplitude Control (CH:%d %.2f)", ch, channel[ch].cc1.amp); break; case 0x2F: /* CC1 LFO1 Rate Control */ channel[ch].cc1.lfo1_rate = (float)(val - 64) / 6.4f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC1 LFO1 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].cc1.lfo1_rate); break; case 0x30: /* CC1 LFO1 Pitch Depth */ channel[ch].cc1.lfo1_pitch_depth = conv_lfo_pitch_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC1 LFO1 Pitch Depth (CH:%d %d cents)", ch, channel[ch].cc1.lfo1_pitch_depth); break; case 0x31: /* CC1 LFO1 Filter Depth */ channel[ch].cc1.lfo1_tvf_depth = conv_lfo_filter_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC1 LFO1 Filter Depth (CH:%d %d cents)", ch, channel[ch].cc1.lfo1_tvf_depth); break; case 0x32: /* CC1 LFO1 Amplitude Depth */ channel[ch].cc1.lfo1_tva_depth = (float)val / 127.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC1 LFO1 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].cc1.lfo1_tva_depth); break; case 0x33: /* CC1 LFO2 Rate Control */ channel[ch].cc1.lfo2_rate = (float)(val - 64) / 6.4f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC1 LFO2 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].cc1.lfo2_rate); break; case 0x34: /* CC1 LFO2 Pitch Depth */ channel[ch].cc1.lfo2_pitch_depth = conv_lfo_pitch_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC1 LFO2 Pitch Depth (CH:%d %d cents)", ch, channel[ch].cc1.lfo2_pitch_depth); break; case 0x35: /* CC1 LFO2 Filter Depth */ channel[ch].cc1.lfo2_tvf_depth = conv_lfo_filter_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC1 LFO2 Filter Depth (CH:%d %d cents)", ch, channel[ch].cc1.lfo2_tvf_depth); break; case 0x36: /* CC1 LFO2 Amplitude Depth */ channel[ch].cc1.lfo2_tva_depth = (float)val / 127.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC1 LFO2 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].cc1.lfo2_tva_depth); break; case 0x37: /* CC2 Pitch Control */ if(val > 0x58) {val = 0x58;} else if(val < 0x28) {val = 0x28;} channel[ch].cc2.pitch = val - 64; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC2 Pitch Control (CH:%d %d semitones)", ch, channel[ch].cc2.pitch); break; case 0x38: /* CC2 Filter Cutoff Control */ channel[ch].cc2.cutoff = (val - 64) * 150; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC2 Filter Cutoff Control (CH:%d %d cents)", ch, channel[ch].cc2.cutoff); break; case 0x39: /* CC2 Amplitude Control */ channel[ch].cc2.amp = (float)val / 64.0f - 1.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC2 Amplitude Control (CH:%d %.2f)", ch, channel[ch].cc2.amp); break; case 0x3A: /* CC2 LFO1 Rate Control */ channel[ch].cc2.lfo1_rate = (float)(val - 64) / 6.4f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC2 LFO1 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].cc2.lfo1_rate); break; case 0x3B: /* CC2 LFO1 Pitch Depth */ channel[ch].cc2.lfo1_pitch_depth = conv_lfo_pitch_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC2 LFO1 Pitch Depth (CH:%d %d cents)", ch, channel[ch].cc2.lfo1_pitch_depth); break; case 0x3C: /* CC2 LFO1 Filter Depth */ channel[ch].cc2.lfo1_tvf_depth = conv_lfo_filter_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC2 LFO1 Filter Depth (CH:%d %d cents)", ch, channel[ch].cc2.lfo1_tvf_depth); break; case 0x3D: /* CC2 LFO1 Amplitude Depth */ channel[ch].cc2.lfo1_tva_depth = (float)val / 127.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC2 LFO1 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].cc2.lfo1_tva_depth); break; case 0x3E: /* CC2 LFO2 Rate Control */ channel[ch].cc2.lfo2_rate = (float)(val - 64) / 6.4f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC2 LFO2 Rate Control (CH:%d %.1f Hz)", ch, channel[ch].cc2.lfo2_rate); break; case 0x3F: /* CC2 LFO2 Pitch Depth */ channel[ch].cc2.lfo2_pitch_depth = conv_lfo_pitch_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC2 LFO2 Pitch Depth (CH:%d %d cents)", ch, channel[ch].cc2.lfo2_pitch_depth); break; case 0x40: /* CC2 LFO2 Filter Depth */ channel[ch].cc2.lfo2_tvf_depth = conv_lfo_filter_depth(val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC2 LFO2 Filter Depth (CH:%d %d cents)", ch, channel[ch].cc2.lfo2_tvf_depth); break; case 0x41: /* CC2 LFO2 Amplitude Depth */ channel[ch].cc2.lfo2_tva_depth = (float)val / 127.0f; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CC2 LFO2 Amplitude Depth (CH:%d %.2f)", ch, channel[ch].cc2.lfo2_tva_depth); break; case 0x42: /* Note Limit Low */ channel[ch].note_limit_low = val; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Note Limit Low (CH:%d VAL:%d)", ch, val); break; case 0x43: /* Note Limit High */ channel[ch].note_limit_high = val; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Note Limit High (CH:%d VAL:%d)", ch, val); break; case 0x44: /* Velocity Limit Low */ channel[ch].vel_limit_low = val; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Velocity Limit Low (CH:%d VAL:%d)", ch, val); break; case 0x45: /* Velocity Limit High */ channel[ch].vel_limit_high = val; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Velocity Limit High (CH:%d VAL:%d)", ch, val); break; case 0x46: /* Rx. Note Off */ if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); set_rx_drum(channel[ch].drums[note], RX_NOTE_OFF, val); ctl_cmsg(CMSG_INFO, VERB_NOISY, "Drum Instrument Rx. Note Off (CH:%d NOTE:%d VAL:%d)", ch, note, val); break; case 0x47: /* Rx. Note On */ if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); set_rx_drum(channel[ch].drums[note], RX_NOTE_ON, val); ctl_cmsg(CMSG_INFO, VERB_NOISY, "Drum Instrument Rx. Note On (CH:%d NOTE:%d VAL:%d)", ch, note, val); break; case 0x48: /* Rx. Pitch Bend */ set_rx(ch, RX_PITCH_BEND, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Pitch Bend (CH:%d VAL:%d)", ch, val); break; case 0x49: /* Rx. Channel Pressure */ set_rx(ch, RX_CH_PRESSURE, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Channel Pressure (CH:%d VAL:%d)", ch, val); break; case 0x4A: /* Rx. Program Change */ set_rx(ch, RX_PROGRAM_CHANGE, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Program Change (CH:%d VAL:%d)", ch, val); break; case 0x4B: /* Rx. Control Change */ set_rx(ch, RX_CONTROL_CHANGE, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Control Change (CH:%d VAL:%d)", ch, val); break; case 0x4C: /* Rx. Poly Pressure */ set_rx(ch, RX_POLY_PRESSURE, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Poly Pressure (CH:%d VAL:%d)", ch, val); break; case 0x4D: /* Rx. Note Message */ set_rx(ch, RX_NOTE_MESSAGE, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Note Message (CH:%d VAL:%d)", ch, val); break; case 0x4E: /* Rx. RPN */ set_rx(ch, RX_RPN, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. RPN (CH:%d VAL:%d)", ch, val); break; case 0x4F: /* Rx. NRPN */ set_rx(ch, RX_NRPN, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. NRPN (CH:%d VAL:%d)", ch, val); break; case 0x50: /* Rx. Modulation */ set_rx(ch, RX_MODULATION, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Modulation (CH:%d VAL:%d)", ch, val); break; case 0x51: /* Rx. Volume */ set_rx(ch, RX_VOLUME, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Volume (CH:%d VAL:%d)", ch, val); break; case 0x52: /* Rx. Panpot */ set_rx(ch, RX_PANPOT, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Panpot (CH:%d VAL:%d)", ch, val); break; case 0x53: /* Rx. Expression */ set_rx(ch, RX_EXPRESSION, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Expression (CH:%d VAL:%d)", ch, val); break; case 0x54: /* Rx. Hold1 */ set_rx(ch, RX_HOLD1, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Hold1 (CH:%d VAL:%d)", ch, val); break; case 0x55: /* Rx. Portamento */ set_rx(ch, RX_PORTAMENTO, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Portamento (CH:%d VAL:%d)", ch, val); break; case 0x56: /* Rx. Sostenuto */ set_rx(ch, RX_SOSTENUTO, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Sostenuto (CH:%d VAL:%d)", ch, val); break; case 0x57: /* Rx. Soft */ set_rx(ch, RX_SOFT, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Soft (CH:%d VAL:%d)", ch, val); break; case 0x58: /* Rx. Bank Select */ set_rx(ch, RX_BANK_SELECT, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Bank Select (CH:%d VAL:%d)", ch, val); break; case 0x59: /* Rx. Bank Select LSB */ set_rx(ch, RX_BANK_SELECT_LSB, val); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Rx. Bank Select LSB (CH:%d VAL:%d)", ch, val); break; case 0x60: /* Reverb Type (GM2) */ if (val > 8) {val = 8;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Reverb Type (%d)", val); reverb->set_reverb_macro_gm2(val); reverb->recompute_reverb_status_gs(); reverb->init_reverb(); break; case 0x61: /* Chorus Type (GM2) */ if (val > 5) {val = 5;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Type (%d)", val); reverb->set_chorus_macro_gs(val); reverb->recompute_chorus_status_gs(); reverb->init_ch_chorus(); break; default: break; } return; } else if(ev == ME_SYSEX_GS_LSB) { /* GS system exclusive message */ msb = channel[ch].sysex_gs_msb_addr; note = channel[ch].sysex_gs_msb_val; channel[ch].sysex_gs_msb_addr = channel[ch].sysex_gs_msb_val = 0; switch(b) { case 0x00: /* EQ ON/OFF */ if(!opt_eq_control) {break;} channel[ch].eq_gs = val; break; case 0x01: /* EQ LOW FREQ */ if(!opt_eq_control) {break;} reverb->eq_status_gs.low_freq = val; reverb->recompute_eq_status_gs(); break; case 0x02: /* EQ LOW GAIN */ if(!opt_eq_control) {break;} reverb->eq_status_gs.low_gain = val; reverb->recompute_eq_status_gs(); break; case 0x03: /* EQ HIGH FREQ */ if(!opt_eq_control) {break;} reverb->eq_status_gs.high_freq = val; reverb->recompute_eq_status_gs(); break; case 0x04: /* EQ HIGH GAIN */ if(!opt_eq_control) {break;} reverb->eq_status_gs.high_gain = val; reverb->recompute_eq_status_gs(); break; case 0x05: /* Reverb Macro */ if (val > 7) {val = 7;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Reverb Macro (%d)",val); reverb->set_reverb_macro_gs(val); reverb->recompute_reverb_status_gs(); reverb->init_reverb(); break; case 0x06: /* Reverb Character */ if (val > 7) {val = 7;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Reverb Character (%d)",val); if (reverb->reverb_status_gs.character != val) { reverb->reverb_status_gs.character = val; reverb->recompute_reverb_status_gs(); reverb->init_reverb(); } break; case 0x07: /* Reverb Pre-LPF */ if (val > 7) {val = 7;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Reverb Pre-LPF (%d)",val); if(reverb->reverb_status_gs.pre_lpf != val) { reverb->reverb_status_gs.pre_lpf = val; reverb->recompute_reverb_status_gs(); } break; case 0x08: /* Reverb Level */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Reverb Level (%d)",val); if(reverb->reverb_status_gs.level != val) { reverb->reverb_status_gs.level = val; reverb->recompute_reverb_status_gs(); reverb->init_reverb(); } break; case 0x09: /* Reverb Time */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Reverb Time (%d)",val); if(reverb->reverb_status_gs.time != val) { reverb->reverb_status_gs.time = val; reverb->recompute_reverb_status_gs(); reverb->init_reverb(); } break; case 0x0A: /* Reverb Delay Feedback */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Reverb Delay Feedback (%d)",val); if(reverb->reverb_status_gs.delay_feedback != val) { reverb->reverb_status_gs.delay_feedback = val; reverb->recompute_reverb_status_gs(); reverb->init_reverb(); } break; case 0x0C: /* Reverb Predelay Time */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Reverb Predelay Time (%d)",val); if(reverb->reverb_status_gs.pre_delay_time != val) { reverb->reverb_status_gs.pre_delay_time = val; reverb->recompute_reverb_status_gs(); reverb->init_reverb(); } break; case 0x0D: /* Chorus Macro */ if (val > 7) {val = 7;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Macro (%d)",val); reverb->set_chorus_macro_gs(val); reverb->recompute_chorus_status_gs(); reverb->init_ch_chorus(); break; case 0x0E: /* Chorus Pre-LPF */ if (val > 7) {val = 7;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Pre-LPF (%d)",val); if (reverb->chorus_status_gs.pre_lpf != val) { reverb->chorus_status_gs.pre_lpf = val; reverb->recompute_chorus_status_gs(); } break; case 0x0F: /* Chorus Level */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Level (%d)",val); if (reverb->chorus_status_gs.level != val) { reverb->chorus_status_gs.level = val; reverb->recompute_chorus_status_gs(); reverb->init_ch_chorus(); } break; case 0x10: /* Chorus Feedback */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Feedback (%d)",val); if (reverb->chorus_status_gs.feedback != val) { reverb->chorus_status_gs.feedback = val; reverb->recompute_chorus_status_gs(); reverb->init_ch_chorus(); } break; case 0x11: /* Chorus Delay */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Delay (%d)",val); if (reverb->chorus_status_gs.delay != val) { reverb->chorus_status_gs.delay = val; reverb->recompute_chorus_status_gs(); reverb->init_ch_chorus(); } break; case 0x12: /* Chorus Rate */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Rate (%d)",val); if (reverb->chorus_status_gs.rate != val) { reverb->chorus_status_gs.rate = val; reverb->recompute_chorus_status_gs(); reverb->init_ch_chorus(); } break; case 0x13: /* Chorus Depth */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Depth (%d)",val); if (reverb->chorus_status_gs.depth != val) { reverb->chorus_status_gs.depth = val; reverb->recompute_chorus_status_gs(); reverb->init_ch_chorus(); } break; case 0x14: /* Chorus Send Level to Reverb */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Send Level to Reverb (%d)",val); if (reverb->chorus_status_gs.send_reverb != val) { reverb->chorus_status_gs.send_reverb = val; reverb->recompute_chorus_status_gs(); reverb->init_ch_chorus(); } break; case 0x15: /* Chorus Send Level to Delay */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Send Level to Delay (%d)",val); if (reverb->chorus_status_gs.send_delay != val) { reverb->chorus_status_gs.send_delay = val; reverb->recompute_chorus_status_gs(); reverb->init_ch_chorus(); } break; case 0x16: /* Delay Macro */ if (val > 7) {val = 7;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Delay Macro (%d)",val); reverb->set_delay_macro_gs(val); reverb->recompute_delay_status_gs(); reverb->init_ch_delay(); break; case 0x17: /* Delay Pre-LPF */ if (val > 7) {val = 7;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Delay Pre-LPF (%d)",val); val &= 0x7; if (reverb->delay_status_gs.pre_lpf != val) { reverb->delay_status_gs.pre_lpf = val; reverb->recompute_delay_status_gs(); } break; case 0x18: /* Delay Time Center */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Delay Time Center (%d)",val); if (reverb->delay_status_gs.time_c != val) { reverb->delay_status_gs.time_c = val; reverb->recompute_delay_status_gs(); reverb->init_ch_delay(); } break; case 0x19: /* Delay Time Ratio Left */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Delay Time Ratio Left (%d)",val); if (val == 0) {val = 1;} if (reverb->delay_status_gs.time_l != val) { reverb->delay_status_gs.time_l = val; reverb->recompute_delay_status_gs(); reverb->init_ch_delay(); } break; case 0x1A: /* Delay Time Ratio Right */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Delay Time Ratio Right (%d)",val); if (val == 0) {val = 1;} if (reverb->delay_status_gs.time_r != val) { reverb->delay_status_gs.time_r = val; reverb->recompute_delay_status_gs(); reverb->init_ch_delay(); } break; case 0x1B: /* Delay Level Center */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Delay Level Center (%d)",val); if (reverb->delay_status_gs.level_center != val) { reverb->delay_status_gs.level_center = val; reverb->recompute_delay_status_gs(); reverb->init_ch_delay(); } break; case 0x1C: /* Delay Level Left */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Delay Level Left (%d)",val); if (reverb->delay_status_gs.level_left != val) { reverb->delay_status_gs.level_left = val; reverb->recompute_delay_status_gs(); reverb->init_ch_delay(); } break; case 0x1D: /* Delay Level Right */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Delay Level Right (%d)",val); if (reverb->delay_status_gs.level_right != val) { reverb->delay_status_gs.level_right = val; reverb->recompute_delay_status_gs(); reverb->init_ch_delay(); } break; case 0x1E: /* Delay Level */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Delay Level (%d)",val); if (reverb->delay_status_gs.level != val) { reverb->delay_status_gs.level = val; reverb->recompute_delay_status_gs(); reverb->init_ch_delay(); } break; case 0x1F: /* Delay Feedback */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Delay Feedback (%d)",val); if (reverb->delay_status_gs.feedback != val) { reverb->delay_status_gs.feedback = val; reverb->recompute_delay_status_gs(); reverb->init_ch_delay(); } break; case 0x20: /* Delay Send Level to Reverb */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Delay Send Level to Reverb (%d)",val); if (reverb->delay_status_gs.send_reverb != val) { reverb->delay_status_gs.send_reverb = val; reverb->recompute_delay_status_gs(); reverb->init_ch_delay(); } break; case 0x21: /* Velocity Sense Depth */ channel[ch].velocity_sense_depth = val; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Velocity Sense Depth (CH:%d VAL:%d)",ch,val); break; case 0x22: /* Velocity Sense Offset */ channel[ch].velocity_sense_offset = val; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Velocity Sense Offset (CH:%d VAL:%d)",ch,val); break; case 0x23: /* Insertion Effect ON/OFF */ if(!opt_insertion_effect) {break;} if(channel[ch].insertion_effect != val) { //if(val) {//ctl_cmsg(CMSG_INFO,VERB_NOISY,"EFX ON (CH:%d)",ch);} //else {//ctl_cmsg(CMSG_INFO,VERB_NOISY,"EFX OFF (CH:%d)",ch);} } channel[ch].insertion_effect = val; break; case 0x24: /* Assign Mode */ channel[ch].assign_mode = val; if(val == 0) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Assign Mode: Single (CH:%d)",ch); } else if(val == 1) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Assign Mode: Limited-Multi (CH:%d)",ch); } else if(val == 2) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Assign Mode: Full-Multi (CH:%d)",ch); } break; case 0x25: /* TONE MAP-0 NUMBER */ channel[ch].tone_map0_number = val; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Tone Map-0 Number (CH:%d VAL:%d)",ch,val); break; case 0x26: /* Pitch Offset Fine */ channel[ch].pitch_offset_fine = (double)((((int32_t)val << 4) | (int32_t)val) - 0x80) / 10.0; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Pitch Offset Fine (CH:%d %3fHz)",ch,channel[ch].pitch_offset_fine); break; case 0x27: /* Insertion Effect Parameter */ if(!opt_insertion_effect) {break;} temp = reverb->insertion_effect_gs.type; reverb->insertion_effect_gs.type_msb = val; reverb->insertion_effect_gs.type = ((int32_t)reverb->insertion_effect_gs.type_msb << 8) | (int32_t)reverb->insertion_effect_gs.type_lsb; if(temp == reverb->insertion_effect_gs.type) { reverb->recompute_insertion_effect_gs(); } else { reverb->realloc_insertion_effect_gs(); } break; case 0x28: /* Insertion Effect Parameter */ if(!opt_insertion_effect) {break;} temp = reverb->insertion_effect_gs.type; reverb->insertion_effect_gs.type_lsb = val; reverb->insertion_effect_gs.type = ((int32_t)reverb->insertion_effect_gs.type_msb << 8) | (int32_t)reverb->insertion_effect_gs.type_lsb; if(temp == reverb->insertion_effect_gs.type) { reverb->recompute_insertion_effect_gs(); } else { reverb->realloc_insertion_effect_gs(); } break; case 0x29: reverb->insertion_effect_gs.parameter[0] = val; reverb->recompute_insertion_effect_gs(); break; case 0x2A: reverb->insertion_effect_gs.parameter[1] = val; reverb->recompute_insertion_effect_gs(); break; case 0x2B: reverb->insertion_effect_gs.parameter[2] = val; reverb->recompute_insertion_effect_gs(); break; case 0x2C: reverb->insertion_effect_gs.parameter[3] = val; reverb->recompute_insertion_effect_gs(); break; case 0x2D: reverb->insertion_effect_gs.parameter[4] = val; reverb->recompute_insertion_effect_gs(); break; case 0x2E: reverb->insertion_effect_gs.parameter[5] = val; reverb->recompute_insertion_effect_gs(); break; case 0x2F: reverb->insertion_effect_gs.parameter[6] = val; reverb->recompute_insertion_effect_gs(); break; case 0x30: reverb->insertion_effect_gs.parameter[7] = val; reverb->recompute_insertion_effect_gs(); break; case 0x31: reverb->insertion_effect_gs.parameter[8] = val; reverb->recompute_insertion_effect_gs(); break; case 0x32: reverb->insertion_effect_gs.parameter[9] = val; reverb->recompute_insertion_effect_gs(); break; case 0x33: reverb->insertion_effect_gs.parameter[10] = val; reverb->recompute_insertion_effect_gs(); break; case 0x34: reverb->insertion_effect_gs.parameter[11] = val; reverb->recompute_insertion_effect_gs(); break; case 0x35: reverb->insertion_effect_gs.parameter[12] = val; reverb->recompute_insertion_effect_gs(); break; case 0x36: reverb->insertion_effect_gs.parameter[13] = val; reverb->recompute_insertion_effect_gs(); break; case 0x37: reverb->insertion_effect_gs.parameter[14] = val; reverb->recompute_insertion_effect_gs(); break; case 0x38: reverb->insertion_effect_gs.parameter[15] = val; reverb->recompute_insertion_effect_gs(); break; case 0x39: reverb->insertion_effect_gs.parameter[16] = val; reverb->recompute_insertion_effect_gs(); break; case 0x3A: reverb->insertion_effect_gs.parameter[17] = val; reverb->recompute_insertion_effect_gs(); break; case 0x3B: reverb->insertion_effect_gs.parameter[18] = val; reverb->recompute_insertion_effect_gs(); break; case 0x3C: reverb->insertion_effect_gs.parameter[19] = val; reverb->recompute_insertion_effect_gs(); break; case 0x3D: reverb->insertion_effect_gs.send_reverb = val; reverb->recompute_insertion_effect_gs(); break; case 0x3E: reverb->insertion_effect_gs.send_chorus = val; reverb->recompute_insertion_effect_gs(); break; case 0x3F: reverb->insertion_effect_gs.send_delay = val; reverb->recompute_insertion_effect_gs(); break; case 0x40: reverb->insertion_effect_gs.control_source1 = val; reverb->recompute_insertion_effect_gs(); break; case 0x41: reverb->insertion_effect_gs.control_depth1 = val; reverb->recompute_insertion_effect_gs(); break; case 0x42: reverb->insertion_effect_gs.control_source2 = val; reverb->recompute_insertion_effect_gs(); break; case 0x43: reverb->insertion_effect_gs.control_depth2 = val; reverb->recompute_insertion_effect_gs(); break; case 0x44: reverb->insertion_effect_gs.send_eq_switch = val; reverb->recompute_insertion_effect_gs(); break; case 0x45: /* Rx. Channel */ reset_controllers(ch); all_notes_off(ch); if (val == 0x80) remove_channel_layer(ch); else add_channel_layer(ch, val); break; case 0x46: /* Channel Msg Rx Port */ reset_controllers(ch); all_notes_off(ch); channel[ch].port_select = val; break; case 0x47: /* Play Note Number */ if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); channel[ch].drums[note]->play_note = val; ctl_cmsg(CMSG_INFO, VERB_NOISY, "Drum Instrument Play Note (CH:%d NOTE:%d VAL:%d)", ch, note, channel[ch].drums[note]->play_note); channel[ch].pitchfactor = 0; break; default: break; } return; } else if(ev == ME_SYSEX_XG_LSB) { /* XG system exclusive message */ msb = channel[ch].sysex_xg_msb_addr; note = channel[ch].sysex_xg_msb_val; if (note == 3 && msb == 0) { /* Effect 2 */ note = 0; /* force insertion effect num 0 ?? */ if (note >= XG_INSERTION_EFFECT_NUM || note < 0) {return;} switch(b) { case 0x00: /* Insertion Effect Type MSB */ if (reverb->insertion_effect_xg[note].type_msb != val) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Insertion Effect Type MSB (%d %02X)", note, val); reverb->insertion_effect_xg[note].type_msb = val; reverb->realloc_effect_xg(&reverb->insertion_effect_xg[note]); } break; case 0x01: /* Insertion Effect Type LSB */ if (reverb->insertion_effect_xg[note].type_lsb != val) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Insertion Effect Type LSB (%d %02X)", note, val); reverb->insertion_effect_xg[note].type_lsb = val; reverb->realloc_effect_xg(&reverb->insertion_effect_xg[note]); } break; case 0x02: /* Insertion Effect Parameter 1 - 10 */ case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: if (reverb->insertion_effect_xg[note].use_msb) {break;} temp = b - 0x02; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Insertion Effect Parameter %d (%d %d)", temp + 1, note, val); if (reverb->insertion_effect_xg[note].param_lsb[temp] != val) { reverb->insertion_effect_xg[note].param_lsb[temp] = val; reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); } break; case 0x0C: /* Insertion Effect Part */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Insertion Effect Part (%d %d)", note, val); if (reverb->insertion_effect_xg[note].part != val) { reverb->insertion_effect_xg[note].part = val; reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); } break; case 0x0D: /* MW Insertion Control Depth */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"MW Insertion Control Depth (%d %d)", note, val); if (reverb->insertion_effect_xg[note].mw_depth != val) { reverb->insertion_effect_xg[note].mw_depth = val; reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); } break; case 0x0E: /* BEND Insertion Control Depth */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"BEND Insertion Control Depth (%d %d)", note, val); if (reverb->insertion_effect_xg[note].bend_depth != val) { reverb->insertion_effect_xg[note].bend_depth = val; reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); } break; case 0x0F: /* CAT Insertion Control Depth */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CAT Insertion Control Depth (%d %d)", note, val); if (reverb->insertion_effect_xg[note].cat_depth != val) { reverb->insertion_effect_xg[note].cat_depth = val; reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); } break; case 0x10: /* AC1 Insertion Control Depth */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"AC1 Insertion Control Depth (%d %d)", note, val); if (reverb->insertion_effect_xg[note].ac1_depth != val) { reverb->insertion_effect_xg[note].ac1_depth = val; reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); } break; case 0x11: /* AC2 Insertion Control Depth */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"AC2 Insertion Control Depth (%d %d)", note, val); if (reverb->insertion_effect_xg[note].ac2_depth != val) { reverb->insertion_effect_xg[note].ac2_depth = val; reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); } break; case 0x12: /* CBC1 Insertion Control Depth */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CBC1 Insertion Control Depth (%d %d)", note, val); if (reverb->insertion_effect_xg[note].cbc1_depth != val) { reverb->insertion_effect_xg[note].cbc1_depth = val; reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); } break; case 0x13: /* CBC2 Insertion Control Depth */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CBC2 Insertion Control Depth (%d %d)", note, val); if (reverb->insertion_effect_xg[note].cbc2_depth != val) { reverb->insertion_effect_xg[note].cbc2_depth = val; reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); } break; case 0x20: /* Insertion Effect Parameter 11 - 16 */ case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: temp = b - 0x20 + 10; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Insertion Effect Parameter %d (%d %d)", temp + 1, note, val); if (reverb->insertion_effect_xg[note].param_lsb[temp] != val) { reverb->insertion_effect_xg[note].param_lsb[temp] = val; reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); } break; case 0x30: /* Insertion Effect Parameter 1 - 10 MSB */ case 0x32: case 0x34: case 0x36: case 0x38: case 0x3A: case 0x3C: case 0x3E: case 0x40: case 0x42: if (!reverb->insertion_effect_xg[note].use_msb) {break;} temp = (b - 0x30) / 2; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Insertion Effect Parameter %d MSB (%d %d)", temp + 1, note, val); if (reverb->insertion_effect_xg[note].param_msb[temp] != val) { reverb->insertion_effect_xg[note].param_msb[temp] = val; reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); } break; case 0x31: /* Insertion Effect Parameter 1 - 10 LSB */ case 0x33: case 0x35: case 0x37: case 0x39: case 0x3B: case 0x3D: case 0x3F: case 0x41: case 0x43: if (!reverb->insertion_effect_xg[note].use_msb) {break;} temp = (b - 0x31) / 2; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Insertion Effect Parameter %d LSB (%d %d)", temp + 1, note, val); if (reverb->insertion_effect_xg[note].param_lsb[temp] != val) { reverb->insertion_effect_xg[note].param_lsb[temp] = val; reverb->recompute_effect_xg(&reverb->insertion_effect_xg[note]); } break; default: break; } } else if (note == 2 && msb == 1) { /* Effect 1 */ note = 0; /* force variation effect num 0 ?? */ switch(b) { case 0x00: /* Reverb Type MSB */ if (reverb->reverb_status_xg.type_msb != val) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Reverb Type MSB (%02X)", val); reverb->reverb_status_xg.type_msb = val; reverb->realloc_effect_xg(&reverb->reverb_status_xg); } break; case 0x01: /* Reverb Type LSB */ if (reverb->reverb_status_xg.type_lsb != val) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Reverb Type LSB (%02X)", val); reverb->reverb_status_xg.type_lsb = val; reverb->realloc_effect_xg(&reverb->reverb_status_xg); } break; case 0x02: /* Reverb Parameter 1 - 10 */ case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Reverb Parameter %d (%d)", b - 0x02 + 1, val); if (reverb->reverb_status_xg.param_lsb[b - 0x02] != val) { reverb->reverb_status_xg.param_lsb[b - 0x02] = val; reverb->recompute_effect_xg(&reverb->reverb_status_xg); } break; case 0x0C: /* Reverb Return */ #if 0 /* XG specific reverb is not currently implemented */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Reverb Return (%d)", val); if (reverb->reverb_status_xg.ret != val) { reverb->reverb_status_xg.ret = val; reverb->recompute_effect_xg(&reverb->reverb_status_xg); } #else /* use GS reverb instead */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Reverb Return (%d)", val); if (reverb->reverb_status_gs.level != val) { reverb->reverb_status_gs.level = val; reverb->recompute_reverb_status_gs(); reverb->init_reverb(); } #endif break; case 0x0D: /* Reverb Pan */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Reverb Pan (%d)", val); if (reverb->reverb_status_xg.pan != val) { reverb->reverb_status_xg.pan = val; reverb->recompute_effect_xg(&reverb->reverb_status_xg); } break; case 0x10: /* Reverb Parameter 11 - 16 */ case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: temp = b - 0x10 + 10; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Reverb Parameter %d (%d)", temp + 1, val); if (reverb->reverb_status_xg.param_lsb[temp] != val) { reverb->reverb_status_xg.param_lsb[temp] = val; reverb->recompute_effect_xg(&reverb->reverb_status_xg); } break; case 0x20: /* Chorus Type MSB */ if (reverb->chorus_status_xg.type_msb != val) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Type MSB (%02X)", val); reverb->chorus_status_xg.type_msb = val; reverb->realloc_effect_xg(&reverb->chorus_status_xg); } break; case 0x21: /* Chorus Type LSB */ if (reverb->chorus_status_xg.type_lsb != val) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Type LSB (%02X)", val); reverb->chorus_status_xg.type_lsb = val; reverb->realloc_effect_xg(&reverb->chorus_status_xg); } break; case 0x22: /* Chorus Parameter 1 - 10 */ case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2A: case 0x2B: //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Parameter %d (%d)", b - 0x22 + 1, val); if (reverb->chorus_status_xg.param_lsb[b - 0x22] != val) { reverb->chorus_status_xg.param_lsb[b - 0x22] = val; reverb->recompute_effect_xg(&reverb->chorus_status_xg); } break; case 0x2C: /* Chorus Return */ #if 0 /* XG specific chorus is not currently implemented */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Return (%d)", val); if (reverb->chorus_status_xg.ret != val) { reverb->chorus_status_xg.ret = val; reverb->recompute_effect_xg(&reverb->chorus_status_xg); } #else /* use GS chorus instead */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Return (%d)", val); if (reverb->chorus_status_gs.level != val) { reverb->chorus_status_gs.level = val; reverb->recompute_chorus_status_gs(); reverb->init_ch_chorus(); } #endif break; case 0x2D: /* Chorus Pan */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Pan (%d)", val); if (reverb->chorus_status_xg.pan != val) { reverb->chorus_status_xg.pan = val; reverb->recompute_effect_xg(&reverb->chorus_status_xg); } break; case 0x2E: /* Send Chorus To Reverb */ //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Send Chorus To Reverb (%d)", val); if (reverb->chorus_status_xg.send_reverb != val) { reverb->chorus_status_xg.send_reverb = val; reverb->recompute_effect_xg(&reverb->chorus_status_xg); } break; case 0x30: /* Chorus Parameter 11 - 16 */ case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: temp = b - 0x30 + 10; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Parameter %d (%d)", temp + 1, val); if (reverb->chorus_status_xg.param_lsb[temp] != val) { reverb->chorus_status_xg.param_lsb[temp] = val; reverb->recompute_effect_xg(&reverb->chorus_status_xg); } break; case 0x40: /* Variation Type MSB */ if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} if (reverb->variation_effect_xg[note].type_msb != val) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Variation Type MSB (%02X)", val); reverb->variation_effect_xg[note].type_msb = val; reverb->realloc_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x41: /* Variation Type LSB */ if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} if (reverb->variation_effect_xg[note].type_lsb != val) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Variation Type LSB (%02X)", val); reverb->variation_effect_xg[note].type_lsb = val; reverb->realloc_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x42: /* Variation Parameter 1 - 10 MSB */ case 0x44: case 0x46: case 0x48: case 0x4A: case 0x4C: case 0x4E: case 0x50: case 0x52: case 0x54: if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} temp = (b - 0x42) / 2; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Variation Parameter %d MSB (%d)", temp, val); if (reverb->variation_effect_xg[note].param_msb[temp] != val) { reverb->variation_effect_xg[note].param_msb[temp] = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x43: /* Variation Parameter 1 - 10 LSB */ case 0x45: case 0x47: case 0x49: case 0x4B: case 0x4D: case 0x4F: case 0x51: case 0x53: case 0x55: if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} temp = (b - 0x43) / 2; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Variation Parameter %d LSB (%d)", temp, val); if (reverb->variation_effect_xg[note].param_lsb[temp] != val) { reverb->variation_effect_xg[note].param_lsb[temp] = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x56: /* Variation Return */ if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Variation Return (%d)", val); if (reverb->variation_effect_xg[note].ret != val) { reverb->variation_effect_xg[note].ret = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x57: /* Variation Pan */ if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Variation Pan (%d)", val); if (reverb->variation_effect_xg[note].pan != val) { reverb->variation_effect_xg[note].pan = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x58: /* Send Variation To Reverb */ if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Send Variation To Reverb (%d)", val); if (reverb->variation_effect_xg[note].send_reverb != val) { reverb->variation_effect_xg[note].send_reverb = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x59: /* Send Variation To Chorus */ if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Send Variation To Chorus (%d)", val); if (reverb->variation_effect_xg[note].send_chorus != val) { reverb->variation_effect_xg[note].send_chorus = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x5A: /* Variation Connection */ if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Variation Connection (%d)", val); if (reverb->variation_effect_xg[note].connection != val) { reverb->variation_effect_xg[note].connection = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x5B: /* Variation Part */ if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Variation Part (%d)", val); if (reverb->variation_effect_xg[note].part != val) { reverb->variation_effect_xg[note].part = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x5C: /* MW Variation Control Depth */ if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"MW Variation Control Depth (%d)", val); if (reverb->variation_effect_xg[note].mw_depth != val) { reverb->variation_effect_xg[note].mw_depth = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x5D: /* BEND Variation Control Depth */ if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"BEND Variation Control Depth (%d)", val); if (reverb->variation_effect_xg[note].bend_depth != val) { reverb->variation_effect_xg[note].bend_depth = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x5E: /* CAT Variation Control Depth */ if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CAT Variation Control Depth (%d)", val); if (reverb->variation_effect_xg[note].cat_depth != val) { reverb->variation_effect_xg[note].cat_depth = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x5F: /* AC1 Variation Control Depth */ if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"AC1 Variation Control Depth (%d)", val); if (reverb->variation_effect_xg[note].ac1_depth != val) { reverb->variation_effect_xg[note].ac1_depth = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x60: /* AC2 Variation Control Depth */ if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"AC2 Variation Control Depth (%d)", val); if (reverb->variation_effect_xg[note].ac2_depth != val) { reverb->variation_effect_xg[note].ac2_depth = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x61: /* CBC1 Variation Control Depth */ if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CBC1 Variation Control Depth (%d)", val); if (reverb->variation_effect_xg[note].cbc1_depth != val) { reverb->variation_effect_xg[note].cbc1_depth = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x62: /* CBC2 Variation Control Depth */ if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"CBC2 Variation Control Depth (%d)", val); if (reverb->variation_effect_xg[note].cbc2_depth != val) { reverb->variation_effect_xg[note].cbc2_depth = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; case 0x70: /* Variation Parameter 11 - 16 */ case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: temp = b - 0x70 + 10; if (note >= XG_VARIATION_EFFECT_NUM || note < 0) {break;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Variation Parameter %d (%d)", temp + 1, val); if (reverb->variation_effect_xg[note].param_lsb[temp] != val) { reverb->variation_effect_xg[note].param_lsb[temp] = val; reverb->recompute_effect_xg(&reverb->variation_effect_xg[note]); } break; default: break; } } else if (note == 2 && msb == 40) { /* Multi EQ */ switch(b) { case 0x00: /* EQ type */ if(opt_eq_control) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ type (%d)", val); reverb->multi_eq_xg.type = val; reverb->set_multi_eq_type_xg(val); reverb->recompute_multi_eq_xg(); } break; case 0x01: /* EQ gain1 */ if(opt_eq_control) { if(val > 0x4C) {val = 0x4C;} else if(val < 0x34) {val = 0x34;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ gain1 (%d dB)", val - 0x40); reverb->multi_eq_xg.gain1 = val; reverb->recompute_multi_eq_xg(); } break; case 0x02: /* EQ frequency1 */ if(opt_eq_control) { if(val > 60) {val = 60;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ frequency1 (%d Hz)", (int32_t)eq_freq_table_xg[val]); reverb->multi_eq_xg.freq1 = val; reverb->recompute_multi_eq_xg(); } break; case 0x03: /* EQ Q1 */ if(opt_eq_control) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ Q1 (%f)", (double)val / 10.0); reverb->multi_eq_xg.q1 = val; reverb->recompute_multi_eq_xg(); } break; case 0x04: /* EQ shape1 */ if(opt_eq_control) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ shape1 (%d)", val); reverb->multi_eq_xg.shape1 = val; reverb->recompute_multi_eq_xg(); } break; case 0x05: /* EQ gain2 */ if(opt_eq_control) { if(val > 0x4C) {val = 0x4C;} else if(val < 0x34) {val = 0x34;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ gain2 (%d dB)", val - 0x40); reverb->multi_eq_xg.gain2 = val; reverb->recompute_multi_eq_xg(); } break; case 0x06: /* EQ frequency2 */ if(opt_eq_control) { if(val > 60) {val = 60;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ frequency2 (%d Hz)", (int32_t)eq_freq_table_xg[val]); reverb->multi_eq_xg.freq2 = val; reverb->recompute_multi_eq_xg(); } break; case 0x07: /* EQ Q2 */ if(opt_eq_control) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ Q2 (%f)", (double)val / 10.0); reverb->multi_eq_xg.q2 = val; reverb->recompute_multi_eq_xg(); } break; case 0x09: /* EQ gain3 */ if(opt_eq_control) { if(val > 0x4C) {val = 0x4C;} else if(val < 0x34) {val = 0x34;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ gain3 (%d dB)", val - 0x40); reverb->multi_eq_xg.gain3 = val; reverb->recompute_multi_eq_xg(); } break; case 0x0A: /* EQ frequency3 */ if(opt_eq_control) { if(val > 60) {val = 60;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ frequency3 (%d Hz)", (int32_t)eq_freq_table_xg[val]); reverb->multi_eq_xg.freq3 = val; reverb->recompute_multi_eq_xg(); } break; case 0x0B: /* EQ Q3 */ if(opt_eq_control) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ Q3 (%f)", (double)val / 10.0); reverb->multi_eq_xg.q3 = val; reverb->recompute_multi_eq_xg(); } break; case 0x0D: /* EQ gain4 */ if(opt_eq_control) { if(val > 0x4C) {val = 0x4C;} else if(val < 0x34) {val = 0x34;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ gain4 (%d dB)", val - 0x40); reverb->multi_eq_xg.gain4 = val; reverb->recompute_multi_eq_xg(); } break; case 0x0E: /* EQ frequency4 */ if(opt_eq_control) { if(val > 60) {val = 60;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ frequency4 (%d Hz)", (int32_t)eq_freq_table_xg[val]); reverb->multi_eq_xg.freq4 = val; reverb->recompute_multi_eq_xg(); } break; case 0x0F: /* EQ Q4 */ if(opt_eq_control) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ Q4 (%f)", (double)val / 10.0); reverb->multi_eq_xg.q4 = val; reverb->recompute_multi_eq_xg(); } break; case 0x11: /* EQ gain5 */ if(opt_eq_control) { if(val > 0x4C) {val = 0x4C;} else if(val < 0x34) {val = 0x34;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ gain5 (%d dB)", val - 0x40); reverb->multi_eq_xg.gain5 = val; reverb->recompute_multi_eq_xg(); } break; case 0x12: /* EQ frequency5 */ if(opt_eq_control) { if(val > 60) {val = 60;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ frequency5 (%d Hz)", (int32_t)eq_freq_table_xg[val]); reverb->multi_eq_xg.freq5 = val; reverb->recompute_multi_eq_xg(); } break; case 0x13: /* EQ Q5 */ if(opt_eq_control) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ Q5 (%f)", (double)val / 10.0); reverb->multi_eq_xg.q5 = val; reverb->recompute_multi_eq_xg(); } break; case 0x14: /* EQ shape5 */ if(opt_eq_control) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ shape5 (%d)", val); reverb->multi_eq_xg.shape5 = val; reverb->recompute_multi_eq_xg(); } break; } } else if (note == 8 && msb == 0) { /* Multi Part */ switch(b) { case 0x99: /* Rcv CHANNEL, remapped from 0x04 */ reset_controllers(ch); all_notes_off(ch); if (val == 0x7f) remove_channel_layer(ch); else { if((ch < REDUCE_CHANNELS) != (val < REDUCE_CHANNELS)) { channel[ch].port_select = ch < REDUCE_CHANNELS ? 1 : 0; } if((ch % REDUCE_CHANNELS) != (val % REDUCE_CHANNELS)) { add_channel_layer(ch, val); } } break; case 0x06: /* Same Note Number Key On Assign */ if(val == 0) { channel[ch].assign_mode = 0; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Same Note Number Key On Assign: Single (CH:%d)",ch); } else if(val == 1) { channel[ch].assign_mode = 2; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Same Note Number Key On Assign: Multi (CH:%d)",ch); } else if(val == 2) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Same Note Number Key On Assign: Inst is not supported. (CH:%d)",ch); } break; case 0x11: /* Dry Level */ channel[ch].dry_level = val; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Dry Level (CH:%d VAL:%d)", ch, val); break; } } else if ((note & 0xF0) == 0x30) { /* Drum Setup */ note = msb; switch(b) { case 0x0E: /* EG Decay1 */ if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Drum Instrument EG Decay1 (CH:%d NOTE:%d VAL:%d)", ch, note, val); channel[ch].drums[note]->drum_envelope_rate[EG_DECAY1] = val; break; case 0x0F: /* EG Decay2 */ if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Drum Instrument EG Decay2 (CH:%d NOTE:%d VAL:%d)", ch, note, val); channel[ch].drums[note]->drum_envelope_rate[EG_DECAY2] = val; break; default: break; } } return; } } /*! convert GS NRPN to vibrato rate ratio. */ /* from 0 to 3.0. */ double Player::gs_cnv_vib_rate(int rate) { double ratio; if(rate == 0) { ratio = 1.6 / 100.0; } else if(rate == 64) { ratio = 1.0; } else if(rate <= 100) { ratio = (double)rate * 1.6 / 100.0; } else { ratio = (double)(rate - 101) * 1.33 / 26.0 + 1.67; } return (1.0 / ratio); } /*! convert GS NRPN to vibrato depth. */ /* from -9.6 cents to +9.45 cents. */ int32_t Player::gs_cnv_vib_depth(int depth) { double cent; cent = (double)(depth - 64) * 0.15; return (int32_t)(cent * 256.0 / 400.0); } /*! convert GS NRPN to vibrato delay. */ /* from 0 ms to 5074 ms. */ int32_t Player::gs_cnv_vib_delay(int delay) { double ms; ms = 0.2092 * exp(0.0795 * (double)delay); if(delay == 0) {ms = 0;} return (int32_t)((double)playback_rate * ms * 0.001); } int Player::last_rpn_addr(int ch) { int lsb, msb, addr, i; const struct rpn_tag_map_t *addrmap; struct rpn_tag_map_t { int addr, mask, tag; }; static const struct rpn_tag_map_t nrpn_addr_map[] = { {0x0108, 0xffff, NRPN_ADDR_0108}, {0x0109, 0xffff, NRPN_ADDR_0109}, {0x010a, 0xffff, NRPN_ADDR_010A}, {0x0120, 0xffff, NRPN_ADDR_0120}, {0x0121, 0xffff, NRPN_ADDR_0121}, {0x0130, 0xffff, NRPN_ADDR_0130}, {0x0131, 0xffff, NRPN_ADDR_0131}, {0x0134, 0xffff, NRPN_ADDR_0134}, {0x0135, 0xffff, NRPN_ADDR_0135}, {0x0163, 0xffff, NRPN_ADDR_0163}, {0x0164, 0xffff, NRPN_ADDR_0164}, {0x0166, 0xffff, NRPN_ADDR_0166}, {0x1400, 0xff00, NRPN_ADDR_1400}, {0x1500, 0xff00, NRPN_ADDR_1500}, {0x1600, 0xff00, NRPN_ADDR_1600}, {0x1700, 0xff00, NRPN_ADDR_1700}, {0x1800, 0xff00, NRPN_ADDR_1800}, {0x1900, 0xff00, NRPN_ADDR_1900}, {0x1a00, 0xff00, NRPN_ADDR_1A00}, {0x1c00, 0xff00, NRPN_ADDR_1C00}, {0x1d00, 0xff00, NRPN_ADDR_1D00}, {0x1e00, 0xff00, NRPN_ADDR_1E00}, {0x1f00, 0xff00, NRPN_ADDR_1F00}, {0x3000, 0xff00, NRPN_ADDR_3000}, {0x3100, 0xff00, NRPN_ADDR_3100}, {0x3400, 0xff00, NRPN_ADDR_3400}, {0x3500, 0xff00, NRPN_ADDR_3500}, {-1, -1, 0} }; static const struct rpn_tag_map_t rpn_addr_map[] = { {0x0000, 0xffff, RPN_ADDR_0000}, {0x0001, 0xffff, RPN_ADDR_0001}, {0x0002, 0xffff, RPN_ADDR_0002}, {0x0003, 0xffff, RPN_ADDR_0003}, {0x0004, 0xffff, RPN_ADDR_0004}, {0x0005, 0xffff, RPN_ADDR_0005}, {0x7f7f, 0xffff, RPN_ADDR_7F7F}, {0xffff, 0xffff, RPN_ADDR_FFFF}, {-1, -1} }; if (channel[ch].nrpn == -1) return -1; lsb = channel[ch].lastlrpn; msb = channel[ch].lastmrpn; if (lsb == 0xff || msb == 0xff) return -1; addr = (msb << 8 | lsb); if (channel[ch].nrpn) addrmap = nrpn_addr_map; else addrmap = rpn_addr_map; for (i = 0; addrmap[i].addr != -1; i++) if (addrmap[i].addr == (addr & addrmap[i].mask)) return addrmap[i].tag; return -1; } void Player::update_rpn_map(int ch, int addr, int update_now) { int val, drumflag, i, note; val = channel[ch].rpnmap[addr]; drumflag = 0; switch (addr) { case NRPN_ADDR_0108: /* Vibrato Rate */ if (op_nrpn_vibrato) { //ctl_cmsg(CMSG_INFO, VERB_NOISY, "Vibrato Rate (CH:%d VAL:%d)", ch, val - 64); channel[ch].vibrato_ratio = gs_cnv_vib_rate(val); } if (update_now) adjust_pitch(ch); break; case NRPN_ADDR_0109: /* Vibrato Depth */ if (op_nrpn_vibrato) { //ctl_cmsg(CMSG_INFO, VERB_NOISY, "Vibrato Depth (CH:%d VAL:%d)", ch, val - 64); channel[ch].vibrato_depth = gs_cnv_vib_depth(val); } if (update_now) adjust_pitch(ch); break; case NRPN_ADDR_010A: /* Vibrato Delay */ if (op_nrpn_vibrato) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Vibrato Delay (CH:%d VAL:%d)", ch, val); channel[ch].vibrato_delay = gs_cnv_vib_delay(val); } if (update_now) adjust_pitch(ch); break; case NRPN_ADDR_0120: /* Filter Cutoff Frequency */ if (timidity_lpf_def) { //ctl_cmsg(CMSG_INFO, VERB_NOISY, "Filter Cutoff (CH:%d VAL:%d)", ch, val - 64); channel[ch].param_cutoff_freq = val - 64; } break; case NRPN_ADDR_0121: /* Filter Resonance */ if (timidity_lpf_def) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Filter Resonance (CH:%d VAL:%d)", ch, val - 64); channel[ch].param_resonance = val - 64; } break; case NRPN_ADDR_0130: /* EQ BASS */ if (opt_eq_control) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ BASS (CH:%d %.2f dB)", ch, 0.19 * (double)(val - 0x40)); channel[ch].eq_xg.bass = val; recompute_part_eq_xg(&(channel[ch].eq_xg)); } break; case NRPN_ADDR_0131: /* EQ TREBLE */ if (opt_eq_control) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ TREBLE (CH:%d %.2f dB)", ch, 0.19 * (double)(val - 0x40)); channel[ch].eq_xg.treble = val; recompute_part_eq_xg(&(channel[ch].eq_xg)); } break; case NRPN_ADDR_0134: /* EQ BASS frequency */ if (opt_eq_control) { if(val < 4) {val = 4;} else if(val > 40) {val = 40;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ BASS frequency (CH:%d %d Hz)", ch, (int32_t)eq_freq_table_xg[val]); channel[ch].eq_xg.bass_freq = val; recompute_part_eq_xg(&(channel[ch].eq_xg)); } break; case NRPN_ADDR_0135: /* EQ TREBLE frequency */ if (opt_eq_control) { if(val < 28) {val = 28;} else if(val > 58) {val = 58;} //ctl_cmsg(CMSG_INFO,VERB_NOISY,"EQ TREBLE frequency (CH:%d %d Hz)", ch, (int32_t)eq_freq_table_xg[val]); channel[ch].eq_xg.treble_freq = val; recompute_part_eq_xg(&(channel[ch].eq_xg)); } break; case NRPN_ADDR_0163: /* Attack Time */ if (opt_tva_attack) {set_envelope_time(ch, val, EG_ATTACK);} break; case NRPN_ADDR_0164: /* EG Decay Time */ if (opt_tva_decay) {set_envelope_time(ch, val, EG_DECAY);} break; case NRPN_ADDR_0166: /* EG Release Time */ if (opt_tva_release) {set_envelope_time(ch, val, EG_RELEASE);} break; case NRPN_ADDR_1400: /* Drum Filter Cutoff (XG) */ drumflag = 1; note = channel[ch].lastlrpn; if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Drum Instrument Filter Cutoff (CH:%d NOTE:%d VAL:%d)", ch, note, val); channel[ch].drums[note]->drum_cutoff_freq = val - 64; break; case NRPN_ADDR_1500: /* Drum Filter Resonance (XG) */ drumflag = 1; note = channel[ch].lastlrpn; if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Drum Instrument Filter Resonance (CH:%d NOTE:%d VAL:%d)", ch, note, val); channel[ch].drums[note]->drum_resonance = val - 64; break; case NRPN_ADDR_1600: /* Drum EG Attack Time (XG) */ drumflag = 1; if (opt_tva_attack) { val = val & 0x7f; note = channel[ch].lastlrpn; if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); val -= 64; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Drum Instrument Attack Time (CH:%d NOTE:%d VAL:%d)", ch, note, val); channel[ch].drums[note]->drum_envelope_rate[EG_ATTACK] = val; } break; case NRPN_ADDR_1700: /* Drum EG Decay Time (XG) */ drumflag = 1; if (opt_tva_decay) { val = val & 0x7f; note = channel[ch].lastlrpn; if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); val -= 64; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Drum Instrument Decay Time (CH:%d NOTE:%d VAL:%d)", ch, note, val); channel[ch].drums[note]->drum_envelope_rate[EG_DECAY1] = channel[ch].drums[note]->drum_envelope_rate[EG_DECAY2] = val; } break; case NRPN_ADDR_1800: /* Coarse Pitch of Drum (GS) */ drumflag = 1; note = channel[ch].lastlrpn; if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); channel[ch].drums[note]->coarse = val - 64; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Drum Instrument Pitch Coarse (CH:%d NOTE:%d VAL:%d)", ch, note, channel[ch].drums[note]->coarse); channel[ch].pitchfactor = 0; break; case NRPN_ADDR_1900: /* Fine Pitch of Drum (XG) */ drumflag = 1; note = channel[ch].lastlrpn; if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); channel[ch].drums[note]->fine = val - 64; ctl_cmsg(CMSG_INFO, VERB_NOISY, "Drum Instrument Pitch Fine (CH:%d NOTE:%d VAL:%d)", ch, note, channel[ch].drums[note]->fine); channel[ch].pitchfactor = 0; break; case NRPN_ADDR_1A00: /* Level of Drum */ drumflag = 1; note = channel[ch].lastlrpn; if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Drum Instrument TVA Level (CH:%d NOTE:%d VAL:%d)", ch, note, val); channel[ch].drums[note]->drum_level = calc_drum_tva_level(ch, note, val); break; case NRPN_ADDR_1C00: /* Panpot of Drum */ drumflag = 1; note = channel[ch].lastlrpn; if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); if(val == 0) { val = int_rand(128); channel[ch].drums[note]->pan_random = 1; } else channel[ch].drums[note]->pan_random = 0; channel[ch].drums[note]->drum_panning = val; if (update_now && adjust_panning_immediately && ! channel[ch].pan_random) adjust_drum_panning(ch, note); break; case NRPN_ADDR_1D00: /* Reverb Send Level of Drum */ drumflag = 1; note = channel[ch].lastlrpn; if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); ctl_cmsg(CMSG_INFO, VERB_NOISY, "Reverb Send Level of Drum (CH:%d NOTE:%d VALUE:%d)", ch, note, val); if (channel[ch].drums[note]->reverb_level != val) { channel[ch].drum_effect_flag = 0; } channel[ch].drums[note]->reverb_level = val; break; case NRPN_ADDR_1E00: /* Chorus Send Level of Drum */ drumflag = 1; note = channel[ch].lastlrpn; if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); ctl_cmsg(CMSG_INFO, VERB_NOISY, "Chorus Send Level of Drum (CH:%d NOTE:%d VALUE:%d)", ch, note, val); if (channel[ch].drums[note]->chorus_level != val) { channel[ch].drum_effect_flag = 0; } channel[ch].drums[note]->chorus_level = val; break; case NRPN_ADDR_1F00: /* Variation Send Level of Drum */ drumflag = 1; note = channel[ch].lastlrpn; if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Delay Send Level of Drum (CH:%d NOTE:%d VALUE:%d)", ch, note, val); if (channel[ch].drums[note]->delay_level != val) { channel[ch].drum_effect_flag = 0; } channel[ch].drums[note]->delay_level = val; break; case NRPN_ADDR_3000: /* Drum EQ BASS */ drumflag = 1; note = channel[ch].lastlrpn; if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); break; case NRPN_ADDR_3100: /* Drum EQ TREBLE */ drumflag = 1; note = channel[ch].lastlrpn; if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); break; case NRPN_ADDR_3400: /* Drum EQ BASS frequency */ drumflag = 1; note = channel[ch].lastlrpn; if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); break; case NRPN_ADDR_3500: /* Drum EQ TREBLE frequency */ drumflag = 1; note = channel[ch].lastlrpn; if (channel[ch].drums[note] == NULL) play_midi_setup_drums(ch, note); break; case RPN_ADDR_0000: /* Pitch bend sensitivity */ ctl_cmsg(CMSG_INFO, VERB_DEBUG, "Pitch Bend Sensitivity (CH:%d VALUE:%d)", ch, val); /* for mod2mid.c, arpeggio */ if (channel[ch].rpnmap[RPN_ADDR_0000] > 24) channel[ch].rpnmap[RPN_ADDR_0000] = 24; channel[ch].pitchfactor = 0; break; case RPN_ADDR_0001: /* Master Fine Tuning */ ctl_cmsg(CMSG_INFO, VERB_DEBUG, "Master Fine Tuning (CH:%d VALUE:%d)", ch, val); channel[ch].pitchfactor = 0; break; case RPN_ADDR_0002: /* Master Coarse Tuning */ ctl_cmsg(CMSG_INFO, VERB_DEBUG, "Master Coarse Tuning (CH:%d VALUE:%d)", ch, val); channel[ch].pitchfactor = 0; break; case RPN_ADDR_0003: /* Tuning Program Select */ ctl_cmsg(CMSG_INFO, VERB_DEBUG, "Tuning Program Select (CH:%d VALUE:%d)", ch, val); for (i = 0; i < upper_voices; i++) if (voice[i].status != VOICE_FREE) { voice[i].temper_instant = 1; recompute_freq(i); } break; case RPN_ADDR_0004: /* Tuning Bank Select */ ctl_cmsg(CMSG_INFO, VERB_DEBUG, "Tuning Bank Select (CH:%d VALUE:%d)", ch, val); for (i = 0; i < upper_voices; i++) if (voice[i].status != VOICE_FREE) { voice[i].temper_instant = 1; recompute_freq(i); } break; case RPN_ADDR_0005: /* GM2: Modulation Depth Range */ channel[ch].mod.lfo1_pitch_depth = (((int32_t)channel[ch].rpnmap[RPN_ADDR_0005] << 7) | channel[ch].rpnmap_lsb[RPN_ADDR_0005]) * 100 / 128; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Modulation Depth Range (CH:%d VALUE:%d)", ch, channel[ch].rpnmap[RPN_ADDR_0005]); break; case RPN_ADDR_7F7F: /* RPN reset */ channel[ch].rpn_7f7f_flag = 1; break; case RPN_ADDR_FFFF: /* RPN initialize */ /* All reset to defaults */ channel[ch].rpn_7f7f_flag = 0; memset(channel[ch].rpnmap, 0, sizeof(channel[ch].rpnmap)); channel[ch].lastlrpn = channel[ch].lastmrpn = 0; channel[ch].nrpn = 0; channel[ch].rpnmap[RPN_ADDR_0000] = 2; channel[ch].rpnmap[RPN_ADDR_0001] = 0x40; channel[ch].rpnmap[RPN_ADDR_0002] = 0x40; channel[ch].rpnmap_lsb[RPN_ADDR_0005] = 0x40; channel[ch].rpnmap[RPN_ADDR_0005] = 0; /* +- 50 cents */ channel[ch].pitchfactor = 0; break; } drumflag = 0; if (drumflag && midi_drumpart_change(ch, 1)) { midi_program_change(ch, channel[ch].program); } } void Player::voice_increment(int n) { int i; for(i = 0; i < n; i++) { if(voices == max_voices) break; voice[voices].status = VOICE_FREE; voice[voices].temper_instant = 0; voice[voices].chorus_link = voices; voices++; } } void Player::voice_decrement(int n) { int i, j, lowest; int32_t lv, v; /* decrease voice */ for(i = 0; i < n && voices > 0; i++) { voices--; if(voice[voices].status == VOICE_FREE) continue; /* found */ for(j = 0; j < voices; j++) if(voice[j].status == VOICE_FREE) break; if(j != voices) { voice[j] = voice[voices]; continue; /* found */ } /* Look for the decaying note with the lowest volume */ lv = 0x7FFFFFFF; lowest = -1; for(j = 0; j <= voices; j++) { if(voice[j].status & ~(VOICE_ON | VOICE_DIE)) { v = voice[j].left_mix; if((voice[j].panned==PANNED_MYSTERY) && (voice[j].right_mix > v)) v = voice[j].right_mix; if(v < lv) { lv = v; lowest = j; } } } if(lowest != -1) { cut_notes++; free_voice(lowest); voice[lowest] = voice[voices]; } else lost_notes++; } if(upper_voices > voices) upper_voices = voices; } /* EAW -- do not throw away good notes, stop decrementing */ void Player::voice_decrement_conservative(int n) { int i, j, lowest, finalnv; int32_t lv, v; /* decrease voice */ finalnv = voices - n; for(i = 1; i <= n && voices > 0; i++) { if(voice[voices-1].status == VOICE_FREE) { voices--; continue; /* found */ } for(j = 0; j < finalnv; j++) if(voice[j].status == VOICE_FREE) break; if(j != finalnv) { voice[j] = voice[voices-1]; voices--; continue; /* found */ } /* Look for the decaying note with the lowest volume */ lv = 0x7FFFFFFF; lowest = -1; for(j = 0; j < voices; j++) { if(voice[j].status & ~(VOICE_ON | VOICE_DIE) && !(voice[j].sample->note_to_use && ISDRUMCHANNEL(voice[j].channel))) { v = voice[j].left_mix; if((voice[j].panned==PANNED_MYSTERY) && (voice[j].right_mix > v)) v = voice[j].right_mix; if(v < lv) { lv = v; lowest = j; } } } if(lowest != -1) { voices--; cut_notes++; free_voice(lowest); voice[lowest] = voice[voices]; } else break; } if(upper_voices > voices) upper_voices = voices; } void Player::mix_signal(int32_t *dest, int32_t *src, int32_t count) { int32_t i; for (i = 0; i < count; i++) { dest[i] += src[i]; } } int Player::is_insertion_effect_xg(int ch) { int i; for (i = 0; i < XG_INSERTION_EFFECT_NUM; i++) { if (reverb->insertion_effect_xg[i].part == ch) { return 1; } } for (i = 0; i < XG_VARIATION_EFFECT_NUM; i++) { if (reverb->variation_effect_xg[i].connection == XG_CONN_INSERTION && reverb->variation_effect_xg[i].part == ch) { return 1; } } return 0; } /* do_compute_data_midi() with DSP Effect */ void Player::do_compute_data(int32_t count) { int i, j, uv, stereo, n, ch, note; int32_t *vpblist[MAX_CHANNELS]; int channel_effect, channel_reverb, channel_chorus, channel_delay, channel_eq; int32_t cnt = count * 2, rev_max_delay_out; struct DrumPartEffect *de; stereo = true; n = count * ((stereo) ? 8 : 4); /* in bytes */ memset(buffer_pointer, 0, n); memset(insertion_effect_buffer, 0, n); if (timidity_reverb == 3) { rev_max_delay_out = 0x7fffffff; /* disable */ } else { rev_max_delay_out = REVERB_MAX_DELAY_OUT; } /* are effects valid? / don't supported in mono */ channel_reverb = (stereo && (timidity_reverb == 1 || timidity_reverb == 3 || (timidity_reverb < 0 && timidity_reverb & 0x80))); channel_chorus = (stereo && timidity_chorus && !timidity_surround_chorus); channel_delay = 0; /* is EQ valid? */ channel_eq = 0; channel_effect = (stereo && (channel_reverb || channel_chorus || channel_delay || channel_eq || opt_insertion_effect)); uv = upper_voices; for(i = 0; i < uv; i++) { if(voice[i].status != VOICE_FREE) { channel[voice[i].channel].lasttime = current_sample + count; } } /* appropriate buffers for channels */ if(channel_effect) { int buf_index = 0; if(reverb_buffer == NULL) { /* allocating buffer for channel effect */ reverb_buffer = (char *)safe_malloc(MAX_CHANNELS * AUDIO_BUFFER_SIZE * 8); } for(i = 0; i < MAX_CHANNELS; i++) { if(opt_insertion_effect && channel[i].insertion_effect) { vpblist[i] = insertion_effect_buffer; } else if(channel[i].eq_gs || (get_reverb_level(i) != DEFAULT_REVERB_SEND_LEVEL && current_sample - channel[i].lasttime < rev_max_delay_out) || channel[i].chorus_level > 0 || channel[i].delay_level > 0 || channel[i].eq_xg.valid || channel[i].dry_level != 127 || (timidity_drum_effect && ISDRUMCHANNEL(i)) || is_insertion_effect_xg(i)) { vpblist[i] = (int32_t*)(reverb_buffer + buf_index); buf_index += n; } else { vpblist[i] = buffer_pointer; } /* clear buffers of drum-part effect */ if (timidity_drum_effect && ISDRUMCHANNEL(i)) { for (j = 0; j < channel[i].drum_effect_num; j++) { if (channel[i].drum_effect[j].buf != NULL) { memset(channel[i].drum_effect[j].buf, 0, n); } } } } if(buf_index) {memset(reverb_buffer, 0, buf_index);} } for (i = 0; i < uv; i++) { if (voice[i].status != VOICE_FREE) { int32_t *vpb = NULL; int8_t flag; if (channel_effect) { flag = 0; ch = voice[i].channel; if (timidity_drum_effect && ISDRUMCHANNEL(ch)) { make_drum_effect(ch); note = voice[i].note; for (j = 0; j < channel[ch].drum_effect_num; j++) { if (channel[ch].drum_effect[j].note == note) { vpb = channel[ch].drum_effect[j].buf; flag = 1; } } if (flag == 0) {vpb = vpblist[ch];} } else { vpb = vpblist[ch]; } } else { vpb = buffer_pointer; } if(!IS_SET_CHANNELMASK(channel_mute, voice[i].channel)) { mixer->mix_voice(vpb, i, count); } else { free_voice(i); } if(voice[i].timeout == 1 && voice[i].timeout < current_sample) { free_voice(i); } } } while(uv > 0 && voice[uv - 1].status == VOICE_FREE) {uv--;} upper_voices = uv; if(play_system_mode == XG_SYSTEM_MODE && channel_effect) { /* XG */ if (opt_insertion_effect) { /* insertion effect */ for (i = 0; i < XG_INSERTION_EFFECT_NUM; i++) { if (reverb->insertion_effect_xg[i].part <= MAX_CHANNELS) { reverb->do_insertion_effect_xg(vpblist[reverb->insertion_effect_xg[i].part], cnt, &reverb->insertion_effect_xg[i]); } } for (i = 0; i < XG_VARIATION_EFFECT_NUM; i++) { if (reverb->variation_effect_xg[i].part <= MAX_CHANNELS) { reverb->do_insertion_effect_xg(vpblist[reverb->variation_effect_xg[i].part], cnt, &reverb->variation_effect_xg[i]); } } } for(i = 0; i < MAX_CHANNELS; i++) { /* system effects */ int32_t *p; p = vpblist[i]; if(p != buffer_pointer) { if (timidity_drum_effect && ISDRUMCHANNEL(i)) { for (j = 0; j < channel[i].drum_effect_num; j++) { de = &(channel[i].drum_effect[j]); if (de->reverb_send > 0) { reverb->set_ch_reverb(de->buf, cnt, de->reverb_send); } if (de->chorus_send > 0) { reverb->set_ch_chorus(de->buf, cnt, de->chorus_send); } if (de->delay_send > 0) { reverb->set_ch_delay(de->buf, cnt, de->delay_send); } mix_signal(p, de->buf, cnt); } } else { if(channel_eq && channel[i].eq_xg.valid) { reverb->do_ch_eq_xg(p, cnt, &(channel[i].eq_xg)); } if(channel_chorus && channel[i].chorus_level > 0) { reverb->set_ch_chorus(p, cnt, channel[i].chorus_level); } if(channel_delay && channel[i].delay_level > 0) { reverb->set_ch_delay(p, cnt, channel[i].delay_level); } if(channel_reverb && channel[i].reverb_level > 0 && current_sample - channel[i].lasttime < rev_max_delay_out) { reverb->set_ch_reverb(p, cnt, channel[i].reverb_level); } } if(channel[i].dry_level == 127) { reverb->set_dry_signal(p, cnt); } else { reverb->set_dry_signal_xg(p, cnt, channel[i].dry_level); } } } if(channel_reverb) { reverb->set_ch_reverb(buffer_pointer, cnt, DEFAULT_REVERB_SEND_LEVEL); } reverb->set_dry_signal(buffer_pointer, cnt); /* mixing signal and applying system effects */ reverb->mix_dry_signal(buffer_pointer, cnt); if(channel_delay) { reverb->do_variation_effect1_xg(buffer_pointer, cnt);} if(channel_chorus) { reverb->do_ch_chorus_xg(buffer_pointer, cnt);} if(channel_reverb) { reverb->do_ch_reverb(buffer_pointer, cnt);} if(reverb->multi_eq_xg.valid) { reverb->do_multi_eq_xg(buffer_pointer, cnt);} } else if(channel_effect) { /* GM & GS */ if(opt_insertion_effect) { /* insertion effect */ /* applying insertion effect */ reverb->do_insertion_effect_gs(insertion_effect_buffer, cnt); /* sending insertion effect voice to channel effect */ reverb->set_ch_chorus(insertion_effect_buffer, cnt, reverb->insertion_effect_gs.send_chorus); reverb->set_ch_delay(insertion_effect_buffer, cnt, reverb->insertion_effect_gs.send_delay); reverb->set_ch_reverb(insertion_effect_buffer, cnt, reverb->insertion_effect_gs.send_reverb); if(reverb->insertion_effect_gs.send_eq_switch && channel_eq) { reverb->set_ch_eq_gs(insertion_effect_buffer, cnt); } else { reverb->set_dry_signal(insertion_effect_buffer, cnt); } } for(i = 0; i < MAX_CHANNELS; i++) { /* system effects */ int32_t *p; p = vpblist[i]; if(p != buffer_pointer && p != insertion_effect_buffer) { if (timidity_drum_effect && ISDRUMCHANNEL(i)) { for (j = 0; j < channel[i].drum_effect_num; j++) { de = &(channel[i].drum_effect[j]); if (de->reverb_send > 0) { reverb->set_ch_reverb(de->buf, cnt, de->reverb_send); } if (de->chorus_send > 0) { reverb->set_ch_chorus(de->buf, cnt, de->chorus_send); } if (de->delay_send > 0) { reverb->set_ch_delay(de->buf, cnt, de->delay_send); } mix_signal(p, de->buf, cnt); } } else { if(channel_chorus && channel[i].chorus_level > 0) { reverb->set_ch_chorus(p, cnt, channel[i].chorus_level); } if(channel_delay && channel[i].delay_level > 0) { reverb->set_ch_delay(p, cnt, channel[i].delay_level); } if(channel_reverb && channel[i].reverb_level > 0 && current_sample - channel[i].lasttime < rev_max_delay_out) { reverb->set_ch_reverb(p, cnt, channel[i].reverb_level); } } if(channel_eq && channel[i].eq_gs) { reverb->set_ch_eq_gs(p, cnt); } else { reverb->set_dry_signal(p, cnt); } } } if(channel_reverb) { reverb->set_ch_reverb(buffer_pointer, cnt, DEFAULT_REVERB_SEND_LEVEL); } reverb->set_dry_signal(buffer_pointer, cnt); /* mixing signal and applying system effects */ reverb->mix_dry_signal(buffer_pointer, cnt); if(channel_eq) { reverb->do_ch_eq_gs(buffer_pointer, cnt);} if(channel_chorus) { reverb->do_ch_chorus(buffer_pointer, cnt);} if(channel_delay) { reverb->do_ch_delay(buffer_pointer, cnt);} if(channel_reverb) { reverb->do_ch_reverb(buffer_pointer, cnt);} } current_sample += count; } int Player::compute_data(float *buffer, int32_t count) { if (count == 0) return RC_OK; std::lock_guard lock(CvarCritSec); if (last_reverb_setting != timidity_reverb) { // If the reverb mode has changed some buffers need to be reallocated before doing any sound generation. reverb->free_effect_buffers(); reverb->init_reverb(); last_reverb_setting = timidity_reverb; } buffer_pointer = common_buffer; computed_samples += count; while (count > 0) { int process = std::min(count, AUDIO_BUFFER_SIZE); do_compute_data(process); count -= process; effect->do_effect(common_buffer, process); // pass to caller for (int i = 0; i < process*2; i++) { *buffer++ = (common_buffer[i])*(5.f / 0x80000000u); } } return RC_OK; } void Player::update_modulation_wheel(int ch) { int i, uv = upper_voices; channel[ch].pitchfactor = 0; for(i = 0; i < uv; i++) if(voice[i].status != VOICE_FREE && voice[i].channel == ch) { /* Set/Reset mod-wheel */ voice[i].vibrato_control_counter = voice[i].vibrato_phase = 0; recompute_amp(i); mixer->apply_envelope_to_amp(i); recompute_freq(i); recompute_voice_filter(i); } } void Player::drop_portamento(int ch) { int i, uv = upper_voices; channel[ch].porta_control_ratio = 0; for(i = 0; i < uv; i++) if(voice[i].status != VOICE_FREE && voice[i].channel == ch && voice[i].porta_control_ratio) { voice[i].porta_control_ratio = 0; recompute_freq(i); } channel[ch].last_note_fine = -1; } void Player::update_portamento_controls(int ch) { if(!channel[ch].portamento || (channel[ch].portamento_time_msb | channel[ch].portamento_time_lsb) == 0) drop_portamento(ch); else { double mt, dc; int d; mt = midi_time_table[channel[ch].portamento_time_msb & 0x7F] * midi_time_table2[channel[ch].portamento_time_lsb & 0x7F] * PORTAMENTO_TIME_TUNING; dc = playback_rate * mt; d = (int)(1.0 / (mt * PORTAMENTO_CONTROL_RATIO)); d++; channel[ch].porta_control_ratio = (int)(d * dc + 0.5); channel[ch].porta_dpb = d; } } void Player::update_portamento_time(int ch) { int i, uv = upper_voices; int dpb; int32_t ratio; update_portamento_controls(ch); dpb = channel[ch].porta_dpb; ratio = channel[ch].porta_control_ratio; for(i = 0; i < uv; i++) { if(voice[i].status != VOICE_FREE && voice[i].channel == ch && voice[i].porta_control_ratio) { voice[i].porta_control_ratio = ratio; voice[i].porta_dpb = dpb; recompute_freq(i); } } } void Player::update_legato_controls(int ch) { double mt, dc; int d; mt = 0.06250 * PORTAMENTO_TIME_TUNING * 0.3; dc = playback_rate * mt; d = (int)(1.0 / (mt * PORTAMENTO_CONTROL_RATIO)); d++; channel[ch].porta_control_ratio = (int)(d * dc + 0.5); channel[ch].porta_dpb = d; } int Player::play_event(MidiEvent *ev) { int32_t i, j; int k, l, ch, orig_ch, port_ch, offset, layered; current_event = ev; #ifndef SUPPRESS_CHANNEL_LAYER orig_ch = ev->channel; layered = !IS_SYSEX_EVENT_TYPE(ev); for (k = 0; k < MAX_CHANNELS; k += 16) { port_ch = (orig_ch + k) % MAX_CHANNELS; offset = port_ch & ~0xf; for (l = offset; l < offset + 16; l++) { if (!layered && (k || l != offset)) continue; if (layered) { if (!IS_SET_CHANNELMASK(channel[l].channel_layer, port_ch) || channel[l].port_select != (orig_ch >> 4)) continue; ev->channel = l; } #endif ch = ev->channel; switch (ev->type) { /* MIDI Events */ case ME_NOTEOFF: note_off(ev); break; case ME_NOTEON: note_on(ev); break; case ME_KEYPRESSURE: adjust_pressure(ev); break; case ME_PROGRAM: midi_program_change(ch, ev->a); break; case ME_CHANNEL_PRESSURE: adjust_channel_pressure(ev); break; case ME_PITCHWHEEL: channel[ch].pitchbend = ev->a + ev->b * 128; channel[ch].pitchfactor = 0; /* Adjust pitch for notes already playing */ adjust_pitch(ch); break; /* Controls */ case ME_TONE_BANK_MSB: channel[ch].bank_msb = ev->a; break; case ME_TONE_BANK_LSB: channel[ch].bank_lsb = ev->a; break; case ME_MODULATION_WHEEL: channel[ch].mod.val = ev->a; update_modulation_wheel(ch); break; case ME_MAINVOLUME: channel[ch].volume = ev->a; adjust_volume(ch); break; case ME_PAN: channel[ch].panning = ev->a; channel[ch].pan_random = 0; if (adjust_panning_immediately && !channel[ch].pan_random) adjust_panning(ch); break; case ME_EXPRESSION: channel[ch].expression = ev->a; adjust_volume(ch); break; case ME_SUSTAIN: if (channel[ch].sustain == 0 && ev->a >= 64) { update_redamper_controls(ch); } channel[ch].sustain = ev->a; if (channel[ch].damper_mode == 0) { /* half-damper is not allowed. */ if (channel[ch].sustain >= 64) { channel[ch].sustain = 127; } else { channel[ch].sustain = 0; } } if (channel[ch].sustain == 0 && channel[ch].sostenuto == 0) drop_sustain(ch); break; case ME_SOSTENUTO: channel[ch].sostenuto = (ev->a >= 64); if (channel[ch].sustain == 0 && channel[ch].sostenuto == 0) drop_sustain(ch); else { update_sostenuto_controls(ch); } break; case ME_LEGATO_FOOTSWITCH: channel[ch].legato = (ev->a >= 64); break; case ME_HOLD2: break; case ME_BREATH: break; case ME_FOOT: break; case ME_BALANCE: break; case ME_PORTAMENTO_TIME_MSB: channel[ch].portamento_time_msb = ev->a; update_portamento_time(ch); break; case ME_PORTAMENTO_TIME_LSB: channel[ch].portamento_time_lsb = ev->a; update_portamento_time(ch); break; case ME_PORTAMENTO: channel[ch].portamento = (ev->a >= 64); if (!channel[ch].portamento) drop_portamento(ch); break; case ME_SOFT_PEDAL: if (timidity_lpf_def) { channel[ch].soft_pedal = ev->a; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Soft Pedal (CH:%d VAL:%d)", ch, channel[ch].soft_pedal); } break; case ME_HARMONIC_CONTENT: if (timidity_lpf_def) { channel[ch].param_resonance = ev->a - 64; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Harmonic Content (CH:%d VAL:%d)", ch, channel[ch].param_resonance); } break; case ME_BRIGHTNESS: if (timidity_lpf_def) { channel[ch].param_cutoff_freq = ev->a - 64; //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Brightness (CH:%d VAL:%d)", ch, channel[ch].param_cutoff_freq); } break; case ME_DATA_ENTRY_MSB: if (channel[ch].rpn_7f7f_flag) /* disable */ break; if ((i = last_rpn_addr(ch)) >= 0) { channel[ch].rpnmap[i] = ev->a; update_rpn_map(ch, i, 1); } break; case ME_DATA_ENTRY_LSB: if (channel[ch].rpn_7f7f_flag) /* disable */ break; if ((i = last_rpn_addr(ch)) >= 0) { channel[ch].rpnmap_lsb[i] = ev->a; } break; case ME_REVERB_EFFECT: if (timidity_reverb) { if (ISDRUMCHANNEL(ch) && get_reverb_level(ch) != ev->a) { channel[ch].drum_effect_flag = 0; } set_reverb_level(ch, ev->a); } break; case ME_CHORUS_EFFECT: if (timidity_chorus) { if (timidity_chorus == 1) { if (ISDRUMCHANNEL(ch) && channel[ch].chorus_level != ev->a) { channel[ch].drum_effect_flag = 0; } channel[ch].chorus_level = ev->a; } else { channel[ch].chorus_level = -timidity_chorus; } if (ev->a) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Chorus Send (CH:%d LEVEL:%d)", ch, ev->a); } } break; case ME_TREMOLO_EFFECT: //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Tremolo Send (CH:%d LEVEL:%d)", ch, ev->a); break; case ME_CELESTE_EFFECT: if (opt_delay_control) { if (ISDRUMCHANNEL(ch) && channel[ch].delay_level != ev->a) { channel[ch].drum_effect_flag = 0; } channel[ch].delay_level = ev->a; if (play_system_mode == XG_SYSTEM_MODE) { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Variation Send (CH:%d LEVEL:%d)", ch, ev->a); } else { //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Delay Send (CH:%d LEVEL:%d)", ch, ev->a); } } break; case ME_ATTACK_TIME: if (!opt_tva_attack) { break; } set_envelope_time(ch, ev->a, EG_ATTACK); break; case ME_RELEASE_TIME: if (!opt_tva_release) { break; } set_envelope_time(ch, ev->a, EG_RELEASE); break; case ME_PHASER_EFFECT: //ctl_cmsg(CMSG_INFO,VERB_NOISY,"Phaser Send (CH:%d LEVEL:%d)", ch, ev->a); break; case ME_RPN_INC: if (channel[ch].rpn_7f7f_flag) /* disable */ break; if ((i = last_rpn_addr(ch)) >= 0) { if (channel[ch].rpnmap[i] < 127) channel[ch].rpnmap[i]++; update_rpn_map(ch, i, 1); } break; case ME_RPN_DEC: if (channel[ch].rpn_7f7f_flag) /* disable */ break; if ((i = last_rpn_addr(ch)) >= 0) { if (channel[ch].rpnmap[i] > 0) channel[ch].rpnmap[i]--; update_rpn_map(ch, i, 1); } break; case ME_NRPN_LSB: channel[ch].lastlrpn = ev->a; channel[ch].nrpn = 1; break; case ME_NRPN_MSB: channel[ch].lastmrpn = ev->a; channel[ch].nrpn = 1; break; case ME_RPN_LSB: channel[ch].lastlrpn = ev->a; channel[ch].nrpn = 0; break; case ME_RPN_MSB: channel[ch].lastmrpn = ev->a; channel[ch].nrpn = 0; break; case ME_ALL_SOUNDS_OFF: all_sounds_off(ch); break; case ME_RESET_CONTROLLERS: reset_controllers(ch); break; case ME_ALL_NOTES_OFF: all_notes_off(ch); break; case ME_MONO: channel[ch].mono = 1; all_notes_off(ch); break; case ME_POLY: channel[ch].mono = 0; all_notes_off(ch); break; /* TiMidity Extensionals */ case ME_RANDOM_PAN: channel[ch].panning = int_rand(128); channel[ch].pan_random = 1; if (adjust_panning_immediately && !channel[ch].pan_random) adjust_panning(ch); break; case ME_SET_PATCH: i = channel[ch].special_sample = current_event->a; instruments->setSpecialPatchOffset(i, 0); break; case ME_TEMPO: current_play_tempo = ch + ev->b * 256 + ev->a * 65536; break; case ME_CHORUS_TEXT: case ME_LYRIC: case ME_MARKER: case ME_INSERT_TEXT: case ME_TEXT: case ME_KARAOKE_LYRIC: case ME_GSLCD: break; case ME_MASTER_VOLUME: master_volume_ratio = (int32_t)ev->a + 256 * (int32_t)ev->b; adjust_master_volume(); break; case ME_RESET: change_system_mode(ev->a); reset_midi(1); break; case ME_PATCH_OFFS: i = channel[ch].special_sample; instruments->setSpecialPatchOffset(i, current_event->a | (256 * current_event->b)); break; case ME_WRD: break; case ME_SHERRY: break; case ME_DRUMPART: if (midi_drumpart_change(ch, current_event->a)) { /* Update bank information */ midi_program_change(ch, channel[ch].program); } break; case ME_KEYSHIFT: i = (int)current_event->a - 0x40; if (i != channel[ch].key_shift) { all_sounds_off(ch); channel[ch].key_shift = (int8_t)i; } break; case ME_KEYSIG: if (opt_init_keysig != 8) break; current_keysig = current_event->a + current_event->b * 16; if (opt_force_keysig != 8) { i = current_keysig - ((current_keysig < 8) ? 0 : 16), j = 0; while (i != opt_force_keysig && i != opt_force_keysig + 12) i += (i > 0) ? -5 : 7, j++; while (abs(j - note_key_offset) > 7) j += (j > note_key_offset) ? -12 : 12; if (abs(j - timidity_key_adjust) >= 12) j += (j > timidity_key_adjust) ? -12 : 12; note_key_offset = j; kill_all_voices(); } i = current_keysig + ((current_keysig < 8) ? 7 : -9), j = 0; while (i != 7) i += (i < 7) ? 5 : -7, j++; j += note_key_offset, j -= floor(j / 12.0) * 12; current_freq_table = j; break; case ME_MASTER_TUNING: set_master_tuning((ev->b << 8) | ev->a); adjust_all_pitch(); break; case ME_SCALE_TUNING: recache->resamp_cache_refer_alloff(ch, computed_samples); channel[ch].scale_tuning[current_event->a] = current_event->b; adjust_pitch(ch); break; case ME_BULK_TUNING_DUMP: set_single_note_tuning(ch, current_event->a, current_event->b, 0); break; case ME_SINGLE_NOTE_TUNING: set_single_note_tuning(ch, current_event->a, current_event->b, 1); break; case ME_TEMPER_KEYSIG: current_temper_keysig = (current_event->a + 8) % 32 - 8; temper_adj = ((current_event->a + 8) & 0x20) ? 1 : 0; i = current_temper_keysig + ((current_temper_keysig < 8) ? 7 : -9); j = 0; while (i != 7) i += (i < 7) ? 5 : -7, j++; j += note_key_offset, j -= floor(j / 12.0) * 12; current_temper_freq_table = j; if (current_event->b) for (i = 0; i < upper_voices; i++) if (voice[i].status != VOICE_FREE) { voice[i].temper_instant = 1; recompute_freq(i); } break; case ME_TEMPER_TYPE: channel[ch].temper_type = current_event->a; if (temper_type_mute) { if (temper_type_mute & (1 << (current_event->a - ((current_event->a >= 0x40) ? 0x3c : 0)))) { SET_CHANNELMASK(channel_mute, ch); } else { UNSET_CHANNELMASK(channel_mute, ch); } } if (current_event->b) for (i = 0; i < upper_voices; i++) if (voice[i].status != VOICE_FREE) { voice[i].temper_instant = 1; recompute_freq(i); } break; case ME_MASTER_TEMPER_TYPE: for (i = 0; i < MAX_CHANNELS; i++) { channel[i].temper_type = current_event->a; } if (temper_type_mute) { if (temper_type_mute & (1 << (current_event->a - ((current_event->a >= 0x40) ? 0x3c : 0)))) { FILL_CHANNELMASK(channel_mute); } else { CLEAR_CHANNELMASK(channel_mute); } } if (current_event->b) for (i = 0; i < upper_voices; i++) if (voice[i].status != VOICE_FREE) { voice[i].temper_instant = 1; recompute_freq(i); } break; case ME_USER_TEMPER_ENTRY: set_user_temper_entry(ch, current_event->a, current_event->b); break; case ME_SYSEX_LSB: process_sysex_event(ME_SYSEX_LSB, ch, current_event->a, current_event->b); break; case ME_SYSEX_MSB: process_sysex_event(ME_SYSEX_MSB, ch, current_event->a, current_event->b); break; case ME_SYSEX_GS_LSB: process_sysex_event(ME_SYSEX_GS_LSB, ch, current_event->a, current_event->b); break; case ME_SYSEX_GS_MSB: process_sysex_event(ME_SYSEX_GS_MSB, ch, current_event->a, current_event->b); break; case ME_SYSEX_XG_LSB: process_sysex_event(ME_SYSEX_XG_LSB, ch, current_event->a, current_event->b); break; case ME_SYSEX_XG_MSB: process_sysex_event(ME_SYSEX_XG_MSB, ch, current_event->a, current_event->b); break; case ME_NOTE_STEP: break; case ME_EOT: break; } #ifndef SUPPRESS_CHANNEL_LAYER } } ev->channel = orig_ch; #endif return RC_OK; } void Player::set_master_tuning(int tune) { if (tune & 0x4000) /* 1/8192 semitones + 0x2000 | 0x4000 */ tune = (tune & 0x3FFF) - 0x2000; else if (tune & 0x8000) /* 1 semitones | 0x8000 */ tune = ((tune & 0x7F) - 0x40) << 13; else /* millisemitones + 0x400 */ tune = (((tune - 0x400) << 13) + 500) / 1000; master_tuning = tune; } void Player::set_single_note_tuning(int part, int a, int b, int rt) { static int tp; /* tuning program number */ static int kn; /* MIDI key number */ static int st; /* the nearest equal-tempered semitone */ double f, fst; /* fraction of semitone */ int i; switch (part) { case 0: tp = a; break; case 1: kn = a, st = b; break; case 2: if (st == 0x7f && a == 0x7f && b == 0x7f) /* no change */ break; f = 440 * pow(2.0, (st - 69) / 12.0); fst = pow(2.0, (a << 7 | b) / 196608.0); freq_table_tuning[tp][kn] = f * fst * 1000 + 0.5; if (rt) for (i = 0; i < upper_voices; i++) if (voice[i].status != VOICE_FREE) { voice[i].temper_instant = 1; recompute_freq(i); } break; } } void Player::set_user_temper_entry(int part, int a, int b) { static int tp; /* temperament program number */ static int ll; /* number of formula */ static int fh, fl; /* applying pitch bit mask (forward) */ static int bh, bl; /* applying pitch bit mask (backward) */ static int aa, bb; /* fraction (aa/bb) */ static int cc, dd; /* power (cc/dd)^(ee/ff) */ static int ee, ff; static int ifmax, ibmax, count; static double rf[11], rb[11]; int i, j, k, l, n, m; double ratio[12], f, sc; switch (part) { case 0: for (i = 0; i < 11; i++) rf[i] = rb[i] = 1; ifmax = ibmax = 0; count = 0; tp = a, ll = b; break; case 1: fh = a, fl = b; break; case 2: bh = a, bl = b; break; case 3: aa = a, bb = b; break; case 4: cc = a, dd = b; break; case 5: ee = a, ff = b; for (i = 0; i < 11; i++) { if (((fh & 0xf) << 7 | fl) & 1 << i) { rf[i] *= (double) aa / bb * pow((double) cc / dd, (double) ee / ff); if (ifmax < i + 1) ifmax = i + 1; } if (((bh & 0xf) << 7 | bl) & 1 << i) { rb[i] *= (double) aa / bb * pow((double) cc / dd, (double) ee / ff); if (ibmax < i + 1) ibmax = i + 1; } } if (++count < ll) break; ratio[0] = 1; for (i = n = m = 0; i < ifmax; i++, m = n) { n += (n > 4) ? -5 : 7; ratio[n] = ratio[m] * rf[i]; if (ratio[n] > 2) ratio[n] /= 2; } for (i = n = m = 0; i < ibmax; i++, m = n) { n += (n > 6) ? -7 : 5; ratio[n] = ratio[m] / rb[i]; if (ratio[n] < 1) ratio[n] *= 2; } sc = 27 / ratio[9] / 16; /* syntonic comma */ for (i = 0; i < 12; i++) for (j = -1; j < 11; j++) { f = 440 * pow(2.0, (i - 9) / 12.0 + j - 5); for (k = 0; k < 12; k++) { l = i + j * 12 + k; if (l < 0 || l >= 128) continue; if (! (fh & 0x40)) { /* major */ freq_table_user[tp][i][l] = f * ratio[k] * 1000 + 0.5; freq_table_user[tp][i + 36][l] = f * ratio[k] * sc * 1000 + 0.5; } if (! (bh & 0x40)) { /* minor */ freq_table_user[tp][i + 12][l] = f * ratio[k] * sc * 1000 + 0.5; freq_table_user[tp][i + 24][l] = f * ratio[k] * 1000 + 0.5; } } } break; } } struct midi_file_info *Player::new_midi_file_info() { struct midi_file_info *p = &midifileinfo; /* Initialize default members */ memset(p, 0, sizeof(struct midi_file_info)); p->hdrsiz = -1; p->format = -1; p->tracks = -1; p->divisions = -1; p->time_sig_n = p->time_sig_d = -1; p->samples = -1; p->max_channel = -1; COPY_CHANNELMASK(p->drumchannels, default_drumchannels); COPY_CHANNELMASK(p->drumchannel_mask, default_drumchannel_mask); return p; } /* * For MIDI stream player. */ void Player::playmidi_stream_init(void) { int i; static int first = 1; note_key_offset = timidity_key_adjust; midi_time_ratio = timidity_tempo_adjust; CLEAR_CHANNELMASK(channel_mute); if (temper_type_mute & 1) FILL_CHANNELMASK(channel_mute); if (first) { first = 0; init_mblock(&playmidi_pool); midi_streaming = 1; } else reuse_mblock(&playmidi_pool); /* Fill in current_file_info */ current_file_info = &midifileinfo; current_file_info->readflag = 1; current_file_info->hdrsiz = 0; current_file_info->format = 0; current_file_info->tracks = 0; current_file_info->divisions = 192; /* ?? */ current_file_info->time_sig_n = 4; /* 4/ */ current_file_info->time_sig_d = 4; /* /4 */ current_file_info->time_sig_c = 24; /* clock */ current_file_info->time_sig_b = 8; /* q.n. */ current_file_info->samples = 0; current_file_info->max_channel = MAX_CHANNELS; current_file_info->compressed = 0; current_play_tempo = 500000; check_eot_flag = 0; /* Setup default drums */ COPY_CHANNELMASK(current_file_info->drumchannels, default_drumchannels); COPY_CHANNELMASK(current_file_info->drumchannel_mask, default_drumchannel_mask); for(i = 0; i < MAX_CHANNELS; i++) memset(channel[i].drums, 0, sizeof(channel[i].drums)); change_system_mode(DEFAULT_SYSTEM_MODE); reset_midi(0); playmidi_tmr_reset(); } void Player::playmidi_tmr_reset(void) { int i; current_sample = 0; buffer_pointer = common_buffer; for(i = 0; i < MAX_CHANNELS; i++) channel[i].lasttime = 0; } /*! initialize Part EQ (XG) */ void Player::init_part_eq_xg(struct part_eq_xg *p) { p->bass = 0x40; p->treble = 0x40; p->bass_freq = 0x0C; p->treble_freq = 0x36; p->valid = 0; } /*! recompute Part EQ (XG) */ void Player::recompute_part_eq_xg(struct part_eq_xg *p) { int8_t vbass, vtreble; if(p->bass_freq >= 4 && p->bass_freq <= 40 && p->bass != 0x40) { vbass = 1; p->basss.q = 0.7; p->basss.freq = eq_freq_table_xg[p->bass_freq]; if(p->bass == 0) {p->basss.gain = -12.0;} else {p->basss.gain = 0.19 * (double)(p->bass - 0x40);} reverb->calc_filter_shelving_low(&(p->basss)); } else {vbass = 0;} if(p->treble_freq >= 28 && p->treble_freq <= 58 && p->treble != 0x40) { vtreble = 1; p->trebles.q = 0.7; p->trebles.freq = eq_freq_table_xg[p->treble_freq]; if(p->treble == 0) {p->trebles.gain = -12.0;} else {p->trebles.gain = 0.19 * (double)(p->treble - 0x40);} reverb->calc_filter_shelving_high(&(p->trebles)); } else {vtreble = 0;} p->valid = vbass || vtreble; } void Player::init_midi_controller(midi_controller *p) { p->val = 0; p->pitch = 0; p->cutoff = 0; p->amp = 0.0; p->lfo1_rate = p->lfo2_rate = p->lfo1_tva_depth = p->lfo2_tva_depth = 0; p->lfo1_pitch_depth = p->lfo2_pitch_depth = p->lfo1_tvf_depth = p->lfo2_tvf_depth = 0; p->variation_control_depth = p->insertion_control_depth = 0; } float Player::get_midi_controller_amp(midi_controller *p) { return (1.0 + (float)p->val * (1.0f / 127.0f) * p->amp); } float Player::get_midi_controller_filter_cutoff(midi_controller *p) { return ((float)p->val * (1.0f / 127.0f) * (float)p->cutoff); } float Player::get_midi_controller_filter_depth(midi_controller *p) { return ((float)p->val * (1.0f / 127.0f) * (float)p->lfo1_tvf_depth); } int32_t Player::get_midi_controller_pitch(midi_controller *p) { return ((int32_t)(p->val * p->pitch) << 6); } int16_t Player::get_midi_controller_pitch_depth(midi_controller *p) { return (int16_t)((float)p->val * (float)p->lfo1_pitch_depth * (1.0f / 127.0f * 256.0 / 400.0)); } int16_t Player::get_midi_controller_amp_depth(midi_controller *p) { return (int16_t)((float)p->val * (float)p->lfo1_tva_depth * (1.0f / 127.0f * 256.0)); } void Player::init_rx(int ch) { channel[ch].rx = 0xFFFFFFFF; /* all on */ } void Player::set_rx(int ch, int32_t rx, int flag) { if(ch > MAX_CHANNELS) {return;} if(flag) {channel[ch].rx |= rx;} else {channel[ch].rx &= ~rx;} } void Player::init_rx_drum(struct DrumParts *p) { p->rx = 0xFFFFFFFF; /* all on */ } void Player::set_rx_drum(struct DrumParts *p, int32_t rx, int flag) { if(flag) {p->rx |= rx;} else {p->rx &= ~rx;} } int32_t Player::get_rx_drum(struct DrumParts *p, int32_t rx) { return (p->rx & rx); } Instrument *Player::play_midi_load_instrument(int dr, int bk, int prog) { bool load_success; // The inner workings of this function which alters the instrument data has been put into the Instruments class. auto instr = instruments->play_midi_load_instrument(dr, bk, prog, &load_success); //if (load_success) send_output(NULL, 0); /* Update software buffer */ return instr; } void Player::change_system_mode(int mode) { pan_table = sc_pan_table; switch (mode) { case GM_SYSTEM_MODE: if (play_system_mode == DEFAULT_SYSTEM_MODE) { play_system_mode = GM_SYSTEM_MODE; vol_table = def_vol_table; } break; case GM2_SYSTEM_MODE: play_system_mode = GM2_SYSTEM_MODE; vol_table = def_vol_table; pan_table = gm2_pan_table; break; case GS_SYSTEM_MODE: play_system_mode = GS_SYSTEM_MODE; vol_table = gs_vol_table; break; case XG_SYSTEM_MODE: if (play_system_mode != XG_SYSTEM_MODE) { reverb->init_all_effect_xg(); } play_system_mode = XG_SYSTEM_MODE; vol_table = xg_vol_table; break; default: play_system_mode = DEFAULT_SYSTEM_MODE; vol_table = def_vol_table; break; } } /*! initialize channel layers. */ void Player::init_channel_layer(int ch) { if (ch >= MAX_CHANNELS) return; CLEAR_CHANNELMASK(channel[ch].channel_layer); SET_CHANNELMASK(channel[ch].channel_layer, ch); channel[ch].port_select = ch >> 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 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 status, int parm1, int parm2) { MidiEvent ev; ev.type = ME_NONE; ev.channel = status & 0x0000000f; //ev.channel = ev.channel + port * 16; ev.a = (uint8_t)parm1; ev.b = (uint8_t)parm2; switch ((int)(status & 0x000000f0)) { case 0x80: ev.type = ME_NOTEOFF; break; case 0x90: ev.type = (ev.b) ? ME_NOTEON : ME_NOTEOFF; break; case 0xa0: ev.type = ME_KEYPRESSURE; break; case 0xb0: if (!convert_midi_control_change(ev.channel, ev.a, ev.b, &ev)) ev.type = ME_NONE; break; case 0xc0: ev.type = ME_PROGRAM; break; case 0xd0: ev.type = ME_CHANNEL_PRESSURE; break; case 0xe0: ev.type = ME_PITCHWHEEL; break; /* case 0xf0: if ((status & 0x000000ff) == 0xf2) { ev.type = ME_PROGRAM; } break; */ default: break; } if (ev.type != ME_NONE) { play_event(&ev); } return 0; } void Player::send_long_event(const uint8_t *sysexbuffer, int exlen) { int i, ne; MidiEvent ev; MidiEvent evm[260]; SysexConvert sc; if ((sysexbuffer[0] != 0xf0) && (sysexbuffer[0] != 0xf7)) 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); effect->init_effect(); instruments->init_userdrum(); instruments->init_userinst(); playmidi_stream_init(); } play_event(&ev); return; } if ((ne = sc.parse_sysex_event_multi(sysexbuffer + 1, exlen - 1, evm, instruments))) { for (i = 0; i < ne; i++) { play_event(&evm[i]); } } } }