I have been experimenting with a number of Audio wav files and have been able
to make different files play on each re-evaluation of the dsp:DSP
Also I have been able to get a callback loop to automate the re-evaluation.
The complete file is on my gist:
https://gist.github.com/georgejwright/f5803a34b4dbf2d413563cee45389f26(sys:load "libs/core/audio_dsp.xtm")
(sys:load "libs/core/audiobuffer.xtm")
;; Load 10 AudioBuffers
;; a collection of AudioBuffers
(bind-val abuf0 AudioBuffer* (AudioBuffer "tmp/Mouth organ.wav"))
;; ....
;; ....
(bind-val abuf9 AudioBuffer* (AudioBuffer "tmp/Filling_Pipe_16.wav"))
;; Put all these buffers into an array - halloc'ed
(bind-val all-buffers |10,AudioBuffer*|* (halloc)) ;; SetValue: all-buffers >>> |10,AudioBuffer*|*
;; Fill the array
($ (afill! all-buffers abuf0 abuf1 abuf2 abuf3 abuf4 abuf5 abuf6 abuf7 abuf8 abuf9))
;; On each re-evaluation a different random buffer may be chosen
;; Note: AudioBuffer_read and AudioBuffer_read_interp behave differently from AudioBuffer_read_looped
(bind-func dsp:DSP
(let (
(array-index (imp_rand2_i64 0 10))
(ab (aref all-buffers array-index)))
; (setPlayhd_Phase all-buffers) ;; see note below
(AudioBuffer_set_playhead ab 0)
(AudioBuffer_set_phase ab 0.)
(lambda (in time chan dat)
(AudioBuffer_read_looped ab chan))))
(dsp:set! dsp)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Automate the re-evaluations
(bind-func change_array_index ;; change_array_index >>> [AudioBuffer*,i64]*
(lambda (array-index:i64)
(dsp.ab (aref all-buffers array-index))
))
(define retrigger-loop
(lambda (time index)
; ($ (setPlayhd_Phase all-buffers)) ;; Start all playheads at zero. See note below
(change_array_index
($ (imp_rand2_i64 0 10))) ;; i64 is sent to change_array_index
(callback time 'retrigger-loop (+ time (* 4 *second*)) 10))) ;; loop every 4 seconds
(retrigger-loop (now) ($ (imp_rand2_i64 0 10)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; An xtlang function to reset phase and playhead
(bind-func reset_Buffer:[AudioBuffer*,i64]* ;; change_array_index >>> [AudioBuffer*,i64]*
(lambda (array-index:i64)
(AudioBuffer_set_phase (aref all-buffers array-index) 0.0)
(AudioBuffer_set_playhead (aref all-buffers array-index) 0) ;; could reset to a different index
(aref all-buffers array-index)
))
;; Set all the playheads and phase to zeros
(bind-func setPlayhd_Phase
(lambda (buffers:|10,AudioBuffer*|*)
(let (
(k:i64 0))
(dotimes (k 10)
(reset_Buffer:[AudioBuffer*,i64]* k)))))
($ (setPlayhd_Phase all-buffers)) ;; This will set all playheads to zero
;; If using plain AudioBuffer_read or AudioBuffer_read_interp
;; the buffers will all be silently stuck at end of file after some time
;; Evaluate the above setPlayhd_Phase to bring them all back to being readable.
;; Alternatively the (setPlayhd_Phase all-buffers) can be included within the dsp
;; However - depending on the callback time - some buffers will never play to end
;; and keep repeating the beginning samples.