mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-22 20:21:26 +00:00
1624 lines
43 KiB
C++
1624 lines
43 KiB
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
|
|
*/
|
|
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "timidity.h"
|
|
#include "common.h"
|
|
#include "instrum.h"
|
|
#include "playmidi.h"
|
|
#include "tables.h"
|
|
#include "resample.h"
|
|
#include "mix.h"
|
|
#include "optcode.h"
|
|
|
|
namespace TimidityPlus
|
|
{
|
|
extern float min_sustain_time;
|
|
|
|
|
|
#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)
|
|
{
|
|
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);
|
|
}
|
|
|
|
}
|