📄 reverb.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*//* * REVERB EFFECT FOR TIMIDITY++-1.X (Version 0.06e 1999/1/28) * * Copyright (C) 1997,1998,1999 Masaki Kiryu <mkiryu@usa.net> * (http://w3mb.kcom.ne.jp/~mkiryu/) * * reverb.c -- main reverb engine. * */#ifdef HAVE_CONFIG_H#include "config.h"#endif /* HAVE_CONFIG_H */#ifndef NO_STRING_H#include <string.h>#else#include <strings.h>#endif#include "timidity.h"#include "controls.h"#include "tables.h"#include "common.h"#include "output.h"#include "reverb.h"#include "mt19937ar.h"#include <math.h>#include <stdlib.h>#define SYS_EFFECT_PRE_LPF/* #define SYS_EFFECT_CLIP */#ifdef SYS_EFFECT_CLIP#define CLIP_AMP_MAX (1L << (32 - GUARD_BITS))#define CLIP_AMP_MIN (-1L << (32 - GUARD_BITS))#endif /* SYS_EFFECT_CLIP */static double REV_INP_LEV = 1.0;#define MASTER_CHORUS_LEVEL 1.7#define MASTER_DELAY_LEVEL 3.25/* *//* Dry Signal *//* */static int32 direct_buffer[AUDIO_BUFFER_SIZE * 2];static int32 direct_bufsize = sizeof(direct_buffer);#if OPT_MODE != 0 && ( defined(_MSC_VER) || defined(__WATCOMC__)|| (defined(__BORLANDC__) && (__BORLANDC__ >= 1380)) )void set_dry_signal(int32 *buf, int32 count){ int32 *dbuf = direct_buffer; _asm { mov ecx, [count] mov esi, [buf] test ecx, ecx jz short L2 mov edi, [dbuf]L1: mov eax, [esi] mov ebx, [edi] add esi, 4 add ebx, eax mov [edi], ebx add edi, 4 dec ecx jnz L1L2: }}#elsevoid set_dry_signal(register int32 *buf, int32 n){#if USE_ALTIVEC if(is_altivec_available()) { v_set_dry_signal(direct_buffer, buf, n); } else {#endif register int32 i; register int32 *dbuf = direct_buffer; for(i = n - 1; i >= 0; i--) { dbuf[i] += buf[i]; }#if USE_ALTIVEC }#endif}#endif/* XG has "dry level". */#if OPT_MODE != 0 /* fixed-point implementation */#if defined(_MSC_VER) || defined(__WATCOMC__) || (defined(__BORLANDC__) && (__BORLANDC__ >= 1380))void set_dry_signal_xg(int32 *buf, int32 count, int32 level){ int32 *dbuf = direct_buffer; if(!level) {return;} level = level * 65536 / 127; _asm { mov ecx, [count] mov esi, [buf] mov ebx, [level] test ecx, ecx jz short L2 mov edi, [dbuf]L1: mov eax, [esi] imul ebx shr eax, 16 shl edx, 16 or eax, edx /* u */ mov edx, [edi] /* v */ add esi, 4 /* u */ add edx, eax /* v */ mov [edi], edx /* u */ add edi, 4 /* v */ dec ecx /* u */ jnz L1 /* v */L2: }}#elsevoid set_dry_signal_xg(register int32 *sbuffer, int32 n, int32 level){ register int32 i; int32 *buf = direct_buffer; if(!level) {return;} level = level * 65536 / 127; for(i = n - 1; i >= 0; i--) {buf[i] += imuldiv16(sbuffer[i], level);}}#endif /* _MSC_VER */#else /* floating-point implementation */void set_dry_signal_xg(register int32 *sbuffer, int32 n, int32 level){ register int32 i; register int32 count = n; if(!level) {return;} FLOAT_T send_level = (FLOAT_T)level / 127.0; for(i = 0; i < count; i++) { direct_buffer[i] += sbuffer[i] * send_level; }}#endif /* OPT_MODE != 0 */#ifdef SYS_EFFECT_CLIPvoid mix_dry_signal(int32 *buf, int32 n){ int32 i, x; for (i = 0; i < n; i++) { x = direct_buffer[i]; buf[i] = (x > CLIP_AMP_MAX) ? CLIP_AMP_MAX : (x < CLIP_AMP_MIN) ? CLIP_AMP_MIN : x; } memset(direct_buffer, 0, sizeof(int32) * n);}#else /* SYS_EFFECT_CLIP */void mix_dry_signal(int32 *buf, int32 n){ memcpy(buf, direct_buffer, sizeof(int32) * n); memset(direct_buffer, 0, sizeof(int32) * n);}#endif /* SYS_EFFECT_CLIP *//* *//* Effect Utilities *//* */static inline int isprime(int val){ int i; if (val == 2) {return 1;} if (val & 1) { for (i = 3; i < (int)sqrt((double)val) + 1; i += 2) { if ((val % i) == 0) {return 0;} } return 1; /* prime */ } else {return 0;} /* even */}/*! delay */static void free_delay(delay *delay){ if(delay->buf != NULL) { free(delay->buf); delay->buf = NULL; }}static void set_delay(delay *delay, int32 size){ if(size < 1) {size = 1;} free_delay(delay); delay->buf = (int32 *)safe_malloc(sizeof(int32) * size); if(delay->buf == NULL) {return;} delay->index = 0; delay->size = size; memset(delay->buf, 0, sizeof(int32) * delay->size);}static inline void do_delay(int32 *stream, int32 *buf, int32 size, int32 *index){ int32 output; output = buf[*index]; buf[*index] = *stream; if (++*index >= size) {*index = 0;} *stream = output;}/*! LFO (low frequency oscillator) */static void init_lfo(lfo *lfo, double freq, int type, double phase){ int32 i, cycle, diff; lfo->count = 0; lfo->freq = freq; if (lfo->freq < 0.05f) {lfo->freq = 0.05f;} cycle = (double)play_mode->rate / lfo->freq; if (cycle < 1) {cycle = 1;} lfo->cycle = cycle; lfo->icycle = TIM_FSCALE((SINE_CYCLE_LENGTH - 1) / (double)cycle, 24) - 0.5; diff = SINE_CYCLE_LENGTH * phase / 360.0f; if(lfo->type != type) { /* generate LFO waveform */ switch(type) { case LFO_SINE: for(i = 0; i < SINE_CYCLE_LENGTH; i++) lfo->buf[i] = TIM_FSCALE((lookup_sine(i + diff) + 1.0) / 2.0, 16); break; case LFO_TRIANGULAR: for(i = 0; i < SINE_CYCLE_LENGTH; i++) lfo->buf[i] = TIM_FSCALE((lookup_triangular(i + diff) + 1.0) / 2.0, 16); break; default: for(i = 0; i < SINE_CYCLE_LENGTH; i++) {lfo->buf[i] = TIM_FSCALE(0.5, 16);} break; } } lfo->type = type;}/* returned value is between 0 and (1 << 16) */static inline int32 do_lfo(lfo *lfo){ int32 val; val = lfo->buf[imuldiv24(lfo->count, lfo->icycle)]; if(++lfo->count == lfo->cycle) {lfo->count = 0;} return val;}/*! modulated delay with allpass interpolation (for Chorus Effect,...) */static void free_mod_delay(mod_delay *delay){ if(delay->buf != NULL) { free(delay->buf); delay->buf = NULL; }}static void set_mod_delay(mod_delay *delay, int32 ndelay, int32 depth){ int32 size = ndelay + depth + 1; free_mod_delay(delay); delay->buf = (int32 *)safe_malloc(sizeof(int32) * size); if(delay->buf == NULL) {return;} delay->rindex = 0; delay->windex = 0; delay->hist = 0; delay->ndelay = ndelay; delay->depth = depth; delay->size = size; memset(delay->buf, 0, sizeof(int32) * delay->size);}static inline void do_mod_delay(int32 *stream, int32 *buf, int32 size, int32 *rindex, int32 *windex, int32 ndelay, int32 depth, int32 lfoval, int32 *hist){ int32 t1, t2; if (++*windex == size) {*windex = 0;} t1 = buf[*rindex]; t2 = imuldiv24(lfoval, depth); *rindex = *windex - ndelay - (t2 >> 8); if (*rindex < 0) {*rindex += size;} t2 = 0xFF - (t2 & 0xFF); *hist = t1 + imuldiv8(buf[*rindex] - *hist, t2); buf[*windex] = *stream; *stream = *hist;}/*! modulated allpass filter with allpass interpolation (for Plate Reverberator,...) */static void free_mod_allpass(mod_allpass *delay){ if(delay->buf != NULL) { free(delay->buf); delay->buf = NULL; }}static void set_mod_allpass(mod_allpass *delay, int32 ndelay, int32 depth, double feedback){ int32 size = ndelay + depth + 1; free_mod_allpass(delay); delay->buf = (int32 *)safe_malloc(sizeof(int32) * size); if(delay->buf == NULL) {return;} delay->rindex = 0; delay->windex = 0; delay->hist = 0; delay->ndelay = ndelay; delay->depth = depth; delay->size = size; delay->feedback = feedback; delay->feedbacki = TIM_FSCALE(feedback, 24); memset(delay->buf, 0, sizeof(int32) * delay->size);}static inline void do_mod_allpass(int32 *stream, int32 *buf, int32 size, int32 *rindex, int32 *windex, int32 ndelay, int32 depth, int32 lfoval, int32 *hist, int32 feedback){ int t1, t2, t3; if (++*windex == size) {*windex = 0;} t3 = *stream + imuldiv24(*hist, feedback); t1 = buf[*rindex]; t2 = imuldiv24(lfoval, depth); *rindex = *windex - ndelay - (t2 >> 8); if (*rindex < 0) {*rindex += size;} t2 = 0xFF - (t2 & 0xFF); *hist = t1 + imuldiv8(buf[*rindex] - *hist, t2); buf[*windex] = t3; *stream = *hist - imuldiv24(t3, feedback);}/* allpass filter */static void free_allpass(allpass *allpass){ if(allpass->buf != NULL) { free(allpass->buf); allpass->buf = NULL; }}static void set_allpass(allpass *allpass, int32 size, double feedback){ if(allpass->buf != NULL) { free(allpass->buf); allpass->buf = NULL; } allpass->buf = (int32 *)safe_malloc(sizeof(int32) * size); if(allpass->buf == NULL) {return;} allpass->index = 0; allpass->size = size; allpass->feedback = feedback; allpass->feedbacki = TIM_FSCALE(feedback, 24); memset(allpass->buf, 0, sizeof(int32) * allpass->size);}static inline void do_allpass(int32 *stream, int32 *buf, int32 size, int32 *index, int32 feedback){ int32 bufout, output; bufout = buf[*index]; output = *stream - imuldiv24(bufout, feedback); buf[*index] = output; if (++*index >= size) {*index = 0;} *stream = bufout + imuldiv24(output, feedback);}static void init_filter_moog(filter_moog *svf){ svf->b0 = svf->b1 = svf->b2 = svf->b3 = svf->b4 = 0;}/*! calculate Moog VCF coefficients */void calc_filter_moog(filter_moog *svf){ double res, fr, p, q, f; if (svf->freq > play_mode->rate / 2) {svf->freq = play_mode->rate / 2;} else if(svf->freq < 20) {svf->freq = 20;} if(svf->freq != svf->last_freq || svf->res_dB != svf->last_res_dB) { if(svf->last_freq == 0) {init_filter_moog(svf);} svf->last_freq = svf->freq, svf->last_res_dB = svf->res_dB; res = pow(10, (svf->res_dB - 96) / 20); fr = 2.0 * (double)svf->freq / (double)play_mode->rate; q = 1.0 - fr; p = fr + 0.8 * fr * q; f = p + p - 1.0; q = res * (1.0 + 0.5 * q * (1.0 - q + 5.6 * q * q)); svf->f = TIM_FSCALE(f, 24); svf->p = TIM_FSCALE(p, 24); svf->q = TIM_FSCALE(q, 24); }}static inline void do_filter_moog(int32 *stream, int32 *high, int32 f, int32 p, int32 q, int32 *b0, int32 *b1, int32 *b2, int32 *b3, int32 *b4){ int32 t1, t2, t3, tb0 = *b0, tb1 = *b1, tb2 = *b2, tb3 = *b3, tb4 = *b4; t3 = *stream - imuldiv24(q, tb4); t1 = tb1; tb1 = imuldiv24(t3 + tb0, p) - imuldiv24(tb1, f); t2 = tb2; tb2 = imuldiv24(tb1 + t1, p) - imuldiv24(tb2, f); t1 = tb3; tb3 = imuldiv24(tb2 + t2, p) - imuldiv24(tb3, f); *stream = tb4 = imuldiv24(tb3 + t1, p) - imuldiv24(tb4, f);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -