;; where mix is 0.0-1.0 and mixes between buf1 and buf2
(bind-func AudioBuffer_read_interp_mix
(lambda (buffer:AudioBuffer* buffer2:AudioBuffer* freq:SAMPLE chan:i64 mix:float)
(let ((channels:i64 (AudioBuffer_channels buffer))
(frames (AudioBuffer_frames buffer))
(looplgth (AudioBuffer_loop_frames buffer))
(loopstart (AudioBuffer_loop_start buffer))
(oneshot (= looplgth 0))
(segments (if oneshot 0 (/ frames looplgth)))
(phase:double (AudioBuffer_phase buffer))
(rate (/ (convert freq) (convert (midi2frq_local (convert (AudioBuffer_root_pitch buffer))))))
(pos:double phase)
(lgth:i64 (if oneshot
(- (- frames 1) loopstart)
(clamp looplgth
0
(- frames loopstart))))
(lgthf:double (convert lgth))
(dat1 (AudioBuffer_ptr buffer (clamp loopstart 0 (- frames looplgth)) chan))
(dat2 (AudioBuffer_ptr buffer2 (clamp loopstart 0 (- frames looplgth)) chan))
(dy1 0.0) (dx0 0.0) (dx1 0.0) (dx2 0.0)
(y1 0.0)
(y1pos:i64 (* channels (convert (floor (% (- pos rate) lgthf)))))
(x0 0.0)
(x0pos:i64 (* channels (convert (floor pos))))
(x1 0.0)
(x1pos:i64 (* channels (convert (floor (% (+ pos rate) lgthf)))))
(x2 0.0)
(x2pos:i64 (* channels (convert (floor (% (+ pos rate rate) lgthf))))))
(set! mix (fabs mix))
(if (> pos lgthf) 0.0
(begin
(set! dy1 (- (pref dat2 y1pos) (pref dat1 y1pos)))
(set! y1 (if (and oneshot (< x0pos 1)) 0.0 (+ (pref dat1 y1pos) (* dy1 mix))))
(set! dx0 (- (pref dat2 x0pos) (pref dat1 x0pos)))
(set! x0 (+ (pref dat1 x0pos) (* dx0 mix)))
(set! dx1 (- (pref dat2 x1pos) (pref dat1 x1pos)))
(set! x1 (+ (pref dat1 x1pos) (* dx1 mix)))
(set! dx2 (- (pref dat2 x2pos) (pref dat1 x2pos)))
(set! x2 (+ (pref dat1 x2pos) (* dx2 mix)))
(if (= chan 0) ;; increment phase
(AudioBuffer_set_phase buffer
(if oneshot
(+ pos rate)
(% (+ pos rate) lgthf))))
;; return interpolated result
(hermite_interp_local (dtof (% pos 1.0)) y1 x0 x1 x2))))))