Randomly sending one of several AudioBuffers to dsp:DSP

6 views
Skip to first unread message

George

unread,
Jan 24, 2026, 4:38:55 PM (12 days ago) Jan 24
to Extempore
Hi all
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.



Reply all
Reply to author
Forward
0 new messages