In the previous article (part 1 of 2), we explored how to get a single column CSV [comma-separated-values] file working with Kyma. We used this single stream of numbers to generate MIDI messages that controlled pitch, amplitude, timbre, location, and note duration. This article builds upon that knowledge, adding multi-column CSV/TSV [tab-separated-values] files as parameter arrays inside Kyma.
The following article will tackle four CSV/TSV data topics.
1. Importing TSV files into the Sample Editor (data as waveform)
2. TSV controls MIDI messages (MIDI Script)
3. TSV controls EventValues (MIDI Script)
4. TSV controls spectra (MIDI Script)
Quick terminology. CSV and TSV files structure data similarly, but each use a different delimiter (comma vs. tab) within the file. It is important to note that Kyma works extremely well with TSV files. If you use multi-column CSV files, you’ll need to either convert your file to TSV (I recommend csvkit), or specify Capytalk to ignore comma characters. For purposes of this article, all example files will use TSV format.
Now’s a good time to download [link to Community Library] [but for now, download is on jpbellona] the example files. Of course, feel free to continue reading without the examples.
1. Importing TSV files in the Sample Editor (data as waveform)
The Sample Editor in Kyma 7, (File > New > Sample file), allows you to generate audio from a variety of inputs (zero, connect points, fourier, polynomial, impulse response, and data file). Using the “from data file” selection in the Generate tab (Figure 1), we can import data from a TSV file, translating our TSV data into samples of amplitude data (e.g. an audio waveform).
The column number input (Figure 2) selects which column to import, and clicking on “Insert” translates this single column into amplitude data. In the included file, ‘BobJames_1-10000.tsv’ there are two columns, each column contains 5000 points of data. To understand how TSV data is translated into amplitude information (-1 to +1), this .tsv file contains amplitude data from an audio file–the first column contain the first 5000 samples, and the second column contain another 5000 samples of audio. Click “Insert” on column 1 and watch as how the audio waveform is recreated in front of our eyes.
Listening back, we hear a kick drum.
Regardless of information from the TSV file, data is normalized between -1 and +1 in the Sample Editor. Because one data point is translated into one sample of audio, treating these files as short wavetables may be best (4096 samples anyone?)
Column 2 contains another 5000 values. Below is Figure 4 playback, with loop on.
Other non-audio data can also be imported. The next two examples use ‘grid_74_73_61_60_59_48_47_46_36_35.tsv’, which represents Palmer Drought Severity Index (PDSI) for grids within California over the last 2000 years. Each line (data point) represents a single year, and each column accounts for a different grid in California. There are 2003 data point arrays. Each array has ten values. As we import different columns of like data, we can see and hear how the PDSI index for different locations in California change, especially listening with loop on. Looped continuously, each file generates a nice, sonic texture. PDSI grids 61 and 36 (TSV columns 3 and 9) are included below.
2. TSV controls MIDI messages
Sections 2-4 describe how TSV data control different sound parameters (MIDI message, EventValues, spectra tracks) within Kyma. All three sections use the MIDI Script. While this article is not dedicated to Scripts per se, variables (?var), EventValues (!Pan), and MIDI messages, all may be controlled by TSV data from within the MIDI Script using CapyTalk. I certainly do not profess to know much about Scripts; however, we can use Scripts to translate our data arrays into sound event controls over time.
Building from the first article, we convert our entire TSV data line into an array (instead of one-column, single value variables). The conversion to data array variables takes two steps. First, we open the file and call textFileStream
when we declare our file variable.
f := 'SanFran1990-2015_rows2-5.tsv' asFilename textFileStream.
We cannot use readStream
as we want to utilize CapyTalk that will allow us to save an array of parameters in one function call. The function we want to utilize is nextParameters
.
lineValArray := f nextParameters.
nextParameters
creates an array of elements for the entire line. Since commas are considered elements within nextParameters
, be sure to only use TSV files.
The rest of the code in the Sound uses the data array to construct a MIDI message. Instead of one variable, however, there are multiple data points we may utilize within each MIDI message. To access a data point, use (ArrayName at: Index) syntax. For example,
register := ((lineValArray at: 2) roundTo: 12).
The TSV array, lineValArray, gets the second index value (2nd column of TSV) and rounds to the closest multiple of 12. In the example, we use this value for octave transposition within our MIDI note-on message. Open up the Sound “TSV_file temperature data as MIDI message” to see more examples of how the TSV values were used in the script. Audio of San Francisco Weather Data 1990-2015 is below.
Any Sound passing through a MIDI Script has its parameters available for mapping. This is especially important for mapping TSV data onto control parameters within other Sounds. One way to control parameters is to use EventValues. Inside the Sound “TSV_file controls EventValues” the MIDI Script uses two TSV data values (TSV columns 1 and 2) to control EventValues !Reverb
and !Pan
separately. EventValues !Reverb
and !Pan
reference HotValues in the Eugenio Reverb Sound passing through the MIDI Script. Here is how a data value is used to control the EventValue !Pan
.
params := f nextParameters.
pan := ((params at: 1) into: #({-2.341@0} {1.758@1}) ) abs.
self controller: !Pan slideTo: pan byTime: (line * 100) ms.
Like before, nextParameters converts the TSV line into an array (params). The next line normalizes the data (TSV column 1) to between 0 and 1. (note: I used the first column of data’s maximum and minimum (-2.341 and 1.758) to achieve this linear mapping). The data is stored into a variable (pan). The last line of code points to the EventValue !Pan
and algorithmically sets its value to our variable, pan, within 100 ms. Consecutive data points are interpolated by Kyma. Listening back, we hear how the Reverb and Pan are independently controlled by the data.
In the VCS window, !Reverb and !Pan are absent from view. (Figure 9)
This is because the MIDI Script grabbed these EventValues before they got to the VCS…. (C&K:::: Is this true? How would one display the algorithmically controlled data (e.g. EventValue) if one wanted to view values while running the Sound???)
This last example is a bit more complex. A TSV data array controls an array of spectra over time. The mapping seems pretty straight-forward, but during my initial research, I got a little over my head in CapyTalk. (A big thank you to Carla and Kurt for helping out.) In the Sound “TSV_PDSI_CA controls spectra amplitude” navigate to the SpectrumModifier Sound. The AmpScale parameter field contains the CapyTalk
TrackNumber of: {!Fader copies: 20}
The first 20 spectral tracks are copied into an array of EventValues {!Faders}. Every time point, we loop through our params array (10 points of data) and set the value for each !Fader. Our ten TSV values are used twice, once for spectra !Fader 0-9 and a second loop for spectra !Fader 10-19.
1 to: params size do: [ :i |
self controller: (i - 1 of: {!Fader copies: 20}) slideTo: ((params at: i) into: #({-3.617@0} {0@0.1} {2.186@1}) ) abs byTime: (line * 100) ms. "each line is 100 ms"
"reloop and use params for next 10 Faders too"
self controller: (i + 9 of: {!Fader copies: 20}) slideTo: ((params at: i) into: #({-3.617@0} {0@0.1} {2.186@1}) ) abs byTime: (line * 100) ms].
The Script only utilizes the first 20 spectra tracks from the OscillatorBank, even though more spectra are available. The TSV data is the Palmer Drought Severity Index (PDSI) for CA, and we are tying the data to spectral amplitudes of the sound of rain. Lower rainfall levels equate to quieter sound (lower spectral amplitudes), while the increased sound of rain equates to higher levels of rainfall.
Going a step further, the next Sound “TSV_PDSI_CA controls spectra on/off and amplitude” not only control 40 spectral tracks of amplitude, but also turns these tracks on/off depending on a threshold. As we can see inside the Script, I am reusing ten data points a bit much. However, now that one can control individual spectra with a Script, larger arrays of data points could easily be assimilated within Kyma. (e.g. 128 columns of TSV data for 128 spectral tracks)
Conclusion
As the article outlines, TSV files are just a single click (or a line of code) away from integration with Kyma. Whether data is used to algorithmically control MIDI events, EventValues, or any other type of parameter inside Kyma, one can quickly listen to data in new and interesting ways. Feel free to populate the example files [add link to Community Library] with your own data, or try inserting your data directly into Kyma’s Sample Editor (File > New > Sample File). Please leave a Reply with a link to your own TSV data sound! #csvkyma