Introducing “Python Score” for Csound

PYTHON SCORE is a Python script for Csound score generation and processing. With it you will compose music easily and efficiently. No computer should be without one!

This effort has been weeks in the making, if you disregard the 10+ years I’ve spent creating various Csound score utilities I’ve coded up in Perl, Python, C and Java. Much of the focus on this project is directed at keeping the score familiar to Csounders, integrating Python with the Csound score using the CsScore bin feature, and removing as much unnecessary clutter. For example, you won’t need to open and close any files in your programs, Python Score handles it for you. And I’m attempting to keep the point of entry easy as possible for all; You’ll only need to know tiny bit of Python to get started.

Python Score is currently part of the Csound CSD Python library, though it will receive its own repository in the future. Here are the highlights. More information will follow.

The score() function

The first priority of Python Score is to allow traditional Csound score composers to transition into this new score environment in a near seamless fashion. Csounders will be able to use the full breadth of their knowledge of the traditional score they’ve acquired over the years. With the score() function, Csounders accomplish just that. The following example (test.csd) is a complete CsScore section in a Csound csd file:

<CsScore bin="python pysco.py">

score('''
f 1 0 8192 10 1
t 0 189

i 1 0 0.5 0.707 9.02
i 1 + .   .     8.07
i 1 + .   .     8.09
i 1 + .   .     8.11
i 1 + .   .     9.00
i 1 + .   .     8.09
i 1 + .   .     8.11
i 1 + .   .     8.07
''')

</CsScore>

A Csounder has successfully transitioned into this new environment once they’ve learned how to setup the call in the CsScore tag using the bin feature and embed their traditional Csound score code in a score() function. Once this has taken place, the composer is now only a step away from a plethora of new features to include in their arsenal of computer music tools.

The “cue” Object

Where as the score() function makes it easy for Csounders to make the leap into Python Score, the “cue” object is what makes it worthwhile. That and all the goodness Python brings to the mix.

The “cue” object enables composers to utilize nested programming techniques for placing events in time, similar to for-loops and if-then conditional branching. This allows composers to do things such as think-in-time localized to a measure rather than the absolute time of the global score.

The “cue” object works by translating the start values in pfield 2. Consider the following line of code:

score('i 1 0 4 0.707 8.00')

Looking at p-field 2, the event takes place at beat 0. By utilizing the “cue” object using the Python “with” statement, we can move the start time of the event without ever touching p-field 2. The follow block of code plays the same event at beat 64 in the score.

with cue(64):
    score('i 1 0 4 0.707 8.00')

The “cue” is a bit like a flux capacitor, as it makes time travel possible. Or at minimum, it saves a composer time, and lots of it, since they can easily move small and/or large sections of score, in time, without changing each and every value in the p-field 2 column. Notes, licks, phrases, bars, sections, entire compositions, etc… All of these time-based musical concepts benefit from the organizational power of the “cue”.

The following example from test10.csd shows the first three measures of Bach’s Invention 1. The beginning of each measure is designated by the use of a “with cue(t)” statement. Since the native time of the Csound score is in beats, and the fact that the piece is in 4/4, the values used with the “cue” object are multiples of 4.

with cue(0):
    score('''
    i 1 0.5 0.5 0.5 8.00
    i 1 +   .   .   8.02
    i 1 +   .   .   8.04
    i 1 +   .   .   8.05
    i 1 +   .   .   8.02
    i 1 +   .   .   8.04
    i 1 +   .   .   8.00
    ''')

with cue(4):
    score('''
    i 1 0 1    0.5 8.07
    i 1 + .    .   9.00
    i 1 + 0.25 .   8.11
    i 1 + 0.25 .   8.09
    i 1 + 0.5  .   8.11
    i 1 + .    .   9.00

    i 1 0.5 0.5 0.5 7.00
    i 1 +   .   .   7.02
    i 1 +   .   .   7.04
    i 1 +   .   .   7.05
    i 1 +   .   .   7.02
    i 1 +   .   .   7.04
    i 1 +   .   .   7.00
    ''')

with cue(8):
    score('''
    i 1 0 0.5 0.5 9.02
    i 1 + .   .   8.07
    i 1 + .   .   8.09
    i 1 + .   .   8.11
    i 1 + .   .   9.00
    i 1 + .   .   8.09
    i 1 + .   .   8.11
    i 1 + .   .   8.07

    i 1 0 1 0.5 7.07
    i 1 + . 0.5 6.07
    ''')

The “cue” also acts as a stack, meaning you can nest multiple “with cue(t)” statements. The following score event happens at 21.05. That is 16 + 4 + 1 + 0.05.

with cue(16):
    with cue(4):
        with cue(1):
            with cue(0.05):
                score('i 1 0 1 0.707 8.00')

P-field Converters

Csound is loaded with value converters. Though all of these exist in the orchestra side of Csound and there is currently no Csound mechanism to apply value converters to the score. Unless you count macros, but these are limiting. Two functions have been created to allow composers to apply pfield converters, either from an existing library or to create their own. These functions are p_callback() and pmap().

The p_callback() function registers a user-selected function that is applied to a selected pfield for a selected instrument. This registered function is applied when the score() function is called.

The pmap() function works similarly, except that it applies a user-selected function to everything already written to the score. Think of it is a post-score processor, while p_callback() is a pre-score processor.

The example (test2.csd) demonstrates two functions: conv_to_hz() which translates conventional notation into hz, and dB() which translates decibel values into standard amplitude values. Both of these are located in convert.py.

<CsScore bin="./pysco.py">

p_callback('i', 1, 5, conv_to_hz)

score('''
f 1 0 8192 10 1
t 0 120

i 1 0 0.5 -3 D5
i 1 + .   .  G4
i 1 + .   .  A4
i 1 + .   .  B4
i 1 + .   .  C5
i 1 + .   .  A4
i 1 + .   .  B4
i 1 + .   .  G5
''')

pmap('i', 1, 4, dB)

</CsScore>

What else?

The functions presented so far are just the basic mechanisms included in Python Score to help solve specific score related issues. Beyond these there is Python. Having a true mature scripting language at your disposal opens up score creation an processing in ways that Csound alone could never do on it’s own. What Python offers will be the topic of many follow up posts and examples to come.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>