Custom Sequence List Generators

Python’s built-in range() list generator is full of possibilities when used in conjunction with Slipmat’s @ scheduler. And that’s just one generator out of, dare I say, a million possibilities.

Imagine being able to conveniently import generators from a massive user library of modules. This will be a reality for Slipmat for two reasons:

I built a list generator called range_plus(), which takes Python’s range() function a few steps farther. range() is limited to integers; range_plus() removes this restriction and allows for floats. range() supports a single increment step value; range_plus() additionally allows users to pass a list of increment step values that are chosen at random.

Here’s the working Python defintion for range_plus():

def range_plus(start, stop, random_steps=1):
    '''
    Returns a list of successive incremented values
    chosen randomly from a list.

    Input:
    start -- Starting value
    stop --  End point
    random_steps -- A list of incremental values chosen at random or a
        single numeric value
        
    Output:
    return -- A numeric list
    '''
    
    if stop < start:  # Avoid infinite loop from bad input
        return []

    if not isinstance(random_steps, list):
        random_steps = [random_steps]

    L = []

    while start < stop:
        L.append(start)
        start = start + random.choice(random_steps)

    return L

I made sure to write the docstrings, to make life easier for anyone who may import my code later. Here's a Python interpreter session to test out some numbers:

>>> from MyListGenerators import range_plus
>>> range_plus(0, 4, 0.5)
[0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5]
>>> range_plus(0, 4, [0.25, 0.25, 0.5, 0.75])
[0, 0.5, 1.0, 1.5, 1.75, 2.5, 3.0, 3.25, 3.75]

As applied to music, range_plus() would be a perfect fit for randomly generating rhythmic patterns, for things such as hi-hats.

@0  @range_plus(0, 4, [0.25, 0.25, 0.5, 0.75]) hat()
@4  @range_plus(0, 4, [0.25, 0.25, 0.5, 0.75]) hat()
@12 @range_plus(0, 4, [0.25, 0.25, 0.5, 0.75]) hat()
@16 @range_plus(0, 4, [0.25, 0.25, 0.5, 0.75]) hat()

Here's is one scenario for what those patterns would look like in trigger notation:

Bar 1:  x.x. x.xx ..x. xx.x
Bar 2:  xx.. x..x ..x. .xx.
Bar 3:  x..x ..x. xx.x .x..
Bar 4:  x.x. .xxx .xxx x..x

The 'x' is a 16th note trigger, the '.' is a 16th note rest, and spaces are used to distinguish between each quarter note.

Music and Visuals

If slipmat at its core is a general purpose programming language augmented with advanced timing and scheduling capabilities, then slipmat would be well suited for both music and visuals.

This isn’t really too much of a stretch. Audio unit generators won’t be built into the core language, but instead will be stored as separate modules and imported as needed; The same would be true for visual modules. Musical GUI elements such as sliders are already visual in nature. There are existing audio/visual systems out in the wild, such as Max/MSP/Jitter and Impromptu. Various functions and objects designed for music could also be applied to visuals; The same envelope that controls frequency can be used to control the position of a circle:

t = 10                          # time = 10 beats
my_circle = Circle(0, 200, 15)  # x position, y position, radius
env = line(0, t, 1)             # start value, duration, end value
sine(1.0, 440 * env)            # amp, frequency
my_circle.xpos(env * 400)       # x position over time

The example is a bit crude and omits many practical things, but the idea of syncing visuals with audio is there.

Beyond music and visuals, anything that is time-based would theoretically work in slipmat, providing a module is written.

Roll Your Own Score Syntax

A music language that comes with a fully-loaded set of string capabilities, including regular expressions, would allow users to develop their own methods for notating music. For example, here is a horizontal representation for rhythm guitar.

@0  strum('C',  '/... /... /./. /...')
@4  strum('Dm', '/... /... //// /./.')
@8  strum('G7', '/... /... ///. ../.')
@12 strum('C',  '/... /... /... ///.')

The slash triggers an event and advances time by a 16th note. The dot just advances time by a 16th note. A space does nothing.

These 4 lines of code represent 24 events. Not only does this shorten the score and save keystrokes, but is far more readable than if each individual event was explicitly written. In fact, I bet there are many guitar players out there that could play this as it’s written, providing he or she was given a brief explanation about the notation.

What about a system for triggering drums? Here’s the all-to-familiar 4-beat rock pattern with 8th note hats.

trigger(hat(),   'x.x. x.x. x.x. x.x.')
trigger(snare(), '.... x... .... x...')
trigger(kick(),  'x... .... x... ....')

Once again, the music is notated horizontally. Instead of 12 lines of code, there are only 3. Let’s take a look at the vertical equivalent:

@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()

In theory, people could write slipmat modules that mimic other text-based notation systems, such as the Csound score language.

import CsoundScore as CS
from MyLibrary import bassFM
from MyLibrary import pad

# For mapping slipmat instruments to a Csound-styled score
instrs = {"i1": bassFM(), "i2": pad()}

# A Csound-styled score
score = '''
i 1 0 2 0.5 7.00
i 1 + . .   6.05

i 2 0 8 0.333 8.09 0.77 1000
'''

CS.playScore(instrs, score)  # Play Csound-styled score

That would translate to:

@0 bassFM(2, 0.5, 7.00)
@2 bassFM(2, 0.5, 6.05)
@0 pad(8, 0.333, 8.09, 0.77, 1000)

Much of this can be done with some of the existing music languages out in the wild. The guitar strum and drum trigger examples can be accomplished in pure Csound code (see dseq — A Drum Machine Micro-Language). Even more so, Csound combined with the Python API can do some truly amazing things along these lines. Though it probably wouldn’t be nearly as fluid as a language that had this in mind when being designed from the ground up.

If you haven’t done so yet, take a moment to ponder the possibilities. And be sure to think about the things others will dream up that can be simply imported into your own compositions/synthesizers/sequencers/etc…