Csound: CONTROLSTRUCTURES
In a way, control structures are the core of a programming language. The fundamental element in each language is the conditional if branch. Actually all other control structures like for-, until- or while-loops can be traced back to if-statements.
En cierto modo, las estructuras de control son el núcleo de un lenguaje de programación. El elemento fundamental en cada lengua es el condicional si rama. En realidad, todas las demás estructuras de control como for-, until o while-loops pueden rastrearse hasta if-statements.
So, Csound provides mainly the if-statement; either in the usual if-then-else form, or in the older way of an if-goto statement. These will be covered first. Though all necessary loops can be built just by if-statements, Csound's while, until and loop facility offer a more comfortable way of performing loops. They will be introduced later, in the Loop and the While / Until section of this chapter. Finally, time loops are shown, which are particulary important in audio programming languages.
Por lo tanto, Csound proporciona principalmente la instrucción if; Ya sea en la forma usual if-then-else, o en la forma más antigua de una sentencia if-goto. Estos serán cubiertos en primer lugar. Aunque todos los bucles necesarios pueden ser construidos por if-statements, Csounds while, hasta y loop facility ofrecen una forma más cómoda de realizar bucles. Se presentarán más adelante, en la sección Loop y en la sección While / Until de este capítulo. Finalmente, se muestran los bucles de tiempo, que son particularmente importantes en los lenguajes de programación de audio.
The fundamental difference in Csound between i-time and k-time which has been explained in chapter 03A, must be regarded very carefully when you work with control structures. If you make a conditional branch at i-time, the condition will be tested just once for each note, at the initialization pass. If you make a conditional branch at k-time, the condition will be tested again and again in each control-cycle.
La diferencia fundamental en Csound entre i-time y k-time que se ha explicado en el capítulo 03A, debe considerarse con mucho cuidado cuando se trabaja con estructuras de control. Si realiza una rama condicional en i-time, la condición se probará una vez para cada nota, en el paso de inicialización. Si usted hace una rama condicional en k-tiempo, la condición será probada una y otra vez en cada ciclo de control.
For instance, if you test a soundfile whether it is mono or stereo, this is done at init-time. If you test an amplitude value to be below a certain threshold, it is done at performance time (k-time). If you get user-input by a scroll number, this is also a k-value, so you need a k-condition.
Por ejemplo, si prueba un archivo de sonido si es mono o estéreo, esto se hace a init-time. Si se prueba un valor de amplitud por debajo de cierto umbral, se realiza en el tiempo de ejecución (k-time). Si obtiene la entrada de usuario por un número de desplazamiento, esto también es un valor k, por lo que necesita una condición k.
Thus, all if and loop opcodes have an "i" and a "k" descendant. In the next few sections, a general introduction into the different control tools is given, followed by examples both at i-time and at k-time for each tool.
Por lo tanto, todos los opcodes if y loop poseen un i y un descendiente k. En las siguientes secciones, se proporciona una introducción general a las diferentes herramientas de control, seguida de ejemplos tanto en i-tiempo como en k-time para cada herramienta.
The use of the if-then-else statement is very similar to other programming languages. Note that in Csound, "then" must be written in the same line as "if" and the expression to be tested, and that you must close the if-block with an "endif" statement on a new line:
El uso de la instrucción if-then-else es muy similar a otros lenguajes de programación. Tenga en cuenta que en Csound, entonces debe escribirse en la misma línea que if y la expresión a probar, y que debe cerrar el if-block con una instrucción endif en una nueva línea:
if <condition> then ... else ... endif
It is also possible to have no "else" statement:
También es posible no tener otra declaración:
if <condition> then ... endif
Or you can have one or more "elseif-then" statements in between:
O puede tener una o más declaraciones elseif-then entre ellas:
if <condition1> then
... elseif <condition2> then ... else ... endif
If statements can also be nested. Each level must be closed with an "endif". This is an example with three levels:
Si las sentencias también pueden anidarse. Cada nivel debe estar cerrado con un endif. Este es un ejemplo con tres niveles:
if <condition1> then; first condition opened if <condition2> then; second condition openend if <condition3> then; third condition openend ... else ... endif; third condition closed elseif <condition2a> then ... endif; second condition closed else ... endif; first condition closed
A typical problem in Csound: You have either mono or stereo files, and want to read both with a stereo output. For the real stereo ones that means: use soundin (diskin / diskin2) with two output arguments. For the mono ones it means: use soundin / diskin / diskin2 with one output argument, and throw it to both output channels:
Un problema típico en Csound: Usted tiene archivos mono o estéreo, y quiere leer ambos con una salida estéreo. Para los estereofónicos reales que significa: use soundin (diskin / diskin2) con dos argumentos de salida. Para los mono esto significa: use soundin / diskin / diskin2 con un argumento de salida, y lánzalo a ambos canales de salida:
EXAMPLE 03C01_IfThen_i.csd
<CsoundSynthesizer> <CsOptions> -o dac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 instr 1 Sfile = "/my/file.wav" ;your soundfile path here ifilchnls filenchnls Sfile if ifilchnls == 1 then ;mono aL soundin Sfile aR = aL else ;stereo aL, aR soundin Sfile endif outs aL, aR endin </CsInstruments> <CsScore> i 1 0 5 </CsScore> </CsoundSynthesizer>
If you use CsoundQt, you can browse in the widget panel for the soundfile. See the corresponding example in the CsoundQt Example menu.
Si utiliza CsoundQt, puede explorar el panel de widgets para el archivo de sonido. Consulte el ejemplo correspondiente en el menú de ejemplo CsoundQt.
The following example establishes a moving gate between 0 and 1. If the gate is above 0.5, the gate opens and you hear a tone. If the gate is equal or below 0.5, the gate closes, and you hear nothing.
El siguiente ejemplo establece una puerta móvil entre 0 y 1. Si la compuerta está por encima de 0,5, la compuerta se abre y se oye un tono. Si la compuerta es igual o inferior a 0,5, la compuerta se cierra y no se oye nada.
EXAMPLE 03C02_IfThen_k.csd
<CsoundSynthesizer> <CsOptions> -odac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 seed 0; random values each time different giTone ftgen 0, 0, 2^10, 10, 1, .5, .3, .1 instr 1 ; move between 0 and 1 (3 new values per second) kGate randomi 0, 1, 3 ; move between 300 and 800 hz (1 new value per sec) kFreq randomi 300, 800, 1 ; move between -12 and 0 dB (5 new values per sec) kdB randomi -12, 0, 5 aSig oscil3 1, kFreq, giTone kVol init 0 if kGate > 0.5 then; if kGate is larger than 0.5 kVol = ampdb(kdB); open gate else kVol = 0; otherwise close gate endif kVol port kVol, .02; smooth volume curve to avoid clicks aOut = aSig * kVol outs aOut, aOut endin </CsInstruments> <CsScore> i 1 0 30 </CsScore> </CsoundSynthesizer>
If you need an if-statement to give a value to an (i- or k-) variable, you can also use a traditional short form in parentheses: (a v b ? x : y).1 It asks whether the condition a or b is true. If a, the value is set to x; if b, to y. For instance, the last example could be written in this way:
Si necesita una instrucción if para dar un valor a una variable (i- o k-), también puede usar un formulario corto tradicional entre paréntesis: (avb? X: y) .1 Pregunta si la condición a o b es verdad. Si a, el valor se establece en x; Si b, a y. Por ejemplo, el último ejemplo podría escribirse de esta manera:
EXAMPLE 03C03_IfThen_short_form.csd
<CsoundSynthesizer> <CsOptions> -odac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 seed 0 giTone ftgen 0, 0, 2^10, 10, 1, .5, .3, .1 instr 1 kGate randomi 0, 1, 3; moves between 0 and 1 (3 new values per second) kFreq randomi 300, 800, 1; moves between 300 and 800 hz ;(1 new value per sec) kdB randomi -12, 0, 5; moves between -12 and 0 dB ;(5 new values per sec) aSig oscil3 1, kFreq, giTone kVol init 0 kVol = (kGate > 0.5 ? ampdb(kdB) : 0); short form of condition kVol port kVol, .02; smooth volume curve to avoid clicks aOut = aSig * kVol outs aOut, aOut endin </CsInstruments> <CsScore> i 1 0 20 </CsScore> </CsoundSynthesizer>
An older way of performing a conditional branch - but still useful in certain cases - is an "if" statement which is not followed by a "then", but by a label name. The "else" construction follows (or doesn't follow) in the next line. Like the if-then-else statement, the if-goto works either at i-time or at k-time. You should declare the type by either using igoto or kgoto. Usually you need an additional igoto/kgoto statement for omitting the "else" block if the first condition is true. This is the general syntax:
Una forma más antigua de realizar una rama condicional, pero aún útil en ciertos casos, es una instrucción if que no es seguida por un then, sino por un nombre de etiqueta. La otra construcción sigue (o no sigue) en la línea siguiente. Al igual que la instrucción if-then-else, el if-goto funciona en i-time o en k-time. Debe declarar el tipo utilizando igoto o kgoto. Por lo general, necesita una instrucción igoto / kgoto adicional para omitir el bloque else si la primera condición es verdadera. Esta es la sintaxis general:
i-time
if <condition> igoto this; same as if-then igoto that; same as else this: ;the label "this" ... ... igoto continue ;skip the "that" block that: ; ... and the label "that" must be found ... continue: ;go on after the conditional branch ...
k-time
if <condition> kgoto this; same as if-then kgoto that; same as else this: ;the label "this" ... ... kgoto continue ;skip the "that" block that: ; ... and the label "that" must be found ... continue: ;go on after the conditional branch ...
This is the same example as above in the if-then-else syntax for a branch depending on a mono or stereo file. If you just want to know whether a file is mono or stereo, you can use the "pure" if-igoto statement:
Este es el mismo ejemplo que el anterior en la sintaxis if-then-else para una rama dependiendo de un archivo mono o estéreo. Si sólo desea saber si un archivo es mono o estéreo, puede utilizar la instrucción if-igoto pura:
EXAMPLE 03C04_IfGoto_i.csd
<CsoundSynthesizer> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 instr 1 Sfile = "/Joachim/Materialien/SamplesKlangbearbeitung/Kontrabass.aif" ifilchnls filenchnls Sfile if ifilchnls == 1 igoto mono; condition if true igoto stereo; else condition mono: prints "The file is mono!%n" igoto continue stereo: prints "The file is stereo!%n" continue: endin </CsInstruments> <CsScore> i 1 0 0 </CsScore> </CsoundSynthesizer>
But if you want to play the file, you must also use a k-rate if-kgoto, because, not only do you have an event at i-time (initializing the soundin opcode) but also at k-time (producing an audio signal). So the code in this case is much more cumbersome, or obfuscated, than the previous if-then-else example.
Pero si quieres reproducir el archivo, también debes usar k-rate if-kgoto, porque no solo tienes un evento en i-time (inicializando el opcode de soundin), sino también en k-time (produciendo un audio señal). Por lo tanto, el código en este caso es mucho más engorroso u ofuscado que el anterior ejemplo if-then-else.
EXAMPLE 03C05_IfGoto_ik.csd
<CsoundSynthesizer> <CsOptions> -odac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 instr 1 Sfile = "my/file.wav" ifilchnls filenchnls Sfile if ifilchnls == 1 kgoto mono kgoto stereo if ifilchnls == 1 igoto mono; condition if true igoto stereo; else condition mono: aL soundin Sfile aR = aL igoto continue kgoto continue stereo: aL, aR soundin Sfile continue: outs aL, aR endin </CsInstruments> <CsScore> i 1 0 5 </CsScore> </CsoundSynthesizer>
This is the same example as above (03C02) in the if-then-else syntax for a moving gate between 0 and 1:
Este es el mismo ejemplo que el anterior (03C02) en la sintaxis if-then-else para una puerta en movimiento entre 0 y 1:
EXAMPLE 03C06_IfGoto_k.csd
<CsoundSynthesizer> <CsOptions> -odac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 seed 0 giTone ftgen 0, 0, 2^10, 10, 1, .5, .3, .1 instr 1 kGate randomi 0, 1, 3; moves between 0 and 1 (3 new values per second) kFreq randomi 300, 800, 1; moves between 300 and 800 hz ;(1 new value per sec) kdB randomi -12, 0, 5; moves between -12 and 0 dB ;(5 new values per sec) aSig oscil3 1, kFreq, giTone kVol init 0 if kGate > 0.5 kgoto open; if condition is true kgoto close; "else" condition open: kVol = ampdb(kdB) kgoto continue close: kVol = 0 continue: kVol port kVol, .02; smooth volume curve to avoid clicks aOut = aSig * kVol outs aOut, aOut endin </CsInstruments> <CsScore> i 1 0 30 </CsScore> </CsoundSynthesizer>
Loops can be built either at i-time or at k-time just with the "if" facility. The following example shows an i-rate and a k-rate loop created using the if-i/kgoto facility:
Los bucles pueden ser construidos ya sea en i-time o en k-time sólo con la instalación if. El siguiente ejemplo muestra un bucle i-rate y k-rate creado usando la función if-i / kgoto:
EXAMPLE 03C07_Loops_with_if.csd
<CsoundSynthesizer> <CsInstruments> ;Example by Joachim Heintz instr 1 ;i-time loop: counts from 1 until 10 has been reached icount = 1 count: print icount icount = icount + 1 if icount < 11 igoto count prints "i-END!%n" endin instr 2 ;k-rate loop: counts in the 100th k-cycle from 1 to 11 kcount init 0 ktimek timeinstk ;counts k-cycle from the start of this instrument if ktimek == 100 kgoto loop kgoto noloop loop: printks "k-cycle %d reached!%n", 0, ktimek kcount = kcount + 1 printk2 kcount if kcount < 11 kgoto loop printks "k-END!%n", 0 noloop: endin </CsInstruments> <CsScore> i 1 0 0 i 2 0 1 </CsScore> </CsoundSynthesizer>
But Csound offers a slightly simpler syntax for this kind of i-rate or k-rate loops. There are four variants of the loop opcode. All four refer to a label as the starting point of the loop, an index variable as a counter, an increment or decrement, and finally a reference value (maximum or minimum) as comparision:
Pero Csound ofrece una sintaxis ligeramente más simple para este tipo de bucles de i-rate o k-rate. Hay cuatro variantes del código de bucle. Los cuatro se refieren a una etiqueta como punto de partida del bucle, una variable de índice como un contador, un incremento o decremento y finalmente un valor de referencia (máximo o mínimo) como comparación:
As always, all four opcodes can be applied either at i-time or at k-time. Here are some examples, first for i-time loops, and then for k-time loops.
Como siempre, los cuatro opcodes se pueden aplicar en i-time o en k-time. Aquí hay algunos ejemplos, primero para bucles de i-tiempo, y luego para k-tiempo bucles.
The following .csd provides a simple example for all four loop opcodes:
El siguiente .csd proporciona un ejemplo sencillo para los cuatro opcodes de bucle:
EXAMPLE 03C08_Loop_opcodes_i.csd
<CsoundSynthesizer> <CsInstruments> ;Example by Joachim Heintz instr 1 ;loop_lt: counts from 1 upwards and checks if < 10 icount = 1 loop: print icount loop_lt icount, 1, 10, loop prints "Instr 1 terminated!%n" endin instr 2 ;loop_le: counts from 1 upwards and checks if <= 10 icount = 1 loop: print icount loop_le icount, 1, 10, loop prints "Instr 2 terminated!%n" endin instr 3 ;loop_gt: counts from 10 downwards and checks if > 0 icount = 10 loop: print icount loop_gt icount, 1, 0, loop prints "Instr 3 terminated!%n" endin instr 4 ;loop_ge: counts from 10 downwards and checks if >= 0 icount = 10 loop: print icount loop_ge icount, 1, 0, loop prints "Instr 4 terminated!%n" endin </CsInstruments> <CsScore> i 1 0 0 i 2 0 0 i 3 0 0 i 4 0 0 </CsScore> </CsoundSynthesizer>
The next example produces a random string of 10 characters and prints it out:
El siguiente ejemplo produce una cadena aleatoria de 10 caracteres e imprime:
EXAMPLE 03C09_Random_string.csd
<CsoundSynthesizer> <CsInstruments> ;Example by Joachim Heintz instr 1 icount = 0 Sname = ""; starts with an empty string loop: ichar random 65, 90.999 Schar sprintf "%c", int(ichar); new character Sname strcat Sname, Schar; append to Sname loop_lt icount, 1, 10, loop; loop construction printf_i "My name is '%s'!\n", 1, Sname; print result endin </CsInstruments> <CsScore> ; call instr 1 ten times r 10 i 1 0 0 </CsScore> </CsoundSynthesizer>
You can also use an i-rate loop to fill a function table (= buffer) with any kind of values. This table can then be read, or manipulated and then be read again. In the next example, a function table with 20 positions (indices) is filled with random integers between 0 and 10 by instrument 1. Nearly the same loop construction is used afterwards to read these values by instrument 2.
También puede utilizar un bucle i-rate para llenar una tabla de funciones (= buffer) con cualquier tipo de valores. Esta tabla puede ser leída o manipulada y leída de nuevo. En el siguiente ejemplo, una tabla de funciones con 20 posiciones (índices) se rellena con números enteros aleatorios entre 0 y 10 por el instrumento 1. Casi la misma construcción de bucle se utiliza después para leer estos valores por el instrumento 2.
EXAMPLE 03C10_Random_ftable_fill.csd
<CsoundSynthesizer> <CsInstruments> ;Example by Joachim Heintz giTable ftgen 0, 0, -20, -2, 0; empty function table with 20 points seed 0; each time different seed instr 1 ; writes in the table icount = 0 loop: ival random 0, 10.999 ;random value ; --- write in giTable at first, second, third ... position tableiw int(ival), icount, giTable loop_lt icount, 1, 20, loop; loop construction endin instr 2; reads from the table icount = 0 loop: ; --- read from giTable at first, second, third ... position ival tablei icount, giTable print ival; prints the content loop_lt icount, 1, 20, loop; loop construction endin </CsInstruments> <CsScore> i 1 0 0 i 2 0 0 </CsScore> </CsoundSynthesizer>
The next example performs a loop at k-time. Once per second, every value of an existing function table is changed by a random deviation of 10%. Though there are some vectorial opcodes for this task (and in Csound 6 probably array), it can also be done by a k-rate loop like the one shown here:
El siguiente ejemplo realiza un bucle en k-time. Una vez por segundo, cada valor de una tabla de funciones existente se cambia por una desviación aleatoria de 10%. Aunque hay algunos opcodes vectoriales para esta tarea (y en Csound 6 probablemente matriz), también puede hacerse mediante un k-rate loop como el mostrado aquí:
EXAMPLE 03C11_Table_random_dev.csd
<CsoundSynthesizer> <CsOptions> -odac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 441 nchnls = 2 0dbfs = 1 giSine ftgen 0, 0, 256, 10, 1; sine wave seed 0; each time different seed instr 1 ktiminstk timeinstk ;time in control-cycles kcount init 1 if ktiminstk == kcount * kr then; once per second table values manipulation: kndx = 0 loop: krand random -.1, .1;random factor for deviations kval table kndx, giSine; read old value knewval = kval + (kval * krand); calculate new value tablew knewval, kndx, giSine; write new value loop_lt kndx, 1, 256, loop; loop construction kcount = kcount + 1; increase counter endif asig poscil .2, 400, giSine outs asig, asig endin </CsInstruments> <CsScore> i 1 0 10 </CsScore> </CsoundSynthesizer>
Since the release of Csound 6, it has been possible to write loops in a manner similar to that used by many other programming languages, using the keywords while or until. The general syntax is:2
Desde el lanzamiento de Csound 6, ha sido posible escribir bucles de una manera similar a la utilizada por muchos otros lenguajes de programación, usando las palabras clave mientras o hasta. La sintaxis general es: 2
while <condition> do
... od until <condition> do ... od
The body of the while loop will be performed again and again, as long as is true. The body of the until loop will be performed, as long as is false (not true). This is a simple example at i-rate:
El cuerpo del bucle while se realizará una y otra vez, siempre y cuando la condición sea verdadera. El cuerpo del bucle hasta se realizará, siempre y cuando la condición sea falsa (no es verdadera). Este es un ejemplo simple en i-rate:
EXAMPLE 03C12_while_until_i-rate.csd
<CsoundSynthesizer> <CsOptions> -nm0 </CsOptions> <CsInstruments> ksmps = 32 instr 1 iCounter = 0 while iCounter < 5 do print iCounter iCounter += 1 od prints "\n" endin instr 2 iCounter = 0 until iCounter >= 5 do print iCounter iCounter += 1 od endin </CsInstruments> <CsScore> i 1 0 .1 i 2 .1 .1 </CsScore> </CsoundSynthesizer> ;example by joachim heintz
Prints:
instr 1: iprint = 0.000
instr 1: iprint = 1.000
instr 1: iprint = 2.000
instr 1: iprint = 3.000
instr 1: iprint = 4.000
instr 2: iprint = 0.000
instr 2: iprint = 1.000
instr 2: iprint = 2.000
instr 2: iprint = 3.000
instr 2: iprint = 4.000
The most important thing in using the while/until loop is to increment the variable you are using in the loop (here: iCounter). This is done by the statement
Lo más importante al usar el bucle while / until es incrementar la variable que está utilizando en el bucle (aquí: iCounter). Esto se hace mediante la declaración
iCounter += 1
which is equivalent to the "old" way of writing as
Que es equivalente a la vieja manera de escribir como
iCounter = iCounter + 1
If you miss this increment, Csound will perform an endless loop, and you will have to terminate it by the operating system.
Si pierde este incremento, Csound realizará un bucle interminable, y tendrá que terminarlo por el sistema operativo.
The next example shows a similar process at k-rate. It uses a while loop to print the values of an array, and also set new values. As this procedure is repeated in each control cycle, the instrument is being turned off after the third cycle.
El siguiente ejemplo muestra un proceso similar a k-rate. Utiliza un bucle while para imprimir los valores de una matriz y también establece nuevos valores. Como este procedimiento se repite en cada ciclo de control, el instrumento se apaga después del tercer ciclo.
EXAMPLE 03C13_while_until_k-rate.csd
<CsoundSynthesizer> <CsOptions> -nm0 </CsOptions> <CsInstruments> ksmps = 32 ;create and fill an array gkArray[] fillarray 1, 2, 3, 4, 5 instr 1 ;count performance cycles and print it kCycle timeinstk printks "kCycle = %d\n", 0, kCycle ;set index to zero kIndex = 0 ;perform the loop while kIndex < lenarray(gkArray) do ;print array value printf " gkArray[%d] = %d\n", kIndex+1, kIndex, gkArray[kIndex] ;square array value gkArray[kIndex] = gkArray[kIndex] * gkArray[kIndex] ;increment index kIndex += 1 od ;stop after third control cycle if kCycle == 3 then turnoff endif endin </CsInstruments> <CsScore> i 1 0 1 </CsScore> </CsoundSynthesizer> ;example by joachim heintz
Prints:
kCycle = 1
gkArray[0] = 1
gkArray[1] = 2
gkArray[2] = 3
gkArray[3] = 4
gkArray[4] = 5
kCycle = 2
gkArray[0] = 1
gkArray[1] = 4
gkArray[2] = 9
gkArray[3] = 16
gkArray[4] = 25
kCycle = 3
gkArray[0] = 1
gkArray[1] = 16
gkArray[2] = 81
gkArray[3] = 256
gkArray[4] = 625
Until now, we have just discussed loops which are executed "as fast as possible", either at i-time or at k-time. But, in an audio programming language, time loops are of particular interest and importance. A time loop means, repeating any action after a certain amount of time. This amount of time can be equal to or different to the previous time loop. The action can be, for instance: playing a tone, or triggering an instrument, or calculating a new value for the movement of an envelope.
Hasta ahora, acabamos de hablar de loops que se ejecutan lo más rápido posible, ya sea en i-time o en k-time. Pero, en un lenguaje de programación de audio, los bucles de tiempo son de particular interés e importancia. Un lazo de tiempo significa repetir cualquier acción después de cierto tiempo. Esta cantidad de tiempo puede ser igual o diferente al bucle de tiempo anterior. La acción puede ser, por ejemplo: tocar un tono, activar un instrumento o calcular un nuevo valor para el movimiento de un sobre.
In Csound, the usual way of performing time loops, is the timout facility. The use of timout is a bit intricate, so some examples are given, starting from very simple to more complex ones.
En Csound, la forma habitual de realizar bucles de tiempo, es la facilidad de tiempo. El uso de timout es un poco intrincado, por lo que algunos ejemplos se dan, a partir de muy simple a los más complejos.
Another way of performing time loops is by using a measurement of time or k-cycles. This method is also discussed and similar examples to those used for the timout opcode are given so that both methods can be compared.
Otra forma de realizar bucles de tiempo es usando una medición de tiempo o ciclos k. Este método también se discute y se dan ejemplos similares a los utilizados para el código de operación de temporización para que ambos métodos puedan compararse.
The timout opcode refers to the fact that in the traditional way of working with Csound, each "note" (an "i" score event) has its own time. This is the duration of the note, given in the score by the duration parameter, abbreviated as "p3". A timout statement says: "I am now jumping out of this p3 duration and establishing my own time." This time will be repeated as long as the duration of the note allows it.
El opcode timout se refiere al hecho de que en la forma tradicional de trabajar con Csound, cada nota (un evento de puntuación i) tiene su propio tiempo. Esta es la duración de la nota, dada en la partitura por el parámetro duración, abreviado como p3. Una declaración de timout dice: Ahora estoy saltando de esta duración de p3 y estableciendo mi propio tiempo. Este tiempo se repetirá siempre y cuando la duración de la nota lo permita.
Let's see an example. This is a sine tone with a moving frequency, starting at 400 Hz and ending at 600 Hz. The duration of this movement is 3 seconds for the first note, and 5 seconds for the second note:
Veamos un ejemplo. Se trata de un tono seno con una frecuencia de movimiento, que comienza en 400 Hz y termina en 600 Hz. La duración de este movimiento es de 3 segundos para la primera nota y de 5 segundos para la segunda nota:
EXAMPLE 03C14_Timout_pre.csd
<CsoundSynthesizer> <CsOptions> -odac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 giSine ftgen 0, 0, 2^10, 10, 1 instr 1 kFreq expseg 400, p3, 600 aTone poscil .2, kFreq, giSine outs aTone, aTone endin </CsInstruments> <CsScore> i 1 0 3 i 1 4 5 </CsScore> </CsoundSynthesizer>
Now we perform a time loop with timout which is 1 second long. So, for the first note, it will be repeated three times, and five times for the second note:
Ahora realizamos un bucle de tiempo con temporización que es de 1 segundo de largo. Por lo tanto, para la primera nota, se repetirá tres veces y cinco veces para la segunda nota:
EXAMPLE 03C15_Timout_basics.csd
<CsoundSynthesizer> <CsOptions> -odac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 giSine ftgen 0, 0, 2^10, 10, 1 instr 1 loop: timout 0, 1, play reinit loop play: kFreq expseg 400, 1, 600 aTone poscil .2, kFreq, giSine outs aTone, aTone endin </CsInstruments> <CsScore> i 1 0 3 i 1 4 5 </CsScore> </CsoundSynthesizer>
This is the general syntax of timout:
Esta es la sintaxis general de timout:
first_label: timout istart, idur, second_label reinit first_label second_label: ... <any action you want to have here>
The first_label is an arbitrary word (followed by a colon) to mark the beginning of the time loop section. The istart argument for timout tells Csound, when the second_label section is to be executed. Usually istart is zero, telling Csound: execute the second_label section immediately, without any delay. The idur argument for timout defines for how many seconds the second_label section is to be executed before the time loop begins again. Note that the reinit first_label is necessary to start the second loop after idur seconds with a resetting of all the values. (See the explanations about reinitialization in the chapter Initialization And Performance Pass section 03A.)
La primera etiqueta es una palabra arbitraria (seguida de dos puntos) para marcar el comienzo de la sección de lazo de tiempo. El argumento istart para timout le dice a Csound, cuando se va a ejecutar la sección second_label. Usualmente istart es cero, diciéndole a Csound: ejecute la sección second_label inmediatamente, sin demora alguna. El argumento idur para timout define durante cuántos segundos la sección second_label debe ejecutarse antes de que el bucle de tiempo comience de nuevo. Tenga en cuenta que el reinit first_label es necesario para iniciar el segundo bucle después de idur segundos con un restablecimiento de todos los valores. (Consulte las explicaciones sobre la reinicialización en el capítulo Inicialización y paso de rendimiento, sección 03A).
As usual when you work with the reinit opcode, you can use a rireturn statement to constrain the reinit-pass. In this way you can have both, the timeloop section and the non-timeloop section in the body of an instrument:
Como de costumbre cuando se trabaja con el opcode reinit, se puede usar una sentencia rireturn para restringir el reinit-pass. De esta manera puede tener tanto la sección timeloop como la sección no timeloop en el cuerpo de un instrumento:
EXAMPLE 03C16_Timeloop_and_not.csd
<CsoundSynthesizer> <CsOptions> -odac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 giSine ftgen 0, 0, 2^10, 10, 1 instr 1 loop: timout 0, 1, play reinit loop play: kFreq1 expseg 400, 1, 600 aTone1 oscil3 .2, kFreq1, giSine rireturn ;end of the time loop kFreq2 expseg 400, p3, 600 aTone2 poscil .2, kFreq2, giSine outs aTone1+aTone2, aTone1+aTone2 endin </CsInstruments> <CsScore> i 1 0 3 i 1 4 5 </CsScore> </CsoundSynthesizer>
In a time loop, it is very important to change the duration of the loop. This can be done either by referring to the duration of this note (p3) ...
En un bucle de tiempo, es muy importante cambiar la duración del bucle. Esto puede hacerse refiriéndose a la duración de esta nota (p3) ...
EXAMPLE 03C17_Timout_different_durations.csd
<CsoundSynthesizer> <CsOptions> -odac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 giSine ftgen 0, 0, 2^10, 10, 1 instr 1 loop: timout 0, p3/5, play reinit loop play: kFreq expseg 400, p3/5, 600 aTone poscil .2, kFreq, giSine outs aTone, aTone endin </CsInstruments> <CsScore> i 1 0 3 i 1 4 5 </CsScore> </CsoundSynthesizer>
... or by calculating new values for the loop duration on each reinit pass, for instance by random values:
... o calculando nuevos valores para la duración del bucle en cada paso reinit, por ejemplo mediante valores aleatorios:
EXAMPLE 03C18_Timout_random_durations.csd
<CsoundSynthesizer> <CsOptions> -odac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 giSine ftgen 0, 0, 2^10, 10, 1 instr 1 loop: idur random .5, 3 ;new value between 0.5 and 3 seconds each time timout 0, idur, play reinit loop play: kFreq expseg 400, idur, 600 aTone poscil .2, kFreq, giSine outs aTone, aTone endin </CsInstruments> <CsScore> i 1 0 20 </CsScore> </CsoundSynthesizer>
The applications discussed so far have the disadvantage that all the signals inside the time loop must definitely be finished or interrupted, when the next loop begins. In this way it is not possible to have any overlapping of events. To achieve this, the time loop can be used to simply trigger an event. This can be done with event_i or scoreline_i. In the following example, the time loop in instrument 1 triggers a new instance of instrument 2 with a duration of 1 to 5 seconds, every 0.5 to 2 seconds. So in most cases, the previous instance of instrument 2 will still be playing when the new instance is triggered. Random calculations are executed in instrument 2 so that each note will have a different pitch,creating a glissando effect:
Las aplicaciones discutidas hasta ahora tienen la desventaja de que todas las señales dentro del bucle de tiempo definitivamente deben ser terminadas o interrumpidas, cuando comienza el siguiente bucle. De esta manera no es posible tener ninguna superposición de eventos. Para lograr esto, el bucle de tiempo puede usarse para simplemente disparar un evento. Esto se puede hacer con event_i o scoreline_i. En el ejemplo siguiente, el bucle de tiempo del instrumento 1 activa una nueva instancia del instrumento 2 con una duración de 1 a 5 segundos, cada 0,5 a 2 segundos. Por lo tanto, en la mayoría de los casos, la instancia anterior del instrumento 2 seguirá reproduciéndose cuando se active la nueva instancia. Los cálculos aleatorios se ejecutan en el instrumento 2 para que cada nota tenga un tono diferente, creando un efecto glissando:
EXAMPLE 03C19_Timout_trigger_events.csd
<CsoundSynthesizer> <CsOptions> -odac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 giSine ftgen 0, 0, 2^10, 10, 1 instr 1 loop: idurloop random .5, 2 ;duration of each loop timout 0, idurloop, play reinit loop play: idurins random 1, 5 ;duration of the triggered instrument event_i "i", 2, 0, idurins ;triggers instrument 2 endin instr 2 ifreq1 random 600, 1000 ;starting frequency idiff random 100, 300 ;difference to final frequency ifreq2 = ifreq1 - idiff ;final frequency kFreq expseg ifreq1, p3, ifreq2 ;glissando iMaxdb random -12, 0 ;peak randomly between -12 and 0 dB kAmp transeg ampdb(iMaxdb), p3, -10, 0 ;envelope aTone poscil kAmp, kFreq, giSine outs aTone, aTone endin </CsInstruments> <CsScore> i 1 0 30 </CsScore> </CsoundSynthesizer>
The last application of a time loop with the timout opcode which is shown here, is a randomly moving envelope. If you want to create an envelope in Csound which moves between a lower and an upper limit, and has one new random value in a certain time span (for instance, once a second), the time loop with timout is one way to achieve it. A line movement must be performed in each time loop, from a given starting value to a new evaluated final value. Then, in the next loop, the previous final value must be set as the new starting value, and so on. Here is a possible solution:
La última aplicación de un bucle de tiempo con el código de operación de temporización que se muestra aquí, es un envolvente que se mueve aleatoriamente. Si desea crear un envolvente en Csound que se mueve entre un límite inferior y un límite superior y tiene un nuevo valor aleatorio en un cierto intervalo de tiempo (por ejemplo, una vez por segundo), el bucle de tiempo con temporización es una forma de lograrlo . Se debe realizar un movimiento de línea en cada ciclo de tiempo, desde un valor inicial dado hasta un nuevo valor final evaluado. A continuación, en el siguiente ciclo, el valor final anterior debe establecerse como el nuevo valor inicial, y así sucesivamente. He aquí una posible solución:
EXAMPLE 03C20_Timout_random_envelope.csd
<CsoundSynthesizer> <CsOptions> -odac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 giSine ftgen 0, 0, 2^10, 10, 1 seed 0 instr 1 iupper = 0; upper and ... ilower = -24; ... lower limit in dB ival1 random ilower, iupper; starting value loop: idurloop random .5, 2; duration of each loop timout 0, idurloop, play reinit loop play: ival2 random ilower, iupper; final value kdb linseg ival1, idurloop, ival2 ival1 = ival2; let ival2 be ival1 for next loop rireturn ;end reinit section aTone poscil ampdb(kdb), 400, giSine outs aTone, aTone endin </CsInstruments> <CsScore> i 1 0 30 </CsScore> </CsoundSynthesizer>
Note that in this case the oscillator has been put after the time loop section (which is terminated by the rireturn statement. Otherwise the oscillator would start afresh with zero phase in each time loop, thus producing clicks.
Tenga en cuenta que en este caso el oscilador se ha puesto después de la sección de bucle de tiempo (que se termina por la declaración de rieturn), de lo contrario el oscilador empezaría de nuevo con fase cero en cada ciclo de tiempo, produciendo así clics.
The metro opcode outputs a "1" at distinct times, otherwise it outputs a "0". The frequency of this "banging" (which is in some way similar to the metro objects in PD or Max) is given by the kfreq input argument. So the output of metro offers a simple and intuitive method for controlling time loops, if you use it to trigger a separate instrument which then carries out another job. Below is a simple example for calling a subinstrument twice per second:
El opcode de metro emite un 1 en momentos distintos, de lo contrario emite un 0. La frecuencia de este golpeo (que es de alguna manera similar a los objetos de metro en PD o Max) es dada por el argumento de entrada kfreq. Así que la salida del metro ofrece un método simple e intuitivo para controlar los bucles de tiempo, si se utiliza para activar un instrumento separado que luego lleva a cabo otro trabajo. A continuación se muestra un ejemplo sencillo para llamar a un subinstrumento dos veces por segundo:
EXAMPLE 03C21_Timeloop_metro.csd
<CsoundSynthesizer> <CsOptions> -odac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 instr 1; triggering instrument kTrig metro 2; outputs "1" twice a second if kTrig == 1 then event "i", 2, 0, 1 endif endin instr 2; triggered instrument aSig oscils .2, 400, 0 aEnv transeg 1, p3, -10, 0 outs aSig*aEnv, aSig*aEnv endin </CsInstruments> <CsScore> i 1 0 10 </CsScore> </CsoundSynthesizer>
The example which is given above (03C19_Timout_trigger_events.csd) as a flexible time loop by timout, can be done with the metro opcode in this way:
El ejemplo que se da arriba (03C19_Timout_trigger_events.csd) como un bucle de tiempo flexible por timout, se puede hacer con el opcode metro de esta manera:
EXAMPLE 03C22_Metro_trigger_events.csd
<CsoundSynthesizer> <CsOptions> -odac </CsOptions> <CsInstruments> ;Example by Joachim Heintz sr = 44100 ksmps = 32 nchnls = 2 0dbfs = 1 giSine ftgen 0, 0, 2^10, 10, 1 seed 0 instr 1 kfreq init 1; give a start value for the trigger frequency kTrig metro kfreq if kTrig == 1 then ;if trigger impulse: kdur random 1, 5; random duration for instr 2 event "i", 2, 0, kdur; call instr 2 kfreq random .5, 2; set new value for trigger frequency endif endin instr 2 ifreq1 random 600, 1000; starting frequency idiff random 100, 300; difference to final frequency ifreq2 = ifreq1 - idiff; final frequency kFreq expseg ifreq1, p3, ifreq2; glissando iMaxdb random -12, 0; peak randomly between -12 and 0 dB kAmp transeg ampdb(iMaxdb), p3, -10, 0; envelope aTone poscil kAmp, kFreq, giSine outs aTone, aTone endin </CsInstruments> <CsScore> i 1 0 30 </CsScore> </CsoundSynthesizer>
Note the differences in working with the metro opcode compared to the timout feature:
Tenga en cuenta las diferencias en el trabajo con el opcode metro en comparación con la característica de tiempo de espera:
As metro works at k-time, you must use the k-variants of event or scoreline to call the subinstrument. With timout you must use the i-variants of event or scoreline (event_i and scoreline_i), because it uses reinitialization for performing the time loops.
Como el metro trabaja en k-time, debe usar las variantes k de evento o scoreline para llamar al subinstrumento. Con timout debes utilizar las i-variantes del evento o scoreline (event_i y scoreline_i), porque utiliza la reinicialización para realizar los bucles de tiempo.
You must select the one k-cycle where the metro opcode sends a "1". This is done with an if-statement. The rest of the instrument is not affected. If you use timout, you usually must seperate the reinitialized from the not reinitialized section by a rireturn statement.
Debe seleccionar el ciclo k en el que el opcode metro envía un 1. Esto se hace con una sentencia if. El resto del instrumento no se ve afectado. Si utiliza timout, por lo general debe separar la reinicializada de la sección no reinicializada por una declaración rireturn.
Links
Steven Yi: Control Flow (Part I = Csound Journal Spring 2006, Part 2 = Csound Journal Summer 2006)
There has been error in communication with Booktype server. Not sure right now where is the problem.
You should refresh this page.