/* TiMidity++ -- MIDI to WAVE converter and player Copyright (C) 1999-2002 Masanao Izumo Copyright (C) 1995 Tuukka Toivonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA mix.c */ #include #include #include #include "timidity.h" #include "common.h" #include "instrum.h" #include "playmidi.h" #include "tables.h" #include "resample.h" #include "mix.h" #include "optcode.h" #include "c_cvars.h" CUSTOM_CVAR(Float, min_sustain_time, 5000, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) { if (self < 0) self = 0; } namespace TimidityPlus { #define FROM_FINAL_VOLUME(a) (a) #define OFFSET_MAX (0x3FFFFFFFL) typedef int32_t mix_t; #define MIXATION(a) *lp++ += (a) * s #define DELAYED_MIXATION(a) *lp++ += pan_delay_buf[pan_delay_spt]; \ if (++pan_delay_spt == PAN_DELAY_BUF_MAX) {pan_delay_spt = 0;} \ pan_delay_buf[pan_delay_wpt] = (a) * s; \ if (++pan_delay_wpt == PAN_DELAY_BUF_MAX) {pan_delay_wpt = 0;} /**************** interface function ****************/ void Mixer::mix_voice(int32_t *buf, int v, int32_t c) { Resampler re(player); Voice *vp = player->voice + v; resample_t *sp; if (vp->status == VOICE_DIE) { if (c >= MAX_DIE_TIME) c = MAX_DIE_TIME; sp = re.resample_voice(v, &c); if (do_voice_filter(v, sp, filter_buffer, c)) { sp = filter_buffer; } if (c > 0) ramp_out(sp, buf, v, c); player->free_voice(v); } else { vp->delay_counter = c; if (vp->delay) { if (c < vp->delay) { vp->delay -= c; if (vp->tremolo_phase_increment) update_tremolo(v); if (timidity_modulation_envelope && vp->sample->modes & MODES_ENVELOPE) update_modulation_envelope(v); return; } buf += vp->delay * 2; c -= vp->delay; vp->delay = 0; } sp = re.resample_voice(v, &c); if (do_voice_filter(v, sp, filter_buffer, c)) { sp = filter_buffer; } if (vp->panned == PANNED_MYSTERY) { if (vp->envelope_increment || vp->tremolo_phase_increment) mix_mystery_signal(sp, buf, v, c); else mix_mystery(sp, buf, v, c); } else if (vp->panned == PANNED_CENTER) { if (vp->envelope_increment || vp->tremolo_phase_increment) mix_center_signal(sp, buf, v, c); else mix_center(sp, buf, v, c); } else { /* It's either full left or full right. In either case, * every other sample is 0. Just get the offset right: */ if (vp->panned == PANNED_RIGHT) buf++; if (vp->envelope_increment || vp->tremolo_phase_increment) mix_single_signal(sp, buf, v, c); else mix_single(sp, buf, v, c); } } } /* return 1 if filter is enabled. */ int Mixer::do_voice_filter(int v, resample_t *sp, mix_t *lp, int32_t count) { FilterCoefficients *fc = &(player->voice[v].fc); int32_t i, f, q, p, b0, b1, b2, b3, b4, t1, t2, x; if (fc->type == 1) { /* copy with applying Chamberlin's lowpass filter. */ recalc_voice_resonance(v); recalc_voice_fc(v); f = fc->f, q = fc->q, b0 = fc->b0, b1 = fc->b1, b2 = fc->b2; for(i = 0; i < count; i++) { b0 = b0 + imuldiv24(b2, f); b1 = sp[i] - b0 - imuldiv24(b2, q); b2 = imuldiv24(b1, f) + b2; lp[i] = b0; } fc->b0 = b0, fc->b1 = b1, fc->b2 = b2; return 1; } else if(fc->type == 2) { /* copy with applying Moog lowpass VCF. */ recalc_voice_resonance(v); recalc_voice_fc(v); f = fc->f, q = fc->q, p = fc->p, b0 = fc->b0, b1 = fc->b1, b2 = fc->b2, b3 = fc->b3, b4 = fc->b4; for(i = 0; i < count; i++) { x = sp[i] - imuldiv24(q, b4); /* feedback */ t1 = b1; b1 = imuldiv24(x + b0, p) - imuldiv24(b1, f); t2 = b2; b2 = imuldiv24(b1 + t1, p) - imuldiv24(b2, f); t1 = b3; b3 = imuldiv24(b2 + t2, p) - imuldiv24(b3, f); lp[i] = b4 = imuldiv24(b3 + t1, p) - imuldiv24(b4, f); b0 = x; } fc->b0 = b0, fc->b1 = b1, fc->b2 = b2, fc->b3 = b3, fc->b4 = b4; return 1; } else { return 0; } } //#define MOOG_RESONANCE_MAX 0.897638f #define MOOG_RESONANCE_MAX 0.88f void Mixer::recalc_voice_resonance(int v) { double q; FilterCoefficients *fc = &(player->voice[v].fc); if (fc->reso_dB != fc->last_reso_dB || fc->q == 0) { fc->last_reso_dB = fc->reso_dB; if(fc->type == 1) { q = 1.0 / chamberlin_filter_db_to_q_table[(int)(fc->reso_dB * 4)]; fc->q = TIM_FSCALE(q, 24); if(fc->q <= 0) {fc->q = 1;} /* must never be 0. */ } else if(fc->type == 2) { fc->reso_lin = fc->reso_dB * MOOG_RESONANCE_MAX / 20.0f; if (fc->reso_lin > MOOG_RESONANCE_MAX) {fc->reso_lin = MOOG_RESONANCE_MAX;} else if(fc->reso_lin < 0) {fc->reso_lin = 0;} } fc->last_freq = -1; } } void Mixer::recalc_voice_fc(int v) { double f, p, q, fr; FilterCoefficients *fc = &(player->voice[v].fc); if (fc->freq != fc->last_freq) { if(fc->type == 1) { f = 2.0 * sin(M_PI * (double)fc->freq / (double)playback_rate); fc->f = TIM_FSCALE(f, 24); } else if(fc->type == 2) { fr = 2.0 * (double)fc->freq / (double)playback_rate; q = 1.0 - fr; p = fr + 0.8 * fr * q; f = p + p - 1.0; q = fc->reso_lin * (1.0 + 0.5 * q * (1.0 - q + 5.6 * q * q)); fc->f = TIM_FSCALE(f, 24); fc->p = TIM_FSCALE(p, 24); fc->q = TIM_FSCALE(q, 24); } fc->last_freq = fc->freq; } } /* Ramp a note out in c samples */ void Mixer::ramp_out(mix_t *sp, int32_t *lp, int v, int32_t c) { /* should be final_volume_t, but uint8_t gives trouble. */ int32_t left, right, li, ri, i; /* silly warning about uninitialized s */ mix_t s = 0; Voice *vp = &player->voice[v]; int32_t pan_delay_wpt = vp->pan_delay_wpt, *pan_delay_buf = vp->pan_delay_buf, pan_delay_spt = vp->pan_delay_spt; left = player->voice[v].left_mix; li = -(left / c); if (! li) li = -1; if (true) { if (player->voice[v].panned == PANNED_MYSTERY) { right = player->voice[v].right_mix; ri = -(right / c); if(vp->pan_delay_rpt == 0) { for (i = 0; i < c; i++) { left += li; if (left < 0) left = 0; right += ri; if (right < 0) right = 0; s = *sp++; MIXATION(left); MIXATION(right); } } else if(vp->panning < 64) { for (i = 0; i < c; i++) { left += li; if (left < 0) left = 0; right += ri; if (right < 0) right = 0; s = *sp++; MIXATION(left); DELAYED_MIXATION(right); } } else { for (i = 0; i < c; i++) { left += li; if (left < 0) left = 0; right += ri; if (right < 0) right = 0; s = *sp++; DELAYED_MIXATION(left); MIXATION(right); } } vp->pan_delay_wpt = pan_delay_wpt; vp->pan_delay_spt = pan_delay_spt; } else if (player->voice[v].panned == PANNED_CENTER) for (i = 0; i < c; i++) { left += li; if (left < 0) return; s = *sp++; MIXATION(left); MIXATION(left); } else if (player->voice[v].panned == PANNED_LEFT) for (i = 0; i < c; i++) { left += li; if (left < 0) return; s = *sp++; MIXATION(left); lp++; } else if (player->voice[v].panned == PANNED_RIGHT) for (i = 0; i < c; i++) { left += li; if (left < 0) return; s = *sp++; lp++; MIXATION(left); } } else /* Mono output. */ for (i = 0; i < c; i++) { left += li; if (left < 0) return; s = *sp++; MIXATION(left); } } void Mixer::mix_mono_signal( mix_t *sp, int32_t *lp, int v, int count) { Voice *vp = player->voice + v; final_volume_t left = vp->left_mix; int cc, i; mix_t s; int32_t linear_left; if (! (cc = vp->control_counter)) { cc = control_ratio; if (update_signal(v)) /* Envelope ran out */ return; left = vp->left_mix; } compute_mix_smoothing(vp); while (count) if (cc < count) { count -= cc; linear_left = FROM_FINAL_VOLUME(left); if (vp->left_mix_offset) { linear_left += vp->left_mix_offset; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } for (i = 0; vp->left_mix_offset && i < cc; i++) { s = *sp++; MIXATION(left); vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } vp->old_left_mix = linear_left; cc -= i; for (i = 0; i < cc; i++) { s = *sp++; MIXATION(left); } cc = control_ratio; if (update_signal(v)) /* Envelope ran out */ return; left = vp->left_mix; compute_mix_smoothing(vp); } else { vp->control_counter = cc - count; linear_left = FROM_FINAL_VOLUME(left); if (vp->left_mix_offset) { linear_left += vp->left_mix_offset; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } for (i = 0; vp->left_mix_offset && i < count; i++) { s = *sp++; MIXATION(left); vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } vp->old_left_mix = linear_left; count -= i; for (i = 0; i < count; i++) { s = *sp++; MIXATION(left); } return; } } void Mixer::mix_mystery_signal( mix_t *sp, int32_t *lp, int v, int count) { Voice *vp = player->voice + v; final_volume_t left = vp->left_mix, right = vp->right_mix; int cc, i; mix_t s; int32_t linear_left, linear_right; int32_t pan_delay_wpt = vp->pan_delay_wpt, *pan_delay_buf = vp->pan_delay_buf, pan_delay_spt = vp->pan_delay_spt; if (! (cc = vp->control_counter)) { cc = control_ratio; if (update_signal(v)) /* Envelope ran out */ return; left = vp->left_mix; right = vp->right_mix; } compute_mix_smoothing(vp); while (count) if (cc < count) { count -= cc; linear_left = FROM_FINAL_VOLUME(left); if (vp->left_mix_offset) { linear_left += vp->left_mix_offset; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } linear_right = FROM_FINAL_VOLUME(right); if (vp->right_mix_offset) { linear_right += vp->right_mix_offset; if (linear_right > MAX_AMP_VALUE) { linear_right = MAX_AMP_VALUE; vp->right_mix_offset = 0; } right = FINAL_VOLUME(linear_right); } if(vp->pan_delay_rpt == 0) { for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) && i < cc; i++) { s = *sp++; MIXATION(left); MIXATION(right); if (vp->left_mix_offset) { vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } if (vp->right_mix_offset) { vp->right_mix_offset += vp->right_mix_inc; linear_right += vp->right_mix_inc; if (linear_right > MAX_AMP_VALUE) { linear_right = MAX_AMP_VALUE; vp->right_mix_offset = 0; } right = FINAL_VOLUME(linear_right); } } } else if(vp->panning < 64) { for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) && i < cc; i++) { s = *sp++; MIXATION(left); DELAYED_MIXATION(right); if (vp->left_mix_offset) { vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } if (vp->right_mix_offset) { vp->right_mix_offset += vp->right_mix_inc; linear_right += vp->right_mix_inc; if (linear_right > MAX_AMP_VALUE) { linear_right = MAX_AMP_VALUE; vp->right_mix_offset = 0; } right = FINAL_VOLUME(linear_right); } } } else { for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) && i < cc; i++) { s = *sp++; DELAYED_MIXATION(left); MIXATION(right); if (vp->left_mix_offset) { vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } if (vp->right_mix_offset) { vp->right_mix_offset += vp->right_mix_inc; linear_right += vp->right_mix_inc; if (linear_right > MAX_AMP_VALUE) { linear_right = MAX_AMP_VALUE; vp->right_mix_offset = 0; } right = FINAL_VOLUME(linear_right); } } } vp->old_left_mix = linear_left; vp->old_right_mix = linear_right; cc -= i; if(vp->pan_delay_rpt == 0) { for (i = 0; i < cc; i++) { s = *sp++; MIXATION(left); MIXATION(right); } } else if(vp->panning < 64) { for (i = 0; i < cc; i++) { s = *sp++; MIXATION(left); DELAYED_MIXATION(right); } } else { for (i = 0; i < cc; i++) { s = *sp++; DELAYED_MIXATION(left); MIXATION(right); } } cc = control_ratio; if (update_signal(v)) /* Envelope ran out */ return; left = vp->left_mix; right = vp->right_mix; compute_mix_smoothing(vp); } else { vp->control_counter = cc - count; linear_left = FROM_FINAL_VOLUME(left); if (vp->left_mix_offset) { linear_left += vp->left_mix_offset; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } linear_right = FROM_FINAL_VOLUME(right); if (vp->right_mix_offset) { linear_right += vp->right_mix_offset; if (linear_right > MAX_AMP_VALUE) { linear_right = MAX_AMP_VALUE; vp->right_mix_offset = 0; } right = FINAL_VOLUME(linear_right); } if(vp->pan_delay_rpt == 0) { for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) && i < count; i++) { s = *sp++; MIXATION(left); MIXATION(right); if (vp->left_mix_offset) { vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } if (vp->right_mix_offset) { vp->right_mix_offset += vp->right_mix_inc; linear_right += vp->right_mix_inc; if (linear_right > MAX_AMP_VALUE) { linear_right = MAX_AMP_VALUE; vp->right_mix_offset = 0; } right = FINAL_VOLUME(linear_right); } } } else if(vp->panning < 64) { for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) && i < count; i++) { s = *sp++; MIXATION(left); DELAYED_MIXATION(right); if (vp->left_mix_offset) { vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } if (vp->right_mix_offset) { vp->right_mix_offset += vp->right_mix_inc; linear_right += vp->right_mix_inc; if (linear_right > MAX_AMP_VALUE) { linear_right = MAX_AMP_VALUE; vp->right_mix_offset = 0; } right = FINAL_VOLUME(linear_right); } } } else { for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) && i < count; i++) { s = *sp++; DELAYED_MIXATION(left); MIXATION(right); if (vp->left_mix_offset) { vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } if (vp->right_mix_offset) { vp->right_mix_offset += vp->right_mix_inc; linear_right += vp->right_mix_inc; if (linear_right > MAX_AMP_VALUE) { linear_right = MAX_AMP_VALUE; vp->right_mix_offset = 0; } right = FINAL_VOLUME(linear_right); } } } vp->old_left_mix = linear_left; vp->old_right_mix = linear_right; count -= i; if(vp->pan_delay_rpt == 0) { for (i = 0; i < count; i++) { s = *sp++; MIXATION(left); MIXATION(right); } } else if(vp->panning < 64) { for (i = 0; i < count; i++) { s = *sp++; MIXATION(left); DELAYED_MIXATION(right); } } else { for (i = 0; i < count; i++) { s = *sp++; DELAYED_MIXATION(left); MIXATION(right); } } vp->pan_delay_wpt = pan_delay_wpt; vp->pan_delay_spt = pan_delay_spt; return; } } void Mixer::mix_mystery(mix_t *sp, int32_t *lp, int v, int count) { final_volume_t left = player->voice[v].left_mix, right = player->voice[v].right_mix; mix_t s; int i; Voice *vp = player->voice + v; int32_t linear_left, linear_right; int32_t pan_delay_wpt = vp->pan_delay_wpt, *pan_delay_buf = vp->pan_delay_buf, pan_delay_spt = vp->pan_delay_spt; compute_mix_smoothing(vp); linear_left = FROM_FINAL_VOLUME(left); if (vp->left_mix_offset) { linear_left += vp->left_mix_offset; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } linear_right = FROM_FINAL_VOLUME(right); if (vp->right_mix_offset) { linear_right += vp->right_mix_offset; if (linear_right > MAX_AMP_VALUE) { linear_right = MAX_AMP_VALUE; vp->right_mix_offset = 0; } right = FINAL_VOLUME(linear_right); } if(vp->pan_delay_rpt == 0) { for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) && i < count; i++) { s = *sp++; MIXATION(left); MIXATION(right); if (vp->left_mix_offset) { vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } if (vp->right_mix_offset) { vp->right_mix_offset += vp->right_mix_inc; linear_right += vp->right_mix_inc; if (linear_right > MAX_AMP_VALUE) { linear_right = MAX_AMP_VALUE; vp->right_mix_offset = 0; } right = FINAL_VOLUME(linear_right); } } } else if(vp->panning < 64) { for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) && i < count; i++) { s = *sp++; MIXATION(left); DELAYED_MIXATION(right); if (vp->left_mix_offset) { vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } if (vp->right_mix_offset) { vp->right_mix_offset += vp->right_mix_inc; linear_right += vp->right_mix_inc; if (linear_right > MAX_AMP_VALUE) { linear_right = MAX_AMP_VALUE; vp->right_mix_offset = 0; } right = FINAL_VOLUME(linear_right); } } } else { for (i = 0; (vp->left_mix_offset | vp->right_mix_offset) && i < count; i++) { s = *sp++; DELAYED_MIXATION(left); MIXATION(right); if (vp->left_mix_offset) { vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } if (vp->right_mix_offset) { vp->right_mix_offset += vp->right_mix_inc; linear_right += vp->right_mix_inc; if (linear_right > MAX_AMP_VALUE) { linear_right = MAX_AMP_VALUE; vp->right_mix_offset = 0; } right = FINAL_VOLUME(linear_right); } } } vp->old_left_mix = linear_left; vp->old_right_mix = linear_right; count -= i; if(vp->pan_delay_rpt == 0) { for (i = 0; i < count; i++) { s = *sp++; MIXATION(left); MIXATION(right); } } else if(vp->panning < 64) { for (i = 0; i < count; i++) { s = *sp++; MIXATION(left); DELAYED_MIXATION(right); } } else { for (i = 0; i < count; i++) { s = *sp++; DELAYED_MIXATION(left); MIXATION(right); } } vp->pan_delay_wpt = pan_delay_wpt; vp->pan_delay_spt = pan_delay_spt; } void Mixer::mix_center_signal( mix_t *sp, int32_t *lp, int v, int count) { Voice *vp = player->voice + v; final_volume_t left=vp->left_mix; int cc, i; mix_t s; int32_t linear_left; if (! (cc = vp->control_counter)) { cc = control_ratio; if (update_signal(v)) /* Envelope ran out */ return; left = vp->left_mix; } compute_mix_smoothing(vp); while (count) if (cc < count) { count -= cc; linear_left = FROM_FINAL_VOLUME(left); if (vp->left_mix_offset) { linear_left += vp->left_mix_offset; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } for (i = 0; vp->left_mix_offset && i < cc; i++) { s = *sp++; MIXATION(left); MIXATION(left); vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } vp->old_left_mix = vp->old_right_mix = linear_left; cc -= i; for (i = 0; i < cc; i++) { s = *sp++; MIXATION(left); MIXATION(left); } cc = control_ratio; if (update_signal(v)) /* Envelope ran out */ return; left = vp->left_mix; compute_mix_smoothing(vp); } else { vp->control_counter = cc - count; linear_left = FROM_FINAL_VOLUME(left); if (vp->left_mix_offset) { linear_left += vp->left_mix_offset; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } for (i = 0; vp->left_mix_offset && i < count; i++) { s = *sp++; MIXATION(left); MIXATION(left); vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } vp->old_left_mix = vp->old_right_mix = linear_left; count -= i; for (i = 0; i < count; i++) { s = *sp++; MIXATION(left); MIXATION(left); } return; } } void Mixer::mix_center(mix_t *sp, int32_t *lp, int v, int count) { final_volume_t left = player->voice[v].left_mix; mix_t s; int i; Voice *vp = player->voice + v; int32_t linear_left; compute_mix_smoothing(vp); linear_left = FROM_FINAL_VOLUME(left); if (vp->left_mix_offset) { linear_left += vp->left_mix_offset; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } for (i = 0; vp->left_mix_offset && i < count; i++) { s = *sp++; MIXATION(left); MIXATION(left); vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } vp->old_left_mix = vp->old_right_mix = linear_left; count -= i; for (i = 0; i < count; i++) { s = *sp++; MIXATION(left); MIXATION(left); } } void Mixer::mix_single_signal(mix_t *sp, int32_t *lp, int v, int count) { Voice *vp = player->voice + v; final_volume_t left = vp->left_mix; int cc, i; mix_t s; int32_t linear_left; if (!(cc = vp->control_counter)) { cc = control_ratio; if (update_signal(v)) /* Envelope ran out */ return; left = vp->left_mix; } compute_mix_smoothing(vp); while (count) if (cc < count) { count -= cc; linear_left = FROM_FINAL_VOLUME(left); if (vp->left_mix_offset) { linear_left += vp->left_mix_offset; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } for (i = 0; vp->left_mix_offset && i < cc; i++) { s = *sp++; MIXATION(left); lp++; vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } vp->old_left_mix = linear_left; cc -= i; for (i = 0; i < cc; i++) { s = *sp++; MIXATION(left); lp++; } cc = control_ratio; if (update_signal(v)) /* Envelope ran out */ return; left = vp->left_mix; compute_mix_smoothing(vp); } else { vp->control_counter = cc - count; linear_left = FROM_FINAL_VOLUME(left); if (vp->left_mix_offset) { linear_left += vp->left_mix_offset; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } for (i = 0; vp->left_mix_offset && i < count; i++) { s = *sp++; MIXATION(left); lp++; vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } vp->old_left_mix = linear_left; count -= i; for (i = 0; i < count; i++) { s = *sp++; MIXATION(left); lp++; } return; } } void Mixer::mix_single(mix_t *sp, int32_t *lp, int v, int count) { final_volume_t left = player->voice[v].left_mix; mix_t s; int i; Voice *vp = player->voice + v; int32_t linear_left; compute_mix_smoothing(vp); linear_left = FROM_FINAL_VOLUME(left); if (vp->left_mix_offset) { linear_left += vp->left_mix_offset; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } for (i = 0; vp->left_mix_offset && i < count; i++) { s = *sp++; MIXATION(left); lp++; vp->left_mix_offset += vp->left_mix_inc; linear_left += vp->left_mix_inc; if (linear_left > MAX_AMP_VALUE) { linear_left = MAX_AMP_VALUE; vp->left_mix_offset = 0; } left = FINAL_VOLUME(linear_left); } vp->old_left_mix = linear_left; count -= i; for (i = 0; i < count; i++) { s = *sp++; MIXATION(left); lp++; } } /* Returns 1 if the note died */ int Mixer::update_signal(int v) { Voice *vp = &player->voice[v]; if (vp->envelope_increment && update_envelope(v)) return 1; if (vp->tremolo_phase_increment) update_tremolo(v); if (timidity_modulation_envelope && vp->sample->modes & MODES_ENVELOPE) update_modulation_envelope(v); return apply_envelope_to_amp(v); } int Mixer::update_envelope(int v) { Voice *vp = &player->voice[v]; vp->envelope_volume += vp->envelope_increment; if ((vp->envelope_increment < 0) ^ (vp->envelope_volume > vp->envelope_target)) { vp->envelope_volume = vp->envelope_target; if (recompute_envelope(v)) return 1; } return 0; } int Mixer::get_eg_stage(int v, int stage) { int eg_stage; Voice *vp = &player->voice[v]; eg_stage = stage; if (vp->sample->inst_type == INST_SF2) { if (stage >= EG_SF_RELEASE) { eg_stage = EG_RELEASE; } } else { if (stage == EG_GUS_DECAY) { eg_stage = EG_DECAY; } else if (stage == EG_GUS_SUSTAIN) { eg_stage = EG_NULL; } else if (stage >= EG_GUS_RELEASE1) { eg_stage = EG_RELEASE; } } return eg_stage; } /* Returns 1 if envelope runs out */ int Mixer::recompute_envelope(int v) { int stage, ch; double sustain_time; int32_t envelope_width; Voice *vp = &player->voice[v]; stage = vp->envelope_stage; if (stage > EG_GUS_RELEASE3) { voice_ran_out(v); return 1; } else if (stage > EG_GUS_SUSTAIN && vp->envelope_volume <= 0) { /* Remove silent player->voice in the release stage */ voice_ran_out(v); return 1; } /* Routine to decay the sustain envelope * * Disabled if !min_sustain_time. * min_sustain_time is given in msec, and is the minimum * time it will take to decay a note to zero. * 2000-3000 msec seem to be decent values to use. */ if (stage == EG_GUS_RELEASE1 && vp->sample->modes & MODES_ENVELOPE && vp->status & (VOICE_ON | VOICE_SUSTAINED)) { int32_t new_rate; ch = vp->channel; /* Don't adjust the current rate if VOICE_ON */ if (vp->status & VOICE_ON) return 0; if (min_sustain_time > 0 || player->channel[ch].loop_timeout > 0) { if (min_sustain_time == 1) /* The sustain stage is ignored. */ return next_stage(v); if (player->channel[ch].loop_timeout > 0 && player->channel[ch].loop_timeout * 1000 < min_sustain_time) { /* timeout (See also "#extension timeout" line in *.cfg file */ sustain_time = player->channel[ch].loop_timeout * 1000; } else { sustain_time = min_sustain_time; } /* Sustain must not be 0 or else lots of dead notes! */ if (player->channel[ch].sostenuto == 0 && player->channel[ch].sustain > 0) { sustain_time *= (double)player->channel[ch].sustain / 127.0f; } /* Calculate the width of the envelope */ envelope_width = sustain_time * playback_rate / (1000.0f * (double)control_ratio); if (vp->sample->inst_type == INST_SF2) { /* If the instrument is SoundFont, it sustains at the sustain stage. */ vp->envelope_increment = -1; vp->envelope_target = vp->envelope_volume - envelope_width; if (vp->envelope_target < 0) {vp->envelope_target = 0;} } else { /* Otherwise, it decays at the sustain stage. */ vp->envelope_target = 0; new_rate = vp->envelope_volume / envelope_width; /* Use the Release1 rate if slower than new rate */ if (vp->sample->envelope_rate[EG_GUS_RELEASE1] && vp->sample->envelope_rate[EG_GUS_RELEASE1] < new_rate) new_rate = vp->sample->envelope_rate[EG_GUS_RELEASE1]; /* Use the Sustain rate if slower than new rate */ /* (Sustain rate exists only in GUS patches) */ if (vp->sample->inst_type == INST_GUS && vp->sample->envelope_rate[EG_GUS_SUSTAIN] && vp->sample->envelope_rate[EG_GUS_SUSTAIN] < new_rate) new_rate = vp->sample->envelope_rate[EG_GUS_SUSTAIN]; /* Avoid freezing */ if (!new_rate) new_rate = 1; vp->envelope_increment = -new_rate; } } return 0; } return next_stage(v); } /* Envelope ran out. */ void Mixer::voice_ran_out(int v) { /* Already displayed as dead */ int died = (player->voice[v].status == VOICE_DIE); player->free_voice(v); } int Mixer::next_stage(int v) { int stage, ch, eg_stage; int32_t offset, val; double rate, temp_rate; Voice *vp = &player->voice[v]; stage = vp->envelope_stage++; offset = vp->sample->envelope_offset[stage]; rate = vp->sample->envelope_rate[stage]; if (vp->envelope_volume == offset || (stage > EG_GUS_SUSTAIN && vp->envelope_volume < offset)) return recompute_envelope(v); ch = vp->channel; /* there is some difference between GUS patch and Soundfont at envelope. */ eg_stage = get_eg_stage(v, stage); /* HACK -- force ramps to occur over 20 msec windows to avoid pops */ /* Do not apply to attack envelope */ if (eg_stage > EG_ATTACK) { temp_rate = control_ratio * (labs(vp->envelope_volume - offset) / (playback_rate * 0.02)); if (temp_rate < 1) temp_rate = 1; if (rate < 0) temp_rate = -temp_rate; if (fabs(temp_rate) < fabs(rate)) rate = temp_rate; } /* envelope generator (see also playmidi.[ch]) */ if (player->ISDRUMCHANNEL(ch)) val = (player->channel[ch].drums[vp->note] != NULL) ? player->channel[ch].drums[vp->note]->drum_envelope_rate[eg_stage] : -1; else { if (vp->sample->envelope_keyf[stage]) /* envelope key-follow */ rate *= pow(2.0, (double) (player->voice[v].note - 60) * (double)vp->sample->envelope_keyf[stage] / 1200.0f); val = player->channel[ch].envelope_rate[eg_stage]; } if (vp->sample->envelope_velf[stage]) /* envelope velocity-follow */ rate *= pow(2.0, (double) (player->voice[v].velocity - vp->sample->envelope_velf_bpo) * (double)vp->sample->envelope_velf[stage] / 1200.0f); /* just before release-phase, some modifications are necessary */ if (stage > EG_GUS_SUSTAIN) { /* adjusting release-rate for consistent release-time */ rate *= (double) vp->envelope_volume / vp->sample->envelope_offset[EG_GUS_ATTACK]; /* calculating current envelope scale and a inverted value for optimization */ vp->envelope_scale = vp->last_envelope_volume; vp->inv_envelope_scale = TIM_FSCALE(OFFSET_MAX / (double)vp->envelope_volume, 16); } /* regularizing envelope */ if (offset < vp->envelope_volume) { /* decaying phase */ if (val != -1) { if(eg_stage > EG_DECAY) { rate *= sc_eg_release_table[val & 0x7f]; } else { rate *= sc_eg_decay_table[val & 0x7f]; } if (fabs(rate) > OFFSET_MAX) rate = (rate > 0) ? OFFSET_MAX : -OFFSET_MAX; else if (fabs(rate) < 1) rate = (rate > 0) ? 1 : -1; } if(stage < EG_SF_DECAY && rate > OFFSET_MAX) { /* instantaneous decay */ vp->envelope_volume = offset; return recompute_envelope(v); } else if(rate > vp->envelope_volume - offset) { /* fastest decay */ rate = -vp->envelope_volume + offset - 1; } else if (rate < 1) { /* slowest decay */ rate = -1; } else { /* ordinary decay */ rate = -rate; } } else { /* attacking phase */ if (val != -1) { rate *= sc_eg_attack_table[val & 0x7f]; if (fabs(rate) > OFFSET_MAX) rate = (rate > 0) ? OFFSET_MAX : -OFFSET_MAX; else if (fabs(rate) < 1) rate = (rate > 0) ? 1 : -1; } if(stage < EG_SF_DECAY && rate > OFFSET_MAX) { /* instantaneous attack */ vp->envelope_volume = offset; return recompute_envelope(v); } else if(rate > offset - vp->envelope_volume) { /* fastest attack */ rate = offset - vp->envelope_volume + 1; } else if (rate < 1) {rate = 1;} /* slowest attack */ } /* HACK -- force ramps to occur over 20 msec windows to avoid pops */ /* Do not apply to attack envelope */ /* Must check again in case the above conditions shortened it */ if (eg_stage > EG_ATTACK) { temp_rate = control_ratio * (labs(vp->envelope_volume - offset) / (playback_rate * 0.02)); if (temp_rate < 1) temp_rate = 1; if (rate < 0) temp_rate = -temp_rate; if (fabs(temp_rate) < fabs(rate)) rate = temp_rate; } vp->envelope_increment = (int32_t)rate; vp->envelope_target = offset; return 0; } void Mixer::update_tremolo(int v) { Voice *vp = &player->voice[v]; int32_t depth = vp->tremolo_depth << 7; if(vp->tremolo_delay > 0) { vp->tremolo_delay -= vp->delay_counter; if(vp->tremolo_delay > 0) { vp->tremolo_volume = 1.0; return; } vp->tremolo_delay = 0; } if (vp->tremolo_sweep) { /* Update sweep position */ vp->tremolo_sweep_position += vp->tremolo_sweep; if (vp->tremolo_sweep_position >= 1 << SWEEP_SHIFT) /* Swept to max amplitude */ vp->tremolo_sweep = 0; else { /* Need to adjust depth */ depth *= vp->tremolo_sweep_position; depth >>= SWEEP_SHIFT; } } vp->tremolo_phase += vp->tremolo_phase_increment; if(vp->sample->inst_type == INST_SF2) { vp->tremolo_volume = 1.0 + TIM_FSCALENEG( lookup_sine(vp->tremolo_phase >> RATE_SHIFT) * depth * TREMOLO_AMPLITUDE_TUNING, 17); } else { vp->tremolo_volume = 1.0 + TIM_FSCALENEG( lookup_sine(vp->tremolo_phase >> RATE_SHIFT) * depth * TREMOLO_AMPLITUDE_TUNING, 17); } /* I'm not sure about the +1.0 there -- it makes tremoloed voices' * volumes on average the lower the higher the tremolo amplitude. */ } int Mixer::apply_envelope_to_amp(int v) { Voice *vp = &player->voice[v]; double lamp = vp->left_amp, ramp, *v_table = vp->sample->inst_type == INST_SF2 ? sb_vol_table : player->vol_table; int32_t la, ra; if (vp->panned == PANNED_MYSTERY) { ramp = vp->right_amp; if (vp->tremolo_phase_increment) { lamp *= vp->tremolo_volume; ramp *= vp->tremolo_volume; } if (vp->sample->modes & MODES_ENVELOPE) { if (vp->envelope_stage > 3) vp->last_envelope_volume = v_table[ imuldiv16(vp->envelope_volume, vp->inv_envelope_scale) >> 20] * vp->envelope_scale; else if (vp->envelope_stage > 1) vp->last_envelope_volume = v_table[ vp->envelope_volume >> 20]; else vp->last_envelope_volume = attack_vol_table[ vp->envelope_volume >> 20]; lamp *= vp->last_envelope_volume; ramp *= vp->last_envelope_volume; } la = TIM_FSCALE(lamp, AMP_BITS); if (la > MAX_AMP_VALUE) la = MAX_AMP_VALUE; ra = TIM_FSCALE(ramp, AMP_BITS); if (ra > MAX_AMP_VALUE) ra = MAX_AMP_VALUE; if ((vp->status & (VOICE_OFF | VOICE_SUSTAINED)) && (la | ra) <= 0) { player->free_voice(v); return 1; } vp->left_mix = FINAL_VOLUME(la); vp->right_mix = FINAL_VOLUME(ra); } else { if (vp->tremolo_phase_increment) lamp *= vp->tremolo_volume; if (vp->sample->modes & MODES_ENVELOPE) { if (vp->envelope_stage > 3) vp->last_envelope_volume = v_table[ imuldiv16(vp->envelope_volume, vp->inv_envelope_scale) >> 20] * vp->envelope_scale; else if (vp->envelope_stage > 1) vp->last_envelope_volume = v_table[ vp->envelope_volume >> 20]; else vp->last_envelope_volume = attack_vol_table[ vp->envelope_volume >> 20]; lamp *= vp->last_envelope_volume; } la = TIM_FSCALE(lamp, AMP_BITS); if (la > MAX_AMP_VALUE) la = MAX_AMP_VALUE; if ((vp->status & (VOICE_OFF | VOICE_SUSTAINED)) && la <= 0) { player->free_voice(v); return 1; } vp->left_mix = FINAL_VOLUME(la); } return 0; } void Mixer::compute_mix_smoothing(Voice *vp) { int32_t max_win, delta; /* reduce popping -- ramp the amp over a 20 msec window */ max_win = (playback_rate * 0.02) / control_ratio; delta = FROM_FINAL_VOLUME(vp->left_mix) - vp->old_left_mix; if (labs(delta) > max_win) { vp->left_mix_inc = delta / max_win; vp->left_mix_offset = vp->left_mix_inc * (1 - max_win); } else if (delta) { vp->left_mix_inc = -1; if (delta > 0) vp->left_mix_inc = 1; vp->left_mix_offset = vp->left_mix_inc - delta; } delta = FROM_FINAL_VOLUME(vp->right_mix) - vp->old_right_mix; if (labs(delta) > max_win) { vp->right_mix_inc = delta / max_win; vp->right_mix_offset = vp->right_mix_inc * (1 - max_win); } else if (delta) { vp->right_mix_inc = -1; if (delta > 0) vp->right_mix_inc = 1; vp->right_mix_offset = vp->right_mix_inc - delta; } } int Mixer::update_modulation_envelope(int v) { Voice *vp = &player->voice[v]; if(vp->modenv_delay > 0) { vp->modenv_delay -= vp->delay_counter; if(vp->modenv_delay > 0) {return 1;} vp->modenv_delay = 0; } vp->modenv_volume += vp->modenv_increment; if ((vp->modenv_increment < 0) ^ (vp->modenv_volume > vp->modenv_target)) { vp->modenv_volume = vp->modenv_target; if (recompute_modulation_envelope(v)) { apply_modulation_envelope(v); return 1; } } apply_modulation_envelope(v); return 0; } int Mixer::apply_modulation_envelope(int v) { Voice *vp = &player->voice[v]; if(!timidity_modulation_envelope) {return 0;} if (vp->sample->modes & MODES_ENVELOPE) { vp->last_modenv_volume = modenv_vol_table[vp->modenv_volume >> 20]; } player->recompute_voice_filter(v); if(!(vp->porta_control_ratio && vp->porta_control_counter == 0)) { player->recompute_freq(v); } return 0; } int Mixer::modenv_next_stage(int v) { int stage, ch, eg_stage; int32_t offset, val; double rate; Voice *vp = &player->voice[v]; stage = vp->modenv_stage++; offset = vp->sample->modenv_offset[stage]; rate = vp->sample->modenv_rate[stage]; if (vp->modenv_volume == offset || (stage > EG_GUS_SUSTAIN && vp->modenv_volume < offset)) return recompute_modulation_envelope(v); else if(stage < EG_SF_DECAY && rate > OFFSET_MAX) { /* instantaneous attack */ vp->modenv_volume = offset; return recompute_modulation_envelope(v); } ch = vp->channel; /* there is some difference between GUS patch and Soundfont at envelope. */ eg_stage = get_eg_stage(v, stage); /* envelope generator (see also playmidi.[ch]) */ if (player->ISDRUMCHANNEL(ch)) val = (player->channel[ch].drums[vp->note] != NULL) ? player->channel[ch].drums[vp->note]->drum_envelope_rate[eg_stage] : -1; else { if (vp->sample->modenv_keyf[stage]) /* envelope key-follow */ rate *= pow(2.0, (double) (player->voice[v].note - 60) * (double)vp->sample->modenv_keyf[stage] / 1200.0f); val = player->channel[ch].envelope_rate[eg_stage]; } if (vp->sample->modenv_velf[stage]) rate *= pow(2.0, (double) (player->voice[v].velocity - vp->sample->modenv_velf_bpo) * (double)vp->sample->modenv_velf[stage] / 1200.0f); /* just before release-phase, some modifications are necessary */ if (stage > EG_GUS_SUSTAIN) { /* adjusting release-rate for consistent release-time */ rate *= (double) vp->modenv_volume / vp->sample->modenv_offset[EG_GUS_ATTACK]; } /* regularizing envelope */ if (offset < vp->modenv_volume) { /* decaying phase */ if (val != -1) { if(stage > EG_DECAY) { rate *= sc_eg_release_table[val & 0x7f]; } else { rate *= sc_eg_decay_table[val & 0x7f]; } } if(rate > vp->modenv_volume - offset) { /* fastest decay */ rate = -vp->modenv_volume + offset - 1; } else if (rate < 1) { /* slowest decay */ rate = -1; } else { /* ordinary decay */ rate = -rate; } } else { /* attacking phase */ if (val != -1) rate *= sc_eg_attack_table[val & 0x7f]; if(rate > offset - vp->modenv_volume) { /* fastest attack */ rate = offset - vp->modenv_volume + 1; } else if (rate < 1) {rate = 1;} /* slowest attack */ } vp->modenv_increment = (int32_t)rate; vp->modenv_target = offset; return 0; } int Mixer::recompute_modulation_envelope(int v) { int stage, ch; double sustain_time; int32_t modenv_width; Voice *vp = &player->voice[v]; if(!timidity_modulation_envelope) {return 0;} stage = vp->modenv_stage; if (stage > EG_GUS_RELEASE3) {return 1;} else if (stage > EG_GUS_SUSTAIN && vp->modenv_volume <= 0) { return 1; } /* Routine to sustain modulation envelope * * Disabled if !min_sustain_time. * min_sustain_time is given in msec, and is the minimum * time it will take to sustain a note. * 2000-3000 msec seem to be decent values to use. */ if (stage == EG_GUS_RELEASE1 && vp->sample->modes & MODES_ENVELOPE && vp->status & (VOICE_ON | VOICE_SUSTAINED)) { ch = vp->channel; /* Don't adjust the current rate if VOICE_ON */ if (vp->status & VOICE_ON) return 0; if (min_sustain_time > 0 || player->channel[ch].loop_timeout > 0) { if (min_sustain_time == 1) /* The sustain stage is ignored. */ return modenv_next_stage(v); if (player->channel[ch].loop_timeout > 0 && player->channel[ch].loop_timeout * 1000 < min_sustain_time) { /* timeout (See also "#extension timeout" line in *.cfg file */ sustain_time = player->channel[ch].loop_timeout * 1000; } else { sustain_time = min_sustain_time; } /* Sustain must not be 0 or else lots of dead notes! */ if (player->channel[ch].sostenuto == 0 && player->channel[ch].sustain > 0) { sustain_time *= (double)player->channel[ch].sustain / 127.0f; } /* Calculate the width of the envelope */ modenv_width = sustain_time * playback_rate / (1000.0f * (double)control_ratio); vp->modenv_increment = -1; vp->modenv_target = vp->modenv_volume - modenv_width; if (vp->modenv_target < 0) {vp->modenv_target = 0;} } return 0; } return modenv_next_stage(v); } }