(local pxl8 (require :pxl8)) (var time 0) (var step 0) (var ctx nil) (var params nil) (var bass-params nil) (var playing false) (local melody [60 64 67 72 67 64 60 64 67 72 76 72 67 64 62 66 69 74 69 66 62 66 69 74 78 74 69 66]) (local bass [36 50 40 36 38 38 50 38]) (local step-duration 0.15) (fn init [] (set ctx (pxl8.sfx_context_create)) (local delay (pxl8.sfx_delay_create {:time_l 350 :time_r 500 :feedback 0.4 :mix 0.25})) (local reverb (pxl8.sfx_reverb_create {:room 0.5 :damping 0.5 :mix 0.3})) (local compressor (pxl8.sfx_compressor_create {:threshold -12 :ratio 4 :attack 10 :release 100})) (pxl8.sfx_context_append_node ctx delay) (pxl8.sfx_context_append_node ctx reverb) (pxl8.sfx_context_append_node ctx compressor) (pxl8.sfx_mixer_attach ctx) (set params (pxl8.sfx_voice_params {:waveform pxl8.SFX_WAVE_TRIANGLE :attack 0.005 :decay 0.08 :sustain 0.0 :release 0.05 :filter_type pxl8.SFX_FILTER_LOWPASS :filter_cutoff 2500 :filter_resonance 0.15 :filter_attack 0.005 :filter_decay 0.1 :filter_sustain 0.1 :filter_release 0.05 :filter_env_depth 1500 :fx_send 0.3})) (set bass-params (pxl8.sfx_voice_params {:waveform pxl8.SFX_WAVE_SQUARE :attack 0.005 :decay 0.1 :sustain 0.0 :release 0.05 :filter_type pxl8.SFX_FILTER_LOWPASS :filter_cutoff 600 :filter_resonance 0.2 :fx_send 0.2}))) (fn start [] (set playing true) (set time 0) (set step 0)) (fn stop [] (set playing false) (pxl8.sfx_stop_all ctx)) (fn update [dt] (when playing (set time (+ time dt)) (when (>= time step-duration) (set time (- time step-duration)) (local note (. melody (+ 1 (% step (length melody))))) (pxl8.sfx_play_note ctx note params 0.4) (when (= (% step 4) 0) (local bass-note (. bass (+ 1 (% (math.floor (/ step 4)) (length bass))))) (pxl8.sfx_play_note ctx bass-note bass-params 0.35)) (set step (+ step 1))))) {:init init :start start :stop stop :update update :is-playing (fn [] playing)}