# x Trigger Notation

In Roll You Own Syntax, I theorized how users could construct their own systems of notation using strings. I’ve constructed a working function, called trig(), to show how it’s done.

First, let’s see trig() in action. The following is complete conceptual prototype Slipmat program that generates a rock drum groove with 8th note hats:

#!/usr/bin/env slipmat

from JakeLib.Generators import trig
from EasyKit import hat, snare, kick

@trig('x.x. x.x. x.x. x.x.') hat()
@trig('.... x... .... x...') snare()
@trig('x... .... x... ....') kick()

This horizontal system for notating triggers, and others like it, can greatly improve the legibility of a piece, while catering to a composer’s preferred style of working. A composer quickly scans this and comprehends it without having to reconstruct it in their head from a list of individual events:

@0    hat()
@0    kick()
@0.5  hat()
@1    hat()
@1    snare()
@1.5  hat()
@2    hat()
@2    kick()
@2.5  hat()
@3    hat()
@3    snare()
@3.5  hat()

The form is lost in translation.

Building the function is pretty straight forward if you’re somewhat experienced with Python. I put together the following function definition, with docstrings, in roughly 15 minutes:

def trig(seq, res=0.25):
'''
Creates a numeric sequence from a string and returns a list.

Description:
A string trigger sequencer, where an 'x' creates a trigger, and a
'.' creates a rest. All other glyphs are ignored. The resolution
of triggers and rests are determined by the argument res.

Input:
seq -- A string containing a sequence of 'x' triggers and '.' rests
res -- Resolution of note triggers and rests

Output:
return -- A numeric list
'''

L = []  # The return list
p = 0   # Position in sequence

for c in seq:
if c == 'x':
L.append(p * res)
p += 1
elif c == '.':
p += 1

return L

The trig() function accepts a string formatted in what I call ‘x trigger notation.’ The function parses the string and auto-generates a list of numbers representing trigger times. A trigger is denoted by an ‘x’, while a rest is a ‘.’. All other glyphs are ignored. I use a single space between beats for clarity. The default resolution is a 16th note, though trig() accepts an optional argument for changing the resolution, increasing its usefulness.

Import, Reuse, Remix

The best part about custom functions is that they can be reused multiple times in multiple programs by multiple people with the use of the import. No refactoring of code, no copy and paste, no reinventing of the wheel. Just import, reuse, remix.

About 12 years ago, someone told me that additive synthesis will never be practical. My initial reaction was, “we’ll see about that.” This person’s background was that of modular subtractive synths, and was quite knowledgeable. From that perspective, I could see their point. Who want’s to take the time to create complex envelopes for each individual harmonic? My mind has often wondered back to this incident.

Today, additive synths are becoming more common thanks to faster computers. Many of their UIs do help programmers with the large amounts of complexity additive brings to the table. And there are many useful and valid approaches, each with their own strengths and weaknesses.

My approach has been floating around my head on and off for about a decade. The first iteration was completed around 2002, and was shelved until recently. Today’s csd is a continuation of the second iteration of the design, which I had originally intended to use with Fragments (see here), but ran out of time. For the next couple of weeks, I plan on taking this instrument to its illogical conclusion (I have no idea what it’ll be like when it’s done.) When I am finished, I’ll write an in depth article for The Csound Journal on the final design.

The premise for my approach is to use f-tables as a shortcut for specifying and controlling additive synth data. In today’s example, the audio generator produces a 32 band-limited sawtooth wave. However, before the sine waves are generated with oscil, the synth data is run through two transfer functions, stored as f-tables. One transfer function changes the amplitudes of the harmonics, emulating the EQ of a virtual acoustic body. The other bends the frequencies, causing frequency distortions. Frequencies continue to be processed by the transfer functions, even as they are modulated, which I believe is key to convincing acoustic viability.

The reason why this sounds similar to a bowed stringed instrument is because the amplitude transfer function is filled with the right amount of bipolar noise. The truth is, I had no intention of creating a string-like sound. I was just toying with it and thought I’d try something drastic like using a table filled with noise. After the discovery, I spent considerable time tweaking the values trying to get it to sound a little bit more expressive.

I should warn you, there are some clear cases of aliasing occurring in today’s example. I think I know what’s causing it, but I’ll have to go back and run some tests to be certain. In the mean time, I hope you enjoy.