Reading audio files in Extempore
Extempore’s AudioBuffer library bindings provide functionality for reading and
playing back audio files. Here’s a short example of how to read audio files.
First, load the audiobuffer.xtm library and create an AudioBuffer variable:
(sys:load "libs/core/audiobuffer.xtm")
(bind-func dsp:DSP
(let ((ab (AudioBuffer "assets/samples/christmas_carol.aif")))
(lambda (in time chan dat)
(AudioBuffer_read ab chan))))
(dsp:set! dsp)
Once you run the code, you should hear the (long-ish) christmas carol audio file
start playing (in stereo). Notice that in the body of the dsp closure there’s
no explicit mention of where in the file we’re up to, because the current
“playhead” is stored in the AudioBuffer type.
You can play back from a different position in the file by supplying an extra
argument to AudioBuffer_read. For example, this (slightly weird) playback
approach will only advance the playhead 10% of the time:
(bind-func dsp:DSP
(let ((ab (AudioBuffer "assets/samples/christmas_carol.aif"))
(pos 0))
(lambda (in time chan dat)
(if (< (random) 0.1:f)
(set! pos (+ pos 1)))
(AudioBuffer_read ab pos chan))))
All the AudioBuffer_read functions will stop playback when they reach the end
of the audio data from the file. If you’d like to loop the audio file instead,
you can use AudioBuffer_read_looped
One other thing to say here is that AudioBuffer is both the name of the
(overloaded) constructor function and the name of the type which holds the audio
data and metadata. AudioBuffer is a polymorphic function, and there are
versions for e.g. reading files with non-standard samplerates, and copying audio
data from other AudioBuffer variables, but the simple case (shown above) just
takes a single filename argument and returns an initialised AudioBuffer object
(the audio data is heap-allocated).
To mess with this audio stream, let’s add a low-pass filter to the left channel, and a high-pass filter to the right channel (both with the resonance paramater cranked right up).
;; need to load this library as well to get the lpf/hpf
(sys:load "libs/core/audio_dsp.xtm")
(bind-func dsp:DSP
(let ((ab (AudioBuffer "assets/samples/christmas_carol.aif"))
(lp (lpf_c))
(hp (hpf_c)))
(lambda (in time chan dat)
(cond ((= chan 0)
(lp (AudioBuffer_read ab chan) 400. 0.99))
((= chan 1)
(hp (AudioBuffer_read ab chan) 5000. 0.99))
(else 0.0:f)))))
If you’re looking for more options for messing with the signal at this low
level, have a look at the functions in the audio_dsp.xtm library.