Introducción a la programación en Python
clase 14

Python y Csound (II) - Csound en Python

A través de su API (Application Programming Interface), Csound puede ser importado como un módulo de Python.
De esta manera se puede utilizar todo el motor de síntesis de Csound dentro de un programa escrito en Python, mediante el uso del módulo csnd6.

IMPORTANTE: el módulo csnd6 sólo puede ser importado por Python2.

Mediante esta técnica se pueden desarrollar aplicaciones completas que utilicen el motor de Csound para la generación de sonido.

También puede utilizarse esta facilidad para generar algorítmicamente bloques de código de orquesta y/o de partitura y compilarlos con Csound, todo desde un mismo programa de Python.
Para este tipo de aplicación es suficiente conocer las llamadas básicas para crear y utilizar instancias del objeto Csound.

Ejemplo 14.1

El siguiente programa es un ejemplo mínimo del uso del objeto Csound para compilar una orquesta ya existente.

In [5]:
# ejemplo 1

# se importa el módulo csnd6
import csnd6

c = csnd6.Csound()    # se crea una instancia del objeto Csound
c.Compile('test.csd') # se compila una orquesta de Csound existente
c.Perform()           # se ejecuta la instancia de Csound
c.Stop()              # se finaliza

En este caso la llamada c.Stop() es innecesaria, porque la ejecución termina al finalizar la orquesta. Pero en otros casos es necesaria, y por lo tanto es una buena práctica incluirla siempre.

Ejemplo 14.2

En el ejemplo siguiente, la orquesta y la partitura están definidas dentro del mismo programa, como variables de tipo string.

Las llamadas respectivas son CompileOrc() para compilar la orquesta, y ReadScore para compilar la partitura.

Al tratarse de cadenas de caracteres, es necesaria la llamada a .Start() antes de la llamada a .Perform().

In [7]:
# ejemplo 2

# se importa el módulo csnd6
import csnd6

# se define la orquesta y la partitura como variables de tipo string

# la orquesta es una cadena multilínea
orc = """
sr    =    48000
ksmps =    8
0dbfs =    1

instr 1

iamp    init    ampdbfs(p4)
ifrec   init    p5

kamp    linen   iamp, .01, p3, .05
asig    vco2    kamp, ifrec

    out asig

endin
"""

sco = "i1 0 3 -6 300"

c = csnd6.Csound()
c.SetOption("-odac")  # SetOption() establece opciones de compilación (una por cada llamada)

c.CompileOrc(orc)  # se compila la cadena con la orquesta
c.ReadScore(sco)   # se compila la cadena con la partitura
c.Start()          # cuando se compila de cadenas, es necesaria esta llamada antes de Perform()
c.Perform()
c.Stop()

La llamada SetOption() establece las opciones de la línea de comando (flags). Este método admite un único argumento, por lo que es necesario una llamada por cada opción que se quiera pasar a Csound.

Ejemplo 14.3

En el ejemplo siguiente la cadena de la partitura se genera mediante un loop.

En primer término se define una función que crea una cadena con formato de evento i de Csound, a partir de un iterable (lista o tuple) con los p-fields. El número de intrumento (p1) y el offset temporal para sumar a p2 se pueden recibir como argumentos opcionales (por defecto 1 y 0 respectivamente).

El loop genera elementos con p2 incremental, p3 y p4 fijos, y p5 aleatorio.

In [4]:
# ejemplo 3

import csnd6
import random

# se define la orquesta como variable de tipo string
orc = """
sr    =    48000
ksmps =    8
0dbfs =    1

instr 1

iamp    init    ampdbfs(p4)
ifrec   init    cpsmidinn(p5)   ; p5 en número de nota MIDI

print ifrec

kamp    linen   iamp, .01, p3, .05
asig    vco2    kamp, ifrec

    out asig

endin
"""

# función para generar un evento de Csound a partir de un iterable con p-fields 
def csnd_event(pfields, instr=1, offset=0):
    '''convierte una lista o tuple con p-fields en un evento de csound'''
    pfields = list(pfields)
    pfields[0] += offset # desplazamiento del init-time 
    evento = "i" + str(instr) + "\t" + "\t".join(str(i) for i in pfields) + "\n"
    return evento

# crea una cadena vacía para la partitura
sco = ""
dur = .12
# agrega eventos a la partitura mediante un loop
for i in range(50):
    a = csnd_event([i*dur, dur, -3, random.randint(48, 72)]) # p5 aleatorio
    sco += a

c = csnd6.Csound()
c.SetOption("-odac")

c.CompileOrc(orc)
c.ReadScore(sco)
c.Start()
c.Perform()
c.Stop()

Como la función csnd_event puede ser útil en otras oportunidades, resulta conveniente incluirla en un módulo que pueda ser luego importado por otros programas que necesiten la misma funcionalidad.

In [11]:
%load csound_tools.py
In []:
# función para generar un evento de Csound a partir de un iterable con p-fields 
def csnd_event(pfields, instr=1, offset=0):
    '''convierte una lista o tuple con p-fields en un evento de csound'''
    pfields = list(pfields)
    pfields[0] += offset # desplazamiento del init-time 
    evento = "i" + str(instr) + "\t" + "\t".join(str(i) for i in pfields) + "\n"
    return evento

En el módulo csound_tools podemos incluir en el futuro otras funciones relacionadas que puedan ser reutilizadas.

Ejemplo 14.4

En el ejemplo siguiente se incorpora la función desarrollada oportunamente para generar una melodía isorrítmica a partir de una talea y un color.

In [10]:
# ejemplo 4

import csnd6
import csound_tools as cs # se importa el módulo con la función csnd_event()

# se define la orquesta como variable de tipo string
orc = """
sr    =    48000
ksmps =    8
0dbfs =    1

instr 1

iamp    init    .5
ifrec   init    cpsmidinn(p4)   ; p4 en número de nota MIDI

print ifrec

kamp    linen   iamp, .01, p3, .05
asig    vco2    1, ifrec
afilt   moogladder asig, 4000, 0.3

    out afilt*kamp

endin
"""

def isorritmico(talea, color, t_inicial=0):
    '''crea una melodía isorrítmica a partir de una talea y un color'''

    # extiende las secuencias para que tengan la misma cantidad de elementos
    clen, tlen = len(color), len(talea)
    talea_rep = talea * clen
    color_rep = color * tlen
    tiempos = [t_inicial]
    for i in range(len(talea_rep)-1):
        tiempos.append(tiempos[i]+talea_rep[i])
    # crea la lista de notas como tuples (tiempo inicial, altura, duración)
    notas = [(z, x, y) for z, x, y in zip(tiempos, talea_rep, color_rep)]
    return notas

talea = [1.25, 0.75, 0.5, 0.25, 0.5]
color = [72, 62, 59, 56, 67, 70, 66, 57, 63, 76, 73, 65]

notas = isorritmico(talea, color)

# crea una partitura con indicación de tempo
sco = "t0 92\n"

for nota in notas:
    evento = cs.csnd_event(nota)
    sco += evento

c = csnd6.Csound()
c.SetOption("-odac")

c.CompileOrc(orc)
c.ReadScore(sco)
c.Start()
c.Perform()
c.Stop()

Otros recursos

Steven Yi: Csound 6 - Python API Examples
https://github.com/csound/csoundAPI_examples/tree/master/python

François Pinot: Real-time Coding Using the Python API: Score Events
Csound Journal - Issue 14, 2011
http://www.csounds.com/journal/issue14/realtimeCsoundPython.html

Cadenas de Markov