FLOSS Manuals

 English |  Español |  Français |  Italiano |  Português |  Русский |  Shqip

CSOUND Español

ALEATORIEDAD

Este capítulo se divide en tres partes. La Parte I ofrece una introducción general a los conceptos relacionados con los números aleatorios y sobre cómo trabajar con ellos en Csound. La Parte II se centra en un enfoque más matemático. La Parte III introduce una serie de opcodes para la generación de números aleatorios, funciones y distribuciones y se demuestra su uso en algunos ejemplos musicales.

I. INTRODUCCIÓN GENERAL

Lo Aleatorio es Diferente

El término random (aleatorio) históricamente refiere a una situación en la que un caballo corre tan rápido que pasa a estar 'fuera de control' o 'más allá de lo predecible'.1 Sin embargo, hay diferentes maneras en que se puede correr rápido y estar fuera de control; por lo tanto, hay diferentes tipos de aleatoriedad.

Podemos dividir los tipos de aleatoriedad en dos clases. El primero contiene sucesos aleatorios que son independientes de los eventos anteriores. El ejemplo más común es el lanzamiento de un dado. Incluso si acaba de lanzar tres 1s de manera consecutiva, cuando se lanza de nuevo, el 1 tiene la misma probabilidad que antes (y que cualquiera de los otros números). La segunda clase de números aleatorios implica sucesos aleatorios que dependen de alguna manera de los números o estados anteriores. Ejemplos de esta última clase son las cadenas de Markov y las 'random walks' o caminatas aleatorias.

 

 

El uso de aleatoriedad en la música electrónica es un fenómeno muy extendido. En este capítulo, vamos a tratar de explicar cómo los diferentes "caballos" aleatorios se mueven, y cómo Ud. puede crearlos y modificarlos a su gusto. Aún más, hay muchos opcodes para trabajar la aleatoriedad pre-construidos en Csound, que pueden ser utilizados desde un primer momento (ver el overview en el Manual de Csound). En la sección final de este capítulo se presentan algunas aplicaciones musicales interesantes en base a ellos.

 

Aleatorio sin Historia

 

Un ordenador es típicamente capaz de realizar sólo cálculos. Los cálculos son procesos deterministas: una entrada generará siempre la misma salida, pero un evento aleatorio no es predecible. Para generar algo que se parezca a un evento aleatorio, el equipo utiliza un generador pseudo-aleatorio.

El generador pseudo-aleatorio tiene un número como entrada, y genera otro número como salida. Esta salida es luego la entrada para la próxima generación. Utilizando una gran cantidad de números, se ven como si estuvieran distribuidos aleatoriamente, aunque todo depende de la primera entrada: la semilla. A partir de una semilla dada, es posible predecir los valores siguientes.

 

Distribución Uniforme

La salida de un generador pseudo-aleatorio clásico posee una distribución uniforme: cada valor de un rango dado tiene la misma probabilidad de ocurrencia. El primer ejemplo muestra la influencia de una semilla fija (utilizando la misma cadena de números y comenzando desde la misma ubicación en la cadena cada vez) en contraste con una semilla tomada del reloj del sistema (la forma más habitual de imitar un fenónmeno imprevisible). Los tres primeros grupos de cuatro notas siempre serán los mismos debido a la utilización de la misma semilla, mientras que los tres últimos grupos deberían tener siempre una altura diferente.

 

   EXAMPLE 01D01_different_seed.csd

<CsoundSynthesizer>
<CsOptions>
-d -odac -m0
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 32
nchnls = 2
0dbfs = 1

instr generate
 ;obtener la semilla: 0 = semilla a partir del reloj del sistema
 ;          cualquier otro número = semilla fija
           seed       p4
 ;generar cuatro notas a ser interpretadas desde el subinstrumento
iNoteCount =          0
 until iNoteCount == 4 do
iFreq      random     400, 800
           event_i    "i", "play", iNoteCount, 2, iFreq
iNoteCount +=         1 ;aumentar la cuenta de notas
 enduntil
endin

instr play
iFreq      =          p4
           print      iFreq
aImp       mpulse     .5, p3
aMode      mode       aImp, iFreq, 1000
aEnv       linen      aMode, 0.01, p3, p3-0.01
           outs       aEnv, aEnv
endin
</CsInstruments>
<CsScore>
;repetir tres veces con una semilla fija
r 3
i "generate" 0 2 1
;repetir tres veces con una semilla tomada del reloj del sistema
r 3
i "generate" 0 1 0
</CsScore>
</CsoundSynthesizer>
;ejemplo por joachim heintz

Tenga en cuenta que un generador pseudo-aleatorio repetirá su serie de números después de tantos pasos como sean dados por el tamaño del generador. Si se genera un número de 16 bits, la serie se repetirá después de 65536 pasos. Si escucha con atención el siguiente ejemplo, se escuchará una repetición en la estructura del ruido blanco (que es el resultado de las amplitudes uniformemente distribuidas) después de 1.5 segundos en la primera nota.2 En la segunda nota, no hay repetición que sea perceptible ya que el generador aleatorio ahora trabaja con un número de 31 bits.

 

   EXAMPLE 01D02_white_noises.csd 

<CsoundSynthesizer>
<CsOptions>
-d -odac
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 32
nchnls = 2
0dbfs = 1

instr white_noise
iBit       =          p4 ;0 = 16 bit, 1 = 31 bit
 ;entrada de rand: amplitud, semilla fija (0.5), tamaño de bit
aNoise     rand       .1, 0.5, iBit
           outs       aNoise, aNoise
endin

</CsInstruments>
<CsScore>
i "white_noise" 0 10 0
i "white_noise" 11 10 1
</CsScore>
</CsoundSynthesizer>
;ejemplo por joachim heintz

Dos cosideraciones generales sobre esto:

  1. La forma de establecer la semilla varía de opcode en opcode. Hay varios opcodes tales como el rand utilizado más arriba, que ofrecen la opción de establecer una semilla como parámetro de entrada. En otros, tales como la comúnmente utilizada familia random, la semilla sólo puede establecerse a nivel global a través de la declaración de seed. Esto se hace generalmente en el encabezado de modo que una declaración típica se vería así:
    <CsInstruments>
    sr = 44100
    ksmps = 32
    nchnls = 2
    0dbfs = 1
    seed = 0 ;semilla a partir del tiempo actual

    ...

  2. La generación de números aleatorios en Csound puede hacerse a cualquier tipo de ciclo. El tipo de la variable de salida indica si van a generarse valores aleatorios en ciclos-i, ciclos-k o ciclos-a. Muchos opcodes para aleatoriedad pueden trabajar en todos estos ciclos, por ejemplo random:

    1) ires  random  imin, imax
    2) kres  random  kmin, kmax
    3) ares  random  kmin, kmax

    En el primer caso, un valor aleatorio se genera sólo una vez, cuando un instrumento es llamado durante la inicialización. El valor generado se almacena en la variable ires. En el segundo caso, un valor aleatorio se genera en cada ciclo-k, y se almacena en kres. En el tercer caso, en cada ciclo-k se almacenan tantos valores aleatorios como se necesario para llenar el vector de audio, y se almacenan en la variable ares. Eche un vistazo al ejemplo 03A15_Random_at_ika.csd para ver esto en acción. El Capítulo 03A trata de explicar el trasfondo de los diferentes ciclos en profundidad, y cómo trabajar con ellos.

Otras Distribuciones

La distribución uniforme es aquella que cada equipo puede producir a través de su generador pseudo-aleatorio. Sin embargo, hay muchas situaciones en que no se querrá un azar distribuido uniformemente, sino de cualquier otra forma. Algunas de estas formas son bastante comunes, pero de hecho se pueden construir formas propias utilizando Csound con bastante facilidad. Los siguientes ejemplos muestran cómo hacer esto. Están basados en el capítulo hallado en Dodge/Jerse3 que también sirvió como modelo para muchos opcodes generadores de números aleatorios en Csound.4


Lineal

Una distribución lineal significa que los valores menores o los valores mayores en un rango dado serán más probables:

 

Para conseguir este comportamiento, se generan dos números aleatorios uniformes, y se selecciona el más bajo para lograr la primera forma. Si se necesita la segunda forma en donde prevalecen los valores más altos, el número que se toma es el mayor. El siguiente ejemplo implementa estos generadores aleatorios como Opcodes Definidos por el Usuario (en inglés, UDO). Primero oímos una distribución uniforme, a continuación, una distribución lineal con preferencia por los tonos más bajos (pero de mayor duración) y finalmente una distribución lineal con preferencia de tonos más altos (pero duraciones más cortas).

   EXAMPLE 01D03_linrand.csd  

<CsoundSynthesizer>
<CsOptions>
-d -odac -m0
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 32
nchnls = 2
0dbfs = 1
seed 0

;****CÓDIGOS OPERATIVOS DEFINIDOS PARA UNA DISTRIBUCIÓN LINEAL****

opcode linrnd_low, i, ii
 ;linear random with precedence of lower values 
;aleatoriedad lineal con precedencia de los valores más bajos iMin, iMax xin ;generate two random values with the random opcode
;generar dos valores aleatorios con el código operativo random iOne random iMin, iMax iTwo random iMin, iMax ;comparar y devolver el más bajo iRnd = iOne < iTwo ? iOne : iTwo xout iRnd endop opcode linrnd_high, i, ii ;aleatoriedad lineal con precedencia de los valores más altos iMin, iMax xin ;generar dos valores aleatorios con el código operativo random iOne random iMin, iMax iTwo random iMin, iMax ;comparar y devolver el más alto iRnd = iOne > iTwo ? iOne : iTwo xout iRnd endop ;****INSTRUMENTOS PARA LAS DISTINTAS DISTRIBUCIÓNES**** instr notes_uniform prints "... instr notes_uniform ejecutándose:\n" prints "IGUAL PROBABILIDAD PARA TODAS LAS ALTURAS Y DURACIONES\n" ;cuántas notas se reproducirán iHowMany = p4 ;ejecutar tantas instancias del instrumento play como sean necesarias iThisNote = 0 iStart = 0 until iThisNote == iHowMany do iMidiPch random 36, 84 ;nota midi iDur random .5, 1 ;duración event_i "i", "play", iStart, iDur, int(iMidiPch) iStart += iDur ;aumentar el tiempo de inicio
iThisNote += 1 ;aumentar la cuenta enduntil ;reset the duration of this instr to make all events happen
;reconfigurar la duración de este instrumento para hacer que todos los eventos ocurran
p3 = iStart + 2 ;trigger next instrument two seconds after the last note
;ejecutar el siguiente instrumento pasados dos segundos desde la última nota event_i "i", "notes_linrnd_low", p3, 1, iHowMany endin instr notes_linrnd_low prints "... instr notes_linrnd_low ejecutándose:\n" prints "SE PREFIEREN LAS NOTAS MÁS BAJAS Y LAS DURACIONES MAS LARGAS\n" iHowMany = p4 iThisNote = 0 iStart = 0 until iThisNote == iHowMany do iMidiPch linrnd_low 36, 84 ;se prefieren notas más bajas iDur linrnd_high .5, 1 ;se prefieren duraciones más largas event_i "i", "play", iStart, iDur, int(iMidiPch) iStart += iDur iThisNote += 1 enduntil ;reconfigurar la duración de este instrumento para hacer que todos los eventos ocurran p3 = iStart + 2 ;trigger next instrument two seconds after the last note
;ejecutar el siguiente instrumento pasados dos segundos desde la última nota event_i "i", "notes_linrnd_high", p3, 1, iHowMany endin instr notes_linrnd_high prints "... instr notes_linrnd_high ejecutándose:\n" prints "SE PREFIEREN LAS NOTAS MÁS ALTAS Y LAS DURACIONES MÁS CORTAS\n" iHowMany = p4 iThisNote = 0 iStart = 0 until iThisNote == iHowMany do iMidiPch linrnd_high 36, 84 ;higher pitches preferred iDur linrnd_low .3, 1.2 ;shorter durations preferred event_i "i", "play", iStart, iDur, int(iMidiPch) iStart += iDur iThisNote += 1 enduntil ;reconfigurar la duración de este instrumento para hacer que todos los eventos ocurran p3 = iStart + 2 ;llamar al instrumento exit para salir de Csound event_i "i", "exit", p3+1, 1 endin ;****INSTRUMENTOS PARA REPRODUCIR LOS SONIDOS Y PARA ABANDONAR CSOUND**** instr play ;aumentar la duración en el rango aleatorio iDur random p3, p3*1.5 p3 = iDur ;obtener nota midi y convertirla a frecuencia iMidiNote = p4 iFreq cpsmidinn iMidiNote ;generar nota con el algoritmo de karplus-strong aPluck pluck .2, iFreq, iFreq, 0, 1 aPluck linen aPluck, 0, p3, p3 ;filtro aFilter mode aPluck, iFreq, .1 ;mezclar aPluck y aFilter de acuerdo a MidiNote ;(las notas altas se filtrarán más) aMix ntrpol aPluck, aFilter, iMidiNote, 36, 84 ;paneo también de acuerdo a MidiNote ;(bajo = izquierda, alto = derecha) iPan = (iMidiNote-36) / 48 aL, aR pan2 aMix, iPan outs aL, aR endin instr exit exitnow endin </CsInstruments> <CsScore> i "notes_uniform" 0 1 23 ;establecer el número de notas por instrumento ;los instrumentos linrnd_low y linrnd_high se ejecutan automáticamente e 99999 ;posibilita ejecutar durante mucho tiempo (el abandono del programa será automático) </CsScore> </CsoundSynthesizer> ;ejemplo por joachim heintz

Triangular

En una distribución triangular los valores ubicados más hacia el centro del rango dado tienen más probabilidades que los que están en los extremos. La transición de probabilidad entre el centro y los extremos es lineal:

 

El algoritmo para conseguir esta distribución es también muy simple. Se generan dos números aleatorios uniformes y se toma la media de ellos. El siguiente ejemplo muestra la diferencia entre una distribución uniforme y una distribución triangular en el mismo entorno que el ejemplo anterior.

   EXAMPLE 01D04_trirand.csd   

<CsoundSynthesizer>
<CsOptions>
-d -odac -m0
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 32
nchnls = 2
0dbfs = 1
seed 0

;****UDO PARA DISTRIBUCIÓN TRIANGULAR****
opcode trirnd, i, ii
iMin, iMax xin
 ;se generan dos valores aleatorios con el código operativo random
iOne       random     iMin, iMax
iTwo       random     iMin, iMax
 ;get the mean and output
iRnd       =          (iOne+iTwo) / 2
           xout       iRnd
endop

;****INSTRUMENTOS PARA UNA DISTRIBUCIÓN UNIFORME Y TRIANGULAR****

instr notes_uniform
           prints     "... instr notes_uniform ejecutándose:\n"
           prints     "IGUAL PROBABILIDAD PARA TODAS LAS ALTURAS Y DURACIONES\n"
 ;how many notes to be played
iHowMany   =          p4
 ;disparar tantas instancias del instrumento play como sean necesarias
iThisNote  =          0
iStart     =          0
 until iThisNote == iHowMany do
iMidiPch   random     36, 84 ;nota midi
iDur       random     .25, 1.75 ;duración
           event_i    "i", "play", iStart, iDur, int(iMidiPch)
iStart     +=         iDur ;aumentar el tiempo de inicio
iThisNote  +=         1 ;aumentar el contador
 enduntil
 ;reconfigurar la duración de este instrumento para hacer que todos los eventos ocurran
p3         =          iStart + 2
 ;ejecutar el siguiente instrumento pasados dos segundos desde la última nota 
           event_i    "i", "notes_trirnd", p3, 1, iHowMany
endin

instr notes_trirnd
           prints     "... instr notes_trirnd ejecutándose:\n"
           prints     "SE PREFIEREN NOTAS Y DURACIONES DE LA MEDIA\n"
iHowMany   =          p4
iThisNote  =          0
iStart     =          0
 until iThisNote == iHowMany do
iMidiPch   trirnd     36, 84 ;se prefieren las alturas del medio
iDur       trirnd     .25, 1.75 ;se prefieren las duraciones del medio
           event_i    "i", "play", iStart, iDur, int(iMidiPch)
iStart     +=         iDur
iThisNote  +=         1
 enduntil
 ;reconfigurar la duración de este instrumento para hacer que todos los eventos ocurran
p3         =          iStart + 2
 ;llamar al instrumento correspondiente para abandonar Csound
           event_i    "i", "exit", p3+1, 1
endin


;****INSTRUMENTOS PARA REPRODUCIR LOS SONIDOS Y PARA ABANDONAR CSOUND****

instr play
 ;aumentar la duración en el rango aleatorio
iDur       random     p3, p3*1.5
p3         =          iDur
 ;obtener nota midi y convertirla a frecuencia
iMidiNote  =          p4
iFreq      cpsmidinn  iMidiNote
 ;generar nota con el algoritmo karplus-strong
aPluck     pluck      .2, iFreq, iFreq, 0, 1
aPluck     linen      aPluck, 0, p3, p3
 ;filtro
aFilter    mode       aPluck, iFreq, .1
 ;mezclar aPluck y aFilter de acuerdo a MidiNote
 ;(las notas altas se filtrarán más)
aMix       ntrpol     aPluck, aFilter, iMidiNote, 36, 84
 ;paneo también de acuerdo a MidiNote 
;(bajo = izquierda, alto = derecha)
iPan = (iMidiNote-36) / 48 aL, aR pan2 aMix, iPan outs aL, aR endin instr exit exitnow endin </CsInstruments> <CsScore> i "notes_uniform" 0 1 23 ;establecer el número de notas por instrumento ;el instrumento trirnd se ejecutará automáticamente e 99999 ;posibilita ejecutar durante mucho tiempo (el abandono del programa será automático) </CsScore> </CsoundSynthesizer> ;ejemplo por joachim heintz


Más sobre Lineal y Triangular


Después de haber escrito esto utilizando algunos UDOs muy simples, resulta sencillo enfatizar los picos de probabilidad de las distribuciones mediante la generación de más de dos números al azar. Si generan tres números y se elige el más pequeño de ellos, se obtendrán muchos más números cerca del mínimo para la distribución lineal. Si se generan tres números al azar y se toma la media de ellos, el resultado final se aproximará a más números cercanos a la media para la distribución triangular.

Si queremos escribir UDOs con un número flexible de números sub-generados, deberíamos escribir el código de una manera ligeramente diferente. En lugar de tener una línea de código para cada generador aleatorio, utilizaremos un bucle, que a su vez llamará al generador tantas veces como unidades se deseen obtener. Una variable almacenará los resultados de esta acumulación. Reescribir el código operativo para el UDO trirnd nos llevaría a la siguiente formulación:

 

opcode trirnd, i, ii
iMin, iMax xin
 ;establecer un contador y una cuenta máxima
iCount     =          0
iMaxCount  =          2
 ;establecer el acumulador en cero como valor inicial
iAccum     =          0
 ;ejecutar bucle y acumular
 until iCount == iMaxCount do
iUniRnd    random     iMin, iMax
iAccum     +=         iUniRnd
iCount     +=         1
 enduntil
 ;obtener la media y retornar.
iRnd       =          iAccum / 2
           xout       iRnd
endop

Para tornar ésto completamente flexible, es suficiente con configurar iMaxCount como argumento de entrada. El código para los UDOs de distribución lineal es bastante similar. -- El siguiente ejemplo muestra estos pasos:

  1. Distribución uniforme
  2. Distribución lineal con prevalencia de las alturas más bajas y duraciones más largas, generadas con dos unidades
  3. Ídem pero con cuatro unidades
  4. Distribución lineal con prevalencia de las alturas más altas y duraciones más cortas, generadas con dos unidades
  5. Ídem pero con cuatro unidades
  6. Distribución triangular con prevalencia de alturas y duraciones medias, generadas con dos unidades
  7. Ídem pero con seis unidades

En lugar de utilizar diferentes instrumentos para las distintas distribuciones, el siguiente ejemplo combina todas las posibilidades en un solo instrumento. Dentro del bucle que genera tantas notas como se deseen por medio del argumento iHowMany, una sentencia condicional if calcula el tono y la duración de una nota en función del tipo de distribución y el número de sub-unidades utilizados. La secuencia entera (cuál tipo primero, cuál siguiente, etc.) se almacena en el vector global giSequence. Cada instancia del instrumento "notes", incrementa el puntero giSeqIndx, de modo que en la próxima ejecución se leerá el elemento siguiente del vector. Si el puntero ha alcanzado el final del mismo, el instrumento que ocasiona la salida de Csound es llamado en lugar de una nueva instancia de "notes".

   EXAMPLE 01D05_more_lin_tri_units.csd    

<CsoundSynthesizer>
<CsOptions>
-d -odac -m0
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 32
nchnls = 2
0dbfs = 1
seed 0

;****SECUENCIAS DE UNIDADES COMO ARRAYS****/
giSequence[] array 0, 1.2, 1.4, 2.2, 2.4, 3.2, 3.6
giSeqIndx = 0 ;índice de comienzo

;****DEFINICIONES DE UDOs****
opcode linrnd_low, i, iii
 ;aleatoriedad lineal con prevalencia de los valores más bajos
iMin, iMax, iMaxCount xin
 ;establecer contador y resultado inicial (absurdo)
iCount     =          0
iRnd       =          iMax
 ;bucle y reseteo de iRnd
 until iCount == iMaxCount do
iUniRnd    random     iMin, iMax
iRnd       =          iUniRnd < iRnd ? iUniRnd : iRnd
iCount     +=         1
 enduntil
           xout       iRnd
endop

opcode linrnd_high, i, iii
 ;aleatoriedad lineal con prevalencia de los valores más altos
iMin, iMax, iMaxCount xin
 ;establecer contador y resultado inicial (absurdo)
iCount     =          0
iRnd       =          iMin
 ;bucle y reseteo de iRnd
 until iCount == iMaxCount do
iUniRnd    random     iMin, iMax
iRnd       =          iUniRnd > iRnd ? iUniRnd : iRnd
iCount     +=         1
 enduntil
           xout       iRnd
endop

opcode trirnd, i, iii
iMin, iMax, iMaxCount xin
 ;establecer un contador y un acumulador
iCount     =          0
iAccum     =          0
 ;ejecutar bucle y acumular
 until iCount == iMaxCount do
iUniRnd    random     iMin, iMax
iAccum     +=         iUniRnd
iCount     +=         1
 enduntil
 ;obtener la media y retornar
iRnd       =          iAccum / iMaxCount
           xout       iRnd
endop

;****UN INSTRUMENTO QUE REALIZA TODAS LAS DISTRIBUCIONES****
;0 = uniforme, 1 = linrnd_low, 2 = linrnd_high, 3 = trirnd
;la parte fraccionaria denota el número de unidades, por ejemplo,
;3.4 = distribución triangular con cuatro sub-unidades

instr notes
 ;cuántas notas se ejecutarán
iHowMany   =          p4
 ;por qué distribución con cuántas unidades
iWhich     =          giSequence[giSeqIndx]
iDistrib   =          int(iWhich)
iUnits     =          round(frac(iWhich) * 10)
 ;establecer duración mínima y máxima
iMinDur    =          .1
iMaxDur    =          2
 ;establecer altura mínima y máxima
iMinPch    =          36
iMaxPch    =          84

 ;disparar tantas instancias del instrumento play como sea necesario
iThisNote  =          0
iStart     =          0
iPrint     =          1

 ;por cada nota a ejecutarse
 until iThisNote == iHowMany do

  ;calcular iMidiPch y iDur dependiendo del tipo
  if iDistrib == 0 then
           printf_i   "%s", iPrint, "... distribución uniforme:\n"
           printf_i   "%s", iPrint, "IGUAL PROBABILIDAD PARA TODAS LAS ALTURAS Y DURACIONES\n"
iMidiPch   random     iMinPch, iMaxPch ;nota midi
iDur       random     iMinDur, iMaxDur ;duración
  elseif iDistrib == 1 then
           printf_i    "... distribución lineal baja con %d unidades:\n", iPrint, iUnits
           printf_i    "%s", iPrint, "SE PREFIEREN NOTAS MÁS BAJAS Y DURACIONES MÁS LARGAS\n"
iMidiPch   linrnd_low iMinPch, iMaxPch, iUnits
iDur       linrnd_high iMinDur, iMaxDur, iUnits
  elseif iDistrib == 2 then
           printf_i    "... distribución lineal alta con %d unidades:\n", iPrint, iUnits
           printf_i    "%s", iPrint, "SE PREFIEREN NOTAS MÁS ALTAS Y DURACIONES MÁS CORTAS\n"
iMidiPch   linrnd_high iMinPch, iMaxPch, iUnits
iDur       linrnd_low iMinDur, iMaxDur, iUnits
  else
           printf_i    "... distribución triangular con %d unidades:\n", iPrint, iUnits
           printf_i    "%s", iPrint, "SE PREFIEREN ALTURAS Y DURACIONES MEDIAS\n"
iMidiPch   trirnd     iMinPch, iMaxPch, iUnits
iDur       trirnd     iMinDur, iMaxDur, iUnits
  endif

 ;llamar al subinstrumento para interpretar la nota
           event_i    "i", "play", iStart, iDur, int(iMidiPch)

 ;aumentar tiempo de inicio y contador
iStart     +=         iDur
iThisNote  +=         1
 ;evitar la impresión a pantalla continua
iPrint     =          0
 enduntil

 ;restablecer la duración de este instrumento para hacer que todas las ejecuciones sucedan.
p3         =          iStart + 2

 ;aumentar el índice para la secuencia
giSeqIndx  +=         1
 ;llamar al instrumento de nuevo si la secuencia no ha sido terminada
 if giSeqIndx < lenarray(giSequence) then
           event_i    "i", "notes", p3, 1, iHowMany
 ;o salir
 else
           event_i    "i", "exit", p3, 1
 endif
endin


;****INSTRUMENTOS PARA EJECUTAR LOS SONIDOS Y ABANDONAR CSOUND****
instr play
 ;aumentar la duración en el rango aleatorio
iDur       random     p3, p3*1.5
p3         =          iDur
 ;obtener nota midi y convertirla a frecuencia
iMidiNote  =          p4
iFreq      cpsmidinn  iMidiNote
 ;generar nota con el algoritmo de karplus-strong
aPluck     pluck      .2, iFreq, iFreq, 0, 1
aPluck     linen      aPluck, 0, p3, p3
 ;filtro
aFilter    mode       aPluck, iFreq, .1
 ;mezclar aPluck y aFilter de acuerdo a MidiNote
 ;(las notas más altas se filtrarán más)
aMix       ntrpol     aPluck, aFilter, iMidiNote, 36, 84
 ;paneo de acuerdo a MidiNote
 ;(bajo = izquierda, alto = derecho)
iPan       =          (iMidiNote-36) / 48
aL, aR     pan2       aMix, iPan
           outs       aL, aR
endin

instr exit
           exitnow
endin

</CsInstruments>
<CsScore>
i "notes" 0 1 23 ;establecer el número de notas por instrumento aquí
e 99999 ;posibilita ejecutar durante mucho tiempo (la salida de Csound será automática)
</CsScore>
</CsoundSynthesizer>
;ejemplo por joachim heintz

Con este método podemos construir distribuciones de probabilidad muy similares a las distribuciones exponenciales y gaussianas.5 La forma puede configurarse fácilmente mediante el número de sub-unidades utilizadas.

Scalings [Escalamiento]

La aleatoriedad es un ámbito complejo y sensible. Hay tantas maneras para dejar que el caballo vaya, corra o baile -las condiciones que se establecen para este "modo de moverse" son mucho más importantes que el hecho de que un solo movimiento no sea predecible. ¿Cuáles son las condiciones de esta aleatoriedad?

  • Cuál camino. Esto ya ha sido descripto: aleatoriedad con y sin historia, qué distribución de probabilidad, etc.
  • Cuál RangoEsta es una decisión que viene del compositor/programador. En el ejemplo anterior se han elegido alturas para la notas Midi que van del valor 36 al 84 (C2 a C6), y duraciones de entre 0.1 y 2 segundos. Imagínese cómo habría sonado con alturas con valores de 60 a 67, y duraciones de 0.9 a 1.1 segundos, o bien de 0.1 a 0.2 segundos. No hay una rango "correcto", todo depende de la idea musical.
  • Cuál DesarrolloPor lo general, los límites cambiarán a lo largo de una pieza. El rango de las alturas puede pasar de menor a mayor, o de estrecho a ancho; las duraciones pueden tornarse más bajas, etc.
  • Cuáles Escalamientos. Pensemos sobre esto con mayor detenimiento.

En el ejemplo anterior hemos utilizado dos escalamientos implícitos. Las alturas han sido delimitadas a las de las teclas de un piano o teclado. ¿Por qué? No estamos tocando un piano aquí, obviamente, ... -¿Qué otras posibilidades podrían haberse elegido en su lugar? Una de ellas sería: ningun escalamiento en absoluto. Esta es la forma más fácil de proseguir -si realmente es la mejor, o simplemente actuamos por pereza, sólo puede ser decidido por el compositor o el oyente.

En lugar de utilizar la escala cromática temperada, o de usar ninguna escala en absoluto, se puede utilizar cualquier otra manera de seleccionar o cuantificar las alturas. Trátese de cualquiera que haya o esté siendo usada en cualquier parte del mundo, o sea una de su propia invención, por cualquier fantasía, invención o sistema.

En cuanto a la duración, el ejemplo anterior no ha mostrado escalamiento en absoluto. Esto es sin dudas por pereza ..

El siguiente ejemplo es esencialmente el mismo que el anterior, pero utilizando una escala de alturas que representa la serie de armónicos. Comenzando en el segundo parcial se extiende hacia arriba al parcial número 32. Esta escala está escrita dentro de un vector mediante una declaración en el instrumento 0. Las duraciones poseen valores posibles fijos que también están escritas en otro vector (de la más larga a la más corta) de manera manual. Los valores en ambas vector son luego llamados de acuerdo a su posición.

 

   EXAMPLE 01D06_scalings.csd     

<CsoundSynthesizer>
<CsOptions>
-d -odac -m0
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 32
nchnls = 2
0dbfs = 1
seed 0


;****DURACIONES POSIBLES DENTRO DE UN ARRAY****
giDurs[]   array      3/2, 1, 2/3, 1/2, 1/3, 1/4
giLenDurs  lenarray   giDurs

;****ALTURAS POSIBLES DENTRO DE UN ARRAY****
 ;inicializar array con 31 pasos/escalones
giScale[]  init       31
giLenScale lenarray   giScale
 ;iterar para llenar desde 65 hz en adelante
iStart     =          65
iDenom     =          3 ;inicio con 3/2
iCnt       =          0
 until iCnt = giLenScale do
giScale[iCnt] =       iStart
iStart     =          iStart * iDenom / (iDenom-1)
iDenom     +=         1 ;la siguiente proporción es 4/3 etc.
iCnt       +=         1
 enduntil

;****SECUENCIA DE UNIDADES DENTRO DE UN ARRAY****
giSequence[] array    0, 1.2, 1.4, 2.2, 2.4, 3.2, 3.6
giSeqIndx  =          0 ;startindex

;****UDO DEFINITIONS****
opcode linrnd_low, i, iii
 ;aleatoriedad lineal con preferencia de valores más bajos
iMin, iMax, iMaxCount xin
 ;establecer contador y resultado inicial (absurdo)
iCount     =          0
iRnd       =          iMax
 ;realizar bucle y restablecer iRnd
 until iCount == iMaxCount do
iUniRnd    random     iMin, iMax
iRnd       =          iUniRnd < iRnd ? iUniRnd : iRnd
iCount += 1
enduntil
           xout       iRnd
endop

opcode linrnd_high, i, iii
 ;aleatoriedad lineal con preferencia de valores más altos
iMin, iMax, iMaxCount xin
 ;establecer contador y resultado inicial (absurdo)
iCount     =          0
iRnd       =          iMin
 ;realizar bucle y restablecer iRnd
 until iCount == iMaxCount do
iUniRnd    random     iMin, iMax
iRnd       =          iUniRnd > iRnd ? iUniRnd : iRnd
iCount += 1
enduntil
           xout       iRnd
endop

opcode trirnd, i, iii
iMin, iMax, iMaxCount xin
 ;establecer un contador y un acumulador
iCount     =          0
iAccum     =          0
 ;realizar bucle y acumular
 until iCount == iMaxCount do
iUniRnd    random     iMin, iMax
iAccum += iUniRnd
iCount += 1
enduntil
 ;obtener la media y retornar
iRnd       =          iAccum / iMaxCount
           xout       iRnd
endop


;****UN INSTRUMENTO QUE REALIZA TODAS LAS DISTRIBUCIONES**** 
;0 = uniforme, 1 = linrnd_low, 2 = linrnd_high, 3 = trirnd
;la parte fraccionaria denota el número de unidades, por ejemplo,
;3.4 = distribución triangular con cuatro sub-unidades instr notes ;cuántas notas deberan ejecutarse iHowMany = p4 ;mediante qué distribución y con cuántas unidades iWhich = giSequence[giSeqIndx] iDistrib = int(iWhich) iUnits = round(frac(iWhich) * 10) ;disparar tantas instancias del instrumento play como sea necesario iThisNote = 0 iStart = 0 iPrint = 1 ;para cada nota a ser ejecutada until iThisNote == iHowMany do ;calcular iMidiPch e iDur dependiendo del tipo if iDistrib == 0 then printf_i "%s", iPrint, "... distribución uniforme:\n" printf_i "%s", iPrint, "IGUAL PROBABILIDAD PARA TODAS LAS ALTURAS Y DURACIONES\n" iScaleIndx random 0, giLenScale-.0001 ;nota midi iDurIndx random 0, giLenDurs-.0001 ;duración elseif iDistrib == 1 then printf_i "... distribución lineal baja con %d unidades:\n", iPrint, iUnits printf_i "%s", iPrint, "SE PREFIEREN NOTAS MÁS BAJAS Y DURACIONES MÁS LARGAS\n" iScaleIndx linrnd_low 0, giLenScale-.0001, iUnits iDurIndx linrnd_low 0, giLenDurs-.0001, iUnits elseif iDistrib == 2 then printf_i "... distribución lineal con %d unidades:\n", iPrint, iUnits printf_i "%s", iPrint, "SE PREFIEREN NOTAS MÁS ALTAS Y DURACIONES MÁS CORTAS\n" iScaleIndx linrnd_high 0, giLenScale-.0001, iUnits iDurIndx linrnd_high 0, giLenDurs-.0001, iUnits else printf_i "... distribución triangular con %d unidades:\n", iPrint, iUnits printf_i "%s", iPrint, "SE PREFIEREN NOTAS Y DURACIONES MEDIAS\n" iScaleIndx trirnd 0, giLenScale-.0001, iUnits iDurIndx trirnd 0, giLenDurs-.0001, iUnits endif ;llamar al subinstrumento para ejecutar la nota iDur = giDurs[int(iDurIndx)] iPch = giScale[int(iScaleIndx)] event_i "i", "play", iStart, iDur, iPch ;incrementar el tiempo de inicio y el contador iStart += iDur iThisNote += 1 ;evitar imprimir a pantalla continuadamente iPrint = 0 enduntil ;restablecer la duración de este instrumento para hacer que todos los eventos sucedan p3 = iStart + 2 ;incrementar el índice de la secuencia giSeqIndx += 1 ;llamar al instrumento nuevamente si la secuencia no ha sido terminada if giSeqIndx < lenarray(giSequence) then event_i "i", "notes", p3, 1, iHowMany ;o salir de Csound else event_i "i", "exit", p3, 1 endif endin ;****INTRUMENTOS PARA INTERPRETAR LOS SONIDOS Y SALIR DE CSOUND**** instr play ;incrementar la duración en el rango aleatorio iDur random p3*2, p3*5 p3 = iDur ;obtener frecuencia iFreq = p4 ;generar nota con el algoritmo de karplus-strong aPluck pluck .2, iFreq, iFreq, 0, 1 aPluck linen aPluck, 0, p3, p3 ;filtro aFilter mode aPluck, iFreq, .1 ;mezclar aPluck y aFilter de acuerdo a la frecuencia ;(las notas altas se filtrarán más) aMix ntrpol aPluck, aFilter, iFreq, 65, 65*16 ;paneo también de acuerdo a la frecuencia ;(bajo = izquierda, alto = derecha) iPan = (iFreq-65) / (65*16) aL, aR pan2 aMix, iPan outs aL, aR endin instr exit exitnow endin </CsInstruments> <CsScore> i "notes" 0 1 23 ;establecer número de notas por instrumento aquí e 99999 ;posibilita ejecutar durante mucho tiempo (la salida de Csound será automática) </CsScore> </CsoundSynthesizer> ;ejemplo por joachim heintz

 

Aleatoriedad con Historia

Hay muchas maneras en que un valor determinado dentro de una progresión de números aleatorios puede influir en el valor siguiente. Hay dos que se utilizan con frecuencia. Una cadena de Markov se basa en un número de estados posibles, y define una probabilidad diferente para cada uno de estos estados. Un paseo aleatorio considera al último estado como una posición en una rango o campo, y permite sólo ciertas desviaciones respecto de esta posición.

Cadenas de Markov

Un caso típico de una cadena de Markov en la música es el de una secuencia de ciertos tonos o notas. Para cada nota, la probabilidad de la siguiente nota se escribe en una tabla como esta:

 

Esto significa: la probabilidad de que se repita un elemento a es de 0,2; la probabilidad de que b siga después de a es 0,5; la probabilidad de que c sigua después de a es 0,3. La suma de todas las probabilidades debe, por convención, ser igual a 1. El siguiente ejemplo muestra el algoritmo básico que evalúa la primera línea de la tabla de Markov ilustrada anteriormente, en el caso en que el elemento anterior haya sido 'a'.

 

   EXAMPLE 01D07_markov_basics.csd      

<CsoundSynthesizer>
<CsOptions>
-ndm0
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 32
0dbfs = 1
nchnls = 1
seed 0

instr 1
iLine[]    array      .2, .5, .3
iVal       random     0, 1
iAccum     =          iLine[0]
iIndex     =          0
 until iAccum >= iVal do
iIndex     +=         1
iAccum     +=         iLine[iIndex]
 enduntil
           printf_i   "Número aleatorio = %.3f, siguiente elemento = %c!\n", 1, iVal, iIndex+97
endin
</CsInstruments>
<CsScore>
r 10
i 1 0 0
</CsScore>
</CsoundSynthesizer>
;ejemplo por joachim heintz

Las probabilidades son 0.2, 0.5 y 0.3. En primer lugar se genera un número aleatorio distribuido uniformemente entre 0 y 1. Un acumulador es establecido utilizando el primer elemento de la línea (en este caso 0.2). Luego es interrogado en cuanto a si es más grande que el número aleatorio. Si es así, se devuelve el índice, si no, se añade el segundo elemento (0,2 + 0,5 = 0,7), y el proceso se repite hasta que el acumulador sea mayor o igual al valor aleatorio. La salida del ejemplo debería mostrar algo como esto:

Número aleatorio = 0.850, siguiente elemento = c!
Número aleatorio = 0.010, siguiente elemento = a!
Número aleatorio = 0.805, siguiente elemento = c!
Número aleatorio = 0.696, siguiente elemento = b!
Número aleatorio = 0.626, siguiente elemento = b!
Número aleatorio = 0.476, siguiente elemento = b!
Número aleatorio = 0.420, siguiente elemento = b!
Número aleatorio = 0.627, siguiente elemento = b!
Número aleatorio = 0.065, siguiente elemento = a!
Número aleatorio = 0.782, siguiente elemento = c!

El siguiente ejemplo pone este algoritmo en un opcode definido por el usuario (UDO). Su entrada es una tabla de Markov en forma de un vector bidimensional, y la línea anterior como índice (empezando por el 0). Su salida es el elemento siguiente, también como índice. -- Hay dos cadenas de Markov en este ejemplo: siete alturas y tres duraciones. Ambas se definen en vectores bidimensionales: giProbNotes y giProbDurs. Ambas cadenas de Markov se ejecutan de forma independiente la una de la otra.


   EXAMPLE 01D08_markov_music.csd

<CsoundSynthesizer>
<CsOptions>
-dnm128 -odac
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 32
0dbfs = 1
nchnls = 2
seed 0

;****CÓDIGOS OPERATIVOS DEFINIDOS POR EL USUARIO PARA CADENAS DE MARKOV****
  opcode Markov, i, i[][]i
iMarkovTable[][], iPrevEl xin
iRandom    random     0, 1
iNextEl    =          0
iAccum     =          iMarkovTable[iPrevEl][iNextEl]
 until iAccum >= iRandom do
iNextEl    +=         1
iAccum     +=         iMarkovTable[iPrevEl][iNextEl]
 enduntil
           xout       iNextEl
  endop
  opcode Markovk, k, k[][]k
kMarkovTable[][], kPrevEl xin
kRandom    random     0, 1
kNextEl    =          0
kAccum     =          kMarkovTable[kPrevEl][kNextEl]
 until kAccum >= kRandom do
kNextEl    +=         1
kAccum     +=         kMarkovTable[kPrevEl][kNextEl]
 enduntil
           xout       kNextEl
  endop

;****DEFINICIONES PARA LAS NOTAS****
 ;notas como proporciones y una frecuencia base
giNotes[]  array      1, 9/8, 6/5, 5/4, 4/3, 3/2, 5/3
giBasFreq  =          330
 ;probabilidad de notas como una matriz de markov:
  ;primera -> sólo tercero y cuarto
  ;segunda -> cualquiera menos sí mismo
  ;tercera -> alta probabilidad de repeticiones
  ;cuarta -> idem
  ;quinta -> cualquiera menos tercero y cuarto
  ;sexta -> más que nada el septimo
  ;séptima -> más que nada el sexto
giProbNotes[][] init  7, 7
giProbNotes array     0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0,
                      0.2, 0.0, 0.2, 0.2, 0.2, 0.1, 0.1,
                      0.1, 0.1, 0.5, 0.1, 0.1, 0.1, 0.0,
                      0.0, 0.1, 0.1, 0.5, 0.1, 0.1, 0.1,
                      0.2, 0.2, 0.0, 0.0, 0.2, 0.2, 0.2,
                      0.1, 0.1, 0.0, 0.0, 0.1, 0.1, 0.6,
                      0.1, 0.1, 0.0, 0.0, 0.1, 0.6, 0.1

;****DEFINICIONES PARA DURACIONES****
 ;duraciones posibles
gkDurs[]    array     1, 1/2, 1/3
 ;probabilidad de duraciones como matriz de markov:
  ;primera -> cualquiera
  ;segunda -> más que nada sí misma
  ;tercera -> más que nada la segunda
gkProbDurs[][] init   3, 3
gkProbDurs array      1/3, 1/3, 1/3,
                      0.2, 0.6, 0.3,
                      0.1, 0.5, 0.4

;****ESTABLECER PRIMERA ALTURA Y NOTA PARA EL PROCESO DE MARKOV****
giPrevNote init       1
gkPrevDur  init       1

;****INSTRUMENO PARA LAS DURACIONES****
  instr trigger_note
kTrig      metro      1/gkDurs[gkPrevDur]
 if kTrig == 1 then
           event      "i", "select_note", 0, 1
gkPrevDur  Markovk    gkProbDurs, gkPrevDur
 endif
  endin

;****INSTRUMENTO PARA LAS ALTURAS****
  instr select_note
 ;choose next note according to markov matrix and previous note
 ;and write it to the global variable for (next) previous note
;elegir siguiente nota según la matriz de Markov y la nota previa
 ;y escribirla en la variable global como la (siguiente) nota anterior

 giPrevNote Markov giProbNotes, giPrevNote ;llamar al instrumento para ejecutar esta nota event_i "i", "play_note", 0, 2, giPrevNote ;apagar este instrumento turnoff endin ;****INSTRUMENTO PARA EJECUTAR UNA NOTA**** instr play_note ;get note as index in ginotes array and calculate frequency
;obtener nota como índice en la matriz ginots y calcular la frecuencia
iNote = p4 iFreq = giBasFreq * giNotes[iNote] ;elección aleatoria para la cualidad del filtro mode y el paneo iQ random 10, 200 iPan random 0.1, .9 ;generar tono y volcar a la salida de audio aImp mpulse 1, p3 aOut mode aImp, iFreq, iQ aL, aR pan2 aOut, iPan outs aL, aR endin </CsInstruments> <CsScore> i "trigger_note" 0 100 </CsScore> </CsoundSynthesizer> ;ejemplo por joachim heintz 

 

La Caminata Aleatoria

En el contexto del movimiento entre los valores aleatorios, la 'caminata' puede ser pensada como lo opuesto al 'salto'. Si se salta dentro de los límites A y B, sepuede terminar en cualquier lugar entre esos límites, pero si se camina entre A y B habrá una limitación impuesta por el alcance de los pasos -cada paso aplica una desviación con respecto al anterior. Si el rango de desviación es ligeramente tendiente hacia lo positivo (por caso, de -0,1 a 0,2), la trayectoria general de su caminata estará en la dirección positiva (pero los pasos individuales no estarán necesariamente en la dirección positiva). Si el rango de desviación se inclina hacia lo negativo (digamos de -0,2 a 0,1), entonces la caminata expresará una trayectoria generalmente negativa.

Una forma de implementar una caminata aleatoria podría ser tomando el estado actual, derivando una desviación aleatoria y luego derivando el siguiente estado mediante la adición de esta desviación al estado actual. El siguiente ejemplo muestra dos formas de hacer esto.

La caminata aleatoria de altura comienza en la altura 8 según la notación de octava. La desviación general de altura gkPitchDev  se establece en 0.2, de modo que la siguiente altura podría ser de entre 7.8 y 8.2. Pero también hay una dirección de altura gkPitchDir que se establece como valor inicial en 0.1. Esto significa que el límite superior de la siguiente altura aleatoria es 8.3 en lugar de 8.2, por lo que la altura se moverá hacia arriba en un mayor número de pasos. Cuando se ha cruzado el límite superior giHighestPitch, la variable gkPitchDir cambia de 0.1 a -0.1, así que después de un número de pasos determinado, la altura se tornará más baja. Cada vez que un cambio de dirección como este ocurre, la consola informa de esto con un mensaje impreso en el terminal.

La densidad de las notas se define en término de notas por segundo, y se aplica como frecuencia al opcode metro en el instrumento 'walk'. La densidad más baja posible giLowestDens se establece en 1, la más alta en 8 notas por segundo, y la densidad inical giStartDens se establece en 3. La desviación aleatoria posible para la siguiente densidad se define en un rango que va de cero a uno: cero significa que no hay desviación en absoluto, uno significa que la siguiente densidad puede alterar la densidad actual en un rango que va de la mitad del valor actual hasta dos veces dicho valor. Por ejemplo, si la densidad actual es 4, con gkDensDev = 1 se obtendría una densidad de entre 2 y 8. La dirección de las densidades gkDensDir en esta caminata aleatoria sigue el mismo rango 0...1. Asumiendo que no se tiene ninguna desviación de las densidades en absoluto (gkDensDev = 0), gkDensDir = 0 producirá impulsos siempre a la misma velocidad, mientras que gkDensDir = 1 producirá un aumento muy rápido de velocidad. Al igual que en la caminata de altura, los parámetros de dirección alternan de más a menos, si el borde superior ha sido cruzado, y viceversa.

   EXAMPLE 01D09_random_walk.csd

<CsoundSynthesizer>
<CsOptions>
-dnm128 -odac
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 32
0dbfs = 1
nchnls = 2
seed 1 ;cambiar a 0 para resultados siempre cambiantes

;****CONFIGURACIONES PARA LAS ALTURAS****
 ;define the pitch street(?) in octave notation
;definir el rango de la altura en notación de octava
giLowestPitch = 7 giHighestPitch = 9 ;set pitch startpoint, deviation range and the first direction
;establecer la altura inicial, el rango de desviación y la primera dirección
giStartPitch = 8 gkPitchDev init 0.2 ;rango aleatorio para la próxima altura gkPitchDir init 0.1 ;positivo = en dirección superior ;****CONFIGURACIONES PARA LAS DENSIDADES**** ;define the maximum and minimum density (notes per second)
;definir la densidad máxima y mínima(notas por segundo)
giLowestDens = 1 giHighestDens = 8 ;set first density
;establecer la densidad inicial
giStartDens = 3 ;set possible deviation in range 0..1 ;0 = no deviation at all ;1 = possible deviation is between half and twice the current density
;establecer la posible desviación en el rango de 0..1
;0 = sin desviación
;1 = la desviación posible está entre la mitad y el doble de la densidad actual
gkDensDev init 0.5 ;set direction in the same range 0..1 ;(positive = more dense, shorter notes)
;establecer la dirección en el mismo rango 0..1
;(positivo = notas más densas, más cortas)
gkDensDir init 0.1 ;****INSTRUMENTO PARA LA CAMINATA ALEATORIA**** instr walk ;set initial values
;establecer los valores iniciales
kPitch init giStartPitch kDens init giStartDens ;trigger impulses according to density
;disparar impulsos de acuerdo a la densidad
kTrig metro kDens ;if the metro ticks
;si el metro marca un tick
 if kTrig == 1 then ;1) play current note ;1) reproducir la nota actual
event "i", "play", 0, 1.5/kDens, kPitch ;2) calculate next pitch ;define boundaries according to direction ;2) calcular la altura siguiente
;definir los límites de acuerdo a la dirección
kLowPchBound = gkPitchDir < 0 ? -gkPitchDev+gkPitchDir : -gkPitchDev kHighPchBound = gkPitchDir > 0 ? gkPitchDev+gkPitchDir : gkPitchDev ;get random value in these boundaries
;obtener el valor aleatorio en estos límites
kPchRnd random kLowPchBound, kHighPchBound ;add to current pitch ;agregar a la altura actual
kPitch += kPchRnd ;change direction if maxima are crossed, and report ;cambiar la dirección si se cruza el máximo, e informar
if kPitch > giHighestPitch && gkPitchDir > 0 then gkPitchDir = -gkPitchDir printks " La altura alcanzó el máximo - yendo hacia abajo ahora.\n", 0 elseif kPitch < giLowestPitch && gkPitchDir < 0 then gkPitchDir = -gkPitchDir printks "La altura alcanzó el mínimo - yendo hacia arriba ahora.\n", 0 endif ;3) calculate next density (= metro frequency) ;define boundaries according to direction ;3) calcular la próxima densidad( = frecuencia del metro)
;definir los límites de acuerdo a la dirección
kLowDensBound = gkDensDir < 0 ? -gkDensDev+gkDensDir : -gkDensDev kHighDensBound = gkDensDir > 0 ? gkDensDev+gkDensDir : gkDensDev ;get random value in these boundaries ;obtener el valor aleatorio en estos límites
kDensRnd random kLowDensBound, kHighDensBound ;get multiplier (so that kDensRnd=1 yields to 2, and kDens=-1 to 1/2) ;obtener multiplicador (de modo que kDensRnd=1 produzca 2 y kDens=-1, 1/2)
kDensMult = 2 ^ kDensRnd ;multiply with current duration ;multiplicar con la duración actual
kDens *= kDensMult ;avoid too high values and too low values ;evitar los valores demasiado altos y demasiado bajos
kDens = kDens > giHighestDens*1.5 ? giHighestDens*1.5 : kDens kDens = kDens < giLowestDens/1.5 ? giLowestDens/1.5 : kDens ;change direction if maxima are crossed ;cambiar dirección si se cruza el máximo
if (kDens > giHighestDens && gkDensDir > 0) || (kDens < giLowestDens && gkDensDir < 0) then gkDensDir = -gkDensDir if kDens > giHighestDens then printks " La densidad tocó el borde superior - volviéndose menos denso ahora.\n", 0 else printks " La densidad tocó el borde inferior - volviéndose más denso ahora.\n", 0 endif endif endif endin ;****INSTRUMENTO PARA REPRODUCIR UNA NOTA**** instr play ;get note as octave and calculate frequency and panning ;obtener nota como octava y calcular la frecuencia y el paneo
iOct = p4 iFreq = cpsoct(iOct) iPan ntrpol 0, 1, iOct, giLowestPitch, giHighestPitch ;calculate mode filter quality according to duration ;calcular la calidad del modo del filtro de acuerdo a la duración
iQ ntrpol 10, 400, p3, .15, 1.5 ;generate tone and throw out
;generar tono y dar salida
aImp mpulse 1, p3 aMode mode aImp, iFreq, iQ aOut linen aMode, 0, p3, p3/4 aL, aR pan2 aOut, iPan outs aL, aR endin </CsInstruments> <CsScore> i "walk" 0 999 </CsScore> </CsoundSynthesizer> ;ejemplo por joachim heintz 

II. ALGUNAS PERSPECTIVAS MATEMÁTICAS SOBRE LA ALEATORIEDAD

Procesos Aleatorios

La frecuencia relativa de aparición de una variable aleatoria puede ser descrita por una función de probabilidad (para variables aleatorias discretas) o por funciones de densidad (para variables aleatorias contínuas).

Cuando dos dados son lanzados simultáneamente, la suma x de sus números puede ser 2, 3, ... 12. La siguiente figura muestra la función de probabilidad p(x) de estos posibles resultados. p(x) es siempre menor o igual a 1. La suma de las probabilidades de todos los resultados posibles es 1.

     

Para las variables aleatorias continuas la probabilidad de obtener un valor x específico es 0. Sin embargo, la probabilidad de obtener un valor dentro de un cierto intervalo puede ser indicado por un área que corresponde a esta probabilidad. La función f(x) sobre estas áreas se denomina función de densidad. Respecto a la siguiente densidad, la probabilidad de obtener un número menor que 0 es 0, de obtener un número entre 0 y 0.5 es de 0.5, de obtener un número entre 0.5 y 1 es de 0.5, etc. Las funciones de densidad f(x) pueden alcanzar valores superiores a 1, pero el área bajo la función es 1.

        

 

Generando Números Aleatorios Con una Probabilidad o Densidad Dada

Csound proporciona opcodes para algunas densidades específicas, pero no hay medios para producir números aleatorios con funciones de probabilidad o densidad definidas por el usuario. Los opcodes rand_density y rand_probability (véase más adelante) generan números al azar con probabilidades o densidades dadas por tablas. Se realizan mediante el llamado método de muestreo de rechazo.

Muestreo de Rechazo

El principio del muestreo de rechazo se basa en -primero- generar números aleatorios uniformemente distribuidos en el rango requerido y luego aceptar estos valores de acuerdo a una función de densidad dada (o de otra forma rechazarlos). Veamos un ejemplo de este método usando la función de densidad mostrada en la siguiente figura. (Dado que el método de muestreo de rechazo sólo utiliza la "forma" de la función, el área bajo la función no tiene que ser 1). En primer lugar, generamos números aleatorios uniformemente distribuidos rnd1 en el intervalo [0, 1]. De éstos aceptamos una proporción correspondiente a f(rnd1). Por ejemplo, el valor 0,32 sólo será aceptado en la proporción de f(0,32) = 0.82. Realizamos esto mediante la generación de un nuevo número aleatorio rand2 entre 0 y 1 y aceptamos rnd1 sólo si rand2 < f(rnd1); de lo contrario lo rechazamos. (Ver Señales, Sistemas y Síntesis de Sonido6, capítulo 10.1.4.4)

 

        

 

EXAMPLE 01D10_Rejection_Sampling.csd

<CsoundSynthesizer>
<CsOptions>
-odac
</CsOptions>
<CsInstruments>
;ejemplo por martin neukom
sr = 44100
ksmps = 10
nchnls = 1
0dbfs = 1

; random number generator to a given density function
; kout random number; k_minimum,k_maximum,i_fn for a density function ; generador de númeror aleatorios para una función de densidad dada
; kout número aleatrorio; k_minimum,k_maximum,i_fn para una función de densidad

opcode rand_density, k, kki kmin,kmax,ifn xin loop: krnd1 random 0,1 krnd2 random 0,1 k2 table krnd1,ifn,1 if krnd2 > k2 kgoto loop xout kmin+krnd1*(kmax-kmin) endop ; random number generator to a given probability function ; kout random number ; in: i_nr number of possible values ; i_fn1 function for random values ; i_fn2 probability functionExponential: Generate a uniformly distributed number between 0 and 1 and take its natural logarithm. ; generador de números aleatorios para una función de probabilidad dada
; kout número aleatorio
; in: i_nr número de valores posibles
; i_fn1 función para valores aleatorios
; i_fn2 función de probabilida exponencial: Genera un número uniformemente distribuido entre 0 y 1 y toma su logaritmo natural.
opcode rand_probability, k, iii inr,ifn1,ifn2 xin loop: krnd1 random 0,inr krnd2 random 0,1 k2 table int(krnd1),ifn2,0 if krnd2 > k2 kgoto loop kout table krnd1,ifn1,0 xout kout endop instr 1 krnd rand_density 400,800,2 aout poscil .1,krnd,1 out aout endin instr 2 krnd rand_probability p4,p5,p6 aout poscil .1,krnd,1 out aout endin </CsInstruments> <CsScore> ;sine
;seno
f1 0 32768 10 1 ;density function
;función de densidad
f2 0 1024 6 1 112 0 800 0 112 1 ;random values and their relative probability (two dice)
;valores aleatorios y su probabilidad relativa (dos dados)
f3 0 16 -2 2 3 4 5 6 7 8 9 10 11 12 f4 0 16 2 1 2 3 4 5 6 5 4 3 2 1 ;random values and their relative probability
;valores aleatorios y su probabilidad relativa
f5 0 8 -2 400 500 600 800 f6 0 8 2 .3 .8 .3 .1 i1 0 10 i2 0 10 4 5 6 </CsScore> </CsoundSynthesizer>


Caminata Aleatoria

En una serie de números aleatorios los números particulares son independientes el uno del otro. Los tipos parámetro (figura de la izquierda) o caminos en la habitación (trayectoria de dos dimensiones en la figura de la derecha) creados por números aleatorios se mueven de manera descontrolada.

Ejemplo 1

Table[RandomReal[{-1, 1}], {100}];

    

Obtenemos un camino más suave, denominada caminata aleatoria, mediante la adición en cada paso de tiempo de un número aleatorio r a la posición real de x (x += r).

Ejemplo 2

x = 0; caminata = Table[x += RandomReal[{-.2, .2}], {300}]; 

   

El camino se hace aún más suave mediante la adición de un número aleatorio r a la velocidad real v.

v += r
x += v

El camino puede estar limitado a un área (figura de la derecha) mediante la inversión de la velocidad si el camino excede los límites (min, max):

vif(x < min || x > max) v *= -1

El movimiento puede ser amortiguado mediante la disminución de la velocidad en cada paso de tiempo por un pequeño factor d

 v *= (1-d) 

Ejemplo 3

x = 0; v = 0; caminata = Table[x += v += RandomReal[{-.01, .01}], {300}]; 

   

 

El camino se vuelve de nuevo más suave mediante la adición de un número aleatorio r a la aceleración corriente a, el cambio de la aceleración, etc.

a += r
v += a
x += v

Ejemplo 4

x = 0; v = 0; a = 0;  
Table[x += v += a += RandomReal[{-.0001, .0001}], {300}];

  

(Ver Martin Neukom, Señales, Sistemas y Síntesis de Sonido, capítulo 10.2.3.2)

EXAMPLE 01D11_Random_Walk2.csd

<CsoundSynthesizer>
<CsOptions>
-odac
</CsOptions>
<CsInstruments>
;ejemplo por martin neukom

sr = 44100
ksmps = 128
nchnls = 1
0dbfs = 1

; random frequency
; frecuencia aleatoria
instr 1 kx random -p6, p6 kfreq = p5*2^kx aout oscil p4, kfreq, 1 out aout endin ; random change of frequency
; variación aleatoria de la frecuencia
instr 2 kx init .5 kfreq = p5*2^kx kv random -p6, p6 kv = kv*(1 - p7) kx = kx + kv aout oscil p4, kfreq, 1 out aout endin ; random change of change of frequency
; variacion aleatoria de la variación de la frecuencia
instr 3 kv init 0 kx init .5 kfreq = p5*2^kx ka random -p7, p7 kv = kv + ka kv = kv*(1 - p8) kx = kx + kv kv = (kx < -p6 || kx > p6?-kv : kv) aout oscili p4, kfreq, 1 out aout endin </CsInstruments> <CsScore> f1 0 32768 10 1 ; i1 p4 p5 p6 ; i2 p4 p5 p6 p7 ; amp c_fr rand damp ; i2 0 20 .1 600 0.01 0.001 ; amp c_fr d_fr rand damp ; amp c_fr rand ; i1 0 20 .1 600 0.5 ; i3 p4 p5 p6 p7 p8 i3 0 20 .1 600 1 0.001 0.001 </CsScore> </CsoundSynthesizer>

III. EJEMPLOS DIVERSOS

Csound tiene una serie de opcodes y rutinas GEN para la creación de diversas funciones y distribuciones aleatorias. Tal vez el más simple de ellos es random que simplemente genera un valor aleatorio dentro de un límite mínimo y máximo definido por el usuario y en tiempo-i, ciclo-k o ciclo-a de acuerdo al tipo de variable de su salida (ubicado a la izquierda del opcode):

 

ires random imin, imax
kres random kmin, kmax
ares random kmin, kmax

Los valores se generan de acuerdo con una distribución aleatoria uniforme, lo que significa que cualquier valor dentro de los límites tiene la misma probabilidad de ocurrencia. Las distribuciones no uniformes en las que ciertos valores tienen mayor probabilidad de ocurrencia por sobre otros son a menudo más útiles y musicales. Para estos propósitos, Csound incluye los opcodes generadores de números aleatorios betarand, bexprand, cauchy, exprand, gauss, linrand, pcauchy, poisson, trirand, unirand y weibull. Las distribuciones generadas a partir de varios de estos opcodes se ilustran a continuación:

 

 

 

 

Además de estos denominados 'generadores de ruido de clase x' Csound proporciona generadores de funciones aleatorias, proveyendo valores que cambian con el tiempo en diversas formas.

randomh genera nuevos números aleatorios a un ritmo definido por el usuario. El valor anterior se mantiene hasta que un nuevo valor sea generado, y luego la salida inmediatamente asume ese valor.

La instrucción:

kmin   =         -1
kmax   =         1
kfreq  =         2
kout   randomh   kmin,kmax,kfreq

producirá y generará una salida similar a:

 

randomi es una versión de randomh con interpolación. En lugar de "saltar" hacia los nuevos valores que se generan, randomi produce una interpolación lineal hacia el nuevo valor, alcanzándolo justo en el momento en que un próximo valor se genera. Al remplazar randomh con randomi en el código de ejemplo presentado más arriba se logrará el siguiente resultado:

 

En la práctica, los cambios angulares aleatorios en la dirección a medida que se generan nuevos valores aleatorios podrían ser audibles dependiendo de cómo se use. rsplsine (o más simple aún, jsplsine) permite especificar no sólo una sola frecuencia, sino una frecuencia mínima y una frecuencia máxima, y la función resultante es una spline suave entre los valores mínimo y máximo y estas frecuencias mínimas y máximas. La siguiente entrada:

 

kmin     =         -0.95
kmax     =         0.95
kminfrq  =         1
kmaxfrq  =         4
asig     rspline   kmin, kmax, kminfrq, kmaxfrq

generará algo similar a esto:

 

Tenemos que tener cuidado con lo que hacemos con la salida de rspline ya que ésta puede superar los límites establecidos por kmin y kmax. Los valores mínimo y máximo se pueden establecer de forma conservadora o el opcode limit podría ser utilizado para evitar valores fuera de rango que podrían causar problemas.

El ejemplo siguiente utiliza rspline para humanizar un sintetizador simple. Se toca una melodía corta, primero sin ninguna humanización y luego con humanización. La variación aleatoria de rspline se añade a la amplitud y al tono de cada nota además de un desplazamiento aleatorio sobre el tiempo-i.

 

EXAMPLE 01D12_humanising.csd

<CsoundSynthesizer>
<CsOptions>
-odac
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 32
nchnls = 2
0dbfs = 1
seed 0

giWave  ftgen  0, 0, 2^10, 10, 1,0,1/4,0,1/16,0,1/64,0,1/256,0,1/1024

  instr 1 ; an instrument with no 'humanising'
inote =       p4
aEnv  linen   0.1,0.01,p3,0.01
aSig  poscil  aEnv,cpsmidinn(inote),giWave
      outs    aSig,aSig
  endin

  instr 2 ; an instrument with 'humanising'
inote   =       p4

; generate some i-time 'static' random paramters
iRndAmp random	-3,3   ; amp. will be offset by a random number of decibels
iRndNte random  -5,5   ; note will be offset by a random number of cents

; generate some k-rate random functions
kAmpWob rspline -1,1,1,10   ; amplitude 'wobble' (in decibels)
kNteWob rspline -5,5,0.3,10 ; note 'wobble' (in cents)

; calculate final note function (in CPS)
kcps    =        cpsmidinn(inote+(iRndNte*0.01)+(kNteWob*0.01))

; amplitude envelope (randomisation of attack time)
aEnv    linen   0.1*ampdb(iRndAmp+kAmpWob),0.01+rnd(0.03),p3,0.01
aSig    poscil  aEnv,kcps,giWave
        outs    aSig,aSig
endin

</CsInstruments>
<CsScore>
t 0 80
#define SCORE(i) #
i $i 0 1   60
i .  + 2.5 69
i .  + 0.5 67
i .  + 0.5 65
i .  + 0.5 64
i .  + 3   62
i .  + 1   62
i .  + 2.5 70
i .  + 0.5 69
i .  + 0.5 67
i .  + 0.5 65
i .  + 3   64 #
$SCORE(1)  ; play melody without humanising
b 17
$SCORE(2)  ; play melody with humanising
e
</CsScore>
</CsoundSynthesizer>
;example by Iain McCurdy

El ejemplo final implementa un generador simple de notas algorítmicas. Hace uso de GEN17 para generar histogramas que definen las probabilidades de ciertas notas y ciertas brechas rítmicas que ocurren.

 EXAMPLE 01D13_simple_algorithmic_note_generator.csd

<CsoundSynthesizer>
<CsOptions>
-odac -dm0
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 32
nchnls = 1
0dbfs = 1

giNotes	ftgen	0,0,-100,-17,0,48, 15,53, 30,55, 40,60, 50,63, 60,65, 79,67, 85,70, 90,72, 96,75
giDurs	ftgen	0,0,-100,-17,0,2, 30,0.5, 75,1, 90,1.5

  instr 1
kDur  init        0.5             ; initial rhythmic duration
kTrig metro       2/kDur          ; metronome freq. 2 times inverse of duration
kNdx  trandom     kTrig,0,1       ; create a random index upon each metro 'click'
kDur  table       kNdx,giDurs,1   ; read a note duration value
      schedkwhen  kTrig,0,0,2,0,1 ; trigger a note!
  endin

  instr 2
iNote table     rnd(1),giNotes,1                 ; read a random value from the function table
aEnv  linsegr	0, 0.005, 1, p3-0.105, 1, 0.1, 0 ; amplitude envelope
iPlk  random	0.1, 0.3                         ; point at which to pluck the string
iDtn  random    -0.05, 0.05                      ; random detune
aSig  wgpluck2  0.98, 0.2, cpsmidinn(iNote+iDtn), iPlk, 0.06
      out       aSig * aEnv
  endin
</CsInstruments>

<CsScore>
i 1 0    300  ; start 3 long notes close after one another
i 1 0.01 300
i 1 0.02 300
e
</CsScore>
</CsoundSynthesizer>
;example by Iain McCurdy
  1. http://www.etymonline.com/index.php?term=random^
  2. Esto es debido a que la tasa de muestreo es de 44100 muestras por segundo. Por lo tanto una repetición luego de 65536 muestras implicaría una repetición de valores pasados los 65536/44100 = 1.486 segundos.^
  3. Charles Dodge and Thomas A. Jerse, Computer Music, New York 1985, Chapter 8.1, in particular page 269-278.^
  4. La mayoría de ellos han sido escritos por Paris Smaragdis en 1995: betarnd, bexprnd, cauchy, exprnd, gauss, linrand, pcauchy, poisson, trirand, unirand and weibull.^
  5. De acuerdo a Dodge/Jerse, los algorítmos más comunes para el tipo exponencial y el gaussiano son:
    Exponencial: Generar un número con distribución uniforme entre 0 y 1 y derivar su logaritmo natural.
    Gauss: Tomar la media de números uniformemente distribuídos y escalarlos de acuerdo a la desviación estándar. ^
  6. Neukom, Martin. Signals, systems and sound synthesis. Bern: Peter Lang, 2013. Print. ^
 

There has been error in communication with Booktype server. Not sure right now where is the problem.

You should refresh this page.