Csound Journal — Issue 12

Csound Journal Issue 12 Cover ArtIssue 12 of the Csound Journal is now online, just in time for the holidays. Special thanks to editors James Hearon and Steven Yi for putting together another great issue.

Articles

140 Characters

Inspired by the article Hear Free Generative Music, in Archaic Twitter Haiku, made with SuperCollider at CDM, as well as this Csound Mailing List thread, I had to give 140 characters or less a try.

Listen: 140.mp3
Download: 140.csd

In order to make it work in 140 characters or less, I had to cheat. The minimum size for a CSD file in Csound is 109 characters long. So I only count characters that are embedded in the orchestra and the score. It also didn’t tweet very well. :)

Here’s what the code looks like, or least how it would look if the tweet didn’t chew it up:

instr 1
a2 expon 1,p3,.0001
a1 oscils 8000,88*(p4%9+5),1
out a1*a2
if p2<60 then
event_i "i",1,rnd(.6)+.1,4,p4+rnd(2)
endif
endin
i 1 0 1 8

To all of the artists involved with sc140, superb job!

Making Records

Not of the vinyl variety, but the computer science data structure.

Csound comes with a few ways of generating, storing and retrieving data, with function tables being the primary data structure. Data can also be placed into global variables and chn busses. In terms of data abstractions, there isn’t a whole lot of choice. However, custom data abstractions and structures can be built from within a Csound orchestra.

In my blog Simple Keys — Modularized Key Mapping, I toyed with storing multiple key bindings, frequencies, amplitudes and function table numbers within a single ftable by treating the ftable as if it were an array of records, albeit a fairly clumsy one. Over the weekend, I continued along this line and distilled it even further.

Download: simple_record.csd

So far, I’m very happy with the results. Though the implementation maybe a bit hackish, the user-interface isn’t bad. This new system of making records is composed of five user-defined opcodes: RecordType, RecordField, Record, RecordSet and RecordGet. I additionally wrote wrapper GEN instruments, so they could be accessed from the score.

The first two, RecordType and RecordField, are used to create record abstractions. RecordType creates a new record type, while RecordField appends data fields to the record type. A record type is built from an ftable, thus shares the function table number space. The following score snippet creates a record type as ftable 100, and appends three fields: amp, freq and ftable.

i $RecordType  0 1 100           ; Record type stored at fn 100
i $RecordField 0 1 100 "amp"     ; Append field "amp"
i $RecordField 0 1 100 "freq"    ; Append field "freq"
i $RecordField 0 1 100 "ftable"  ; Append field "ftable"

For a record type to be useful, an instance of it must be created with Record. A record is also an ftable, and requires its own unique function table index. The following line creates a record from record type 100, and stores it in ftable 200:

i $Record 0 1 200 100  ; Instantiate record 200 from type 100

Once a record is created, the values of each field can be set with RecordSet:

i $RecordSet 0 1 200 "amp"    0.5  ; Set field "amp"
i $RecordSet 0 1 200 "freq"   440  ; Set field "freq"
i $RecordSet 0 1 200 "ftable" 1    ; Set field "ftable"

That’s just one record created from a single record type. In the csd, you’ll see I create two more records from the same record type.

Example

The Synth instrument is provided to show a simple example on how to use a record. Instead of passing amplitude, frequency and the function number of a stored single cycle wave as pfield data, a record number is passed to Synth with pfield 4. The user-defined opcode RecordGet is used to pull data from the record. The data is then passed to oscil.

instr $Synth
    irecord = p4  ; Record function number
    iamp RecordGet "amp", irecord        ; Get amplitude from record
    ifreq RecordGet "freq", irecord      ; Get frequency from record
    iftable RecordGet "ftable", irecord  ; Get ftable from record
    a1 oscil iamp, ifreq, iftable, -1
    out a1
endin
...
i $Synth 0 1 200  ; Feed synth record 200

More on all of this later.

Simple Keys — Modularized Key Mapping

Csound can read real-time input from an ASCII keyboard with the sensekey opcode. This is a convenient solution for doing things such as emulating a musical keyboard, or triggering loops.

Since I’m always looking for ways of modularizing code, I came up with a solution that allows me to map ASCII keys using i-events instead of hard coding bindings directly to an instrument. My solution still needs a little more work, though I’m confident that the final product will be fairly elegant. Well, as elegant as things get with Csound.

You can give it a try by downloading and running simple_keys.csd. It’s a one octave sinusoidal piano, that uses the following key map (lowercase only):

 s d  g h j
z x cv b n m,

Technical Overview

Instead of explicitly mapping each key from within an instrument, I worked a little Csound ftable trickery to make it so that I could bind keys using score events. A new key map is created like this with an i-event inside the orchestra:

event_i "i", $NewKeyMap, 0, 1, i_z, cpspch(8.00), 2

The score equivalent would be:

i $NewKeyMap 0 1 122 261.62556 2

The i-variable i_z holds the value of the ASCII code for the letter “z”, which is 122. The fifth parameter is the frequency that is to be associated with “z”. The last parameter is the ftable number of a stored single cycle wave.

When instrument NewKeyMap is called, it appends these parameters to an f-table. This f-table, called record_table, acts as an array of records, where each record stores an ASCII key code, frequency and f-table number.

The Listen instrument waits and listens for key presses. Whenever a key is pressed, the ASCII code of that key is checked against every record inside of record_table. If a match is found, then an event to instrument Synth is generated. The frequency and ftable number from the record is passed along the event as pfields.

I like this approach because I can reuse these three instruments in many ways without modification. For example, I could design a microtonal version of the keyboard just by creating a different set of events to instrument NewKeyMap, and I could use different timbres by generating different wave tables.