⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mix.c

📁 MIDI解码程序(用VC编写)
💻 C
📖 第 1 页 / 共 4 页
字号:
/*    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 + -