From 7113f02ae87482211aec5046f9ac46c3cc9ad017 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Wed, 29 Dec 2010 16:55:25 +0100 Subject: Initial commit --- synth/note.cpp | 437 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 437 insertions(+) create mode 100644 synth/note.cpp (limited to 'synth/note.cpp') diff --git a/synth/note.cpp b/synth/note.cpp new file mode 100644 index 0000000..87f1806 --- /dev/null +++ b/synth/note.cpp @@ -0,0 +1,437 @@ +#include +#include + +#include "note.h" +#include "globals.h" +#include "defines.h" + +using namespace std; + +//this function returns the smallest phase_init possible for a +//given custom_wave which is greater or equal than PHASE_INIT +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; + + n_oscillators=prg.n_osc; + + + pfactor.out=new fixed_t [n_oscillators]; + pfactor.fm=new fixed_t* [n_oscillators]; + for (int i=0;iwave_len, oscillator[i].custom_wave->samp_rate); + else + oscillator[i].phase=ONE * PHASE_INIT; + } + + + portamento_frames=0; + set_portamento_frames(pf); + + set_note(n); + freq=dest_freq; + set_vel(v); + do_ksl(); + + pitchbend=pb; + + program=prg_no; + + filter_params=prg.filter_settings; + orig.filter_params=prg.filter_settings; + + if (filter_params.enabled) + { + filter_envelope=new Envelope( + filter_params.env_settings.attack, + filter_params.env_settings.decay, + filter_params.env_settings.sustain, + filter_params.env_settings.release, + filter_params.env_settings.hold ); + + filter_update_counter=filter_update_frames; + } + + sync_factor=prg.sync_factor; + sync_phase=0; +} + +Note::~Note() +{ + int i; + + for (i=0;ipfactor.filter_env, vel); + pfactor.filter_res=calc_pfactor(curr_prg->pfactor.filter_res, vel); + pfactor.filter_offset=calc_pfactor(curr_prg->pfactor.filter_offset, vel); + + for (int i=0;ipfactor.out[i], vel); + + for (int j=0;jpfactor.fm[i][j], vel); + } +} + +void Note::apply_pfactor() +{ + //apply pfactor to all necessary parameters + for (int i=0;i>SCALE; + + for (int j=0;j>SCALE; + } + filter_params.env_amount=orig.filter_params.env_amount*pfactor.filter_env /ONE; + filter_params.freqfactor_offset=orig.filter_params.freqfactor_offset*pfactor.filter_offset /ONE; + filter_params.resonance=orig.filter_params.resonance*pfactor.filter_res /ONE; +} + +void Note::set_param(const parameter_t &p, fixed_t v) //ACHTUNG: +{ + //wenn das verändert wird, muss auch program_t::set_param verändert werden! + switch(p.par) + { + case ATTACK: envelope[p.osc]->set_attack(v*samp_rate >>SCALE); break; + case DECAY: envelope[p.osc]->set_decay(v*samp_rate >>SCALE); break; + case SUSTAIN: envelope[p.osc]->set_sustain(v); break; + case RELEASE: envelope[p.osc]->set_release(v*samp_rate >>SCALE); break; + case HOLD: envelope[p.osc]->set_hold(v!=0); break; + + case KSR: oscillator[p.osc].ksr=float(v)/ONE; break; + case KSL: oscillator[p.osc].ksl=float(v)/ONE; break; + + case FACTOR: oscillator[p.osc].factor=v; break; + case MODULATION: oscillator[p.osc].fm_strength[p.index]=v*pfactor.fm[p.osc][p.index] >>SCALE; break; + case OUTPUT: oscillator[p.osc].output=v*pfactor.out[p.osc] >>SCALE; break; + case TREMOLO: oscillator[p.osc].tremolo_depth=v; break; + case TREM_LFO: oscillator[p.osc].tremolo_lfo=v; break; + case VIBRATO: oscillator[p.osc].vibrato_depth=v; break; + case VIB_LFO: oscillator[p.osc].vibrato_lfo=v; break; + case WAVEFORM: oscillator[p.osc].waveform=v; break; + case SYNC: oscillator[p.osc].sync=(v!=0); break; + + case FILTER_ENABLED: output_note("NOTE: cannot enable filter in playing notes"); break; + case FILTER_ENV_AMOUNT: filter_params.env_amount=float(v*pfactor.filter_env)/ONE/ONE; break; + + case FILTER_ATTACK: + if (filter_params.enabled) + filter_envelope->set_attack(v*samp_rate/filter_update_frames >>SCALE); + else + output_note("NOTE: cannot set filter-attack when filter is disabled"); + break; + + case FILTER_DECAY: + if (filter_params.enabled) + filter_envelope->set_decay(v*samp_rate/filter_update_frames >>SCALE); + else + output_note("NOTE: cannot set filter-decay when filter is disabled"); + break; + + case FILTER_SUSTAIN: + if (filter_params.enabled) + filter_envelope->set_sustain(v); + else + output_note("NOTE: cannot set filter-sustain when filter is disabled"); + break; + + case FILTER_RELEASE: + if (filter_params.enabled) + filter_envelope->set_release(v*samp_rate/filter_update_frames >>SCALE); + else + output_note("NOTE: cannot set filter-release when filter is disabled"); + break; + + case FILTER_HOLD: + if (filter_params.enabled) + filter_envelope->set_hold(v!=0); + else + output_note("NOTE: cannot set filter-hold when filter is disabled"); + break; + + case FILTER_OFFSET: filter_params.freqfactor_offset=float(v*pfactor.filter_offset)/ONE/ONE; break; + case FILTER_RESONANCE: filter_params.resonance=float(v*pfactor.filter_res)/ONE/ONE; break; + case FILTER_TREMOLO: filter_params.trem_strength=v; break; + case FILTER_TREM_LFO: filter_params.trem_lfo=v; break; + + case SYNC_FACTOR: sync_factor=v; break; + default: throw string("trying to set an unknown parameter"); + + } +} + +bool Note::still_active() +{ + for (int i=0; i0) && (envelope[i]->still_active())) + return true; + + return false; +} + + +//this function must still work properly if called multiple times +//when called a second time, there shall be no effect +void Note::release_quickly(jack_nframes_t maxt) +{ + for (int i=0;iget_release() > maxt) + envelope[i]->set_release(maxt); + + envelope[i]->release_key(); + + // i don't release the filter-env because lacking to do so + // does not generate a hearable difference (or would you hear + // when in the last half second a tone is filtered or not?) + } +} + +void Note::release() +{ + for (int i=0;irelease_key(); + + if (filter_params.enabled) + filter_envelope->release_key(); +} + +void Note::reattack() +{ + for (int i=0;ireattack(); +} + +void Note::set_pitchbend(fixed_t pb) +{ + pitchbend=pb; +} + +void Note::set_freq(float f) +{ + old_freq=freq; + dest_freq=f*ONE; + portamento_t=0; + + do_ksr(); +} + +void Note::set_freq(float f, bool do_port) +{ + set_freq(f); + + if (!do_port) + old_freq=dest_freq; +} + +void Note::set_note(int n) +{ + note=n; + set_freq(440.0*pow(2.0,(float)(n-69)/12.0)); +} + +void Note::set_note(int n, bool do_port) +{ + note=n; + set_freq(440.0*pow(2.0,(float)(n-69)/12.0), do_port); +} + +int Note::get_note() +{ + return note; +} + +void Note::set_vel(float v) +{ + vel=v*ONE; + + recalc_factors(); + apply_pfactor(); +} + +void Note::do_ksl() +{ //osc.ksl is in Bel/octave (i.e. dB/10) + //if ksl=1, this means that for each octave the loudness + //decreases by half + for (int i=0;iset_max(ONE); + else + envelope[i]->set_max( fixed_t(double(ONE) / pow(freq>>SCALE, oscillator[i].ksl)) ); + } +} + +void Note::do_ksr() +{ + for (int i=0;iset_ratefactor(1.0 / pow(freq>>SCALE, oscillator[i].ksr)); +} + +void Note::set_portamento_frames(jack_nframes_t t) +{ + portamento_frames=t; + portamento_t=0; +} + +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; + + fixed_t fm=0; + fixed_t out=0; + + int i,j; + + if (sync_factor) + { + sync_phase+=(actual_freq*sync_factor/samp_rate) >> SCALE; + + if (sync_phase >= ONE) + { + sync_phase-=ONE; + + for (i=0;iwave_len, oscillator[i].custom_wave->samp_rate); + else + oscillator[i].phase=ONE * PHASE_INIT; + } + } + } + + for (i=0;i>SCALE; + + //phase increases in one second, i.e. in samp_rate frames, by the osc's freq + if (oscillator[i].vibrato_depth!=0) + oscillator[i].phase+=( (curr_lfo[oscillator[i].vibrato_lfo][oscillator[i].vibrato_depth]*actual_freq >>SCALE)*oscillator[i].factor/samp_rate)>>SCALE; + else + oscillator[i].phase+=(actual_freq*oscillator[i].factor/samp_rate)>>SCALE; + + if (oscillator[i].custom_wave) + { + //sampler + custom_wave_t *cw=oscillator[i].custom_wave; + oscval[i]=cw->wave[ ((oscillator[i].phase + fm) * cw->samp_rate >>(2*SCALE)) % cw->wave_len ] * envelope[i]->get_level() >> (SCALE); + } + else + { + //normal oscillator + oscval[i]=wave[oscillator[i].waveform][ ((oscillator[i].phase + fm) * WAVE_RES >>SCALE) % WAVE_RES ] * envelope[i]->get_level() >> (SCALE); + } + + if (oscillator[i].tremolo_depth!=0) + oscval[i]=oscval[i]* curr_lfo[oscillator[i].tremolo_lfo][oscillator[i].tremolo_depth] >> SCALE; + + if (oscillator[i].output!=0) + out+=oscillator[i].output*oscval[i] >>SCALE; + } + + if (filter_params.enabled) + { + filter_update_counter++; + if (filter_update_counter>=filter_update_frames) + { + filter_update_counter=0; + + float cutoff= float(actual_freq)/ONE * + float(curr_lfo[filter_params.trem_lfo][filter_params.trem_strength])/ONE * + ( filter_params.freqfactor_offset + filter_envelope->get_level() * filter_params.env_amount / float(ONE) ); + filter.set_params( cutoff, filter_params.resonance ); + } + + fixed_t tmp=out; + filter.process_sample(&tmp); + return tmp; + } + else + { + return out; + } +} -- cgit v1.2.3