mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-23 12:32:34 +00:00
6148 lines
185 KiB
C++
6148 lines
185 KiB
C++
/*
|
|
TiMidity++ -- MIDI to WAVE converter and player
|
|
Copyright (C) 1999-2009 Masanao Izumo <iz@onicos.co.jp>
|
|
Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
|
|
|
|
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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <algorithm>
|
|
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#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 ConfigMutex;
|
|
int timidity_modulation_wheel = true;
|
|
int timidity_portamento = false;
|
|
int timidity_reverb = 0;
|
|
int timidity_chorus = 0;
|
|
int timidity_surround_chorus = false; // requires restart!
|
|
int timidity_channel_pressure = false;
|
|
int timidity_lpf_def = true;
|
|
int timidity_temper_control = true;
|
|
int timidity_modulation_envelope = true;
|
|
int timidity_overlap_voice_allow = true;
|
|
int timidity_drum_effect = false;
|
|
int 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 = 0;
|
|
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(v<lv)
|
|
{
|
|
lv = v;
|
|
lowest = i;
|
|
}
|
|
}
|
|
}
|
|
return lowest;
|
|
}
|
|
|
|
int Player::find_samples(MidiEvent *e, int *vlist)
|
|
{
|
|
int i, j, ch, bank, prog, note, nv;
|
|
const SpecialPatch *s;
|
|
Instrument *ip;
|
|
|
|
ch = e->channel;
|
|
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 */
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Attack Time (CH:%d VALUE:%d)", ch, val);
|
|
break;
|
|
case EG_DECAY: /* Decay */
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Decay Time (CH:%d VALUE:%d)", ch, val);
|
|
break;
|
|
case EG_RELEASE: /* Release */
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Release Time (CH:%d VALUE:%d)", ch, val);
|
|
break;
|
|
default:
|
|
//printMessage(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 <ewelsh@gpc.wustl.edu>.
|
|
*/
|
|
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;
|
|
printMessage(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);
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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);
|
|
printMessage(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);
|
|
printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Rx. Note Message (CH:%d VAL:%d)", ch, val);
|
|
break;
|
|
case 0x4E: /* Rx. RPN */
|
|
set_rx(ch, RX_RPN, val);
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Rx. RPN (CH:%d VAL:%d)", ch, val);
|
|
break;
|
|
case 0x4F: /* Rx. NRPN */
|
|
set_rx(ch, RX_NRPN, val);
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Rx. NRPN (CH:%d VAL:%d)", ch, val);
|
|
break;
|
|
case 0x50: /* Rx. Modulation */
|
|
set_rx(ch, RX_MODULATION, val);
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Rx. Modulation (CH:%d VAL:%d)", ch, val);
|
|
break;
|
|
case 0x51: /* Rx. Volume */
|
|
set_rx(ch, RX_VOLUME, val);
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Rx. Volume (CH:%d VAL:%d)", ch, val);
|
|
break;
|
|
case 0x52: /* Rx. Panpot */
|
|
set_rx(ch, RX_PANPOT, val);
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Rx. Panpot (CH:%d VAL:%d)", ch, val);
|
|
break;
|
|
case 0x53: /* Rx. Expression */
|
|
set_rx(ch, RX_EXPRESSION, val);
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Rx. Expression (CH:%d VAL:%d)", ch, val);
|
|
break;
|
|
case 0x54: /* Rx. Hold1 */
|
|
set_rx(ch, RX_HOLD1, val);
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Rx. Hold1 (CH:%d VAL:%d)", ch, val);
|
|
break;
|
|
case 0x55: /* Rx. Portamento */
|
|
set_rx(ch, RX_PORTAMENTO, val);
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Rx. Portamento (CH:%d VAL:%d)", ch, val);
|
|
break;
|
|
case 0x56: /* Rx. Sostenuto */
|
|
set_rx(ch, RX_SOSTENUTO, val);
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Rx. Sostenuto (CH:%d VAL:%d)", ch, val);
|
|
break;
|
|
case 0x57: /* Rx. Soft */
|
|
set_rx(ch, RX_SOFT, val);
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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) {//printMessage(CMSG_INFO,VERB_NOISY,"EFX ON (CH:%d)",ch);}
|
|
//else {//printMessage(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) {
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Assign Mode: Single (CH:%d)",ch);
|
|
} else if(val == 1) {
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Assign Mode: Limited-Multi (CH:%d)",ch);
|
|
} else if(val == 2) {
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Assign Mode: Full-Multi (CH:%d)",ch);
|
|
}
|
|
break;
|
|
case 0x25: /* TONE MAP-0 NUMBER */
|
|
channel[ch].tone_map0_number = val;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
printMessage(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) {
|
|
//printMessage(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) {
|
|
//printMessage(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;
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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) {
|
|
//printMessage(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) {
|
|
//printMessage(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:
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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;
|
|
//printMessage(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) {
|
|
//printMessage(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) {
|
|
//printMessage(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:
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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 */
|
|
//printMessage(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;
|
|
//printMessage(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) {
|
|
//printMessage(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) {
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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) {
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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) {
|
|
//printMessage(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) {
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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) {
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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) {
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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) {
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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) {
|
|
//printMessage(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) {
|
|
//printMessage(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;
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Same Note Number Key On Assign: Single (CH:%d)",ch);
|
|
} else if(val == 1) {
|
|
channel[ch].assign_mode = 2;
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Same Note Number Key On Assign: Multi (CH:%d)",ch);
|
|
} else if(val == 2) {
|
|
//printMessage(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;
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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) {
|
|
//printMessage(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) {
|
|
//printMessage(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) {
|
|
//printMessage(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) {
|
|
//printMessage(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) {
|
|
//printMessage(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) {
|
|
//printMessage(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) {
|
|
//printMessage(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;}
|
|
//printMessage(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;}
|
|
//printMessage(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);
|
|
//printMessage(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);
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
printMessage(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);
|
|
//printMessage(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);
|
|
printMessage(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);
|
|
printMessage(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);
|
|
//printMessage(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 */
|
|
printMessage(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 */
|
|
printMessage(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 */
|
|
printMessage(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 */
|
|
printMessage(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 */
|
|
printMessage(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;
|
|
//printMessage(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<std::mutex> lock(ConfigMutex);
|
|
|
|
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;
|
|
//printMessage(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;
|
|
//printMessage(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;
|
|
//printMessage(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) {
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Chorus Send (CH:%d LEVEL:%d)", ch, ev->a);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ME_TREMOLO_EFFECT:
|
|
//printMessage(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) {
|
|
//printMessage(CMSG_INFO,VERB_NOISY,"Variation Send (CH:%d LEVEL:%d)", ch, ev->a);
|
|
}
|
|
else {
|
|
//printMessage(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:
|
|
//printMessage(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)
|
|
{
|
|
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]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|