Looping Sections of an AudioBuffer

21 views
Skip to first unread message

George

unread,
Dec 6, 2025, 4:45:16 PM12/6/25
to Extempore
Andrew
I have not followed up on your suggestion of implementing a version of AudioBuffer_read but I followed your hint that "AudioBuffer_read_interp (and friends) look like they do".
In fact the read-interp version does exactly what I was looking for!
(I'll post the audio file below)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; AudioBuffer_read_interp  has looping built-in

;; I opened the file "tmp/Tom&Greg_Devil_Deal.wav" in Audacity.app and found
;; starting points (frames) of 7 phrases
;; Laboriously copied the starting point and the length of each spoken phrase.
;; In xtlang I generated two vectors: one with 7 i64 integer starting points and
;; one with 7 i64 phrase lengths.
;; Then I randomly chose one of these starting points and the corresponding
;; phrase length.
;; Using AudioBuffer_set_loop_start and AudioBuffer_set_loop_frames I could
;; repeatedly play the selected phrase.

;; On re-evaluating the dsp:DSP code a different phrase may be selected and will
;; loop until another re-evaluation

(bind-func dsp:DSP
  (let ((ab dealWthDevl)
        (vStart:|7,i64|* (alloc))    ;; starting points (frames)
        (vFrame:|7,i64|* (alloc))    ;; representing loop-lengths (frames)
        (array-index (imp_rand1_i64 7)))   ;;
    (afill! vStart  24073 332207 505532 852183 1283089 1791028 2019721)
    (afill! vFrame  308134 175732 187769 334614 286468 113043 247951)
    (AudioBuffer_set_phase ab 0.0)
    (lambda (in time chan dat)
      (AudioBuffer_set_loop_start ab (aref vStart array-index)) ; silent pos
      (AudioBuffer_set_loop_frames ab (aref vFrame array-index)) ;; match length
      (AudioBuffer_read_interp ab (* 1.0 261.6) chan))))

(dsp:set! dsp)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

I have attempted to run a callback loop that re-evaluates the dsp:DSP code at regular intervals without success.
Also attempted to generate the arrays once only outside the dsp:DSP but ran into trouble with bad types.
Would appreciate some help with that.

Regards
George

George

unread,
Dec 6, 2025, 5:14:49 PM12/6/25
to Extempore
Andrew
The file is too big to post here.
I'll Try to find another way.
Or I could send it direct if you give me an address.
George

C K Kashyap

unread,
Dec 6, 2025, 8:04:16 PM12/6/25
to extemp...@googlegroups.com
To join the meeting on Google Meet, click this link: https://meet.google.com/jfu-hawj-dxm

Or open Meet and enter this code: jfu-hawj-dxm

--
You received this message because you are subscribed to the Google Groups "Extempore" group.
To unsubscribe from this group and stop receiving emails from it, send an email to extemporelan...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/extemporelang/9381681b-f050-4825-9998-f2d6348e7cebn%40googlegroups.com.

George

unread,
Jan 8, 2026, 8:13:07 PM (14 days ago) Jan 8
to Extempore

Hi all
I have worked out how to get the callback to retrigger the above dsp at regular intervals.
;; See for example:
;; https://github.com/digego/extempore/blob/81b1193dac2dd60f4cb51999c85a7cb9ce1f2bf0/examples/core/audio_101.xtm#L100
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; An xtlang function that changes the array-index function defined in the let in dsp:DSP
(bind-func change-index
  (lambda (array-index:i64)
    (dsp.array-index  (imp_rand2_i64 0 7)))) ; (imp_rand2_i64 0 7)

;; a "normal scheme" temporal recursion loop
;; for event level control

(define retrigger-loop
  (lambda (time index)
    (change-index
                  ($ (imp_rand2_i64 0 7)))
    ; (println (now))
    (callback time 'retrigger-loop (+ time (* 10 *second*)) 10))) ;; loop every 10 seconds

(retrigger-loop (now) ($ (imp_rand2_i64 0 7)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
In addition I have worked out how to avoid repeatedly creating and filling new arrays.
Now using halloc instead of alloc I build and fill the arrays just once outside the dsp.
;; Define phrase start positions and lengths using heap allocation for persistence
(bind-val phrase-starts |7,i64|* (halloc))
(bind-val phrase-lengths |7,i64|* (halloc))
($ (afill! phrase-starts 24073 332207 505532 852183 1283089 1791028 2019721))
($ (afill! phrase-lengths 308134 175732 187769 334614 286468 113043 247951))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(bind-func dsp:DSP
  (let ((ab dealWthDevl)
        ; (vStart:|7,i64|* (alloc))    ;; Don't need this now
        ; (vFrame:|7,i64|* (alloc))
        (array-index (imp_rand2_i64 0 7) ))   
    ; (afill! vStart  24073 332207 505532 852183 1283089 1791028 2019721) ;; already done
    ; (afill! vFrame  308134 175732 187769 334614 286468 113043 247951)

    (AudioBuffer_set_phase ab 0.0)
    (lambda (in time chan dat)
      (AudioBuffer_set_loop_start ab (aref phrase-starts array-index)) ;; a silent position
      (AudioBuffer_set_loop_frames ab (aref phrase-lengths array-index)) ;; phrase-length

      (AudioBuffer_read_interp ab (* 1.0 261.6) chan))))

(dsp:set! dsp)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

The complete file is on my Gists:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
The file "tmp/Tom&Greg_Devil_Deal.wav"  is too big to load here.
I can send it direct if anyone wants it.

However I think any wav audio file will do but you will have to do the work of gathering phrase data yourself.

Regards
George

Tim Roberts

unread,
Jan 9, 2026, 3:52:54 AM (13 days ago) Jan 9
to extemp...@googlegroups.com
Hey George,
While it’s hazy in my memory, this is something that I was dealing with in the TSM library. I remember getting confused because the function appeared to be processing each sample individually, but was actually being called on a buffer of samples.
Hopefully there’s enough documentation around my code for it to be useful. I think I ended up creating my own buffer that I would fill and draw from.
Cheers,
Tim

--
You received this message because you are subscribed to the Google Groups "Extempore" group.
To unsubscribe from this group and stop receiving emails from it, send an email to extemporelan...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages