#include #include #include #include "defines.h" #include "programs.h" #include "envelope.h" #include "fixed.h" #include "filter.h" #include "note_skel.h" using namespace std; int filter_update_frames=0; int samp_rate=0; fixed_t** wave=NULL; fixed_t** curr_lfo=NULL; typedef void output_note_func_t(string s); typedef string IntToStr_func_t(int i); output_note_func_t* output_note=NULL; IntToStr_func_t* IntToStr=NULL; class Note : public NoteSkel { public: Note(int n, float v,program_t &prg, jack_nframes_t pf, fixed_t pb, int prg_no); ~Note(); fixed_t get_sample(); void release_quickly(jack_nframes_t maxt); void release(); void reattack(); bool still_active(); void set_param(const parameter_t &p, fixed_t v); void destroy(); private: void do_ksl(); void do_ksr(); void recalc_factors(); void apply_pfactor(); // member variables begin here Envelope *env0; //envelope1 is unused //envelope2 is unused //envelope3 is unused fixed_t *oscval; fixed_t *old_oscval; oscillator_t osc0; oscillator_t osc1; oscillator_t osc2; oscillator_t osc3; //sync is disabled //filter is disabled pfactor_value_t pfactor; struct { oscillator_t osc0; oscillator_t osc1; oscillator_t osc2; oscillator_t osc3; //filter is disabled } orig; // member variables end here }; //this function returns the smallest phase_init possible for a //given custom_wave which is greater or equal than PHASE_INIT #define PHASE_INIT 100 inline fixed_t init_custom_osc_phase(int len, fixed_t sr) { return ( (fixed_t(ceil( float(PHASE_INIT) * sr / len / ONE )) *len << (2*SCALE)) / sr); } Note::Note(int n, float v, program_t &prg, jack_nframes_t pf, fixed_t pb, int prg_no) { curr_prg=&prg; oscval=new fixed_t[4]; old_oscval=new fixed_t[4]; for (int i=0;i<4;i++) oscval[i]=old_oscval[i]=0; pfactor.out=new fixed_t [4]; pfactor.fm=new fixed_t* [4]; for (int i=0;i<4;i++) pfactor.fm[i]=new fixed_t [4]; env0=new Envelope (prg.env_settings[0]); //envelope1 is disabled //envelope2 is disabled //envelope3 is disabled osc0=prg.osc_settings[0]; orig.osc0=prg.osc_settings[0]; osc1=prg.osc_settings[1]; orig.osc1=prg.osc_settings[1]; osc2=prg.osc_settings[2]; orig.osc2=prg.osc_settings[2]; osc3=prg.osc_settings[3]; orig.osc3=prg.osc_settings[3]; //initalize oscillator.phase to multiples of their wave resolution osc0.phase=ONE * PHASE_INIT; osc1.phase=ONE * PHASE_INIT; osc2.phase=ONE * PHASE_INIT; osc3.phase=ONE * PHASE_INIT; do_ksl(); portamento_frames=0; set_portamento_frames(pf); set_note(n); freq=dest_freq; set_vel(v); pitchbend=pb; program=prg_no; } Note::~Note() { delete [] osc0.fm_strength; delete env0; delete pfactor.fm[0]; delete [] osc1.fm_strength; //envelope1 is disabled delete pfactor.fm[1]; delete [] osc2.fm_strength; //envelope2 is disabled delete pfactor.fm[2]; delete [] osc3.fm_strength; //envelope3 is disabled delete pfactor.fm[3]; delete [] oscval; delete [] old_oscval; delete [] pfactor.out; delete [] pfactor.fm; } void Note::destroy() { delete this; } void Note::recalc_factors() { for (int i=0;i<4;i++) { pfactor.out[i]=calc_pfactor(curr_prg->pfactor.out[i], vel); for (int j=0;j<4;j++) pfactor.fm[i][j]=calc_pfactor(curr_prg->pfactor.fm[i][j], vel); } } void Note::apply_pfactor() { osc0.output=orig.osc0.output*pfactor.out[0] >>SCALE; for (int i=0;i<4;i++) osc0.fm_strength[i]=orig.osc0.fm_strength[i]*pfactor.fm[0][i] >>SCALE; osc1.output=orig.osc1.output*pfactor.out[1] >>SCALE; for (int i=0;i<4;i++) osc1.fm_strength[i]=orig.osc1.fm_strength[i]*pfactor.fm[1][i] >>SCALE; osc2.output=orig.osc2.output*pfactor.out[2] >>SCALE; for (int i=0;i<4;i++) osc2.fm_strength[i]=orig.osc2.fm_strength[i]*pfactor.fm[2][i] >>SCALE; osc3.output=orig.osc3.output*pfactor.out[3] >>SCALE; for (int i=0;i<4;i++) osc3.fm_strength[i]=orig.osc3.fm_strength[i]*pfactor.fm[3][i] >>SCALE; } bool Note::still_active() { if ( ((osc0.output>0) && (env0->still_active())) /* envelope1 is disabled */ /* envelope2 is disabled */ /* envelope3 is disabled */ ) return true; else return false; } void Note::release() { env0->release_key(); //envelope1 is disabled //envelope2 is disabled //envelope3 is disabled } void Note::release_quickly(jack_nframes_t maxt) { if (env0->get_release() > maxt) env0->set_release(maxt); env0->release_key(); //envelope1 is disabled //envelope2 is disabled //envelope3 is disabled } void Note::reattack() { env0->reattack(); //envelope1 is disabled //envelope2 is disabled //envelope3 is disabled } void Note::do_ksr() { env0->set_ratefactor(1.0 / pow(freq>>SCALE, osc0.ksr)); //envelope1 is disabled //envelope2 is disabled //envelope3 is disabled } void Note::do_ksl() { } fixed_t Note::get_sample() { if (freq!=dest_freq) { // the div.by.zero if p_frames=0 is avoided because then the // if-condition below is always true if (portamento_t>=portamento_frames) freq=dest_freq; else //will only happen if p_t < p_frames -> p_frames is always > 0 -> div. ok freq = old_freq + (dest_freq-old_freq)*portamento_t/portamento_frames; do_ksl(); portamento_t++; } fixed_t actual_freq=freq*pitchbend >>SCALE; fixed_t *temp; temp=old_oscval; //swap the current and old oscval-pointers old_oscval=oscval; oscval=temp; //sync is disabled osc0.phase+= (actual_freq*osc0.factor/samp_rate)>>SCALE; oscval[0] = wave[0][ ( ( osc0.phase + ( + (old_oscval[1]) ) ) * WAVE_RES >>SCALE ) % WAVE_RES ] * env0->get_level() >>SCALE; //oscillator0 has no tremolo osc1.phase+= (actual_freq*osc1.factor/samp_rate)>>SCALE; oscval[1] = wave[0][ ( ( osc1.phase + ( + (old_oscval[2] /2) ) ) * WAVE_RES >>SCALE ) % WAVE_RES ]; //oscillator1 has no tremolo osc2.phase+= (actual_freq*osc2.factor/samp_rate)>>SCALE; oscval[2] = wave[0][ ( ( osc2.phase + ( + (old_oscval[3] * 209715) >>SCALE ) ) * WAVE_RES >>SCALE ) % WAVE_RES ]; //oscillator2 has no tremolo osc3.phase+= (actual_freq*osc3.factor/samp_rate)>>SCALE; oscval[3] = wave[0][ ( osc3.phase * WAVE_RES >>SCALE ) % WAVE_RES ]; //oscillator3 has no tremolo fixed_t out = ( + osc0.output*oscval[0] + osc1.output*oscval[1] + osc2.output*oscval[2] + osc3.output*oscval[3] >>SCALE ); return out; } void Note::set_param(const parameter_t &p, fixed_t v) { oscillator_t *sel_osc=NULL; Envelope *sel_env=NULL; switch (p.osc) { case 0: sel_osc=&osc0; sel_env=env0; break; case 1: sel_osc=&osc1; /* envelope1 is disabled */ break; case 2: sel_osc=&osc2; /* envelope2 is disabled */ break; case 3: sel_osc=&osc3; /* envelope3 is disabled */ break; default: output_note("NOTE: trying to change the nonexistent oscillator"+IntToStr(p.osc)); } if ( ((p.par==ATTACK) || (p.par==DECAY) || (p.par==SUSTAIN) || (p.par==RELEASE) || (p.par==HOLD)) && sel_env==NULL ) { output_note("NOTE: cannot change parameter for envelope"+IntToStr(p.osc)+" because it's disabled"); return; } switch(p.par) { case ATTACK: sel_env->set_attack(v*samp_rate >>SCALE); break; case DECAY: sel_env->set_decay(v*samp_rate >>SCALE); break; case SUSTAIN: sel_env->set_sustain(v); break; case RELEASE: sel_env->set_release(v*samp_rate >>SCALE); break; case HOLD: sel_env->set_hold(v!=0); break; case KSR: sel_osc->ksr=float(v)/ONE; break; case KSL: sel_osc->ksl=float(v)/ONE; break; case FACTOR: sel_osc->factor=v; break; case TREMOLO: sel_osc->tremolo_depth=v; break; case TREM_LFO: sel_osc->tremolo_lfo=v; break; case VIBRATO: sel_osc->vibrato_depth=v; break; case VIB_LFO: sel_osc->vibrato_lfo=v; break; case WAVEFORM: sel_osc->waveform=v; break; case SYNC: sel_osc->sync=(v!=0); break; case MODULATION: sel_osc->fm_strength[p.index]=v*pfactor.fm[p.osc][p.index] >>SCALE; break; case OUTPUT: sel_osc->output=v*pfactor.out[p.osc] >>SCALE; break; case FILTER_ENABLED: case FILTER_ENV_AMOUNT: case FILTER_ATTACK: case FILTER_DECAY: case FILTER_SUSTAIN: case FILTER_RELEASE: case FILTER_HOLD: case FILTER_OFFSET: case FILTER_RESONANCE: case FILTER_TREMOLO: case FILTER_TREM_LFO: output_note("NOTE: trying to set some filter-param, but filter is disabled"); break; case SYNC_FACTOR: output_note("NOTE: trying to set sync_factor, but it's disabled"); break; default: throw string("trying to set an unknown parameter"); } } extern "C" NoteSkel* create_note(int n, float v,program_t &prg, jack_nframes_t pf, fixed_t pb, int prg_no) { if (wave==NULL) throw string("FATAL: trying to create a new note from a shared object without initalizing\n" " the object first! this should /never/ happen, please contact the developer"); return new Note(n,v,prg,pf,pb,prg_no); } extern "C" void init_vars(int sr, int fupfr, fixed_t **w, fixed_t **clfo, output_note_func_t* out_n, IntToStr_func_t* its) { samp_rate=sr; filter_update_frames=fupfr; wave=w; curr_lfo=clfo; IntToStr=its; output_note=out_n; }