;; performance profile (0 high, 1 low)
(bind-func cerberus_note
(lambda ()
(let ((MILLISEC (* .001 SRs))
(amp_env:|4,SAMPLE| (array 0.0:f 0.0 1.0 0.0))
(filter_env:|4,SAMPLE| (array 0.0:f 0.0 1.0 0.0))
(pitch_env:|2,SAMPLE| (array 0.0:f 0.0))
(oldfreq 440.0:f)
(tune1:SAMPLE 1.0)
(tune2:SAMPLE 1.0)
(tune3:SAMPLE 1.0)
(tune4:SAMPLE 1.0)
(osc1_wave:enum PARAM_SAW)
(osc2_wave:enum PARAM_SAW)
(osc3_wave:enum PARAM_SAW)
(osc4_wave:enum PARAM_SAW)
(pw1:SAMPLE 0.5)
(pw2:SAMPLE 0.5)
(pw3:SAMPLE 0.5)
(pw4:SAMPLE 0.5)
(noise:enum PARAM_WHITE) ;; white
(noise_amp:SAMPLE 0.0)
(osc1_amp:SAMPLE 0.25)
(osc2_amp:SAMPLE 0.0)
(osc3_amp:SAMPLE 0.0)
(osc4_amp:SAMPLE 0.0)
(osc_phase_slop 0.1)
(osc1_phase:SAMPLE (* osc_phase_slop .1 (random)))
(osc2_phase:SAMPLE (* osc_phase_slop .1 (random)))
(osc3_phase:SAMPLE (* osc_phase_slop .1 (random)))
(osc4_phase:SAMPLE (* osc_phase_slop .1 (random)))
(osc1_wt:AudioBuffer* DefaultWaveTable)
(osc2_wt:AudioBuffer* DefaultWaveTable)
(osc3_wt:AudioBuffer* DefaultWaveTable)
(osc4_wt:AudioBuffer* DefaultWaveTable)
(osc_slop:SAMPLE 0.0)
(sub_amp:SAMPLE 0.0)
(mod_amp:|4,SAMPLE|* (array_ref 1.0 1.0 1.0 1.0))
(mod_frq:|4,SAMPLE|* (array_ref -1.0 -1.0 -1.0 -1.0))
(mod_phase:|4,SAMPLE|* (array_ref 0.25 0.25 0.25 0.25))
(mod_options:|4,i32|* (array_ref 0 0 0 0))
(mod_attack:|4,SAMPLE|* (array_ref 10.0 10.0 10.0 10.0)) ;; in millis
(mod_decay:|4,SAMPLE|* (array_ref 10.0 10.0 10.0 10.0))
(mod_attack_slope:|4,SAMPLE|* (array_ref 0.0 0.0 0.0 0.0)) ;; between -1.0 log and 1.0 exp (0.0 is linear)
(mod_decay_slope:|4,SAMPLE|* (array_ref 0.0 0.0 0.0 0.0))
(lfo_types:|4,i32|* (array_ref PARAM_TRI PARAM_TRI PARAM_TRI PARAM_TRI))
(mods:|32,SAMPLE|* (alloc))
(mod_matrix:|8,|32,SAMPLE||* (alloc))
(noise_amp_mod:SAMPLE 0.0)
(filter_type:i64 2) ;; LPF2 LPF4, HPF2 HPF4, BPF2 BPF4
(follow_frq 0.0)
(follow_amp 0.0)
(legato #t) ;; if legato is true then don't retrigger adsr's!
(filter_frq:SAMPLE 15000.0) ;;
(filter_env_amt:SAMPLE 0.0) ;; this for lpf
(filter_saturation:SAMPLE 1.0) ;; 1.0-3.0
(pitch_env_amt:SAMPLE 0.0)
(portamento:SAMPLE 0.0) ;; in millis
(res:SAMPLE 0.0)
(performance_profile:i64 0) ;; high by default
(reso:SAMPLE 0.0))
(lambda (data:NoteData* nargs:i64 dargs:SAMPLE*)
(let ((starttime:i64 (note_starttime data))
(notetime:i64 starttime)
(frequency:SAMPLE (+ (note_frequency data) (* (- (random) 0.5) (note_frequency data) osc_slop 0.05)))
(target_frq:SAMPLE frequency)
(amplitude:SAMPLE (note_amplitude data))
(gate:SAMPLE (note_gate data))
(target_amp:SAMPLE amplitude)
(newampinc:SAMPLE 0.0)
(duration:i64 (note_duration data))
(onecycleinhz:SAMPLE (/ SRf (convert duration)))
(mod_frq_actual:|4,SAMPLE|* (alloc))
(mod_amp_actual:|4,SAMPLE|* (alloc))
(glideinc:SAMPLE 0.0) ;; for portamento
(midifrq:SAMPLE 0.0)
(new_note_timer:i64 0)
(lfos:|4,|8,[SAMPLE,i64,i64]*||* (alloc))
(modslocal:|32,SAMPLE|* (alloc))
(frq 0.0)
(fm4_out:SAMPLE 0.0)
(am4_out:SAMPLE 0.0)
(pm4_out:SAMPLE 0.0)
(adsr1 (adsr_c))
(adsr2 (adsr_c))
(adsr3 (adsr_c))
(adsr1_val 0.0)
(adsr2_val 0.0)
(adsr3_val 0.0)
;; (gate:SAMPLE 1.0)
(amp:SAMPLE 0.0)
(cof:SAMPLE 0.0)
(amp_attack (aref amp_env 0))
(amp_decay (aref amp_env 1))
(amp_sustain (aref amp_env 2))
(amp_release (+ 3.0 (aref amp_env 3))) ;; a 3ms release minimum
(amp_release_samples (convert (* SRs (/ amp_release 1000.0)) i64))
(reltime:i64 0)
(filter_attack (aref filter_env 0))
(filter_decay (aref filter_env 1))
(filter_sustain (aref filter_env 2))
(filter_release (aref filter_env 3))
(pitch_attack (aref pitch_env 0))
(pitch_decay (aref pitch_env 1))
(filter:[SAMPLE,SAMPLE,SAMPLE,SAMPLE]* (if (= 0 performance_profile)
(cerberus_moog_ladder_inlined (i64toi32 filter_type))
(lpf_c)))
(_osc1_phase (+ osc1_phase (* osc_phase_slop .1 (random))))
(_osc2_phase (+ osc2_phase (* osc_phase_slop .1 (random))))
(_osc3_phase (+ osc3_phase (* osc_phase_slop .1 (random))))
(_osc4_phase (+ osc4_phase (* osc_phase_slop .1 (random))))
(sin1 (osc_c _osc1_phase))
(sin2 (osc_c _osc2_phase))
(sin3 (osc_c _osc3_phase))
(sin4 (osc_c _osc4_phase))
(saw1 (blsaw_c _osc1_phase #f #f))
(saw2 (blsaw_c _osc2_phase #f #f))
(saw3 (blsaw_c _osc3_phase #f #f))
(saw4 (blsaw_c _osc4_phase #f #f))
(pulse1 (blpulse_c _osc1_phase #f))
(pulse2 (blpulse_c _osc2_phase #f))
(pulse3 (blpulse_c _osc3_phase #f))
(pulse4 (blpulse_c _osc4_phase #f))
(tri1 (bltri_c _osc1_phase))
(tri2 (bltri_c _osc2_phase))
(tri3 (bltri_c _osc3_phase))
(tri4 (bltri_c _osc4_phase))
(wt1 (AudioBuffer_shared_data osc1_wt))
(wt2 (AudioBuffer_shared_data osc2_wt))
(wt3 (AudioBuffer_shared_data osc3_wt))
(wt4 (AudioBuffer_shared_data osc4_wt))
(osc1_out:SAMPLE 0.0)
(osc2_out:SAMPLE 0.0)
(osc3_out:SAMPLE 0.0)
(osc4_out:SAMPLE 0.0)
(tmpmod:|32,SAMPLE|* null)
(tmpval:SAMPLE 0.0)
(tmp:SAMPLE 0.0)
(useosc1 #t)
(useosc2 #f)
(useosc3 #f)
(useosc4 #f)
(usesub #f)
(usenoise #f)
(zero:SAMPLE 0.0)
(white (white_c))
(pink (pink_c))
(noisef (if (= noise PARAM_WHITE) white pink))
(sub_out 0.0)
(noise_out 0.0)
(subosc (osc_c 0.0))
(main_out 0.0:f)
(i:i64 0)
(j:i64 0))
(dotimes (i 4)
(cerberus_create_lfos lfos i frequency onecycleinhz mod_amp mod_frq mod_phase mod_options mod_attack mod_decay mod_attack_slope mod_decay_slope))
(if (= 0 performance_profile) (filter.saturation (clamp filter_saturation 1.0:f 3.0:f)))
;; (if (> osc1_amp 0.001) (set! useosc1 #t)) ;; always
(if (> osc2_amp 0.001) (set! useosc2 #t))
(if (> osc3_amp 0.001) (set! useosc3 #t))
(if (> osc4_amp 0.001) (set! useosc4 #t))
(if (> sub_amp 0.001) (set! usesub #t))
(if (> noise_amp 0.001) (set! usenoise #t))
(lambda (time:i64 chan:i64)
(if (= chan 0)
(begin
(set! notetime (tref data 7)) ;; look for voice steeling
;; this for voice steeling
(if (and (<> starttime notetime) (>= time notetime))
(begin
;; (println "steeling voice:" (convert (frq2midi frequency) i64) "for" (note_frequency data))
(if (not legato)
(begin
(set! amplitude (note_amplitude data)) ;; reset envelopes
(retrigger_adsr adsr1) (retrigger_adsr adsr2) (retrigger_adsr adsr3)))
;; (note_starttime data (tref data 7))
(set! starttime (tref data 7)) ;(note_starttime data))
(set! target_frq (note_frequency data))
(set! glideinc (/ (- target_frq frequency) (* portamento 0.001 SRf)))
(if (< portamento 0.001) (set! frequency target_frq))
(AudioBuffer_set_phase wt1 0.0)
(AudioBuffer_set_phase wt2 0.0)
(AudioBuffer_set_phase wt3 0.0)
(AudioBuffer_set_phase wt4 0.0)
(set! reltime 0)
(set! gate 1.0) ;(note_gate data))
(set! duration (note_duration data))
(set! onecycleinhz (/ SRf (convert duration)))
(dotimes (i 4)
(cerberus_reset_lfos lfos i target_frq onecycleinhz mod_phase mod_options))))
;; voice steeling done
(if (> (fabs (- target_frq frequency)) 0.125) ;; 1/8 hz
(set! frequency (+ frequency glideinc)))
(if (and (> gate 0.5) (> (- time starttime) duration)) (set! gate 0.0))
;; (if (and (> (note_gate data) 0.5) (> (- time starttime) duration)) (note_gate data 0.0)) ;; (set! gate 0.0))
(set! adsr1_val (adsr1 chan gate amp_attack amp_decay amp_sustain amp_release))
(set! adsr2_val (adsr2 chan gate filter_attack filter_decay filter_sustain filter_release))
(set! adsr3_val (adsr3 chan gate pitch_attack pitch_decay 0.0 0.0))
;; calc local mod matrix changes
(begin
(memcpy (cast modslocal i8*) (cast mods i8*) 128)
(dotimes (i 3)
(set! tmp ((aref (aref-ptr lfos i) (aref lfo_types i)) chan i))
(set! tmpmod (aref-ptr mod_matrix (+ i 4))) ;; only get 'note' lfos
(dotimes (j 19) (aset! modslocal j (+ (aref modslocal j) (* tmp (aref tmpmod j)))))
void)
;; the 4th lfo is a modulator
(set! tmp ((aref (aref-ptr lfos 3) (aref lfo_types 3)) chan 3))
(set! tmpmod (aref-ptr mod_matrix (+ 3 4))) ;; only get 'note' lfos
(dotimes (j 19)
(set! tmpval (aref tmpmod j))
(if (> tmpval 0.0)
(aset! modslocal j (* (aref modslocal j) (* tmp (aref tmpmod j))))))
)
(set! amp (* amplitude adsr1_val))
(set! cof (clamp (+ filter_frq (* follow_frq 8.0 frequency) (* follow_amp amplitude 12000.0)
(aref modslocal PARAM_FILTER_FRQ)
(* filter_env_amt adsr2_val))
0.0 22000.0))
(set! res (+ reso (aref modslocal PARAM_FILTER_RES)))
(set! frq (+ frequency (* pitch_env_amt frequency adsr3_val) 0.0))
;; (if (< frq 10.0) (set! frq 10.0))
;; if gate is OFF and amp is sufficiently close to 0.0 then stop note!
(if (< gate 0.1) (set! reltime (+ reltime 1)))
(if (> reltime amp_release_samples)
(if (< amp 0.01)
(note_active data #f) ;; stop note if amp less than 0.01
(begin (set! amplitude (- amplitude 0.01)) #t))) ;; otherwise decrease amplitude over max 100 samples
;; setup mod sources
(if useosc1
(begin
(set! osc1_out (* (+ osc1_amp (aref modslocal PARAM_OSC1_AMP))
(cond ((= osc1_wave 0) (sin1 1.0 (+ (* tune1 frq) (aref modslocal PARAM_OSC1_FRQ))))
((= osc1_wave 1) (saw1 1.0 (+ (* tune1 frq) (aref modslocal PARAM_OSC1_FRQ))))
((= osc1_wave 2) (pulse1 1.0 (+ (* tune1 frq) (aref modslocal PARAM_OSC1_FRQ))
(+ pw1 (aref modslocal PARAM_OSC1_PW))))
((= osc1_wave 3) (tri1 1.0 (+ (* tune1 frq) (aref modslocal PARAM_OSC1_FRQ))))
((= osc1_wave 4) (AudioBuffer_read_interp_pw wt1
(+ (* tune1 frq) (aref modslocal PARAM_OSC1_FRQ))
0
(+ pw1 (aref modslocal PARAM_OSC1_PW))))
(else zero))))))
(if useosc2
(begin
(set! osc2_out (* (+ osc2_amp (aref modslocal PARAM_OSC2_AMP))
(cond ((= osc2_wave 0) (sin2 1.0 (+ (* tune2 frq) (aref modslocal PARAM_OSC2_FRQ))))
((= osc2_wave 1) (saw2 1.0 (+ (* tune2 frq) (aref modslocal PARAM_OSC2_FRQ))))
((= osc2_wave 2) (pulse2 1.0 (+ (* tune2 frq) (aref modslocal PARAM_OSC2_FRQ))
(+ pw2 (aref modslocal PARAM_OSC2_PW))))
((= osc2_wave 3) (tri2 1.0 (+ (* tune2 frq) (aref modslocal PARAM_OSC2_FRQ))))
((= osc2_wave 4) (AudioBuffer_read_interp_pw wt2
(+ (* tune2 frq) (aref modslocal PARAM_OSC2_FRQ))
0
(+ pw2 (aref modslocal PARAM_OSC2_PW))))
(else zero))))))
(if useosc3
(begin
(set! osc3_out (* (+ osc3_amp (aref modslocal PARAM_OSC3_AMP))
(cond ((= osc3_wave 0) (sin3 1.0 (+ (* tune3 frq) (aref modslocal PARAM_OSC3_FRQ))))
((= osc3_wave 1) (saw3 1.0 (+ (* tune3 frq) (aref modslocal PARAM_OSC3_FRQ))))
((= osc3_wave 2) (pulse3 1.0 (+ (* tune3 frq) (aref modslocal PARAM_OSC3_FRQ))
(+ pw3 (aref modslocal PARAM_OSC3_PW))))
((= osc3_wave 3) (tri3 1.0 (+ (* tune3 frq) (aref modslocal PARAM_OSC3_FRQ))))
((= osc3_wave 4) (AudioBuffer_read_interp_pw wt3
(+ (* tune3 frq) (aref modslocal PARAM_OSC3_FRQ))
0
(+ pw3 (aref modslocal PARAM_OSC3_PW))))
(else zero))))))
(if useosc4
(begin
(set! osc4_out (* (+ osc4_amp (aref modslocal PARAM_OSC4_AMP))
(cond ((= osc4_wave 0) (sin4 1.0 (+ (* tune4 frq) (aref modslocal PARAM_OSC4_FRQ))))
((= osc4_wave 1) (saw4 1.0 (+ (* tune4 frq) (aref modslocal PARAM_OSC4_FRQ))))
((= osc4_wave 2) (pulse4 1.0 (+ (* tune4 frq) (aref modslocal PARAM_OSC4_FRQ))
(+ pw4 (aref modslocal PARAM_OSC4_PW))))
((= osc4_wave 3) (tri4 1.0 (+ (* tune4 frq) (aref modslocal PARAM_OSC4_FRQ))))
((= osc4_wave 4) (AudioBuffer_read_interp_pw wt4
(+ (* tune4 frq) (aref modslocal PARAM_OSC4_FRQ))
0
(+ pw4 (aref modslocal PARAM_OSC4_PW))))
(else zero))))))
(if usesub (set! sub_out (subosc sub_amp (* frq 0.25))))
(if usenoise (set! noise_out (* 0.5 (+ noise_amp (aref modslocal PARAM_NOISE_AMP)) (noisef))))
(set! main_out (* amp (filter
(+ osc1_out
osc2_out
osc3_out
osc4_out
sub_out
noise_out)
cof reso)))))
main_out))))))