/* FluidSynth - A Software Synthesizer * * Copyright (C) 2003 Peter Hanappe and others. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307, USA */ #ifndef _FLUID_VOICE_H #define _FLUID_VOICE_H #include "fluid.h" #include "gen.h" namespace FluidS { #define NO_CHANNEL 0xff enum fluid_voice_status { FLUID_VOICE_OFF, FLUID_VOICE_ON, FLUID_VOICE_SUSTAINED }; /* * envelope data */ struct fluid_env_data_t { unsigned int count; // sample count float coeff; float incr; float min; float max; }; /* Indices for envelope tables */ enum fluid_voice_envelope_index_t { FLUID_VOICE_ENVDELAY, FLUID_VOICE_ENVATTACK, FLUID_VOICE_ENVHOLD, FLUID_VOICE_ENVDECAY, FLUID_VOICE_ENVSUSTAIN, FLUID_VOICE_ENVRELEASE, FLUID_VOICE_ENVFINISHED, FLUID_VOICE_ENVLAST }; //--------------------------------------------------------- // Voice //--------------------------------------------------------- class Voice { static float interp_coeff_linear[FLUID_INTERP_MAX][2]; static float interp_coeff[FLUID_INTERP_MAX][4]; static float sinc_table7[FLUID_INTERP_MAX][7]; Fluid* _fluid; double _noteTuning; // +/- in midicent void effects(int count, float* left, float* right, float* reverb, float* chorus); public: unsigned int id; // the id is incremented for every new noteon. // it's used for noteoff's unsigned char status; unsigned char chan; // the channel number, quick access for channel messages unsigned char key; // the key, quick acces for noteoff unsigned char vel; // the velocity Channel* channel; Generator gen[GEN_LAST]; Mod mod[FLUID_NUM_MOD]; int mod_count; bool has_looped; /* Flag that is set as soon as the first loop is completed. */ Sample* sample; int check_sample_sanity_flag; /* Flag that initiates, that sample-related parameters have to be checked. */ unsigned int ticks; float amp; /* the linear amplitude */ Phase phase; // the phase of the sample wave // Temporary variables used in write() float phase_incr; /* the phase increment for the next 64 samples */ float amp_incr; /* amplitude increment value */ float* dsp_buf; /* buffer to store interpolated sample data to */ /* basic parameters */ float pitch; /* the pitch in midicents */ float attenuation; /* the attenuation in centibels */ float min_attenuation_cB; /* Estimate on the smallest possible attenuation * during the lifetime of the voice */ float root_pitch; /* sample and loop start and end points (offset in sample memory). */ int start; int end; int loopstart; int loopend; /* vol env */ fluid_env_data_t volenv_data[FLUID_VOICE_ENVLAST]; unsigned int volenv_count; int volenv_section; float volenv_val; float amplitude_that_reaches_noise_floor_nonloop; float amplitude_that_reaches_noise_floor_loop; /* mod env */ fluid_env_data_t modenv_data[FLUID_VOICE_ENVLAST]; unsigned int modenv_count; int modenv_section; float modenv_val; /* the value of the modulation envelope */ float modenv_to_fc; float modenv_to_pitch; /* mod lfo */ float modlfo_val; /* the value of the modulation LFO */ unsigned int modlfo_delay; /* the delay of the lfo in samples */ float modlfo_incr; /* the lfo frequency is converted to a per-buffer increment */ float modlfo_to_fc; float modlfo_to_pitch; float modlfo_to_vol; /* vib lfo */ float viblfo_val; /* the value of the vibrato LFO */ unsigned int viblfo_delay; /* the delay of the lfo in samples */ float viblfo_incr; /* the lfo frequency is converted to a per-buffer increment */ float viblfo_to_pitch; /* resonant filter */ float fres; /* the resonance frequency, in cents (not absolute cents) */ float last_fres; /* Current resonance frequency of the IIR filter */ /* Serves as a flag: A deviation between fres and last_fres */ /* indicates, that the filter has to be recalculated. */ float q_lin; /* the q-factor on a linear scale */ float filter_gain; /* Gain correction factor, depends on q */ float hist1, hist2; /* Sample history for the IIR filter */ int filter_startup; /* Flag: If set, the filter will be set directly. Else it changes smoothly. */ /* filter coefficients */ /* The coefficients are normalized to a0. */ /* b0 and b2 are identical => b02 */ float b02; /* b0 / a0 */ float b1; /* b1 / a0 */ float a1; /* a0 / a0 */ float a2; /* a1 / a0 */ float b02_incr; float b1_incr; float a1_incr; float a2_incr; int filter_coeff_incr_count; /* pan */ float pan; float amp_left; float amp_right; /* reverb */ float reverb_send; float amp_reverb; /* chorus */ float chorus_send; float amp_chorus; /* interpolation method, as in fluid_interp in fluidsynth.h */ int interp_method; /* for debugging */ int debug; double ref; public: Voice(Fluid*); Channel* get_channel() const { return channel; } void voice_start(); void off(); void init(Sample*, Channel*, int key, int vel, unsigned id, double tuning); void gen_incr(int i, float val); void gen_set(int i, float val); float gen_get(int gen); unsigned int get_id() const { return id; } bool isPlaying() { return ((status == FLUID_VOICE_ON) || (status == FLUID_VOICE_SUSTAINED)); } void set_param(int gen, float nrpn_value, int abs); // Update all the synthesis parameters, which depend on generator // 'gen'. This is only necessary after changing a generator of an // already operating voice. Most applications will not need this // function. void update_param(int gen); double GEN(int n) { return gen[n].val + gen[n].mod + gen[n].nrpn; } void modulate_all(); void modulate(bool _cc, int _ctrl); float get_lower_boundary_for_attenuation(); void check_sample_sanity(); void noteoff(); void kill_excl(); int calculate_hold_decay_frames(int gen_base, int gen_key2base, int is_decay); /* A voice is 'ON', if it has not yet received a noteoff * event. Sending a noteoff event will advance the envelopes to * section 5 (release). */ bool RELEASED() const { return chan == NO_CHANNEL; } bool SUSTAINED() const { return status == FLUID_VOICE_SUSTAINED; } bool PLAYING() const { return (status == FLUID_VOICE_ON) || (status == FLUID_VOICE_SUSTAINED); } bool ON() const { return (status == FLUID_VOICE_ON) && (volenv_section < FLUID_VOICE_ENVRELEASE); } int SAMPLEMODE() const { return ((int)gen[GEN_SAMPLEMODE].val); } void write(unsigned n, float* l, float* r, float* reverb_buf, float* chorus_buf); void add_mod(const Mod* mod, int mode); static void dsp_float_config(); int dsp_float_interpolate_none(unsigned); int dsp_float_interpolate_linear(unsigned); int dsp_float_interpolate_4th_order(unsigned); int dsp_float_interpolate_7th_order(unsigned); }; } #endif /* _FLUID_VOICE_H */