Sonification
Coding Project
Objectives
- Establishing a workflow for editing and testing algorithms in webchuck
- Exploring Chuck unit generators (UGens) and applying simple oscillators (with frequency, amplitude and timbre changes)
- Understanding data mapping functions and iteration in Chuck
- Exploring data sonification
Key Results
- Code experimentation with the new webchuck IDE (running examples, customizing them)
- Using your own datasets and uploading them into webchuck IDE sessions
- Synthesizing using oscillators (or other sound producing) UGens
- Performing the synthesizer using your time series
- Exploring data mappings between the time series data and synthesis parameters
- Saving work to your Gihub site
- Exporting your webchuck project to a one-click webapp
- Sharing finished webapps via links and attachments
Live code experiments
The page shown here (NOAA CO2 level sonification) has a live code editor. It is a one-click, one-file webapp that should run anywhere. Experiment with the suggested modifications.
Live code modifications can't be saved directly from the page. To save, you'll need to download the page to your local machine, open it in an editor, manually copy and paste mods that were made, save, and then open the modified version in a browser.
However, there's a better way! Use the webchuck IDE. We'll run the IDE in a browser on your local machine and store two files in a directory of your choice, also on your local machine.
Download a data file and a chuck file: co2_mm_mlo_2024.csv and sonify.ck (you might need to right-click and "save link as").
Open the webchuck IDE in a separate tab or window and bring in the two files by clicking File : Upload Files. Select sonify.ck
and hit the Start Webchuck button to start the chuck virtual machine, and then the green play button to start playing the sonification. The red button stops program execution.
Really Quick Tutorial - Chuck script
Let's break it down. What does this do?
SinOsc osc => dac;
SinOsc
is a class of oscillator and we're instantiating one of those and naming the instance,osc
dac
is a special UGen which is our sound output, aka digital-to-analog converter
osc
is wired todac
so we can hear the tone
But for how long? rows
is the number of data points in the time series.
for (0 => int i; i < rows; i++) {
...
10::ms => now;
}
The script completes after the last iteration. Total duration =
rows * 10ms
At each iteration the frequency of the oscillator gets updated.
osc.freq(val[i]); // data values in parts per million mapped directly to frequency in hertz
Handling Time Series Data
Now is the time to pick interesting datasets to sonify. You can choose whatever you want, but for starters stay close to the format of the present example. It has 2 columns, with a single line header. The columns are both floating point numbers.
Let's assume that a new .csv file gets downloaded to your local computer to your working directory. If the data values in the second column are not appropriate for frequency values, do a mapping adjustment. For example, scale the range and / or offset the range by adding a constant.
osc.freq(val[i] * 2.0 + 1000.0); // scale by 2.0 and offset by 1000.0 hertz
Up to this point, we've been ignoring the date column in the .csv file. Timing of updates has been a constant 10 ms but this can be made data dependent. If data samples are irregularly spaced in time, for example, then calculating the next update time in the performance loop can be derived from time stamps in the date[]
array.
Create a Composition
Once you have a basic synthesizer and have mapped the dataset, now it's time for some creativity. Try to draw out the character or the unique quality of a dataset. Or simply make some music with the material.
The simple example provided is monophonic
in that it only plays one "voice" at a time. The oscillator gain is by default set to the maximum amplitude -- 1.0. If adding more sound generators / oscillators that play at the same time, be sure to reduce gains, so that the total doesn't exceed the 1.0 maximum signal, otherwise clipping distortion will occur.
This a non-exhaustive list of variables for experimentation in monophonic
texture
- The number of generators
- The frequency, amplitude and timbre of generators
- The harmonic relation between generators
- Generator event timing depends on data value
Exploring polyphonic
textures
- Generator start times differ (staggered patterns)
- Each generator's tempo or event timing gets set differently (so generators' events aren't at the same time))
- Generators play different patterns, best if the patterns are sporked as separate shreds See Concurrency & Shreds in the Chuck documentation and the code examples
spork.html
andsporkTwice.html
included in the starter project directory you can reference.
Happy sonifying!
Webapp Export
You'll need a github pages repository that can serve your data to the world. See the instructions.
Under the webchuck IDE's File menu, choose Export To : WebChuck to produce a standalone html page containing your work. This is a fully functional webapp that can be shared with others via links and attachements.
The export feature does not yet include the data file your sonification depends on, so some steps are required to make if fully standalone.
Save your csv file to your github repository and make sure that it is accessible from a URL (for example, by navigating to the URL from a browser). Above we used https://cchafe.github.io/soniServer/co2_mm_mlo_2024.csv
for the initial example. Parsing that URL, it's https://USER.github.io/REPOSITORY/FILENAME
Edit one item in the javascript code in the html page that you exported from the webchuck IDE. This needs to be done in a text editor that shows the internal page code rather than in webchuck IDE. (some text editors need to be told to show the code rather than display the html page)
Where it shows:
action.addEventListener('click', async () => {
window.theChuck ??= await Chuck.init([]);
Add these arguments to the Chuck.init
call so that it downloads your data file from your github repository:
action.addEventListener('click', async () => {
window.theChuck ??= await Chuck.init(
[
{
serverFilename: 'https://cchafe.github.io/soniServer/co2_mm_mlo_2024.csv',
virtualFilename: 'co2_mm_mlo_2024.csv'
}
]
);
serverFilename
is the URL for the data file
virtualFilename
specifies the name by which it's referenced in the chuck code (can be different)
https://cchafe.github.io/soniServer/sonifyShare.html
Click me to see it in action.
Browsers and Caches
Beware of browser caches where what you see is not up to date with what you've changed. For example, suppose you've made an edit and displayed or uploaded it, but there's no effect from the change that was made to the file. The browser may still be hanging on to the earlier version when displaying the page. To force it to forget the older version, use the Ctrl + Shift + Delete command and confirm your intent to "clear" recent history. Then do a Ctrl + r to refresh the page. (On Mac, substitute Cmd for Ctrl in these commands.)