📄 mix.c
字号:
/* TiMidity++ -- MIDI to WAVE converter and player Copyright (C) 1999-2002 Masanao Izumo <mo@goice.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 mix.c*/#ifdef HAVE_CONFIG_H#include "config.h"#endif /* HAVE_CONFIG_H */#include <math.h>#include <stdio.h>#include <stdlib.h>#include "timidity.h"#include "common.h"#include "instrum.h"#include "playmidi.h"#include "output.h"#include "controls.h"#include "tables.h"#include "resample.h"#include "mix.h"#ifdef SMOOTH_MIXING#ifdef LOOKUP_HACK/* u2l: 0..255 -> -32256..32256 * shift 3 bit: -> within MAX_AMP_VALUE */#define FROM_FINAL_VOLUME(a) (_u2l[(uint8) ~(a)] >> 3)#else#define FROM_FINAL_VOLUME(a) (a)#endif#endif#define OFFSET_MAX (0x3FFFFFFFL)#if OPT_MODE != 0#define VOICE_LPF#endiftypedef int32 mix_t;#ifdef LOOKUP_HACK#define MIXATION(a) *lp++ += mixup[(a << 8) | (uint8) s]#else#define MIXATION(a) *lp++ += (a) * s#endif#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;}void mix_voice(int32 *, int, int32);static inline int do_voice_filter(int, resample_t*, mix_t*, int32);static inline void recalc_voice_resonance(int);static inline void recalc_voice_fc(int);static inline void ramp_out(mix_t *, int32 *, int, int32);static inline void mix_mono_signal(mix_t *, int32 *, int, int);static inline void mix_mono(mix_t *, int32 *, int, int);static inline void mix_mystery_signal(mix_t *, int32 *, int, int);static inline void mix_mystery(mix_t *, int32 *, int, int);static inline void mix_center_signal(mix_t *, int32 *, int, int);static inline void mix_center(mix_t *, int32 *, int, int);static inline void mix_single_signal(mix_t *, int32 *, int, int);static inline void mix_single(mix_t *, int32 *, int, int);static inline int update_signal(int);static inline int update_envelope(int);int recompute_envelope(int);static inline int update_modulation_envelope(int);int apply_modulation_envelope(int);int recompute_modulation_envelope(int);static inline void voice_ran_out(int);static inline int next_stage(int);static inline int modenv_next_stage(int);static inline void update_tremolo(int);int apply_envelope_to_amp(int);#ifdef SMOOTH_MIXINGstatic inline void compute_mix_smoothing(Voice *);#endifint min_sustain_time = 5000;static mix_t filter_buffer[AUDIO_BUFFER_SIZE];/**************** interface function ****************/void mix_voice(int32 *buf, int v, int32 c){ Voice *vp = voice + v; resample_t *sp; if (vp->status == VOICE_DIE) { if (c >= MAX_DIE_TIME) c = MAX_DIE_TIME; sp = 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); 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 (opt_modulation_envelope && vp->sample->modes & MODES_ENVELOPE) update_modulation_envelope(v); return; } if (play_mode->encoding & PE_MONO) buf += vp->delay; else buf += vp->delay * 2; c -= vp->delay; vp->delay = 0; } sp = resample_voice(v, &c); if (do_voice_filter(v, sp, filter_buffer, c)) {sp = filter_buffer;} if (play_mode->encoding & PE_MONO) { /* Mono output. */ if (vp->envelope_increment || vp->tremolo_phase_increment) mix_mono_signal(sp, buf, v, c); else mix_mono(sp, buf, v, c); } else { 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. */static inline int do_voice_filter(int v, resample_t *sp, mix_t *lp, int32 count){ FilterCoefficients *fc = &(voice[v].fc); int32 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.897638fstatic inline void recalc_voice_resonance(int v){ double q; FilterCoefficients *fc = &(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; }}static inline void recalc_voice_fc(int v){ double f, p, q, fr; FilterCoefficients *fc = &(voice[v].fc); if (fc->freq != fc->last_freq) { if(fc->type == 1) { f = 2.0 * sin(M_PI * (double)fc->freq / (double)play_mode->rate); fc->f = TIM_FSCALE(f, 24); } else if(fc->type == 2) { fr = 2.0 * (double)fc->freq / (double)play_mode->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 */static inline void ramp_out(mix_t *sp, int32 *lp, int v, int32 c){ /* should be final_volume_t, but uint8 gives trouble. */ int32 left, right, li, ri, i; /* silly warning about uninitialized s */ mix_t s = 0;#ifdef ENABLE_PAN_DELAY Voice *vp = &voice[v]; int32 pan_delay_wpt = vp->pan_delay_wpt, *pan_delay_buf = vp->pan_delay_buf, pan_delay_spt = vp->pan_delay_spt;#endif left = voice[v].left_mix; li = -(left / c); if (! li) li = -1;#if 0 printf("Ramping out: left=%d, c=%d, li=%d\n", left, c, li);#endif if (! (play_mode->encoding & PE_MONO)) { if (voice[v].panned == PANNED_MYSTERY) {#ifdef ENABLE_PAN_DELAY right = 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 right = voice[v].right_mix; ri = -(right / c); 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); }#endif /* ENABLE_PAN_DELAY */ } else if (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 (voice[v].panned == PANNED_LEFT) for (i = 0; i < c; i++) { left += li; if (left < 0) return; s = *sp++; MIXATION(left); lp++; } else if (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); }}static inline void mix_mono_signal( mix_t *sp, int32 *lp, int v, int count){ Voice *vp = voice + v; final_volume_t left = vp->left_mix; int cc, i; mix_t s;#ifdef SMOOTH_MIXING int32 linear_left;#endif if (! (cc = vp->control_counter)) { cc = control_ratio; if (update_signal(v)) /* Envelope ran out */ return; left = vp->left_mix; }#ifdef SMOOTH_MIXING compute_mix_smoothing(vp);#endif while (count) if (cc < count) { count -= cc;#ifdef SMOOTH_MIXING 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;#endif 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;#ifdef SMOOTH_MIXING compute_mix_smoothing(vp);#endif } else { vp->control_counter = cc - count;#ifdef SMOOTH_MIXING 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;#endif for (i = 0; i < count; i++) { s = *sp++; MIXATION(left); } return; }}static inline void mix_mono(mix_t *sp, int32 *lp, int v, int count){ final_volume_t left = voice[v].left_mix; mix_t s; int i;#ifdef SMOOTH_MIXING Voice *vp = voice + v; int32 linear_left;#endif #ifdef SMOOTH_MIXING 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 = linear_left; count -= i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -