/* TiMidity++ -- MIDI to WAVE converter and player Copyright (C) 1999 Masanao Izumo Copyright (C) 1995 Tuukka Toivonen Suddenly, you realize that this program is free software; you get an overwhelming urge to 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 another copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. I bet they'll be amazed. mix.c */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #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" int min_sustain_time = 0; static void voice_ran_out(int v) { /* Envelope ran out. */ int died = (voice[v].status == VOICE_DIE); /* Already displayed as dead */ voice[v].status = VOICE_FREE; if(!died) ctl_note_event(v); } /* Returns 1 if envelope runs out */ int recompute_envelope(int v) { int stage, ch; int32 rate, offset; Voice *vp = &voice[v]; stage = vp->envelope_stage; if(stage > 5) { voice_ran_out(v); return 1; } if(stage > 2 && vp->envelope_volume <= 0) { /* Remove silent voice in the release stage */ voice_ran_out(v); return 1; } if(stage == 3 && (vp->sample->modes & MODES_ENVELOPE) && (vp->status & (VOICE_ON | VOICE_SUSTAINED))) { /* EAW -- Routine to decay the sustain envelope * * Disabled if !min_sustain_time or if there is no loop. * If calculated decay rate is larger than the regular * stage 3 rate, use the stage 3 rate instead. * min_sustain_time is given in msec, and is the time * it will take to decay a note at maximum volume. * 2000-3000 msec seem to be decent values to use. * */ if(min_sustain_time <= 0) /* Default behavior */ { /* Freeze envelope until note turns off */ vp->envelope_increment = 0; } else if((vp->status & VOICE_SUSTAINED) && (vp->sample->modes & MODES_LOOPING)) { if(min_sustain_time == 1) goto next_stage; /* Go to next stage. * The sustain stage is ignored. */ /* Set envelope volume target to zero. * This cause to be vp->envelope_volume <= 0, then the * voice will be removed. The next stage never come. */ vp->envelope_target = 0; /* Calculate the release phase speed. * (1073741823000 == (2^(15+15)-1) * 1000) */ rate = (int32)(-1073741823000.0 * control_ratio / (min_sustain_time * play_mode->rate)); vp->envelope_increment = -vp->sample->envelope_rate[3]; /* use the slower of the two rates */ if(vp->envelope_increment < rate) vp->envelope_increment = rate; if(!vp->envelope_increment) vp->envelope_increment = -1; /* Avoid freezing */ } else /* it's not decaying, so freeze it */ { /* tiny value to make other functions happy, freeze note */ vp->envelope_increment = 1; /* this will cause update_envelope(v) to undo the +1 inc. */ vp->envelope_target = vp->envelope_volume; } return 0; } next_stage: vp->envelope_stage = stage + 1; offset = vp->sample->envelope_offset[stage]; if(vp->envelope_volume == offset || (stage > 2 && vp->envelope_volume < offset)) return recompute_envelope(v); rate = 0; ch = vp->channel; if(ISDRUMCHANNEL(ch)) { int note; note = vp->note; if(channel[ch].drums[note] != NULL) rate = channel[ch].drums[note]->drum_envelope_rate[stage]; } else rate = channel[ch].envelope_rate[stage]; if(rate == 0) rate = vp->sample->envelope_rate[stage]; vp->envelope_target = offset; vp->envelope_increment = rate; if(vp->envelope_target < vp->envelope_volume) vp->envelope_increment = -vp->envelope_increment; return 0; } int apply_envelope_to_amp(int v) { FLOAT_T lamp=voice[v].left_amp, ramp; int32 la,ra; if (voice[v].panned == PANNED_MYSTERY) { ramp=voice[v].right_amp; if (voice[v].tremolo_phase_increment) { lamp *= voice[v].tremolo_volume; ramp *= voice[v].tremolo_volume; } if (voice[v].sample->modes & MODES_ENVELOPE) { lamp *= vol_table[voice[v].envelope_volume>>23]; ramp *= vol_table[voice[v].envelope_volume>>23]; } la = (int32)TIM_FSCALE(lamp,AMP_BITS); if (la>MAX_AMP_VALUE) la=MAX_AMP_VALUE; ra = (int32)TIM_FSCALE(ramp,AMP_BITS); if (ra>MAX_AMP_VALUE) ra=MAX_AMP_VALUE; if((voice[v].status & (VOICE_OFF | VOICE_SUSTAINED)) && (la | ra) <= MIN_AMP_VALUE) { voice[v].status = VOICE_FREE; ctl_note_event(v); return 1; } voice[v].left_mix=FINAL_VOLUME(la); voice[v].right_mix=FINAL_VOLUME(ra); } else { if (voice[v].tremolo_phase_increment) lamp *= voice[v].tremolo_volume; if (voice[v].sample->modes & MODES_ENVELOPE) lamp *= vol_table[voice[v].envelope_volume>>23]; la = (int32)TIM_FSCALE(lamp,AMP_BITS); if (la>MAX_AMP_VALUE) la=MAX_AMP_VALUE; if((voice[v].status & (VOICE_OFF | VOICE_SUSTAINED)) && la <= MIN_AMP_VALUE) { voice[v].status = VOICE_FREE; ctl_note_event(v); return 1; } voice[v].left_mix=FINAL_VOLUME(la); } return 0; } static inline int update_envelope(int v) { Voice *vp = &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; } static void update_tremolo(int v) { int32 depth=voice[v].sample->tremolo_depth<<7; if (voice[v].tremolo_sweep) { /* Update sweep position */ voice[v].tremolo_sweep_position += voice[v].tremolo_sweep; if (voice[v].tremolo_sweep_position>=(1<>= SWEEP_SHIFT; } } voice[v].tremolo_phase += voice[v].tremolo_phase_increment; /* if (voice[v].tremolo_phase >= (SINE_CYCLE_LENGTH<> RATE_SHIFT) + 1.0) * 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. */ } /* Returns 1 if the note died */ static inline int update_signal(int v) { if (voice[v].envelope_increment && update_envelope(v)) return 1; if (voice[v].tremolo_phase_increment) update_tremolo(v); return apply_envelope_to_amp(v); } #ifdef LOOKUP_HACK # define MIXATION(a) *lp++ += mixup[(a<<8) | (uint8)s]; #else # define MIXATION(a) *lp++ += (a) * s; #endif static void mix_mystery_signal(sample_t *sp, int32 *lp, int v, int count) { Voice *vp = voice + v; final_volume_t left=vp->left_mix, right=vp->right_mix; int cc, i; sample_t s; if (!(cc = vp->control_counter)) { cc = control_ratio; if (update_signal(v)) return; /* Envelope ran out */ left = vp->left_mix; right = vp->right_mix; } while (count) if (cc < count) { count -= cc; for(i = 0; i < cc; i++) { s = *sp++; MIXATION(left); MIXATION(right); } cc = control_ratio; if (update_signal(v)) return; /* Envelope ran out */ left = vp->left_mix; right = vp->right_mix; } else { vp->control_counter = cc - count; for(i = 0; i < count; i++) { s = *sp++; MIXATION(left); MIXATION(right); } return; } } static void mix_center_signal(sample_t *sp, int32 *lp, int v, int count) { Voice *vp = voice + v; final_volume_t left=vp->left_mix; int cc, i; sample_t s; if (!(cc = vp->control_counter)) { cc = control_ratio; if (update_signal(v)) return; /* Envelope ran out */ left = vp->left_mix; } while (count) if (cc < count) { count -= cc; for(i = 0; i < cc; i++) { s = *sp++; MIXATION(left); MIXATION(left); } cc = control_ratio; if (update_signal(v)) return; /* Envelope ran out */ left = vp->left_mix; } else { vp->control_counter = cc - count; for(i = 0; i < count; i++) { s = *sp++; MIXATION(left); MIXATION(left); } return; } } static void mix_single_signal(sample_t *sp, int32 *lp, int v, int count) { Voice *vp = voice + v; final_volume_t left=vp->left_mix; int cc, i; sample_t s; if (!(cc = vp->control_counter)) { cc = control_ratio; if (update_signal(v)) return; /* Envelope ran out */ left = vp->left_mix; } while (count) if (cc < count) { count -= cc; for(i = 0; i < cc; i++) { s = *sp++; MIXATION(left); lp++; } cc = control_ratio; if (update_signal(v)) return; /* Envelope ran out */ left = vp->left_mix; } else { vp->control_counter = cc - count; for(i = 0; i < count; i++) { s = *sp++; MIXATION(left); lp++; } return; } } static void mix_mono_signal(sample_t *sp, int32 *lp, int v, int count) { Voice *vp = voice + v; final_volume_t left=vp->left_mix; int cc, i; sample_t s; if (!(cc = vp->control_counter)) { cc = control_ratio; if (update_signal(v)) return; /* Envelope ran out */ left = vp->left_mix; } while (count) if (cc < count) { count -= cc; for(i = 0; i < cc; i++) { s = *sp++; MIXATION(left); } cc = control_ratio; if (update_signal(v)) return; /* Envelope ran out */ left = vp->left_mix; } else { vp->control_counter = cc - count; for(i = 0; i < count; i++) { s = *sp++; MIXATION(left); } return; } } static void mix_mystery(sample_t *sp, int32 *lp, int v, int count) { final_volume_t left=voice[v].left_mix, right=voice[v].right_mix; sample_t s; int i; for(i = 0; i < count; i++) { s = *sp++; MIXATION(left); MIXATION(right); } } static void mix_center(sample_t *sp, int32 *lp, int v, int count) { final_volume_t left=voice[v].left_mix; sample_t s; int i; for(i = 0; i < count; i++) { s = *sp++; MIXATION(left); MIXATION(left); } } static void mix_single(sample_t *sp, int32 *lp, int v, int count) { final_volume_t left=voice[v].left_mix; sample_t s; int i; for(i = 0; i < count; i++) { s = *sp++; MIXATION(left); lp++; } } static void mix_mono(sample_t *sp, int32 *lp, int v, int count) { final_volume_t left=voice[v].left_mix; sample_t s; int i; for(i = 0; i < count; i++) { s = *sp++; MIXATION(left); } } /* Ramp a note out in c samples */ static void ramp_out(sample_t *sp, int32 *lp, int v, int32 c) { /* should be final_volume_t, but uint8 gives trouble. */ int32 left, right, li, ri, i; sample_t s=0; /* silly warning about uninitialized s */ left=voice[v].left_mix; li=-(left/c); if (!li) li=-1; /* printf("Ramping out: left=%d, c=%d, li=%d\n", left, c, li); */ if (!(play_mode->encoding & PE_MONO)) { if (voice[v].panned==PANNED_MYSTERY) { 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); } } 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); } } } /**************** interface function ******************/ void mix_voice(int32 *buf, int v, int32 c) { Voice *vp=voice+v; sample_t *sp; if (vp->status==VOICE_DIE) { if (c>=MAX_DIE_TIME) c=MAX_DIE_TIME; sp=resample_voice(v, &c); if(c > 0) ramp_out(sp, buf, v, c); vp->status=VOICE_FREE; } else { if(vp->delay) { if(c < vp->delay) { vp->delay -= c; return; } if(play_mode->encoding & PE_MONO) buf += vp->delay; else buf += (2 * vp->delay); c -= vp->delay; vp->delay = 0; } sp=resample_voice(v, &c); 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); } } } }