DSP Study Group - Reading audio data from WAV-files
Exploration from the Scicloj DSP Study Group Second meeting - Nov. 08th 2025 and some follow-up investigation
Welcome! These are notes from our second study group session, where we’re learning digital signal processing together using Clojure. We’re following the excellent book Think DSP by Allen B. Downey (available free online).
Huge thanks to Professor Downey for writing such an accessible and free introduction to DSP, and for sharing with us the work-in-progress notebooks of Think DSP 2.
Along with this study group came the idea to have an online creative coding festival around Clojure in the first months of 2026. In this meeting we spent some time brainstorming on how that might look and what the scope could be. The remaining time of the session we looked into downloading and reading WAV-files in Clojure.
Why WAV Files?
The notebooks in Think DSP 2 work with WAV files loaded from GitHub as a basis for further processing, so we need a way to load these as well. After obtaining the file, we need to get at the audio data it contains.
Simplified WAV Format
First, let’s take a superficial look at what data WAV files contain, before we dive into getting the data. A simple WAV file consists of a header and pure audio data following it. There are several iterations on specifications for the WAV format and the format allows for quite some flexibility in placing different metadata in the file, as well as different encodings.
The WAV (Waveform Audio File Format) file format is a RIFF (Resource Interchange File Format) file which stores data in chunks. Each chunk consists of a tag and data. Lets consider a partial example, which corresponds to the way the WAV file we want to read is arranged:
The header comprises of the tag RIFF, its chunk tagged with the specific format WAVE and a subchunk fmt , which describes the contained audio data. This represents some of the header information in a WAV file with a single, 16-bit mono sound channel and 44.100 samples per second.
As we learned in the first session of the DSP study group:
Sound waves are continuous vibrations in the air. To work with them on a computer, we need to sample them - take measurements at regular intervals. The sample rate tells us how many measurements per second. CD-quality audio uses 44,100 samples per second.
These samples are stored in the WAV files data tagged subchunk. Since this is mono sound, there is one frame with one channel per sample. For multiple channels, each frame consists of all channels and their respective sample.
Libraries We’re Using
- Kindly - Visualization protocol that renders our data as interactive HTML elements (through Clay)
- dtype-next - Efficient numerical arrays and vectorized operations (like NumPy for Clojure)
- Tablecloth - DataFrame library for data manipulation and transformation
- Tableplot - Declarative plotting library built on Plotly
- javax.sound.sampled - Some classes from the Java standard libraries sound package to read WAV Files.
(require '[scicloj.kindly.v4.kind :as kind]
'[clojure.java.io :as io]
'[tech.v3.datatype.functional :as dfn]
'[tablecloth.api :as tc]
'[scicloj.tableplot.v1.plotly :as plotly])(import '(javax.sound.sampled AudioFileFormat
AudioInputStream
AudioSystem)
'(java.io InputStream)
'(java.nio ByteBuffer
ByteOrder))Downloading a WAV File
(defn copy [uri file]
(with-open [in (io/input-stream uri)
out (io/output-stream file)]
(io/copy in out)))(copy tuning-fork-url tuning-fork-path) clojure.core/eval core.clj: 3232
...
dsp.wav-files/eval159546 REPL Input:
dsp.wav-files/copy REPL Input:
...
clojure.java.io/input-stream io.clj: 124
clojure.java.io/input-stream io.clj: 139
clojure.java.io/fn/G io.clj: 72
clojure.java.io/fn io.clj: 259
clojure.java.io/fn/G io.clj: 72
clojure.java.io/fn io.clj: 242
java.net.URL.openStream URL.java: 1325
sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream HttpsURLConnectionImpl.java: 223
sun.net.www.protocol.http.HttpURLConnection.getInputStream HttpURLConnection.java: 1632
sun.net.www.protocol.http.HttpURLConnection.getInputStream0 HttpURLConnection.java: 2030
java.io.FileNotFoundException: https://github.com/AllenDowney/ThinkDSP/raw/master/code/18871__zippi1__sound-bell-440hz.wav
source: src/dsp/wav_files.clj