Sei sulla pagina 1di 109

Csound e Python nella realizzazione di programmi per

l'elaborazione del suono in tempo reale

Bertinoro Agosto 2008

1 di 109

Introduzione..........................................................................................................................................5
Le osservazioni di Koenig sulla costruzione del suono ..................................................................5
L'istante zero di Pietro Grossi..........................................................................................................5
Il software libero e Richard Stallman..............................................................................................5
Programmazione e composzione.....................................................................................................5
Csound..................................................................................................................................................6
Primo incontro con cSound .............................................................................................................6
Orientarsi tra le versioni di cSound ................................................................................................7
....................................................................................................................................................7
....................................................................................................................................................7
....................................................................................................................................................7
Installare Csound su Debian Linux .................................................................................................7
....................................................................................................................................................7
....................................................................................................................................................7
....................................................................................................................................................7
Installazione di Csound 5 in ambiente Windows ............................................................................8
........................................................................................................................................................8
Strumenti e spartiti in cSound .........................................................................................................9
....................................................................................................................................................9
....................................................................................................................................................9
....................................................................................................................................................9
Creare un primo file audio con cSound ........................................................................................11
..................................................................................................................................................11
..................................................................................................................................................11
..................................................................................................................................................11
Opzioni cSound da linea di comando ...........................................................................................12
Strumenti cSound ..........................................................................................................................12
Struttura di un file .csd ..................................................................................................................13
Configurazione di CSound per l'elaborazione in tempo reale del suono (Windows) ...................18
Un semplic file .csd per il tempo-reale .........................................................................................21
Una semplice partitura cSound .....................................................................................................22
La codifica octave point pitch-class ..............................................................................................23
Tipi di variabili in cSound ............................................................................................................23
..................................................................................................................................................23
..................................................................................................................................................23
..................................................................................................................................................23
Scrivere uno strumento cSound ....................................................................................................24
Come si scrive una funzione .........................................................................................................25
Come si scrive una funzione .........................................................................................................25
Variabili di controllo in cSound ....................................................................................................26
Variabili di controllo: inviluppi d'ampiezza ..................................................................................27
Segnali di controllo: stereo, tremolo, vibrato ...............................................................................28
Sintesi additiva con cSound ..........................................................................................................29
GEN09 e GEN19 ..........................................................................................................................31
Oscillatori complessi: buzz e gbuzz ..............................................................................................32
Gestione delle cartelle in Csound (Windows) ..............................................................................35
Gestione delle cartelle in Csound (Linux Debian) ........................................................................36
Sintesi sottrattiva ...........................................................................................................................36
2 di 109

Sintesi sottrattiva e filtri risonanti .................................................................................................39


L'opcode comb ..............................................................................................................................40
Sintesi vettoriale ...........................................................................................................................41
Modulazione ad anello ..................................................................................................................41
Orchestra per la FM semplice ..................................................................................................43
..................................................................................................................................................43
..................................................................................................................................................43
..................................................................................................................................................43
Spettro armonico di semplici FM .................................................................................................44
Introduzione all'opcode foscil .......................................................................................................45
Introduzione all'opcode loscil .......................................................................................................46
Sintesi per distorsione non lineare ................................................................................................47
L'opcode table e la GEN07 ...........................................................................................................49
GEN07..................................................................................................................................49
usage.....................................................................................................................................50
parameters............................................................................................................................50
Gli opcodes delayr, delayw, deltap ...............................................................................................51
Sintesi per modelli fisici: l'opcode pluck ......................................................................................52
L'istruzione if .... kgoto .................................................................................................................53
..................................................................................................................................................53
..................................................................................................................................................53
Algoritmi di sintesi e pedaliera MIDI ...........................................................................................53
Una loop station in cSound ...........................................................................................................55
..................................................................................................................................................55
Pilotare l'opcode diskin con un MIDI controller ..........................................................................60
Pitch detection con gli opcodes spectrum e specptrk ...................................................................61
..................................................................................................................................................61
specptrk .........................................................................................................................................62
Description.....................................................................................................................................62
Syntax............................................................................................................................................62
Initialization...................................................................................................................................62
Performance...................................................................................................................................63
L'opcode specptrk .........................................................................................................................63
Sintesi granulare con l'opcode granule .........................................................................................64
Bibliografia...............................................................................................................................65
Uso dell'opcode timout .................................................................................................................65
..................................................................................................................................................65
..................................................................................................................................................65
Sintesi granulare con l'opcode timout ...........................................................................................67
Sintesi per formanti: FOF .............................................................................................................68
Introduzione agli FLTK Widgets ..................................................................................................71
Esempio di costruzione di un'interfaccia FLTK ............................................................................72
Csound e Python.................................................................................................................................75
Csound e Python: primo incontro .................................................................................................75
Usare Csound con Python: moduli principali ...............................................................................75
......................................................................................................................................................75
PyGame per joystick e joypad ......................................................................................................76
......................................................................................................................................................76
wxPython e pyGame a confronto .............................................................................................76
Programmare joypad e tastiera con pyGame ................................................................................77
3 di 109

Il modulo pySerial ........................................................................................................................78


Esplorare il modulo csnd ..............................................................................................................79
La variabile d'ambiente PYTHONPATH (windows) ....................................................................79
La classe cSoundPerformanceThread ...........................................................................................80
Un sistema di macro per i files csd ...............................................................................................81
L'opcode chnset e l'istruzione GetChannel ...................................................................................82
Alcune considerazioni sull'opcode chnset ....................................................................................83
......................................................................................................................................................83
......................................................................................................................................................83
L'opcode chnget ed il modulo Python csnd ..................................................................................84
......................................................................................................................................................84
......................................................................................................................................................84
Creare un lettore di campioni in Python e Csound .......................................................................85
Subclassing del controllo wxSlider ...............................................................................................87
Una classe Python per grafici in tempo reale ...............................................................................88
Composizione algoritmica e tempo reale ..........................................................................................92
Una classe per la gestione di pattern di accenti ............................................................................92
Modificare pattern di accenti tramite istogrammi .........................................................................95
Generazione di motivi musicali con catene di Markov ................................................................99
Rappresentare una catena di Markov con un file XML ..............................................................101
Passaggio da un range di valori ad un altro con l'interpolazione lineare ....................................103
....................................................................................................................................................103
Permutazioni o disposizioni senza ripetizione ............................................................................105
....................................................................................................................................................105
....................................................................................................................................................105
Random walk ..............................................................................................................................105
....................................................................................................................................................105
....................................................................................................................................................105
Disposizioni con ripetizione .......................................................................................................106
....................................................................................................................................................106
Funzione di conversione di una nota nella sua frequenza corrispondente ..................................107
Una classe per il calcolo delle permutazioni di una serie di note ...............................................108
....................................................................................................................................................108
....................................................................................................................................................108
....................................................................................................................................................108

4 di 109

Introduzione

Le osservazioni di Koenig sulla costruzione del suono


L'istante zero di Pietro Grossi
Il software libero e Richard Stallman
Programmazione e composzione

5 di 109

Csound
Primo incontro con cSound

Csound stato inizialmente scritto da Barry Varcoe nel 1985 (MIT). E' un linguaggio di
"programmazione musicale" multipiattaforma, un sintetizzatore virtuale della famosa famiglia dei
linguaggi MUSICV.
Per una panoramica dettagliata rimando al sito ufficiale http://www.csounds.com/
Inizialmente distribuito sotto licenza MIT, Csound ora distribuito sotto licenza LGPL.
Csound nato come linguaggio orientato alla sintesi ed alla elaborazione audio, ma non in tempo
reale: un sintetizzatore programmabile, flessibile, potentissimo, ma progettato essenzialmente per
essere una sorta di compilatore/generatore di file audio.
Ho incominciato ad usare Csound nel 1997. Il mio primo lavoro pubblicato, realizzato in Csound,
presente nel secondo cd di Anatrofobia: "Ruote che girano a vuoto". "Musica a piccole
dimensioni", questo il titolo, stato realizzato seguendo la tipica procedura di lavoro con il
"vecchio" Csound. Con molta pazienza e tempo ho scritto due file di testo:
"musicaapiccoledimensioni.orc" e "musicapiccoledimensioni.sco". Questi due file contenevano
l'orchestra e la partitura Csound. Il file .orc conteneva gli strumenti di sintesi, il file .sco "le note"
da sintetizzare. Prendendo come input questi due file Csound generava il file audio finale.
Il lavoro con Csound molto simile a quello con un compilatore di un qualsiasi linguaggio di
programmazione. Si scrivono i sorgenti. Si compila. Si ottiene, infine, facendola breve, il
programma desiderato. Ecco, con Csound il meccanismo simile. Semplicemente ci che si ottiene
un file audio..
E' importante ribadire che Csound nato innanzitutto come compilatore che prendendo come
parametri un file .orc ed un file .sco, in grado di generare un file audio finale (aiff, .wav ecc....)
Oggi siamo arrivati alla versione 5 del linguaggio, versione che ha introdotto molte essenziali
innovazioni.

La prima novit che Csound diventato anche uno strumento adatto all'elaborazione del
suono in tempo reale ( o lo sta diventando)
Csound ora un sistema che pu essere incluso in altre applicazioni. Offre delle API che
possono essere richiamate all'interno di programmi scritti in diversi linguaggi di
programmazione (Python,Java,LISP...).
Csound un progetto open-source, che fa ampio uso di librerie standard quali la libreria
grafica FLTK

6 di 109

Orientarsi tra le versioni di


cSound

Navigando nel sito http://sourceforge.net relativo alla sezione di cSound, si


pu rimanere indecisi su quale pacchetto scaricare.
cSound disponibile per sistemi Windows, Linux e Mac. Mentre per Linux e
Mac, la scelta del pacchetto d'installazione unica; per Windows abbiamo a
disposizione due versioni: la versione -d e la versione -f. Come si evince dal
testo sotto riportato, preso dalla FAQ di cSounds.com, la versione pi adatta al
realtime la -f, mentre la -d permette, con i samples memorizzati a 64 bits un
rendering pi accurato (e quindi maggior potenza computazionale).

Installers with 'f' in the filename (short for "float") contain a Csound compiled so that audio
samples are internally represented using single-precision (32-bit) floating-point numbers. This
results in about 15% faster performance relative to the "d" versions on Windows and should have
similar performance gains on other platforms.
Installers with 'd' in the filename (short for "double") contain a Csound compiled so that audio
samples are internally represented using double-precision (64-bit) floating-point numbers. This
results in about 15% slower performance relative to the single-precision version, but will give
greater precision for calculations, especially in filter performance. (Note though that many filters
have recently been changed to always use double-precision calculations where they are critical).
The float version is probably better for real-time performance although the double version is OK
for "light" real-time usage. The double version is to be preferred for non-real-time rendering where
it is available, especially for producing a "finished" rendition of a work

Installare Csound su Debian


Linux

L'installazione di Csound su Debian Linux (distribuzione studio 64) non proprio banale per un
utente linux alle prime armi.
In ogni caso i passaggi che ho effettuato sono stati i seguenti.
Nei prossimi articoli cercheremo di motivare meglio le istruzioni sotto riportate.

7 di 109

Mi sono scaricato l'ultima versione di Csound da


http://csound.sourceforge.net/#Downloads, nella fattispecie il file "Csound5.07i386f.tar.gz", quindi mi sono copiato il file nella mia directory d'utente: /home/utente

Ho aperto una finestra terminale root.

Ho estratto i file dall'archivio .tar.gz con il solito comando tar -xvzf Csound5.07i386f.tar.gz.

Mi sono posizionato nella cartella d'estrazione (es.


64studio:/home/administrator/linux_f32) e ho digitato il comando ./installer

Nella finestra che si aperta con il precedente comando ho selezionato il checkbox


"install in System files" e tutti gli altri checkbox

Con il comando cp /opt/linux_f32/lib/libcsound.so.5.1 /usr/lib/libcsound.so.5.1 ho


copiato la libreria libcsound.so.5.1. Ricordo che il file d'origine potrebbe essere in un
altra cartella. L'obiettivo mettere nella cartella delle librerie condivise di Debian, la
libreria libcsound.so.5.1.

Con il comando cd /usr/local/bin/bin sono entrato nella cartela contenente il programma


csound

Tramite gedit ho creato due semplici file .sco e .orc e li o salvati nella cartella
/usr/local/bin/bin

Installazione di Csound 5 in ambiente


Windows

In questo articolo vediamo come installare Csound 5 su una postazione Windows XP Professional.
Prima di installare cSound, se non lo abbiamo gi installato sulla nostra macchina, occorre
installare Python.
Anche se nelle FAQ di cSound, Python viene indicato come opzionale, in realt per i nostri futuri
scopi, avere Python installato necessario. Addirittura alcune versioni di cSound 5 proprio non
funzionano senza l'interprete Csound installato (o meglio senza la libreria py.dll) .
Quindi innanzitutto andiamo sul sito
http://www.python.org/download/
e scarichiamoci la versione di Python 2.5.x con Windows Installer.

8 di 109

Installiamo il pacchetto Python seguendo le semplici ed immediate indicazioni.


Quindi procuriamoci l'ultima versione di cSound dal sito
http://csound.sourceforge.net/
Come abbiamo gi scritto precedentemente i pacchetti di Csound a disposizione, allo stato attuale,
sono due
Csound5.0.x-win32-f.exe e Csound5.0.x-win32-d.exe
Per capire le differenze tra le due versioni cito la risposta di Michael Gogins
Installers with 'f' in the filename (short for "float") contain a Csound compiled so that audio
samples are internally represented using single-precision (32-bit) floating-point numbers. This
results in about 15% faster performance relative to the "d" versions on Windows and should have
similar performance gains on other platforms.
Installers with 'd' in the filename (short for "double") contain a Csound compiled so that audio
samples are internally represented using double-precision (64-bit) floating-point numbers. This
results in about 15% slower performance relative to the single-precision version, but will give
greater precision for calculations, especially in filter performance. (Note though that many filters
have recently been changed to always use double-precision calculations where they are critical).
The float version is probably better for real-time performance although the double version is OK
for "light" real-time usage. The double version is to be preferred for non-real-time rendering where
it is available, especially for producing a "finished" rendition of a work.
Dati gli interessi di Live-Electronics per le performance in tempo reale, scarichiamo la versione "f".
Quindi seguendo le semplici indicazioni installiamo il pacchetto Csound5.07.2-win32-f.exe (o
successivo)

Strumenti e spartiti in
cSound

cSound, come abbiamo gi detto all'inizio di questo tutorial, appartiene alla famiglia di linguaggi di
programmazione per la computer music di tipo "Music N".
Tutti questi linguaggi partono dal concetto di strumento, da una parte, e di spartito o parte,
dall'altra.
Dal punto di vista di un linguaggio di programmazione tradizionale lo
strumento pu essere pensato come il programma vero e proprio, ci che
implementa gli algoritmi di calcolo. E' la classica macchina di elaborazione che
prende in input certi dati con lo scopo di produrre un determinato output.

9 di 109

Lo strumento agisce ed elabora la partitura.


La partitura pu essera pensata come l'insieme dei dati principali su cui lo strumento agisce.
Un pCreare un primo file audio con cSound
Scritto da Luca Cartolari gioved 29
novembre 2007 In questo articolo vediamo come creare un primo file audio con Csound in
ambiente Windows.
Mi limito, per ora, a elencare le operazioni pratiche da seguire
Dopo aver installato l'ultima versione di Csound creiamo due file di testo (il solito "Notepad", va
benissimo).
Prova.orc
; Initialize the global variables.
sr = 44100
kr = 4410
ksmps = 10
nchnls = 1
; Instrument #1 - a basic oscillator.
instr 1
kamp = 10000
kcps = 440
ifn = 1
a1 oscil kamp, kcps, ifn
out a1
endin
e
Prova.sco
;Table #1, a sine wave.
f 1 0 16384 10 1
; Play Instrument #1 for 2 seconds.
i102
e
Salviamo i nostri due file nella sottocartella bin della cartella principale di cSound (Es.
c:\programmi\csound\bin).
Quindi apriamo il prompt dei comandi. (Start>Esegui>digitare cmd)
Attraverso le opportune istruzioni cd ci posizionamo sotto la directory bin di Csound (Es.
c:\programmi\csound\bin)
A questo punto scriviamo
csound -W -oc:\prova.wav prova.orc prova.sco
e premiamo Invio
Dopo alcuni istanti cSound ha compilato e creato per noi il nostro primo file audio: il
file prova.wav sotto la cartella C.\
rogramma cSound quindi l'applicazione di uno o pi strumenti ad una o pi partiture. Ogni
partitura del resto sempre scritta per un determinato strumento.

10 di 109

Nei prossimi articolo vedremo come gli strumenti cSound vengano scritti o in appositi file di testo
con estensione .orc oppure nella sezione CsInstruments di un file csd; inoltre vedremo come la
partitura o score venga scritta o in appositi file di testo con estensione .sco oppure nella sezione
CsScore di un file csd.

Creare un primo file audio con


cSound

In questo articolo vediamo come creare un primo file audio con Csound in ambiente Windows.
Mi limito, per ora, a elencare le operazioni pratiche da seguire
Dopo aver installato l'ultima versione di Csound creiamo due file di testo (il solito "Notepad", va
benissimo).
Prova.orc
; Initialize the global variables.
sr = 44100
kr = 4410
ksmps = 10
nchnls = 1
; Instrument #1 - a basic oscillator.
instr 1
kamp = 10000
kcps = 440
ifn = 1
a1 oscil kamp, kcps, ifn
out a1
endin
e
Prova.sco
;Table #1, a sine wave.
f 1 0 16384 10 1
; Play Instrument #1 for 2 seconds.
i102
e
Salviamo i nostri due file nella sottocartella bin della cartella principale di cSound (Es.
c:\programmi\csound\bin).
11 di 109

Quindi apriamo il prompt dei comandi. (Start>Esegui>digitare cmd)


Attraverso le opportune istruzioni cd ci posizionamo sotto la directory bin di Csound (Es.
c:\programmi\csound\bin)
A questo punto scriviamo
csound -W -oc:\prova.wav prova.orc prova.sco
e premiamo Invio
Dopo alcuni istanti cSound ha compilato e creato per noi il nostro primo file audio: il
file prova.wav sotto la cartella C.\

Opzioni cSound da linea di


comando

Come abbiamo visto cSound un programma che pu essere utilizzato direttamente dalla linea di
comando
Le opzioni che possono essere utilizzate sulla linea di comando sono molte.
E' possibile ricavare l'elenco completo dei diversi flag direttamente dal manuale di riferimento di
cSound.
http://www.csounds.com/manual/html/CommandFlags.html
Nell'esempio precedentemente riportato
csound -W -oc:\prova.wav prova.orc prova.sco
sono stati usati due dei principali flag cSound
-W, che specifica che il formato del file prodotto da cSound di tipo Microsoft Wav
-o. che specifica il nome (con path completo o relativo) del file di output.

Strumenti
cSound

Programmare suoni con cSound significa innanzitutto realizzare strumenti.

12 di 109

Uno strumento cSound pu essere pensato come il programma che a partire dai parametri introdotti
nel file .sco o nella sezione CsScore del file .csd produce un output audio. Pi semplicemente uno
strumento Csound uno strumento virtuale progettato per l'esecuzione della sua corrispondente
parte strumentale.
Gli strumenti Csound vengono scritti o in file di testo dedicati, con estensione .orc o nell'apposita
sezione CsInstruments di un file .csd.
Per definire uno strumento in cSound occorre utilizzare il costrutto instr n, dove n un numero
intero positivo.
Ad esempio se voglio definire lo strumento 1 dovr scrivere
instr 1
<ISTRUZIONI DI DEFINIZIONE DELLO STRUMENTO>
endin
Il costrutto instr quindi l'accorgimento formale atto a contenere la definizone vera e propria dello
strumento. Ad esempio l'esempio precedente dichiara che le istruzioni interne al costrutto
instr/endin servono a definire lo strumento 1

Struttura di un file
.csd

In questo articolo vediamo come strutturato un file .csd.


Un file .csd (Unified cSound Format for Orchestras and Scores) compone in un unico file con
struttura a marcatori: i flag della linea di comando di cSound, il contenuto del file '.sco' e il
contenuto del file '.orc'.
Il file deve incominciare con il tag <CsoundSynthesizer> e terminare con </CsoundSynthesizer>.
Tutti gli altri tag devono essere inclusi all'interno di questo tag principale.
Il tag <CsOptions></CsOptions> contiene i command line flags.
I flag sono molti. Nell'esempio ne sono riportati 6.
-bNUM
Numero di campioni audio per il buffer dell' I/O software. Per un uso di cSound in tempo reale
occorre specificare un buffer il pi piccolo possibile. Questo numero, multiplo di 2, dovr essere
settato ad un valore testato sperimentalmente di volta in volta in base agli opcode e ai calcoli
dell'orchestra cSound realizzata. Un numero troppo piccolo potr comportare perdita di dati.
-BNUM
Numero di campioni audio per il buffer del DAC hardware. Per un uso di cSound in tempo reale
13 di 109

occorre specificare un buffer il pi piccolo possibile. Questo numero, multiplo di 2, dovr essere
settato ad un valore testato sperimentalmente di volta in volta in base agli opcode e ai calcoli
dell'orchestra cSound realizzata.Un numero troppo piccolo potr comportare perdita di dati.
-odacNUM
Specifica il numero con cui individuato da cSound il driver audio di output. La corretta scelta i
questo driver permetter o meno l'uso di cSound per il tempo reale
-idacNUM
Specifica il numero con cui individuato da cSound il driver audio di input. La corretta scelta i
questo driver permetter o meno l'uso di cSound per il tempo reale.
-MNUM
Specifica il numero con cui individuato da cSound il driver MIDI per l'elaborazione in tempo
reale degli stream MIDI.
-mNUM
Specifica il livello di messaggistica di cSound durante l'elaborazione.
La sezione <CsInstruments> contiene la definizione dell'orchestra, ossia ci che pu venir scritto
in un file .orc, autonomo.
La sezione <CsScore> contiene la definizione della partitura cSound, ossia ci che pu venir
scritto in un file .sco autonomo.
Ecco un esempio completo di file .csd
<CsoundSynthesizer>
<CsOptions>
-b80 -B160 -odac4 -iadc4 -M1 -m0
</CsOptions>
<CsInstruments>
;Pedale 121
sr
=
44100
kr
=
22050
ksmps =
2
nchnls =
2
gaL init 0
gaR init
0
gkMute init 0
instr 1
gkMute chnget "mute"
kVol chnget "volume"
kTrik1 chnget "sampler1"
kTrik2 chnget "sampler2"
kTrik3 chnget "sampler3"
kTrik4 chnget "sampler4"
kTrik5 chnget "sampler5"
14 di 109

kFilters chnget "filters"


klivemicro chnget "livemicro"
knotamin chnget "n1"
knotamax chnget "n2"
if gkMute == 1 kgoto ESCI
asig1,asig2 ins
asig = asig1 + asig2
aGate linseg 0, 2, 1, p3 - 4,1, 2, 0
aGate2 = a(kVol)
ictlno =1
ichan = 1
knota ctrl7 ichan, ictlno, knotamin, knotamax
a1 = asig
aRec1,koutrec1 sndloop a1, 1, kTrik1, 5, 0.05
aRec2,koutrec1 sndloop a1, 1, kTrik2, 7, 0.05
aRec3,koutrec1 sndloop a1, 1, kTrik3, 11, 0.05
aRec4,koutrec1 sndloop a1, 1, kTrik4, 13, 0.05
aRec5,koutrec1 sndloop a1, 1, kTrik5, 17, 0.05

kRec1 rms
kRec2 rms
kRec3 rms
kRec4 rms
kRec5 rms
k1 rms a1

aRec1 * aGate2
aRec2 * aGate2
aRec3 * aGate2
aRec4 * aGate2
aRec5 * aGate2

if kFilters == 0 kgoto SALTA_FILTRI


ifdbgain1 = 0.96
a1 streson a1, knota, ifdbgain1
iord1 = 50
iskip1 = 0.90
ifdbgain2 = 0.96
aRec1 streson aRec1, knota, ifdbgain2
aRec2 streson aRec2, knota, ifdbgain2
aRec3 streson aRec3, knota, ifdbgain2
aRec4 streson aRec4, knota, ifdbgain2
aRec5 streson aRec5, knota, ifdbgain2
iord2 = 60
iskip2 = 0.99
kfeedback2 ctrl7 ichan, ictlno, 0.30, 0.99
aRec1 phaser1 aRec1,knota,iord2,kfeedback2,iskip2
aRec2 phaser1 aRec2,knota,iord2,kfeedback2,iskip2
aRec3 phaser1 aRec3,knota,iord2,kfeedback2,iskip2
aRec4 phaser1 aRec4,knota,iord2,kfeedback2,iskip2
15 di 109

aRec5 phaser1 aRec5,knota,iord2,kfeedback2,iskip2


; gaL = a1 + aRec1 + aRec3 + aRec5
; gaR = a1 + aRec2 + aRec4 + aRec5
SALTA_FILTRI:
gaL = aRec1 + aRec3 + aRec5
gaR = aRec2 + aRec4 + aRec5
if klivemicro == 0 kgoto SALTA_LIVEMICRO_1
gaL = gaL + a1
gaR = gaR + a1
SALTA_LIVEMICRO_1:
aRec1 gain aRec1 * aGate2, kRec1
aRec2 gain aRec2 * aGate2, kRec2
aRec3 gain aRec3 * aGate2, kRec3
aRec4 gain aRec4 * aGate2, kRec4
aRec5 gain aRec5 * aGate2, kRec5
a1 gain a1, k1
aL = aRec1 + aRec3 + aRec5
aR = aRec2 + aRec4 + aRec5
if klivemicro == 1 kgoto SALTA_LIVEMICRO_2
aL = aL + a1
aR = aR + a1
SALTA_LIVEMICRO_2:
outs aL * aGate, aR * aGate
ESCI:
endin

instr 2
kGranule chnget "microsound"
kAtt chnget "attacco"
kRil chnget "rilascio"
kPau chnget "pausa"
kVolL chnget "volumeL"
kVolR chnget "volumeR"
if gkMute == 1 kgoto SALTA
if (kGranule ==0) kgoto SALTA
a1 = gaL
a2 = gaR
ktempAtt = kAtt / 2
krandAtt rand ktempAtt
ktempAtt = kAtt + krandAtt
ktempRil = kRil / 2
krandRil rand ktempRil

16 di 109

ktempRil = kRil + krandRil


ktempPau = kPau / 2
krandPau rand ktempPau
ktempPau = kPau + krandPau
start:
iPause = i(ktempPau)
iDur1 = i(ktempAtt)
iDur2 = i(ktempRil)
iVolL = i(kVolL)
iVolR = i(kVolR)
igap = iDur1 + iDur2 + iPause
timout 0, igap, continue
reinit start
continue:
agateL linseg 0, iDur1 , iVolL, iDur2 , 0
agateR linseg 0, iDur1 , iVolR, iDur2 , 0
rireturn
outs a1 * agateL , a2 * agateR
SALTA:
endin
</CsInstruments>
<CsScore>
i1 0 900
i2 0 900
</CsScore>
</CsoundSynthesizer>

17 di 109

Configurazione di CSound per l'elaborazione in tempo reale del


suono (Windows)

Configurazione di CSound5 per l'elaborazione in tempo reale del suono: CSound5Gui versione
Microsoft Windows.
In questo breve articolo ci soffermeremo sulla configurazione di CSound5 per l'elaborazione in
tempo reale di un suono live.
Pi precisamente configureremo CSound5Gui versione Microsoft Windows.
Innanzitutto occorre specificare quali sono i driver che CSound5 deve utilizzare per l'input e per
l'output.
Aperto CSound5Gui sufficiente cliaccare Options > CSound.
Dalla versione 5.05 di CSound la configurazione banale. Infatti sufficiente entrare nella scheda
Real Time Audio e scegliere gli opportuni Driver, dai due menu Output Device ed Input Device
Se questo menu fosse inutilizzabile (come nella mia versione 5.06
) occorre indicare nella
sezione CsOptions del proprio file .csd il numero di driver di output (parametro -odac) e quello di
input (-idac). Per capire quale numero scrivere, una soluzione empirica, ma efficace, pu essere
quella di mandare in errore il compilatore cSound, indicando un numero di driver scorretto (es.
-odac1000). Tra i messaggi di errore, cSound evidenzier anche i driver disponibili con il loro
numero associato.
A questo punto il gioco fatto.
Questa la configurazione di un mio recente file csd
<CsOptions>
-b20 -B20 -odac4 -iadc4 -M1
</CsOptions
Questa , invece, un'immagine della GUI di cSound.

18 di 109

Di seguito riporto come esempio un altro mio file .csd, utilizzato con cSound 5.0.x. E' un file che
elabora un segnale di ingresso Mono. L'istruzione utilizzata la classica in. L'output ottenuto
stereo (istruzione outs).
Per i nostri scopi la sezione CsOptions fondamentale.
Il flag -b indica in numero di campioni la capacit del buffer di esecuzione di CSound.
Il flag -B indica invece in numero di campioni la capacit del buffer di esecuzione dell'interfaccia
hardware. Esso deve essere un multiplo intero di -b. Solo l'opportuna sperimentazione ci
permetter di trovare i giusti valori per la nostra DAW. Tipicamente i driver ASIO sono quelli con
una miglior risposta e quindi minor ritardo. Pi i valori di -b e -B sono bassi pi l'output audio sar
immediato e maggiore sar il carico della CPU (quindi anche il rischio di errori di elaborazione)
<CsoundSynthesizer>
<CsOptions>
-b20 -B40
</CsOptions>
<CsInstruments>

19 di 109

sr
=
44100
kr
=
2205
ksmps =
20
nchnls =
2
instr

kampMiL linseg 0, p3/6,1, p3/6, 0.6, p3/6 , 0.5, p3/6, 0, p3/6, 0, p3/6,0
kampMiR linseg 0, p3/6, 0, p3/6, 0.6, p3/6 , 1, p3/6, 1, p3/6, 1, p3/6,0
kampSiL linseg 0, p3/6, 0, p3/6, 0.6, p3/6 , 1, p3/6, 1, p3/6, 1, p3/6,0
kampSiR linseg 0, p3/6, 1, p3/6, 0.6, p3/6 , 0.5, p3/6, 0, p3/6, 0, p3/6,0
iOrder=28
iFeedback = 0.82
ainput in
k1 rms ainput
ipch = p4
kNotaMi = cpspch(ipch)
ipch = p5
kNotaSi = cpspch(ipch)
ipitchm = p6
aMi = ainput
aMi phaser1 aMi , kNotaMi, iOrder, iFeedback
ifdbgain = 0.88
aMi streson aMi, kNotaMi, ifdbgain
aMi streson aMi, kNotaMi, ifdbgain
aSi = ainput
aSi phaser1 aSi , kNotaSi, iOrder,iFeedback
ifdbgain = 0.88
aSi streson aSi, kNotaSi, ifdbgain
aSi streson aSi, kNotaSi, ifdbgain
aOutMiL gain aMi , k1 * kampMiL
aOutMiR gain aMi , k1 * kampMiR
aOutSiL gain aSi , k1 * kampSiL
aOutSiR gain aSi , k1 * kampSiR
aL, aR reverbsc aOutMiL + aOutSiL, aOutMiR + aOutSiR, 0.85, 12000, sr, ipitchm, 1
outs aL,aR
endin
</CsInstruments>
<CsScore>
i1 0
e

300 7.09 8.04 0.5

</CsScore>
</CsoundSynthesizer>

20 di 109

Un semplic file .csd per il temporeale

In questo esempio viene illustrato un primo file .csd per l'uso di CSound in tempo reale
<CsoundSynthesizer>
<CsOptions>
-b80 -B160 -odac4 -iadc4 -M1 -m0
</CsOptions>
Commentiamo la sezione CsOptions. I flag -b -B settano le grandezze dei buffer software ed
hardware. -odac4 e -idac4 individuano il numero dei driver per l'output e l'input audio. -M1
specifica il driver per l'input MIDI. -m0 indica nessun messaggio a video, da parte di cSound.
<CsInstruments>
sr
=
44100
kr
=
2205
ksmps =
20
nchnls =
2
sr indica la frequenza di campionamento audio.
kr indica la frequenza di controllo.
ksmps deve essere uguale a sr/kr
nchnls indica il numero di canali di uscita (1 mono, 2 stereo ecc...)
instr 1
asig1,asig2 ins
outs asi1, asig2
endin
L'opcode ins legge, di default, il segnale stereo in ingresso, assegnandolo a due variabili audio.
outs manda un segnale stereo all'output device.
</CsInstruments>
<CsScore>
i1 0 60
La partitura esegue lo strumento 1 per 60 secondi.
</CsScore>
</CsoundSynthesizer>

21 di 109

Una semplice partitura


cSound

Come abbiamo visto negli articoli precedenti, la sezione <CsScore> contiene la definizione della
partitura cSound, ci che pu anche venir scritto in un file .sco autonomo.
<CsScore>
i1 0 60
</CsScore>
In questo esempio la partitura esegue lo strumento 1 per 60 secondi, a partire dall'istante (secondo)
0.
Quindi un file .csd deve contenere almeno una riga che inizi con i: infatti una volta definito uno
strumento devono essere specificati gli eventi sonori propri di quello strumento. Per emettere
qualche suono il nostro strumento virtuale deve eseguire qualche cosa, non necessariamente delle
note, ma un qualche tipo di evento sonoro.
Ogni riga di tipo i-strumento ha tre parametri obbligatori, gli stessi riportati nell'esempio
precedente:
primo parametro (p1) indica il numero di strumento,
secondo parametro (p2) indica l'istante di inizio di esecuzione dell'evento sonoro (es. istante 0),
terzo parametro (p3) indica la durata di esecuzione (es. durata di 60 secondi).
Nell'esempio seguente viene riportata una riga di tipo i-strumento con anche parametri non
obbligatori.
instr 2
ifreq = cpspch(p4)
knh = 3;
ifn = 3
ifdbgain2 = p5
iGain = p6
iL = p7
iR = p8
....................
endin
::::::::::::::::::::::::::::::::::::::::::::::::::
i2 0 10 8.03 0.80 0.70 0.9 0.8
Si vede come ogni parametro passato a livello di score venga visto all'interno dello strumento con
la sintassi pn. Ad esempio il parametro 4 con valore 8.03 viene visto dallo strumento 2 con la
sintassi p4. Cos a seconda dello strumento che creeremo potremo avere diversi parametri (p4, p5,
p6 ....). Ogni parametro assumer un significato diverso a seconda dello strumento che dovr
eseguire l'evento da esso rappresentato.

22 di 109

La codifica octave point pitchclass

Il tipico parametro p4 di un'istruzione i-statement rappresenta la nota che lo strumento cSound deve
eseguire. Questa nota spesso rappresentata in notazione con punto: l'octave point pitch-class
notation.
Cos:
8.00 = DO centrale del pianoforte (261.63 Hz)
8.01 = DO# (277.18 Hz)
8.02 = RE (293.67 Hz)
I numeri interi rappresentano l'ottava (8), mentre i decimali i semitoni.
Aggiungendo pi decimali anche possibile riuscire a rappresentare musica microtonale.
Ad esempio per rappresentare i quarti di noto si pu usare la sequente sintassi
C4 = 8.00
C4+ = 8.005
C# = 8.01
La maggior parte degli opcodes cSound richiede che la frequenza venga espressa in Hz.
In cSound esiste l'espressione il convertitore cpspch, che converte ci che stato scrittto in
pitch in cps (cycles per second).
ifreq = cpspch(p4)

Tipi di variabili in
cSound

Nel comprendere il funzionamento di cSound di particolare importanza il concetto di variabile.


Possiamo pensare le variabili come celle di memoria contenente valori.
Nel tutorial di cSound leggiamo:variables are named cells containing numbers. In realt esistono
variabili Csound contenenti anche sequenze di caratteri (stringhe). Le variabili una volta istanziate,
e quindi dal momento in cui esistono, mettono continuamente a disposizione il loro valore. A
seconda del loro tipo, le variabili possono essere aggiornate con frequenza diversa. Ci sono
variabili che possono modificare il loro valore solo al momento della creazione dell'orchestra (non
del singolo strumento), variabili modificabili in fase di inizializzazione del singolo strumento (ivariables), variabili modificabili alla frequenza di controllo (k-variables), variabili modificabili alla
frequenza audio (a-variables). Il nome di ogni i-variabile deve incominciare con la lettera "i". Le k23 di 109

variabili devono aver nomi che iniziano con la "k". Infine le variabili audio devono avere nomi che
iniziano con la "a".
Le variabili permanenti (quelle del primo tipo) sono definite nel tutorial di cSound
come "rsymbol".
rsymbol is a special reserved symbol (e.g. sr, kr).
Le variabili possono essere divise in locali e globali. Le variabili locali sono variabili che
esistono fino a quando l'istanza di un determinato strumento attiva. Quelle globali, invece, sono
variabili condivise tra tutte le istanze di un'orchestra. Queste variabili devono avere dei nomi che
iniziano con la lettera "g" (gk..., gi....., ga ecc...).
global variables are cells that are accessible by all instruments. The names are either like local
names preceded by the letter g, or are special reserved symbols. Global variables are used for
broadcasting general values, for communicating between instruments (semaphores), or for sending
sound from one instrument to another (e.g. mixing prior to reverberation). ,

Scrivere uno strumento


cSound

Analizziamo un semplice strumento cSound.


instr 1
aSuono oscil
out aSuono
endin

10000,220,1

In questo esempio viene definito lo strumento instr1.


oscil uno dei pi importanti opcode cSound.
La sintassi generica degli opcode cSound la seguente:
variabile opcode aromento_1, argomento_2, ...... argomento_n
In questo caso abbiamo l'opcode oscil, che simula un oscillatore al quale vengono passati tre
argomenti: l'ampiezza 10000 (espressa in valori assoluti e non in db) del segnale generato, la
frequenza 220 e il numero di funzione 1 (Questa funzione verr poi definita in partitura).
L'oscillatore oscil a partire dai suoi parametri produce un valore, depositato nella variabile
aSuono.
L'opcode out invia il risultato depositato in aSuono alla scheda, per farcelo ascoltare.

24 di 109

Come si scrive una


funzione

Le funzioni servono a creare forme d'onda di cui noi possiamo scegliere le caratteristiche.
Le funzioni per la creazione delle forme d'onda possono essere molto varie. Nell'esempio
precedente avevamo stabilito che la forma d'onda era determinata dalla funzione numero 1.
aSuono oscil

10000,220,1

Creiamo dunque questa funzione numero 1.


Scriveremo questa funzione, come qualsiasi altra all'inizio della sezione <CsScore> di un file .csd,
oppure all'inizio di un file .sco.
f1 0 4096 10 1
f1 indica il numero della funzione (funzione 1). Ogni funzione deve essere identificata da un
numero univoco.
0 (creation time) indica da che momento nella partitura viene creata la funzione, se il numero fosse
3 questa funzione verrebbe creata al terzo secondo.
4096 il numero di punti che definiscono la forma d'onda nella tabella di lettura dell'eventuale
oscillatore. In questo esempio, la nostra onda una sinusoide tracciata nella tabella mediante 4096
punti. Nella maggior parte dei casi il numero di punti richiesto in una funzione una potenza di due
(256, 512, 1024, 2048,4096 etc.), in altri casi una potenza di due pi uno, come vedremo. Il
massimo valore possibile 16777216.
10 Questo quarto parametro dedicato al metodo di generazione di forma d'onda o di funzione,
detto GEN. Ogni GEN ha un suo numero con cui viene identificata (GEN01, GEN02...) ed utilizza
un metodo diverso per la generazione di forme d'onda. Bene in questo caso abbiamo la GEN 10,
che crea sinusoidi, perci ogni volta che ci servir una semplice sinusoide useremo questa GEN10.
1 il fatto che ci sia solo un numero dopo il 10 significa che vogliamo una sola sinusoide. Se
scrivessimo f1 0 4096 10 1 1 1, creeremmo tre sinusoidi in rapporto armonico tra loro
(fondamentale, seconda e terza armonica) e con la stessa ampiezza = 1. Per ora accontentiamoci
di una sola armonica.

Come si scrive una


funzione

Le funzioni servono a creare forme d'onda di cui noi possiamo scegliere le caratteristiche.
Le funzioni per la creazione delle forme d'onda possono essere molto varie. Nell'esempio
precedente avevamo stabilito che la forma d'onda era determinata dalla funzione numero 1.

25 di 109

aSuono oscil

10000,220,1

Creiamo dunque questa funzione numero 1.


Scriveremo questa funzione, come qualsiasi altra all'inizio della sezione <CsScore> di un file .csd,
oppure all'inizio di un file .sco.
f1 0 4096 10 1
f1 indica il numero della funzione (funzione 1). Ogni funzione deve essere identificata da un
numero univoco.
0 (creation time) indica da che momento nella partitura viene creata la funzione, se il numero fosse
3 questa funzione verrebbe creata al terzo secondo.
4096 il numero di punti che definiscono la forma d'onda nella tabella di lettura dell'eventuale
oscillatore. In questo esempio, la nostra onda una sinusoide tracciata nella tabella mediante 4096
punti. Nella maggior parte dei casi il numero di punti richiesto in una funzione una potenza di due
(256, 512, 1024, 2048,4096 etc.), in altri casi una potenza di due pi uno, come vedremo. Il
massimo valore possibile 16777216.
10 Questo quarto parametro dedicato al metodo di generazione di forma d'onda o di funzione,
detto GEN. Ogni GEN ha un suo numero con cui viene identificata (GEN01, GEN02...) ed utilizza
un metodo diverso per la generazione di forme d'onda. Bene in questo caso abbiamo la GEN 10,
che crea sinusoidi, perci ogni volta che ci servir una semplice sinusoide useremo questa GEN10.
1 il fatto che ci sia solo un numero dopo il 10 significa che vogliamo una sola sinusoide. Se
scrivessimo f1 0 4096 10 1 1 1, creeremmo tre sinusoidi in rapporto armonico tra loro
(fondamentale, seconda e terza armonica) e con la stessa ampiezza = 1. Per ora accontentiamoci
di una sola armonica.

Variabili di controllo in
cSound

Se una variabile audio tipicamente utilizzata per memorizzare segnali audio,


le variabile di controllo possono servire a molti scopi differenti.
Una variabile di controllo viene aggiornata alla frequenza di controllo.
Come abbiamo visto la frequenza di controllo in genere pi bassa di quella di campionamento ed
specificata dal comando iniziale kr=n oppure come valore implicito risultante di sr/ksmps.
Nell'esempio seguente viene creato un segnale di controllo per realizzare un glissando.
<CsoundSynthesizer>
<CsOptions>
-W -o C:\tone.wav
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 10
nchnls = 1
instr 1
kglis
line
220, p3, 440

;Creazione di un segmento che varia linearmente da 220 a 4

26 di 109

;I risultati affluiscono nella variabile di controllo kgli


a1
oscil
p4, kglis,1
;Gestione della frequenza tramite il segmento sopra descri
adeclick linen 1,0.02, p3, 0.02
out
a1*adeclick
endin
</CsInstruments>

line un opcode che genera un segmento. Come tutti gli opcode, line vuole alcuni argoment
cio ha bisogno di alcuni dati per operare.
Gli argomenti di line sono:
valore iniziale, tempo (per arrivare dal valore iniziale a quello finale), valore finale.
Nell'esempio line crea un segmento che va da 220 Hz a 440 Hz.
Il risultato di questa operazione viene depositato in kglis.
Successivamente i dati contenuti in kglis vengono inseriti nel nostro oscillatore,
al posto del secondo parametro (quello per la frequenza).
Quindi dal momento che questo segmento che va da 220 a 440 viene utilizzato per la frequen
crea un glissando per ogni nota che suoner quello strumento.
In quanto tempo arriver da 220 a 440 Hz quella nota?
Nel tempo p3, che specificato come secondo argomento di line.
Come sappiamo il parametro 3 di una
score indica sempre la durata di una nota.
Ogni nota di questo strumento glisser quindi da 220 a 440 Hz
nel tempo della sua durata (p3).

Variabili di controllo: inviluppi


d'ampiezza

In questo ulteriore esempio tratto da


http://www.lim.dico.unimi.it/membri/elisa/csound0708/Lez02/Esempi01/02_inviluppo.csd
Viene illustrata una variabile di controllo che crea una dinamica interna al suono, cio un inviluppo, l'ampiezza
della sua esecuzione.
<CsoundSynthesizer>
<CsOptions>
-W -o C:\tone.wav
</CsOptions>
<CsInstruments>
sr = 44100
ksmps = 10
nchnls = 1
instr
1
kenv
line 0,p3,10000

;Creazione di un segmento che varia linearmente da 0 a 100


;I risultati affluiscono nella variabile di controllo kenv
;Gestione dell'ampiezza tramite il segmento sopra descritt

a1
oscil kenv,220,1
adeclick linen 1,0.02, p3, 0.02
out
a1*adeclick
;
endin
</CsInstruments>

27 di 109

<CsScore>
f1 0 4096 10 1
i1 0
3
; frequenza fissa a 220, ampiezza che varia da 0 a 10000 in 3 secondi
i1 4 10
</CsScore>
</CsoundSynthesizer>
Dove

linen
Apply a straight line rise and decay pattern to an input amp signal.
kr
linen
kamp, irise, idur, idec
ar
linen
xamp, irise, idur, idec
irise: Rise time in seconds. A zero or negative value signifies no rise modification.
idur: Overall duration in seconds. A zero or negative value will cause initialization to b
idec: Decay time in seconds. Zero means no decay. An idec > idur will cause a truncated de

Segnali di controllo: stereo, tremolo,


vibrato

Come abbiamo visto in questa serie di articoli, la funzione di un segnale di controllo non quella di
suonare, quanto piuttosto quella di generare valori che servono a pilotare altre unit. In questo
articolo vediamo ulteriori esempi di uso di variabili (segnali) di controllo.
Il vibrato
Il vibrato una deviazione di frequenza. L'ampiezza della deviazione di frequenza dipende
dall'ampiezza dell'oscillazione, la velocit del vibrato dipende dalla frequenza dell'oscillazione.
instr 1
kvibrato oscil 2,3,1
asuono oscil 10000,220 + kvibrato, 1
out asuono
endin
In questo esempio la frequenza centrale di 220 Hz. Maggiore l'ampiezza dell'oscillazione,
maggiore la deviazione dalla frequenza centrale. L'ampiezza del'oscillatore modulante 2, in
questo esempio, con valori estremi +2 e -2. Le ampiezze di kvibrato vengono quindi sommate alla
frequenza centrale: il vibrato quindi osciller tra 218 Hz e 222 Hz.. Qual' la velocit di
vibrazione? La velocit di 3 cicli al secondo. Pertanto il segnale audio risultante compir il
seguente ciclo 3 volte al secondo: 220 Hz - 222Hz - 220Hz - 218 Hz -220Hz.
Il tremolo
Per produrre un tremolo avremo bisogno di modulare l'ampiezza (non pi la frequenza come nel

28 di 109

caso del vibrato) del segnale portante.


instr 2
ktremolo oscil .2,2,1
ktremolo = ktremolo + 1 ; oscilla fra 1 + .2= 1.2 e 1 - .2=0.8
asuono oscil 10000*ktremolo,220,1
endin
Stereo
Per valorizzare qualsiasi effetto stereofonico occorrer rendere modificabile nel tempo i valori
d'ampiezza dei due canali stereo.
In questo esempio si ottiene uno spostamento stereofonico continuo grazie all'uso di un oscillatore.
instr 3
kstereo oscili .5,2,1
kstereo = kstereo + .5
asuono oscili 10000,220,2
outs asuono * kstereo, asuono * (1 - kstereo)
endin

Sintesi additiva con


cSound

La sintesi additiva un tipo di sintesi con la quale si pu creare una forma d'onda complessa a
partire dalla somma di forme d'onda semplici, ad esempio una somma di sinusoidi. E stata il primo
metodo di sintesi usato nella musica elettronica. Ovviamente possibile utilizzare anche suoni non
solo puri ma complessi.
Tali suoni possono avere componenti in rapporto di frequenza intero o no.
www.lim.dico.unimi.it/membri/elisa/csound0708/Lez02/Slides_Additiva.pdf
Come abbiamo visto precedentemente la sintesi additiva pi semplice pu essere implementata
tramite l'uso della GEN10, realizzando una sintesi additiva
a spettro fisso con sinusoidi pure in rapporto armonico tra loro.
E' possibile creare suoni di una certa complessit semplicemente
modificando l'ampiezza delle diverse armoniche.
Con la funzione seguente otteniamo un' onda a dente di sega
f1 0 4096 10 10 5 3.3 2.5 2 1.6 1.4 1.25 1.1 1
Con la funzione seguente otteniamo un' onda quadra
f1 0 4096 10 10 0 3.3 0 2 0 1.4 0 1.1

29 di 109

Sintesi additiva a spettro variabile


Rende variabile nel tempo lampiezza delle componenti armoniche. Generando suoni il cui timbro
varia nel tempo.
Si ottiene cos una grande variet di timbri, pi vicniai suoni naturali, grazie alla variazione nel
tempo dell'ampiezza
delle componenti armoniche.
Consideriamo delle componenti armoniche in rapporto intero rispetto
alla fondamentale.
instr 1
kamp1 linseg 0,1,10000,p3-1,0;inviluppo di ampiezza per la fondamentale
kamp2 linseg 0,2,6000,p3-2,0;inviluppo di ampiezza per la III armonica
kamp3 linseg 0,3,8000,p3-3,0;inviluppo di ampiezza per la V armonica
a1 oscil kamp1,200,1 ;fondamentale
a2 oscil kamp2,600,1 ;III armonica
a3 oscil kamp3,1000,1 ;V armonica
aout = a1+a2+a3 ;somma delle tre armoniche
out aout
endin
Per la comprensione dell'esempio ricordo la serie delle armoniche:
f(fondamentale), 2*f(seconda arm.), 3*f, 4*f, 5*f,6*f, ...
Levoluzione temporale indipendente di ogni componente una caratteristica fondamentale dei
suoni naturali.
Da quanto visto dovrebbe essere chiaro che le due orchestre seguenti
ci permettono di ottenere il medesimo risultato sonoro
;orchestra
instr 1
a1 oscil 15000,200,1
out a1
endin
;score
f1 0 4096 10 1 0 1 0 1
i1 0 8
;orchestra
instr 1
a1 oscil 5000,200,1;fondamentale
a2 oscil 5000,600,1;III armonica
a3 oscil 5000,1000,1 ;V armonica
aout = a1+a2+a3
out aout
endin
;score
30 di 109

f1 0 4096 10 1
i1 0 8

I battimenti illustrati in questo esempio, sempre di Elisa Russo, sono un caso particolare di sintesi
additiva.
<CsoundSynthesizer>
<CsOptions>
-W -o C:\tone.wav
</CsOptions>
<CsInstruments>
sr
=
44100
ksmps
=
10
nchnls =
1
instr
1
k4arm linseg 440,p3/2,444,p3/2,440
afond oscili 5000,440,1
arm4 oscili 5000,k4arm,1
adeclick linen 1,0.02, p3, 0.02
out (afond+arm4)*adeclick
endin
</CsInstruments>
<CsScore>
f1 0
4096
10
1
i1
0
10
</CsScore>
</CsoundSynthesizer>

GEN09 e
GEN19

Mentre la GEN10 usa un solo campo per definire una sinusoide, la GEN09 ne utilizza tre:
numero della componente, ampiezza relativa alla componente, fase iniziale della componente.
Ci consente di scrivere le componenti in qualsiasi ordine e di utilizzare la fase.
Per esempio
f1 0 4096 09 1 1 180
una sinusoide che inizia con fase a 180 gradi, quindi prima il semiperiodo negativo e poi quello positivo
La GEN19 consente d'indicare l'offset di corrente continua della componenente (una quantit costante sommata
funzione),
applicata dopo il riscalamento.

<CsoundSynthesizer>

31 di 109

<CsOptions>
-W -o C:\tone.wav
</CsOptions>
<CsInstruments>
sr
=
44100
ksmps
=
10
nchnls =
1
instr
1
;usa GEN9
a1
oscil
10000,220,1
adeclick linen 1,0.02, p3, 0.02
out
a1*adeclick
endin
instr
2
;usa GEN10
a2
oscil
10000,220,2
adeclick linen 1,0.02, p3, 0.02
out
a2*adeclick
endin
instr
3
;usa GEN19
a3
oscil
10000,220,3
adeclick linen 1,0.02, p3, 0.02
out
a3*adeclick
endin
</CsInstruments>
<CsScore>
f1
0
4096
9
1
3
0
f2
0
4096
-10
1
.5
.33
f3
0
4096
19
.5
1
270
i1
0
3
i2
4
3
i3
8
3
;(se il numero di componente 0.5 viene tracciato solo
</CsScore>
</CsoundSynthesizer>

3
.25
1

mezzo ciclo)

Oscillatori complessi: buzz e


gbuzz

buzz e gbuzz sono oscillatori che generano una serie di armoniche sinusoidali della
stessa ampiezza (buzz) o cosinusoidali di ampiezza variabile con
lordine dellarmonica (gbuzz).
a1 buzz xamp, xfreq, knh, ifn
a1 gbuzz xamp, xfreq, knh, klh, km, ifn
knh numero delle armoniche desiderate
klh numero d'ordine della pi bassa armonica desiderata.
km moltiplicatore della serie dei coefficienti di ampiezza delle armoniche, Si tratta di una serie
esponenziale: se la klh-esima armonica

32 di 109

.3

ha ampiezza A, la klh+n armonica avr ampiezza A * kmn


I due esempi seguenti ci permettono di ottenere lo stesso risultato.
a1 buzz iamp, ifrq, 10, 1
con la funzione
f1 0 8192 10 1
e
a1 oscil iamp, ifrq, 2
con la funzione
f2 0 8192 10 1 1 1 1 1 1 1 1 1 1
Infine riporto un esempio pi articolato da
http://iainmccurdy.org/csound.html
;Written by Iain McCurdy, 2006
<CsoundSynthesizer>
<CsOptions>
-odevaudio -b400
</CsOptions>
<CsInstruments>
sr =
kr =
ksmps
nchnls

44100
4410
= 10
= 2

;FLTK INTERFACE
CODE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
LABEL | WIDTH | HEIGHT | X | Y
FLpanel "buzz",
500, 150, 0, 0
;SWITCHES
ON | OFF | TYPE | WIDTH | HEIGHT | X | Y | OPCODE | INS |
STARTTIM | IDUR
gkOnOff,ihOnOff FLbutton "On/Off", 1, -1, 2, 150, 30, 0, 0, 0,
1,
0,
;NUMBER DISPLAY BOXES
idamp
FLvalue " ", 100,
idfreq
FLvalue " ", 100,
;SLIDERS
gkamp, ihamp

FLslider

-1

WIDTH | HEIGHT | X | Y
20, 0, 80
20, 0, 130

MIN | MAX | EXP | TYPE | DISP | WIDTH | HEIGHT | X | Y


"Amplitude",
0, 10000, 0, 5, idamp, 500, 30, 0, 50
33 di 109

gkfreq, ihfreq
100
;COUNTERS
OPCODE
gkharm, ihharm
0, -1

FLslider

"Oscillator Frequency",

1,

5000, -1,

5, idfreq, 500,

30,

0,

MIN | MAX | STEP1 | STEP2 | TYPE | WIDTH | HEIGHT | X | Y |


FLcount "No. of Harmonics",

-1, 80,

1,

2,

2, 120,

30, 380,

;SET INITIAL VALUES


VALUE | HANDLE
FLsetVal_i 7000, ihamp
FLsetVal_i 30, ihharm
FLsetVal_i 100, ihfreq
FLpanel_end

;END OF PANEL CONTENTS

;INSTRUCTIONS AND INFO PANEL


FLpanel " ", 500, 240, 512, 0
;TEXT BOXES
TYPE | FONT | SIZE | WIDTH | HEIGHT | X | Y
ih
FLbox
"
Miscellaneous Waveforms : buzz
", 1,
5, 14,
490, 15, 5, 0
ih
FLbox
"-------------------------------------------------------------", 1,
5, 14, 490,
15, 5, 20
ih
FLbox
"Buzz creates a composite tone of harmonically related sine ", 1,
5,
14, 490, 15, 5, 40
ih
FLbox
"wave partials.
", 1,
5, 14, 490, 15,
5, 60
ih
FLbox
"The user is given control of the number of partials required ", 1,
5,
14, 490, 15, 5, 80
ih
FLbox
"(from the fundemental upwards) and of the the amplitude and ", 1,
5,
14, 490, 15, 5, 100
ih
FLbox
"the fundemental frequency of the tone.
", 1,
5, 14,
490, 15, 5, 120
ih
FLbox
"Buzz requires the user to first supply it with a sine
", 1,
5, 14,
490, 15, 5, 140
ih
FLbox
"waveform via a function table (probably GEN 10). This table ", 1,
5,
14, 490, 15, 5, 160
ih
FLbox
"should not be too small, sizes of 8192 and upwards are
", 1,
5,
14, 490, 15, 5, 180
ih
FLbox
"recommended.
", 1,
5, 14, 490,
15, 5, 200
ih
FLbox
"Buzz provides a useful source for subtractive synthesis. ", 1,
5,
14, 490, 15, 5, 220
FLpanel_end
FLrun ;RUN THE FLTK WIDGET THREAD
;END OF FLTK INTERFACE
CODE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
instr

1
34 di 109

if gkOnOff!=-1 kgoto CONTINUE ;IF FLTK ON/OFF SWITCH IS NOT OFF SKIP TO
'CONTINUE' LABEL
turnoff
;TURNOFF INSTRUMENT
CONTINUE:
;LABEL
ifn = 2
;FUNCTION TABLE USED BY BUZZ OPCODE
;OUTPUT OPCODE AMPLITUDE | FREQUENCY | NO.OF HARMONICS |
FUNCTION_TABLE
asig buzz gkamp,
gkfreq, int(gkharm),
ifn
outs asig, asig
;SEND AUDIO OUTPUT TO THE SPEAKERS
endin
</CsInstruments>
<CsScore>
f2 0 131072 10 1 ;SINE WAVE
f 0 3600 ;DUMMY SCORE EVENT - ALLOW REALTIME PERFORMANCE FOR UP TO 1
HOUR
</CsScore>
</CsoundSynthesizer>

Gestione delle cartelle in cSound (Windows)


Scritto da Luca Cartolari
venerd 11 luglio 2008
Finch tutti i file rimangono nella stessa cartella del programma cSound, non c' bisogno di
particolari attenzioni. Le cose cambiano, ad esempio, quando si vuole cambiare cartella per i files
prodotti o utilizzati da cSound.
In ambiente windows, se si desidera indicare una specifica cartella in cui cui cSound deve salvare i
files audio prodotti, occorre creare una variabile d'ambiente SFDIR (Sound File Directory). Sound
Sample Directory (SSDIR) la cartella dove devono essere posti i soundfile. Sound Analysis
Directory (SADIR) la cartella dove verranno posti i files di analisi generati da cSound
In Windows Xp:
Pannello di controllo > Sistema > scheda Avanzate > pulsante Variabili d'Ambiente > Variabili di
sistema > Aggiunta di SFDIR con relativo percorso

Gestione delle cartelle in Csound


(Windows)

Finch tutti i file rimangono nella stessa cartella del programma cSound, non c' bisogno di
particolari attenzioni. Le cose cambiano, ad esempio, quando si vuole cambiare cartella per i files
prodotti o utilizzati da cSound.

35 di 109

In ambiente windows, se si desidera indicare una specifica cartella in cui cui cSound deve salvare i
files audio prodotti, occorre creare una variabile d'ambiente SFDIR (Sound File Directory). Sound
Sample Directory (SSDIR) la cartella dove devono essere posti i soundfile. Sound Analysis
Directory (SADIR) la cartella dove verranno posti i files di analisi generati da cSound
In Windows Xp:
Pannello di controllo > Sistema > scheda Avanzate > pulsante Variabili d'Ambiente > Variabili di
sistema > Aggiunta di SFDIR con relativo percorso

Gestione delle cartelle in Csound (Linux


Debian)

In ambiente Linux Debian (e quindi anche Linux 64Studio),


se si desidera indicare una specifica cartella in cui cui cSound deve salvare i files audio prodotti,
occorre creare una variabile d'ambiente SFDIR (Sound File Directory)
Inoltre
una variabile d'ambiente SSDIR (Sound Sample Directory)
per la cartella dove devono essere posti i soundfile.
una variabile d'ambiente SADIR (Sound Analysis Directory)
per la cartella dove verranno posti i files di analisi generati da cSound
Per farlo occorre:
Aprile la console terminale da root
Scrivere il comando gedit /etc/bash.bashrc
Editare
export SSDIR=/home/administrator/audio
export SFDIR=/home/administrator/audio
export SADIR=/home/administrator/audio
dove /home/administrator/audio la mia cartella audio.

Sintesi
sottrattiva

36 di 109

La sintesi sottrattiva nasce dallidea di poter creare un suono


sottraendo ampiezza ad alcune componenti spettrali di un altro
suono timbricamente pi complesso di quello da ottenere,
attraverso luso di filtri (da cui dipende la modifica del timbro).
www.lim.dico.unimi.it/membri/elisa/csound0708/Lez03/Slides_Sottrattiva.pdf
Disponendo di un suono con uno spettro molto ricco, possibile
ottenere qualsiasi spettro costituito da un sottoinsieme delle
componenti (armoniche o non armoniche) del suono originale.
Questa procedura sottrattiva di frequenze messa in atto
tramite particolari dispositivi che lasciano passare certe
frequenze piuttosto che altre.
Nella sintesi sottrattiva sono di particolare aiuto
quegli opcodes csound in grado di generare segnali
casuali,) con compresenza di tutte le frequenze udibili.
;strumento
instr 1
a1 rand p4
out a1
endin
;score
i1 0 3 20000
Un filtro pu lavorare non solo sul campione di suono corrente, ma
anche su uno o pi campioni precedenti che vengono conservati in
uno spazio di memoria interno al filtro.
Largomento iskip, utilizzato dalla maggior parte delle
implementazioni di filtri con Csound, determina se lo spazio di
memoria interno al filtro vada azzerato ad ogni nota oppure no, a
seconda che il suo valore sia 0 (non c una coda sonora relativa alla
nota precedente) o 1 (i campioni precedenti vengono conservati in
uno spazio di memoria interno al filtro).
FILTRO PASSA-BASSO: attenua tutte le frequenze al di sopra della
frequenza di taglio.
La curva di taglio tale per cui alla frequenza doppia di quella di
taglio lattenuazione di 6 dB, a quella quadrupla di 12 dB e cos via.
ares tone asig, khp [, iskip]
instr 1
a1 rand 20000
afilt tone a1,1000
out afilt
endin
FILTRO PASSA-ALTO: attenua tutte le frequenze al di sotto della
37 di 109

frequenza di taglio.
La curva di taglio tale per cui alla frequenza che la met di
quella di taglio lattenuazione di 6 dB, a quella che un quarto
di 12 dB e cos` via.
ares atone asig, khp [, iskip]
instr 1
a1 rand 20000
afilt atone a1,1000
out afilt
endin
Filtro di secondo ordine: attenuazione doppia rispetto a filtro di
primo ordine.
Filtro di terzo ordine: attenuazione tripla rispetto a filtro di primo
ordine.
instr 3 ;passa-alto II ordine
a1 rand 20000
afilt atone a1,1000
afilt2 atone afilt,1000
out afilt2
endin
instr 4 ;passa-basso III ordine
a1 rand 20000
afilt tone a1,1000
afilt2 tone afilt,1000
afilt3 tone afilt2,1000
out afilt3
endin
Filtro passa banda: Consente di attenuare le frequenze al di sopra e al di sotto di una
certa banda.
ares reson asig, kcf, kbw [, iscl] [, iskip]
Lunica frequenza che rimane inalterata quella centrale (kcf).
La larghezza di banda di un filtro passa-banda (kbw) ideale del primo
ordine prevede che i suoi estremi abbiano unampiezza di -3dB
rispetto alla frequenza centrale.
I tre valori codificati per il riscalamento (iscl) sono:
0 = nessun riscalamento;
1 = riscalamento in modo tale che lampiezza di picco del segnale
filtrato sia la stessa della parte del segnale dingresso che ricade nella
banda passante del filtro;
2 = riscalamento in modo tale che il valore efficace (RMS) del

38 di 109

segnale filtrato sia lo stesso del segnale dingresso.

Sintesi sottrattiva e filtri


risonanti

La sintesi sottrattiva una delle tecniche di sintesi pi utilizzate. Consiste nel ricavare da un suono
di partenza (spesso del rumore bianco) un suono finale, sottraendo dalla sorgente alcune frequenze
ed amplificandone altre. Per la sintesi sottrattiva CSound mette a disposizione molti opcode.
Opcode streson
ares streson asig, kfr, ifdbgain
L'opcode streson simula la risonanza tipica di uno strumento a corde. Evidenzia la frequenza
specificata da kfr filtrando il segnale asig. La risonanza tanto pi forte quanto il parametro
ifdbgain si avvicina a 1. Se ifdbgain tende a 0 il segnale d'ingresso rimane invariato. Nell'esempio
seguente la frequenza di risonanaza il do centrale 8.00
<CsInstruments>
..........................
instr 1
asig in
aGate linseg 0, 2, 1, p3 - 4, 1, 2, 0
k1 rms (asig * aGate)
asig gain asig, k1
inota1 = cpspch(p4)
ifdbgain = 0.94
a1 = asig
a1 streson a1, inota1, ifdbgain
a1 gain a1, k1
outs a1, a1
endin
</CsInstruments>
<CsScore>
i1 0 10 8.00
</CsScore>
Opcode phaser1
ares phaser1 asig, kfreq, kord, kfeedback [, iskip]
L'opcode phaser1 implementa una catena di filtri collegati in serie che colorano il segnale
d'ingresso asig con la frequenza specificata da kfreq. Il numero di filtri in catena specificato da
kord. Il parametro kfeedback, che varia da -1 a +1, specifica la presenza o meno di feedback
nell'input dei singoli filtri in catenza. iskip indica se mantenere o meno uno spazio di
memorizzazione per preservare il precedente segnale nella catenza dei filtri. Il default 0 non
permette la memorizzazione di alcun valore. Valori diversi dallo 0 implicano la parziale

39 di 109

permanenza del segnale audio precedente nella catenza dei filtri. Con iskip =0 il segnale di uscita
avr un sostegno pi breve, con un valore diverso da 0 verr incrementato il sostegno del segnale.
instr 1
asig in
aGate linseg 0, 2, 1, p3 - 4, 1, 2, 0
k1 rms (asig * aGate)
asig gain asig, k1
inota1 = cpspch(p4)
iord = 20
kfeedback = 0.9
iskip = 0.99
a1 = asig
a1 phaser1 a1,inota1,iord,kfeedback,iskip
a1 gain a1, k1
outs a1, a1
endin

L'opcode
comb

L'opcode comb un tipo di filtro risonante. E' essenzialmente una linea di ritardo con feedback,
come illustrato nella figura seguente

http://www.csounds.com/chapter1/index.html
Come si pu vedere il segnale entra nella linea di ritardo ed il suo ritardo, dopo averlo moltiplicato
con un valore di guadagno (il fattore di feedback), viene messo in feedback nuovamente con il
segnale d'ingresso.
L'opcode csound ha la seguente sintassi
a2 comb a1, krvt,ilpt
a2 segnale audio filtratto
40 di 109

krvt -- the reverberation time (defined as the time in seconds for a signal to decay to 1/1000, or
60dB down from its original amplitude).
ilpt -- loop time in seconds, which determines the echo density of the reverberation.
Come si pu vedere dall'immagine riportata la curva di risposta di comb una sequenza di impulsi
ugualmente distanziati dall'intervallo di tempo specificato da ilpt.
Questo parametro stabilisce quindi la frequenza di risonanza del filtro, che data da 1/lpt.
Se si desidera settare comb su una certa risposta di frequenza si potr utilizzare un codice simile.
ifreq = cpspch(p4)
ilpt = 1 / ifreq
a2 comb a1, krvt,ilpt
Naturalmente se il valore di ilpt lungo, invece di avvertire una coloritura del segnale avvertiremo
degli echi distanziati tra loro da ilpt secondi.

Sintesi
vettoriale

La sintesi vettoriale una variante della sintesi additiva. Se si opera una dissolvenza incrociata fra
pi tabelle, si parla
di sintesi vettoriale
Scrivere uno strumento che implementi questo tipo di sintesi significa sommare suoni diversi suoni
diversi che hanno inviluppi
scritti in modo tale che i suoni stessi siano in dissolvenza incrociata, si tratta solo di studiare da
quale tabella prendere
l'attacco, quanto deve durare, in quanto tempo si svolge la dissolvenza incrociata con il secondo
suono, quale sia il secondo suono, qual'
il suo inviluppo fino alla sua dissolvenza ecc...

Modulazione ad
anello

La modulazione ad anello una delle tecniche di sintesi storiche, utilizzata tra gli altri da
K.Stockhausen in molti suoi pezzi elettronici degli anni '60 e '70, tra cui KontaKte, Mantra,
Hymnen. Consiste nella moltiplazione di due segnali bipolari, uno portante (C) e uno Modulante
(M)
Il segnale portante (C) tipicamente il segnale principale con uno spettro armonico ricco,
mentre quello modulante (M) tradizionalmente una sinusoide. La formula della modulazione ad

41 di 109

anello quindi semplicemente:


CxM
Quando la frequenza del segnale modulante sotto i 20Hz, l'effetto che si ottiene il classico
tremolo. Quando M ha una frequenza udibile, il timbro di C cambia. Per ogni componente
sinusoidale di C, il segnale modulante M produce due nuovi segnali laterali uno uguale alla somma
di C ed M, l'altro uguale alla loro differenza. Un'altra caratteristica della modulazione ad anello
che nello spettro complessivo risultante non compariranno n il segnale modulante n il segnale
portante. Inoltre se i due segnali sono in un rapporto esprimibile con un numero razionale, i segnali
risultanti saranno in rapporto armonico, altrimenti verranno generate delle componenti in rapporto
non armonico.
Per fare un esempio, se C una sinusoide con frequenza 440 e M un'altra sinusoide con frequenza
220, le risultanti saranno di frequenza 660 e 220. D
Il comportamento della modulazione ad anello facilmente comprensibile tenendo presente la
seguente formula di Werner, derivata dalle note formule di prostaferesi.

Concludo riportando un esempio di codice cSound che implementa una modulazione ad anello. La
modulazione attivata in base al valore della variabile del canale software kRing. La frequenza del
segnale modulante letta via MIDI tramite l'istruzione ctrl7 . Il segnale modulante una semplice
sinusoide. Mentre il segnale portante il segnale stereo a2L a2R.
kRing chnget "Ring"
if kRing != 1 kgoto END_RING
if kRing == 1 kgoto START_RING
START_RING:
kFre ctrl7 ichan, ictlno2,220, 440
abimod oscili 5000, kFre, 1
kL rms a2L
kR rms a2R
a2L = a2L * abimod
a2R = a2R * abimod
a2L gain a2L, kL
a2R gain a2R, kR
END_RING:

42 di 109

Orchestra per la FM
semplice

Come si pu vedere dal precedente diagramma di flusso, la sintesi per modulazione di frequenza
(FM) semplice pu essere pensata come l'alterazione o la distorsione della frequenza di un
oscillatore a causa del valore d'ampiezza di un segnale modulante. In altre parole la sintesi per
modulazione di frequenza si ottiene con un'amipezza di vibrato tanto alta da rientrare nel campo
delle frequenze udibili.
Per ottenere una modulazione di frequenza semplice si utilizzano tipicamente due oscillatori
sinusoidali: un'oscillatore portante (Carrier Oscillator) ed un oscillatore modulante (Modulating
Oscillator). Una frequenza portante fc viene sommata all'ouput dell'oscillatore modulante. Il
risultato passato come frequenza di input all'oscillatore portante.
Se l'ampiezza del segnale modulante 0 (ossia quando il valore d 0), non c' modulazione e
l'output dell'oscillatore portante semplicemente uguale all'uscita di un oscillatore con frequenza
fc, ampiezza AMP e forma d'onda ifn1. Quando il segnale modulante diverso da 0 avviene la
modulazione vera e propria. Pi d alto pi aumenta la distorsione del segnale dell'oscillatore
43 di 109

portante.
La modulazione di frequenza particolarmente interessante perch con pochi parametri si possono
creare spettri particolarmente ricchi.
Inoltre possibile prevedere con una semplice equazione quali parziali verranno create tramite la
modulazione e con quali intensit.
Ecco una parte di una mia orchestra Csound che implementa la FM semplice.
kcamp =k1
kcfrq = koct
ifn1 = 1
kmfrq = 100
kindx ctrl7 ichan, ictlno, 0, 20
kmod oscil kmfrq * kindx, kmfrq, ifn1
a1 oscil kcamp, kcfrq + kmod, ifn1

Spettro armonico di semplici


FM

Continuando ad analizzare la modulazione di frequenza semplice, cerchiamo di capire quali


frequenze laterali vengono generate con la sintesi di modulazione di frequenza semplice.

Mentre con la modulazione ad anello (MA) semplice, ossia con oscillatori sinusoidali, le bande
laterali sono soltanto due, nella corrispondente modulazione di frequenza abbiamo una serie,
teoricamente infinita di frequenze aggiunte.
Il numero di bande laterali dipende dalla deviazione D. Pi alto il valore di D, pi aumenta il
44 di 109

numero di bande udibili, con D = I * fm


Come si pu vedere dalla tabella sopra riportata, le bande laterali hanno precisi rapporti
matematici, basati sulla somma e la differenza dei valori di fc ed fm.
Se possibile individuare le frequenze generate dalla FM, pi commplesso stabilirne l'ampiezza.
Diciamo innanzitutto che l'ampiezza delle bande laterali dipende dall'indice di modulazione I,
definito dalla gi citata equazione I = D / fm
Concludiamo per ora, esotericamente, rimandando ad ulteriori articoli per ulteriori
approfondimenti.
Il valore assoluto dell'ampiezza della banda laterale k, dato da Jk(I), dove J una funzione di
Bessel del primo tipo, k l'ordine della funzione e l'argomento l'indice di modulazione I

Introduzione all'opcode
foscil

L'opcode foscil un opcode che implementa una semplice modulazione di frequenza


ares foscil xamp, kcps, xcar, xmod, kndx, ifn [, iphs]

ares la variabile audio d'uscita


xamp l'ampiezza
kcps la frequenza nominale
xcar il fattore per il quale si moltiplica la frequenza nominale per ottenere la frequenza della
portante
xmod il fattore per il quale si moltiplica la frequenza nominale per ottenere la frequenza della
modulante
kndx l'indice di modulazione
ifn il numero della tabella (per lo pi sinusoide)
In conclusione la frequenza effettiva della portante sar: kcps*xcar, mentre la frequenza effettiva
della modulante sar kcps*kmod. Se per esempio vogliamo una portante di 200 Hz e una
modulante di 350 Hz, potremo assegnare indifferentemente ai tre argomenti i seguenti valori:
kcps: 1
kcar:200
kmod:350
oppure
kcps:50
kcar:4

45 di 109

kmod:7
oppure
kcps:200
kcar:1
kmod: 1.75
The actual formula used for this implementation of FM synthesis is xamp * cos(2 * t * kcps * xcar
+ kndx * sin(2 * t * kcps * xmod) - ), assuming that the table is a sine wave.
Ecco un esempio tratto da una mia orchestra
if (gksynth==5) then
kamp = k1
;printk 0.5,kamp
kcps = cpsoct(koct)
kcps = kcps * 0.5
kcar = 20 * kPitch
aosc1 foscil kamp, kcps * 0.125 * 0.125, kcar * 0.25 * kPitch , 60, 2, 1
aosc2 foscil kamp, kcps * 0.125 * 0.25, kcar * kPitch * 2, 80, 2, 1
aosc3 foscil kamp, kcps * 0.125 * 0.25, kcar * kPitch * 3, 70, 3, 1
endif

Introduzione all'opcode
loscil

Come si legge dalla documentazione Csound, l'opcode loscil legge un suono campionato da una
tabella.
Il suono campionato pu avere inclusi dei punti di loop. Questo aspetto dell'opcode, comunque, per
ora lo tralasciamo.
Per evitare di scrivere il percorso completo del file audio da utilizzare con il nostro loscil,
opportuno settare la variabile d'ambiente SSDIR. Nel mio caso ho assegnato a SSDIR, il percorso
C:\Documents and Settings\Administrator\Documenti\Musica\Audio. In questa cartella ho cos
salvato tutti i miei files audio.
La sintassi di base del nostro opcode quindi la seguente:
ar1 [,ar2] loscil xamp, kcps, ifn [, ibas] [, imod1]
ar1 [,ar2] - loscil potr ritorare una o due variabili audio a seconda che il nostro campione sia
mono o stereo.
xamp
- specifica l'ampiezza del segnale in uscita
46 di 109

kcps
- specifica la frequenza del segnale in uscita
ifn
- specifica il numero di tabella contenente il file con il suono campionato caricato tramite
la GEN01
ibas
- specifica la frequenza di base del suono campionato. Se questo valore non conosciuto
occorre indicare il valore 1.
imod1 - specifica la modalit di loop del campione: 1 - loop ;2 loop avanti ed indietro; 0 nessun
loop
Questo opcode lavora quindi con la funzione GEN01.
Nell'esempio successivo la tabella con identificatore 6 costituita da 131072 punti contiene il file
"vetri1.wav" caricato dalla directory specificata da SSDIR
f 6 0 131072 1 "vetri1.wav" 0 0 0
E' possibile non indicare il numero di punti, ma lasciare che venga dedotto dal file caricato. Per
ottenere questo il valore da specificare '0'
f 7 0 0 1 "vetri2.wav" 0 0 0
Riassumendo ecco uno strumento che fa uso dell'opcode loscil.
instr 1
..............
kcps = cpsoct(koct)*0.03125 * kPitch
ibas = 1
imod = 1
;printk 0.5,kamp
; Play the audio sample stored in Table #1.
ifn = 6
aosc1 loscil koscil1 * k1, kcps, ifn, ibas,imod
aosc2 loscil k1, kcps, ifn, ibas,imod
ifn = 7
aosc2 loscil koscil3 * k1, kcps, ifn, ibas,imod
..............
endin
f 6 0 131072 1 "vetri1.wav" 0 0 0
f 7 0 0 1 "vetri2.wav" 0 0 0

Sintesi per distorsione non


lineare

Il 'waveshaping ' la seconda modalit di approccio (dopo la F.M.) alla sintesi del suono mediante
distorsione, ed anch'essa consente di ottenere spettri le cui componenti si evolvono dinamicamente
nel tempo. E' una tecnica dal costo computazionale piuttosto basso (rispetto alla sintesi additiva) e
47 di 109

permette di ottenere degli spettri a banda limitata (diversamente dagli spettri prodotti in FM).
http://www.fisica.unina.it/mfa/acust/materiale%20sito/Sistemi%20di%20sintesi/waveshap.htm
Lo spettro prodotto da uno strumento per il waveshaping cambia con l'ampiezza del suono. Va qui
sottolineato che questo comportamento spettrale tipico degli strumenti acustici e per questo
motivo questa tecnica di sintesi pu essere interessante nella simulazione di alcune famiglie di
strumenti tradizionali (in particolare gli ottoni), anche se la tecnica di sintesi per modelli fisici, dal
punto di vista della simulazione offre maggiori possibilit.
In sostanza, il waveshaping consiste nella distorsione dell'ampiezza di un suono allo scopo di
alterarne la forma d'onda (e quindi il suo contenuto spettrale). Se questa tecnica di distorsione viene
controllata con cura, possibile ottenere timbri interessanti e gradevoli. Il waveshaping permette
(come la F.M.) il controllo continuo dello spettro del segnale per mezzo di un indice, rendendo
quindi possibile la produzione di spettri dinamici mediante la variazione nel tempo dell' indice.
Il cuore di un sistema waveshaping costituito dall'elemento chiamato waveshaper, altrimenti
definito processore non lineare, il cui scopo quello di alterare la forma dell'onda che lo attraversa.
Per meglio comprendere ci che accade, si pensi ad un processore lineare, come potrebbe essere
un'amplificatore ideale: in questo amplificatore 'perfetto' un cambio di ampiezza del segnale in
ingresso produrr una identica variazione nel segnale di uscita. Se ad esempio (sempre in questo
ipotetico amplificatore) si raddoppiasse l'ampiezza del segnale d'ingresso, anche quella del segnale
d'uscita raddoppierebbe.
Nell'esempio riportato la funzione distorcente stata definita tramite la GEN07, che definisce una
spezzata che
vale -1 tra i punti 0 e 1635, quindi passa al valore 1 con una semiretta costituita da 827 punti e
rimane a 1 per i 1635
punti successivi.
Su una tabella di 4096 punti, per valori del segnale d'ingresso a1 (che vanno da 0 a 1 ma che
vengono internamente
tradotti da 0 a 4096) che vanno da 0 a 1635 il segnale viene distorto e posto uguale a -1; per valori
che vanno da 1635
a 2436 il segnale non viene modificato; per valori compresi tra 2462 e 4096, il segnale viene
distorto e posto uguale a 1.

instr 52
ifreq = cpspch(p4)
iAmp = i(gkGain)
iGain = p6
ictlno =$ictlno2;7 le -1
ichan = $ichan2
kAmp2 ctrl7 ichan, ictlno, 0.1, 10
iL =p7
iR =p8
48 di 109

kamp linseg 0, p3 * 0.1, 1, p3 * 0.2, 1, p3 - (p3 * 0.5), 0.5, p3 * 0.1,0


a1 = ga1
k1 rms a1
a1 gain a1, kamp
aDist table a1,6,1
; aDist reson aDist, ifreq, 50
aL gain aDist, k1 *iL * kamp * iGain * 0.1 * kAmp2
aR gain aDist, k1 *iR * kamp * iGain * 0.1 * kAmp2
outs aL, aR
gagL = gagL + aL
gagR = gagL + aR
endin

f 6 0 4096 7 -1 1635 -1 827 1 1635 1

L'opcode table e la
GEN07

L'opcode table genera segnali che possono essere audio, di controllo o di inizializzazione sulla base
della lettura di una tabella.
aOut table andx,ifn,ixmode
andx l'indice a cui corrispondono i valori indicati in tabella.
ifn il numero della tabella
ixmode il modo d'interpretazione dell'indice: 0 specifica un indice grezzo (tra 0 e la lunghezza
della tabella usata), 1 specifica un indice normalizzato
(cio compreso tra 0 e 1).

GEN07
GEN07 generates an f-table function from one or more linear function segments. Each segment is
defined with three parameters:

(a) the starting amplitude,


(b) the width of the segment in samples, and
(c) the ending amplitude.

49 di 109

For GEN07, the segment that's drawn between the starting and ending amplitudes uses a linear
function. For the next segment, t
he ending amplitude is used as the starting amplitude for the next segment. If a discontinuity is
required,
zero-width segments can be defined.
usage

f# time size 7 a n1 b n2 c ...

parameters

size -- number of points in the table. This value must be a power-of-2 or a power-of-2 plus
1.
a, b, c, ... -- ordinate values, in odd-numbered pfields p5, p7, p9, . . .
n1, n2, ... -- length of segment (no. of storage locations), in even-numbered pfields. Cannot
be negative,
but a zero is meaningful for specifying discontinuous waveforms. The sum n1 + n2 + ....
will normally
equal size for fully specified functions. If the sum is smaller,
the function locations not included will be set to zero; if the sum is greater, only the first
size locations will be stored.

In questo esempio si vede un uso dell'opcode table e della GEN07 nella realizzazione di un
semplice esempio di sintesi
per distorsione non lineare

instr 51
ifreq = cpspch(p4)
;ifdbgain2 = p5
iAmp = i(gkGain)
iGain = p6
ictlno =$ictlno1;7
ichan = $ichan1
kbw ctrl7 ichan, ictlno, 5, 50
iL =p7
iR =p8
kamp linseg 0, p3 * 0.1, 1, p3 * 0.2, 1, p3 - (p3 * 0.5), 0.5, p3 * 0.1,0
a1 = ga1
k1 rms a1
a1 gain a1, kamp
aDist table a1,6,1
aDist areson aDist, ifreq, kbw

50 di 109

aL gain aDist, k1 *iL * kamp * iGain * 0.15


aR gain aDist, k1 *iR * kamp * iGain * 0.15
outs aL, aR
gagL = gagL + aL
gagR = gagL + aR
endin

f 6 0 4096 7 -1 1635 -1 827 1 1635 1

Gli opcodes delayr, delayw,


deltap

Gli opcodes delayr, delayw e deltap (deltapi) sebbene presentino un uso leggermente meno
intuitivo rispetto all'opcode delay, sono uno strumento prezioso con cui vale la pena esercitarsi.
Gli opcode delayr e delayw sono in realt un'unica unit. Il loro scopo quello di ritardare di un
certo tempo il segnale entrante:
delayr legge da una linea di ritardo, in cui il segnale impiega idlt secondi per passare dall'ingresso
all'uscita; delayr scrive nella linea di ritardo.
Nell'esempio sottostante i segnali d'ingresso che si desiderano ritardare (a cui si desidera quindi
applicare un delay) sono gaRecL2 e gaRecR2. adump invece il segnale d'uscita ritardato di 5
secondi .
Siccome il parametro di delayr di tipo i, adump risulter sempre in ritardo di 5 secondi durante
tutto il periodo di esecuzione dello strumento (a meno di strumenti con opcode di
reinizializzazione, ma non questo il caso...). L'opcode deltap quindi utile proprio per creare
ritardi multipli o variabili. Nell'esempio, infatti, il tempo di ritardo letto tramite bus software
(istruzione chnget) e quindi potr cambiare durante la performance. La variabile d'ingresso di
deltap, nell'esempio kdur_randomized_delay, in effetti una variabile di controllo.
Dentro ad una linea di ritardo possibile inserire tanti opcode deltap quanti se ne desidera.
Infine importante rammentare che deltap legge da punti intermedi della linea di ritardo creata con
la coppia delayr/delayw: il suo valore non potr quindi superare idlt (nell'esempio 5 secondi)

instr 12
if gkMute == 1 kgoto SALTA
kFilter chnget "Filter"
51 di 109

if kFilter == 0 kgoto SALTA


...........................
kdur_randomized_delay chnget "delay2"
.................................
adump delayr 5
; set maximum distance
aRecL1 deltap kdur_randomized_delay
; move sound source past
delayw gaRecL2
; the listener
adump delayr 5
; set maximum distance
aRecR1 deltap kdur_randomized_delay
; move sound source past
delayw gaRecR2
; the listener
outs aRecL1 , aRecR1
SALTA:
endin

Sintesi per modelli fisici: l'opcode


pluck

La sintesi per modelli fisici (in inglese, physical modeling) costituisce un approccio abbastanza
diverso rispetto alle tecniche di sintesi pi 'standard', in quanto prende l'avvio dall'analisi delle
caratteristiche fisiche di un determinato strumento preesistente (od uno assolutamente virtuale) e,
attraverso la modellizzazione matematico - fisica di ciascun componente essenziale alla sua
realizzazione ne ricostruisce (o ne inventa) il suono.
Nel corso degli anni, molti gruppi di ricerca si sono dedicati allo sviluppo di questa tecnica di
sintesi in quanto essa consente di produrre segnali acustici molto "reali" rispetto ad un modello
esistente e, pertanto, estremamente utile per studiare e comprendere a fondo i meccanismi di
produzione e trasformazione del suono operati dagli strumenti acustici esistenti (o di strumenti nati
solo dalla fantasia di chi li progetta).

http://www.fisica.unina.it/mfa/acust/materiale%20sito/Sistemi%20di%20sintesi/modfis.htm
L'algoritmo di Karplus-Strong, in particolare, un metodo che manipola una forma d'onda
attraverso una linea di delay con dei filtri per simulare suoni di corde plettrate (chitarra) o soggette
a percussione (pianoforte). una tecnica di sintesi sottrattiva basata sulla retroazione (feedback
loop) simile a quella di un filtro comb.
Csound comprende un opcode che implementa l'algoritmo di Karplus e Strong, con alcune
aggiunte: si tratta di pluck e la sua sintassi :
52 di 109

ar pluck kamp, kcps, icps, ifn, imeth [, iparm1] [, iparm2]


kamp: ampiezza
kcps: frequenza
ifn: numero di tabella, se uguale a 0, come nell'algoritmo originale, la tabella verr riempita da
valori casuali.
imeth il metodo usato per la modifica dei valori della tabella durante la generazione del suono. Ve
ne sono sei, alcuni dei quali
utilizzano gli argomenti aggiuntivi iparm1 e iparm2

L'istruzione if ....
kgoto

Nella realizzazione di strumenti cSound risulta particolarmente utile un'istruzione di salto quale
if..... kgoto. Questa istruzione evidenzia come negli strumenti cSound possano venir inserite
istruzioni di controllo di flusso come in un qualsiasi programma tradizionale.
L'istruzione kgoto un'istruzione che viene eseguita su variabili di controllo (una k-variabile).
Tipicamente questo opcode utilizato in coppia con il classico costrutto if, la cui sintassi
if <boolean expr> kgoto ETICHETTA
Se l'espressione booleana verificata il controllo passa al codice etichettato.
Nell'esempio seguente viene implementato un comando di mute, particolarmente utile in uno
strumento da utilizzare in una situazione live.
Quando il canale mute viene valorizzato a 1, il test gkMute==1 verificato e quindi il controllo
viene passato al codice con etichetta ESCI. In pratica il codice dello strumento viene saltato.

instr 1
gkMute chnget "mute"
if gkMute == 1 kgoto ESCI
.....
ESCI:
endin

Algoritmi di sintesi e pedaliera


MIDI

In questo articolo vediamo come sfruttare gli eventi MIDI di tipo Note-On per sostituire, durante
53 di 109

una performance, un algoritmo di sintesi con un altro


L'opcode Csound che ho utilizzato per catturare l'evento MIDI di Note-On
midinoteonkey knote, kvelocity
Il canale MIDI, non essendo setttato esplicitamente il canale 1.
Testando questo opcode con l'aiuto della solita comoda istruzione
printk t, knote
immediato verificare che knote assume il valore di MIDI Note-On, solo quando la nostra
pedaliera MIDI solleva il corrispondente evento. In tutti gli altri istanti knote vale 0. Il nostro
scopo, chiaramente, quello di non considerare i valori nulli; invece, ogni volta che viene ritornato
un valore utile lo dobbiamo memorizzare e sfruttare per cambiare il nostro algoritmo di sintesi.
Un possibile codice per far questo
midinoteonkey knote, kvelocity
if(knote==69) then
gksynth=0
endif
if(knote==71) then
gksynth=1
endif
if(knote==72) then
gksynth=2
endif
In questo esempio le note significative sono la 69, la 71 e la 72. La variabile globale gksynth
memorizza l'algoritmo di sintesi che deve essere eseguito.
In conclusione la nostra orchestra dovr essere cos strutturata:
................
gksynth init 0
..........................
instr 1
kvelocity init 0
knote init 0
.............................
midinoteonkey knote, kvelocity
if(knote==69) then
gksynth=0
endif
if(knote==71) then
54 di 109

gksynth=1
endif
if(knote==72) then
gksynth=2
endif
if (gksynth==1 || gksynth==2) then
.................................
; parte condivisa dell'algoritmo
endif
if (gksynth==1) then
........
endif
if (gksynth==2) then
...........
endif
endin

Una loop station in


cSound

Molta musica d'oggi, in particolare quella di estrazione rock, pop, jazz fa ampio uso di sample
loops.
Sul mercato si possono trovare molte macchine specializzate, le cosiddette loop-station.
Ovviamente in cSound facile realizzarne una, con il vantaggio per, di potervi aggiungere anche
qualche bizzarria personale.

Nella nostra loop station l'interfaccia grafica realizzata usando alcuni dei pi comuni controlli
FLTK:
Un pannello FLpanel, abbastanza grande da contenere 6 bottoni, di cui 5 servono per mettere in
moto 5 possibili campionamenti in parallelo, ed 1 per abilitare o meno i comandi per la
granularizzazione del suono. La nostra loop station, infatti, implementa un semplice sistema di
granularizzazione pilotandolo mediante 5 FLslider. I primi due slider gestiscono i volumi dei due
canali stereo. Gli altri tre servono per definire la durata di ogni singolo grano. I microsuoni
possiedono un inviluppo triangolare. Il primo slider serve cos per definire la durata dell'attacco del
grano, mentre il secondo specifica la durata del rilascio. Il terzo slider definisce la durata della
pausa che separa un grano dal successivo.

55 di 109

L'orchestra fa uso di due strumenti.


Lo strumento 1 la loop-station vera e propria. Lo strumento 2 si occupa invece della
granularizzazione del suono.
gkTrik1 init
gkTrik2 init
gkTrik3 init
gkTrik4 init
gkTrik5 init

0
0
0
0
0

Le variabili gkTrik1-gkTrik5 controllano l'abilitazione o meno degli opcode sndloop. Quando la


sua variabile di controllo gkTrickn vale 0 (pulsante non premuto), l'opcode sndloop non campiona
ed il suo segnale d'uscita identico al segnale d'entrata. Quando la variabile di controllo passa a 1
(pulsante premuto) l'opcode sndloop campiona il suono per la durata prefissata. Quindi se continua
ad essere premuto manda in play il suono campionato.
gkGranule init
gaL init 0
gaR init
0

Queste tre variabili servono per memorizzare lo stato dell'abilitazione della sezione di
granulizzazione e per memorizzare il segnale stereofonico elaborato dal primo
strumento mettendolo a disposizione per il secondo.
FLpanel "LOOP STATION", 1000, 600, 600, 100
ion = 1
ioff = 0
itype = 2
iwidth = 200
iheight = 200
ix = 0
iy = 0
iopcode = -1
istarttim = 0
idur = -1
gkTrik1, ihb1 FLbutton "@>", ion, ioff, itype, iwidth, iheight, ix, iy,-1
ix = 200
gkTrik2, ihb1 FLbutton "@>", ion, ioff, itype, iwidth, iheight, ix, iy,-1
ix = 400
gkTrik3, ihb1 FLbutton "@>", ion, ioff, itype, iwidth, iheight, ix, iy,-1
ix = 600
gkTrik4, ihb1 FLbutton "@>", ion, ioff, itype, iwidth, iheight, ix, iy,-1
ix = 800
gkTrik5, ihb1 FLbutton "@>", ion, ioff, itype, iwidth, iheight, ix, iy,-1
ix = 0
iy = 200
56 di 109

iwidth = 1000
iheight = 50
gkGranule, ihb1 FLbutton "@arrow", ion, ioff, itype, iwidth, iheight, ix, iy,-1
idVolL FLvalue " ", 200,
20, 0, 300
gkVolL, ihVolL FLslider "VOLUME L", 0, 4, 0,
FLsetVal_i 0, ihVolL

5,

idVolL, 200,

20,

0, 280

idVolR FLvalue " ", 200,


20, 200,
gkVolR, ihVolR FLslider "VOLUME R",
FLsetVal_i 0, ihVolR

5,

idVolR, 200,

20,

200, 280

300
0, 4, 0,

idAtt FLvalue " ", 200,


20, 400, 300
gkAtt, ihAtt FLslider "ATTACCO", 0.002, 0.09, 0,
FLsetVal_i 0.05, ihAtt

5,

idAtt, 200,

20,

400, 280

idRil FLvalue " ", 200,


20, 600, 300
gkRil, ihRil FLslider "RILASCIO", 0.002, 0.09, 0,
FLsetVal_i 0.008, ihRil

5,

idRil, 200,

20,

600, 280

idPau FLvalue " ", 200,


20, 800, 300
gkPau, ihPau FLslider "PAUSA", 0.0009, 0.7, 0,
FLsetVal_i 0.04, ihPau

5,

idPau, 200,

idVol FLvalue " ", 800,


40, 0, 500
gkVol, ihVol FLslider "VOL", 0, 1, 0, 1, idVol, 800,
FLsetVal_i 1, ihVol

40,

20,

800, 280

0, 440

FLpanelEnd
FLrun
Lo strumento 1 incomincia leggendo il solito segnale audio monofonico (istruzione asig in).
La variabile audio aGate viene ancora una volta utilizzata per creare un fade-in ed un fade-out
all'inizio ed alla fine della performance, in modo da evitare eventuali click.
La variabile audio aGate2, invece, controlla il volume globale dello strumento 1.
Lo strumento 1 oltre a permettere 5 loop in parallelo sensibilie ai messaggi di control change 1 su
canale 1 (MIDI input)
L'opcode ctl7 viene utilizzato sia per implementare il livello del feedback del filtro phaser1,
sia per creare il glissando dalla nota p4 alla nota p5. E' un opcode che cattura i messaggi MIDI in
input. Il parametro ichan specifica il canale di ascolto, ictlno il numero di control change ;
knotamin e knotamax sono i due valori minimi e massimi su cui vengono mappati i valori effettivi
del control change. In questo modo, qualsiasi sequenza pu essere mappata sui valori che assume
un particolare control-change; anzi, lo stesso control-change, usando diverse occorrenze
dell'opcode clt7, pu pilotare valori di opcode csound differenti
Il cuore della loop station rappresentato dalla sequenza di istruzioni sndloop.
I 5 loop hanno durata diversa (i numeri primi 5, 7, 11, 13, 17) in modo da evitare il pi possibile il
57 di 109

ripresentarsi delle stesse sovrapposizioni di suoni.


instr 1
asig in
aGate linseg 0, 2, 0.30, p3 - 4, 0.30, 2, 0
aGate2 = a(gkVol)
ictlno =1
knotamin = cpspch(p4)
knotamax = cpspch(p5)
ichan = 1
knota ctrl7 ichan, ictlno, knotamin, knotamax
a1 = asig
aRec1,koutrec1 sndloop a1, 1, gkTrik1, 5, 1
aRec2,koutrec1 sndloop a1, 1, gkTrik2, 7, 1
aRec3,koutrec1 sndloop a1, 1, gkTrik3, 11, 1
aRec4,koutrec1 sndloop a1, 1, gkTrik4, 13, 1
aRec5,koutrec1 sndloop a1, 1, gkTrik5, 17, 1
kRec1 rms (aRec1 * aGate )
kRec2 rms (aRec2 * aGate )
kRec3 rms (aRec3 * aGate )
kRec4 rms (aRec4 * aGate )
kRec5 rms (aRec5 * aGate )
k1 rms (a1 * aGate )
ifdbgain1 = 0.96
a1 streson a1, knota, ifdbgain1
iord1 = 50
iskip1 = 0.90
ifdbgain2 = 0.96
aRec1 streson aRec1, knota, ifdbgain2
aRec2 streson aRec2, knota, ifdbgain2
aRec3 streson aRec3, knota, ifdbgain2
aRec4 streson aRec4, knota, ifdbgain2
aRec5 streson aRec5, knota, ifdbgain2
iord2 = 60
iskip2 = 0.99
kfeedback2 ctrl7 ichan, ictlno, 0.30, 0.99
aRec1 phaser1 aRec1,knota,iord2,kfeedback2,iskip2
aRec2 phaser1 aRec2,knota,iord2,kfeedback2,iskip2
aRec3 phaser1 aRec3,knota,iord2,kfeedback2,iskip2
aRec4 phaser1 aRec4,knota,iord2,kfeedback2,iskip2
aRec5 phaser1 aRec5,knota,iord2,kfeedback2,iskip2
aRec1 gain aRec1, kRec1
aRec2 gain aRec2, kRec2
58 di 109

aRec3 gain aRec3, kRec3


aRec4 gain aRec4, kRec4
aRec5 gain aRec5, kRec5
a1 gain a1, k1
gaL = a1 + aRec1 + aRec3 + aRec5
gaR = a1 + aRec2 + aRec4 + aRec5
outs gaL * aGate2, gaR * aGate2
endin
Lo strumento 2 implementa una semplice sintesi granulare in tempo reale, secondo il modello gi
illustrato in un precedente articolo.
La durata di ogni grano (di forma triangolare) definita da un attacco, un rilascio ed una pausa.
Sia l'attacco che il rilascio hanno una componente randomica, riassumibile con la formula:
Valore = Valore +/- Rand(Valore/2)
In modo da evitare tessiture troppo monotone.

instr 2
if (gkGranule ==0) kgoto SALTA
a1 = gaL
a2 = gaR
ktempAtt = gkAtt / 2
krandAtt rand ktempAtt
ktempAtt = gkAtt + krandAtt
ktempRil = gkRil / 2
krandRil rand ktempRil
ktempRil = gkRil + krandRil
ktempPau = gkPau / 2
krandPau rand ktempPau
ktempPau = gkPau + krandPau
start:
iPause = i(ktempPau)
iDur1 = i(ktempAtt)
iDur2 = i(ktempRil)
iVolL = i(gkVolL)
iVolR = i(gkVolR)
igap = iDur1 + iDur2 + iPause
timout 0, igap, continue
reinit start
continue:
agateL linseg 0, iDur1 , iVolL, iDur2 , 0
agateR linseg 0, iDur1 , iVolR, iDur2 , 0
59 di 109

rireturn
outs a1 * agateL , a2 * agateR
SALTA:
endin
</CsInstruments>
<CsScore>
i1 0 900 7.00 7.02
i2 0 900
</CsScore>
</CsoundSynthesizer>

Pilotare l'opcode diskin con un MIDI


controller

L'opcode diskin un opcode particolarmente semplice da usare in Csound: permette di leggere un


file audio da un device esterno e di metterlo in loop alterandone il pitch .
La sintassi dell'opcode la seguente:
ar1 [, ar2 [, ar3 [, ... ar24]]] diskin ifilcod, kpitch [, iskiptim] [, iwraparound] [, iformat] [,
iskipinit]
Mi soffermo a commentare i due parametri principali dell'opcode:
Il parametro ifilcod pu essere un numero indicante l'identificativo di una funzione GEN01, oppure
una stringa contenente il nome del file (con indirizzo relativo se le variabili d'ambiente SSDIR e
SFDIR sono state valorizzate o con indirizzo assoluto).
Il parametro kpitch ha il seguente significato:pu essere un qualsiasi numero reale (un
numero negativo significa un esecuzione in reverse). indicante un rapporto di frequenza; ad
esempio, riportando l'esempio del manule Csound:
1 = normal pitch
2 = 1 octave higher
3 = 12th higher, etc.
.5 = 1 octave lower
.25 = 2 octaves lower, etc
-1 = normal pitch backward

60 di 109

-2 = 1 octave higher backwards, etc.


In questo esempio di codice Csound viene utilizzato l'opcode ctrl7 per trasformare un valore MIDI
in un valore utile per kPitch.
I parametri di diskin sono valorizzati con i seguenti valori:
Ssample una variabile di tipo stringa indicante il file da leggere
kcps una variabile contenente il valore di kPitch arrotondato ad un valore significativo per diskin
iskiptim a zero (il file viene letto dall'inizio)
iwraparound a 1 (il file letto in ciclo continuo)
kPitch ctrl7 ichan, ictlno, 0.25, 10
kcps = round(kPitch)
if(kcps<1) then
kcps = 0.5
endif
asig1 diskin Ssample, kcps,0,1

Pitch detection con gli opcodes spectrum e


specptrk

Attraverso l'uso degli opcodes spectrum e specptrk possibile riuscire a estrapolare da un segnale
audio la sua frequenza
dominante.
L'opcode spectrum il responsabile dell'analisi del segnale audio. L'ouput wsig di tipo window
data (non i pi comuni kontrol o audio).
L'opcode crea una struttura dati su cui l'opcode specptrk opera successivamente per ricavare
ampiezza e frequenza fondamentale.
wsig spectrum xsig, iprd, iocts, ifrqa [, iq] [, ihann] [, idbout] \
[, idsprd] [, idsinrs]
L'analisi fatta ogni iprd secondi sul segnale xsig. L'analisi consiste nell'applicazione di una
particolare implementazione della
Discrete Fourier Transform(DFT). Sebbene pi efficiente della FFT, la DDT richiede che le
frequenze calcolate siano discrete e distanziate
tra loro da una costante di frequenza. In particolare la constant-Q, exponentially-spaced DFT, su
cui si basa l'opcode spectrum
un banco di filtri geometricamente spaziati intorno ad una frequenza centrale
fk = f0 . 2 k/b dove b indica il numero di filtri per ottava
iprd indica il periodo dell'analisi della DFT
iocts indica invece il numero di ottave utilizzate nell'analisi
61 di 109

ifrqa indica il numero di filtri per ottava spaziati esponenzialmente


iq il valore Q dei filtri, dove Q o fattore di risonanza ugual a:
Q= frequenza di taglio / larghezza di banda
ihann set to 1 to apply a hanning window or 0 for the default hamming window
idbout format for the DFT output: 0= magnitude, 1 = dB, 2 = magnitude2, 3= magnitude

specptrk
spectrk Estimates the pitch of the most prominent complex tone in the spectrum.

Description
Estimate the pitch of the most prominent complex tone in the spectrum.

Syntax
koct, kamp specptrk wsig, kvar, ilo, ihi, istr, idbthresh, inptls, \
irolloff [, iodd] [, iconfs] [, interp] [, ifprd] [, iwtflg]

Initialization
ilo, ihi, istr -- pitch range conditioners (low, high, and starting) expressed in decimal octave form.
idbthresh -- energy threshold (in decibels) for pitch tracking to occur. Once begun, tracking will be
continuous until the energy falls below one half the threshold (6 dB down), whence the koct and
kamp outputs will be zero until the full threshold is again surpassed. idbthresh is a guiding value.
At initialization it is first converted to the idbout mode of the source spectrum (and the 6 dB down
point becomes .5, .25, or 1/root 2 for modes 0, 2 and 3). The values are also further scaled to allow
for the weighted partial summation used during correlation.The actual thresholding is done using
the internal weighted and summed kamp value that is visible as the second output parameter.
inptls, irolloff -- number of harmonic partials used as a matching template in the spectrally-based
pitch detection, and an amplitude rolloff for the set expressed as some fraction per octave (linear,
so don't roll off to negative). Since the partials and rolloff fraction can affect the pitch following,
some experimentation will be useful: try 4 or 5 partials with .6 rolloff as an initial setting; raise to
10 or 12 partials with rolloff .75 for complex timbres like the bassoon (weak fundamental).
Computation time is dependent on the number of partials sought. The maximum number is 16.
iodd (optional) -- if non-zero, employ only odd partials in the above set (e.g. inptls of 4 would
employ partials 1,3,5,7). This improves the tracking of some instruments like the clarinet The
default value is 0 (employ all partials).

62 di 109

iconfs (optional) -- number of confirmations required for the pitch tracker to jump an octave, prorated for fractions of an octave (i.e. the value 12 implies a semitone change needs 1 confirmation
(two hits) at the spectrum generating iprd). This parameter limits spurious pitch analyses such as
octave errors. A value of 0 means no confirmations required; the default value is 10.
interp (optional) -- if non-zero, interpolate each output signal (koct, kamp) between incoming wsig
frames. The default value is 0 (repeat the signal values between frames).
ifprd (optional) -- if non-zero, display the internally computed spectrum of candidate fundamentals.
The default value is 0 (no display).
iwtftg (optional) -- wait flag. If non-zero, hold each display until released by the user. The default
value is 0 (no wait).

Performance
At note initialization this unit creates a template of inptls harmonically related partials (odd
partials, if iodd non-zero) with amplitude rolloff to the fraction irolloff per octave. At each new
frame of wsig, the spectrum is cross-correlated with this template to provide an internal spectrum
of candidate fundamentals (optionally displayed). A likely pitch/amp pair (koct, kamp, in decimal
octave and summed idbout form) is then estimated. koct varies from the previous koct by no more
than plus or minus kvar decimal octave units. It is also guaranteed to lie within the hard limit range
ilo -- ihi (decimal octave low and high pitch). kvar can be dynamic, e.g. onset amp dependent.
Pitch resolution uses the originating spectrum ifrqs bins/octave, with further parabolic interpolation
between adjacent bins. Settings of root magnitude, ifrqs = 24, iq = 15 should capture all the
inflections of interest. Between frames, the output is either repeated or interpolated at the k-rate.
(See spectrum.)

wsig spectrum a1, .01, 7, 24, 30, 0, 3


; get a 7-oct spectrum, 24 bibs/oct
ktemp,ka specptrk wsig, kvar, 6.0, 10.0, 9.0, 8, 5, .7, 1, 5, 1, .2 ; the pch and amp
if (cpsoct(ktemp)>50) then
gkNote = cpsoct(ktemp)
endif

L'opcode
specptrk

Riassumendo il valore dei parametri dell'opcode specptrk


koct,
kamp

specptrk

wsig, kvar, ilo, ihi, istr, idbthresh, inptls, irolloff[, iodd, iconfs,

63 di 109

L'opcode ritorna frequenza principale e dinamica dello spettro analizzato e codificato da wsig.

ilo,ihi,istr specificano in formato octave point pitch-class il range di frequenza di analisi ed il punto di partenza
idbthresh esprime in decibel la soglia minima d'ampiezza del segnale analizzabile
inptls rappresenta il numero di parziali che il suono principale deve possedere per essere preso in considerazion
irolloff valore di pendenza del filtro nella zona di transizione di banda
iodd se diverso da zero, l'analisi d'individuazione dell'altezza prende in considerazione solo le parziali dispari
iconfs il numero di conferme richieste prima che il pitch-tracker cambi l'ottava di riferimento.

Sintesi granulare con l'opcode


granule

L'opcode granule uno degli opcode pi utilizzati in csound per la sintesi granulare.
Elettronica1_basso.csd
Come scivevo in un precedente articolo, la sintesi granulare sintetizza il suono, partendo da nubi di
microsuoni. Il risultato ottenuto dipende cos, tanto dalle caratteristiche dei singoli microsuoni,
quanto dalla forma della nube. I parametri di granule permettono di controllare la sintesi:
ares granule xamp, ivoice, iratio, imode, ithd, ifn, ipshift, igskip, \
igskip_os, ilength, kgap, igap_os, kgsize, igsize_os, iatt, idec \
[, iseed] [, ipitch1] [, ipitch2] [, ipitch3] [, ipitch4] [, ifnenv]
ifn: specifica l'f-table usata come sorgente per la sintesi; i micrograni vengono creati segmentando
il suno campionato memorizzato nella fTable. Il valore da assegnare a ifn nell'opcode granule
quindi il numero della f-Table .
ifn = 6
................
aSignalL
granule
ksegL, ivoices, iratio, iptrmode, ithd, ifn, inumpchs, iskip, iskipos, ilen,
kgapL, igapos, ksizeL, isizeos, 35, 35, 0.39,
0.5,1,0.5,1
..........................
f6

16777216

"DoViolS.wav"

ivoice: Indica il numero di voci "polifoniche". Questo parametro permette di considerare la sintesi
creata con granule come una particolare forma di sintesi additiva.
iratio: definisce la velocit del cursore di lettura della fTable con valori relativi ad sr. Un valore di
0.1 espander una durata di 1 secondo con un fattore 10. Quello che nel campione originale durava
64 di 109

1 secondo ora ne durer 10. Viceversa un valore di10 comprimer il suono originale da 1 secondo
originale a 0.1 secondi

Bibliografia
THE CSOUND BOOK - Richard Boulanger Editor - MIT Press (2000)
MICROSOUND - Curtis Roads - MIT Press (2001)

Uso dell'opcode
timout

In un precedente articolo abbiamo visto come utilizzare l'opcode timeout per


implementare una versione molto semplificata di sintesi granulare. In questo
articolo presento un uso un p pi articolato dello stesso opcode.
Come si vede nell'esempio, l'opcode timeout pu essere usato in quei contesti in cui si
richiede che vengano riassegnati ciclicamente alle variabili di inizializzazione dei nuovi
valori. Nel'esempio, alle variabile iStereoL e iStereoR (e a tutte le variabili di
inizializzazioni presenti nella sezione start:) verrano assegnati nuovi valori ad ogni
idur_delay + idur_sample secondi. Quindi gli opcodes utilizzati nella sezione continue
lavoreranno ogni volta partendo da valori di inizializzazione potenzialmente diversi. In
particolare nell'esempio, i valori delle principali variabili vengono modificate tramite
comunicazione attraverso il canale software (iStereoL chnget SpanL). Il musicista
potr cos intervenire, tipicamente tramite GUI e vari controller interfacciati tramite Csound
API, a modificare l'evoluzione del segnale audio prodotto dalla sezione continue
dell'istruzione timeout.

instr 2
iduration = p3
idur_attack = p4
idur_decay = p5
idur_sustain = p6
idur_release = p7
idur_delay = p8
iFlagInstr = p10
iFlagInstr2 = p11
kdurDelay init idur_delay
Svolume sprintf "volume%d", p9
Scounter sprintf "counter%d", p9
Spitch sprintf "pitch%d", p9
65 di 109

SpanL sprintf "panL%d", p9


SpanR sprintf "panR%d", p9
Sdist sprintf "dist%d", p9
Scomb sprintf "comb%d", p9
kVol chnget Svolume
kPitch chnget Spitch
kdist chnget Sdist
kcomb chnget Scomb
idur_sample = idur_attack + idur_decay + idur_sustain + idur_release
ilpt = idur_sample * 0.25
itransaz = 0.05
icounter=1
ifn = 1
if (iFlagInstr2 == 0) then
aRecL, koutrec1 sndloop gaL , kPitch, 1, idur_sample , itransaz
aGateRec linseg 0,idur_sample ,0,idur_sample,1,iduration - (idur_sample)*3,1,
idur_sample,0
aRecL = aRecL * aGateRec
else
aRecL = gaL
endif
if (kdist > 0.1) then
aRecL distort aRecL, kdist, ifn
endif
if (kcomb > 0.1) then
aRecL distort aRecL, kcomb*10, 4
endif
if (iFlagInstr == 1) then
aRecL gain aRecL, gkInstrVol
endif
start:
chnset icounter, Scounter
icounter = icounter + 1
iStereoL chnget SpanL
iStereoR chnget SpanR ; ------ >LETTURA DI PARAMETRI DAL CANALE
SOFTWARE
iPitch
chnget Spitch
iStereoR chnget SpanR
timout 0, idur_delay + idur_sample, continue
reinit start; ---------------- > OGNI idur_delay + idur_sample VIENE RIESEGUITA LA
66 di 109

SEZIONE DI INIZIALIZZAZIONE (start)


continue:
kGate linseg 0,idur_delay,0,idur_attack ,0.6,idur_decay,0.4,idur_sustain,0.3,idur_release,0
aRecR = aRecL
aRecL = aRecL * kGate * iStereoL; * aMainGate ;; ------ >USO DEI PARAMETRI LETTI
PER MODIFICARE L'EVOLUZIONE DEL SEGNALE AUDIO
aRecR = aRecR * kGate * iStereoR; * aMainGate
ga2L = ga2L + aRecL
ga2R = ga2R + aRecR
outs aRecL * kVol, aRecR * kVol
endin

Sintesi granulare con l'opcode


timout

La sintesi granulare una tecnica di sintesi classica, figlia di una delle tante
intuizioni geniali di Iannis Xenakis. Si basa sull'idea che un suono possa essere
scomposto in una nube di microsuoni. Il suono che si ottiene con questo tipo
di sintesi dipende cos tanto dalla forma della nube sonora (densit dei grani)
quanto dalla forma dei singoli micrograni. Csound mette a disposizione diversi
opcode per realizzare musiche che sfruttano la sintesi granulare: timout uno
di questi

L'opcode timout pu essere utilizzato per implementare una particolare forma di sintesi granulare.
La sua sintassi la seguente:
timout istrt, idur, label
timeout salta all'etichetta label a partire da istr secondi e dopo ogni idur secondi.
Esempio1.csd
instr 1
a1 in
k1 rms a1
start:
iPause = p4
iDur1 = p5
67 di 109

iDur2 = p6
igap = iDur1 + iDur2 + iPause
timout 0, igap, continue
reinit start
continue:
agate linseg 0, iDur1 , 1, iDur2 , 0
rireturn
outs a1 * agate , a1 * agate
endin
timout passa il controllo all'etichetta continue a partire dall'istante 0 e dopo ogni igap secondi. Il
ruolo di timeout all'interno di instr1 quello di generare degli eventi sonori composti da
micrograno + pausa: la durata complessiva composto cos da iDur1 (durata attacco dell'inviluppo
del micrograno), iDur2 (durata rilascio inviluppo micrograno), iPause (pausa). L'inviluppo di ogni
micrograno ha cos durata iDur1 + iDur2 e possiede forma triangolare.
L'istruzione timeout spesso utilizzata con reinit. Questo opcode un'istruzione di tipo goto, con
la particolarit di rieseguire istruzioni di inizializzazione. Nell'esempio, le istruzioni di
inizializzazione che vengono rieseguite sono quelle introdotte dall'etichetta start.

Sintesi per formanti:


FOF

Con FOF (Fonction donde formantique) si indica una tecnica di sintesi sviluppata allIRCAM
nellambito del progetto CHANT, il cui obiettivo era lelaborazione di tecniche per la sintesi
realistica della voce cantata. Il principio fondamentale il modello della voce umana a partire da
un generatore di impulsi (che corrisponde alle corde vocali) filtrati da filtri passa-banda (che
rappresentano lescursione delle caratteristiche vocali) e che replicano linviluppo delle formanti.
Poich il generatore di impulsi produce una sequenza di grani, questa tecnica viene anche
accostata alla sintesi granulare. Tuttavia, la FOF differisce da questultima in quanto utilizza grani
regolari e sincroni che producono una forma donda periodica, com appunto nel caso della voce
(Fonte - Richard Dobson (1992). A Dictionary of Electronic and Computer Music Technology.
Oxford University Press.).
http://www.ears.dmu.ac.uk/spip.php?page=rubriqueLang&lang=it&id_rubrique=353

Dal momento che i grani FOF durano pochi millisecondi, si crea una modulazione d'ampiezza fra
inviluppo del grano e la sinusoide,
per cui si creano una serie di bande laterali intorno alla frequenza della sinusoide, che producono
un formante.
68 di 109

Sommando pi generatori FOF si pu ottenere uno spettro con diversi picchi formantici.
Ogni generatore FOF controllato da alcuni parametri, compresi la frequenza fondamentale e
l'ampiezza:
1) frequenza centrale del formante
2) la rghezza di banda del formante
3) ampiezza di picco del formante
4) larghezza del formant skirt (letteralmente, 'gonna del formante') che costituisce la parte pi
bassa del picco
formantico, intorno a -40 db rispetto all'ampiezza di picco. Il parametro "gonna" indipendente
dalla larghezza del
formante e definisce la curva che va da 0 a -40db.
Il principale opcode csound per implementare la sintesi per formanti l'opcode FOF
ar
fof
ifmode]]

xamp, xfund, xform, koct, kband, kris, kdur, kdec, iolaps, ifna, ifnb, itotdur[, iphs[,

xamp ampiezza di picco di ogni treno di sinusoidi


xfund frequenza fondamentale, in Hz, dell'impulso che crea nuovi treni di sinusoidi
xform frequenza del formante
koct indice di ottavizzazione, solitamente zero. Se maggiore di zero traspone verso il grave la
frequenza fondamentale xfund
attenuando i treni di sinusoidi dispari. E' possibile sia usare gli interi, che indicano le ottave, che i
numeri frazionari
kband larghezza di banda del formante ( a -6db)
kris, kdur, kdec tempi di attacco, di durata totale e di decay (in secondi) del treno di sinusoidi. kris
determina la gonna del formante
iolaps numero di spazi preallocati nella memoria necessari a contenere i dati dei treni che si
sovrappongono.
ifna, ifnb numeri di tabella per le funzioni; ifna deve essere una sinusoide di dimensione almeno
pari a 4096; ifnb una tabella che contiene
la forma da attribuire all'attacco e al decay di ogni treno di sinusoidi.
itotdur tempo durante il quale fof rimane attivo
iphs (opzionale) fase iniziale della fondamentale, espressa come frazione di un ciclo (da 0 a 1). Il
valore di default 0.
ifmode (opzionale) modo di frequenza del formante. Se zero, ogni treno di sinusoidi mantiene la
frequenza xform con la quale ha iniziato.
Se diverso da zero, all'interno di ogni xform cambia continuamente.
; Instrument #61.
instr 61
; Values common to all of the formants.
koct init 0
kris init 0.003
kdur init 0.02
kdec init 0.007
iolaps = 14850
ifna = 8
ifnb = 9
69 di 109

itotdur = p3
iL =p7
iR =p8
ifreq = cpspch(p4)
kfund = ifreq
; First formant.
a1 = ga1
k1 rms a1
kamp linseg 0, p3 * 0.1, 0.5, p3 * 0.2, 0.35, p3 - (p3 * 0.5), 0.25, p3 * 0.1,0
k1amp = k1
k1form = ifreq
k1band init 80
; Second formant.
k2amp = ampdb(-4)
k2form = k1form * 3 /2
k2band init 90
; Third formant.
k3amp = ampdb(-20)
k3form = k1form * 2
k3band init 120
; Fourth formant.
k4amp = ampdb(-36)
k4form = k1form * 2 * 2
k4band init 130
; Fifth formant.
k5amp = ampdb(-60)
k5form = k1form * 2 * 2 * 3 /2
k5band init 140
a1 fof k1amp, kfund, k1form, koct, k1band, kris, kdur, kdec, iolaps, ifna, ifnb, itotdur
a2 fof k2amp, kfund, k2form, koct, k2band, kris, kdur, kdec, iolaps, ifna, ifnb, itotdur
a3 fof k3amp, kfund, k3form, koct, k3band, kris, kdur, kdec, iolaps, ifna, ifnb, itotdur
a4 fof k4amp, kfund, k4form, koct, k4band, kris, kdur, kdec, iolaps, ifna, ifnb, itotdur
a5 fof k5amp, kfund, k5form, koct, k5band, kris, kdur, kdec, iolaps, ifna, ifnb, itotdur
; Combine all of the formants together.
aL =(a1+a2+a3+a4+a5)*iL * kamp
aR = (a1+a2+a3+a4+a5) *iR *kamp
outs aL,aR
gagL = gagL + aL
gagR = gagL + aR
endin

70 di 109

Introduzione agli FLTK


Widgets

Gli FLTK Widgets permettono di realizzare una GUI (Graphic User Interface) personalizzata per
pilotare un'orchestra Csound in tempo reale.
I controlli grafici Csound sono derivati dalla libreria open-source FLTK (Fast Light Tool Kit ).
Questa libreria multi-piattaforma (Windows, Linux, Unix and Mac OS) e compatibile con
OpenGL. Il sottoinsime FLTK implementato in CSound comprende:
FLTK Containers, widgets che possono contenere altri widgets:

Panels
Scroll areas
Pack
Tabs
Groups

FLTK Valuators, particolarmente adatti per modificare il valore di un parametro di uno strumento
in tempo reale

Sliders
Knobs
Rollers
Text fields
Joysticks
Counters

Ci sono poi altri FTLK widgets che non rientrano nelle prime due categorie:

Buttons
Button banks
Labels

Quindi ci sono degli opcodes che modificano la visualizzazione dei controlli:

FLcolor
FLcolor2
FLhide
FLlabel
FLsetAlign
FLsetBox
FLsetColor
71 di 109

FLsetColor2
FLsetFont
FLsetPosition
FLsetSize
FLsetText
FLsetTextColor
FLsetTextSize
FLsetTextType
FLsetVal_i
FLsetVal
FLshow
Infine ci sono tre importanti famiglie di opcodes che permettono le tre seguenti azioni
principali

Apertura di un widget thread: FLrun


Caricamento in memoria di una configurazione di widgets precedentemente salvata
FLgetsnap e FLloadsnap.
Salvataggio di widgets: FLsavesnap e FLsets

Esempio di costruzione di un'interfaccia


FLTK

In questo articolo costruiamo una semplice interfaccia FLTK per pilotare in tempo reale i
principali parametri di un'orchestra.
Esempio 1
Viene creato un pannello che rimane aperto per 10 secondi e quindi viene chiuso dopo che l'ultimo
evento della sezione score stato eseguito.
<CsoundSynthesizer>
<CsOptions>
-b16384 -B16384
</CsOptions>
<CsInstruments>
sr
=
44100
kr
=
441
ksmps =
100
nchnls =
2
;LABEL | WIDTH | HEIGHT | X | Y
FLpanel "ELETTRONICA1 - BASSO" , 800, 700,
FLpanel_end
FLrun
instr 1
endin

700, 0

72 di 109

</CsInstruments>
<CsScore>
i 0 10
</CsScore>
</CsoundSynthesizer>
Esempio 2
All' FLpanel stato aggiunto un valutatore FLslider, un visualizzatore del valore corrente del
valutatore (FLvalue), un'istruzione che setta il valore iniziale dell'FLslider (FLsetVal_i). Il valore
dell'FLslider viene assegnato alla variabile di controllo globale gkamp1L. FLSlider modifica il
volume dello strumento: infatti il valore di gkampi1L, che varia da 500 a 800, viene usato come
parametro d'ampiezza dell'operatore oscil. I valori intermedi da 500 a 800 seguono un andamento
esponenziale, come indicato dal quarto parametro (-1).
<CsoundSynthesizer>
<CsOptions>
-b16384 -B16384
</CsOptions>
<CsInstruments>
sr
=
44100
kr
=
22050
ksmps =
2
nchnls =
2
gkamp1L init 0
;LABEL | WIDTH | HEIGHT | X | Y
FLpanel "ELETTRONICA1 - BASSO" , 300,

90,

700, 0

idamp1L FLvalue "Vol.", 75,


20, 0, 25 ;FLvalue Shows the current value of a FLTK
valuator.
gkamp1L, ihamp1L FLslider "I", 120, 90, -1, 5, idamp1L, 280, 20, 0, 0
FLsetVal_i 600, ihamp1L
FLpanel_end
FLrun
instr 1
printk 1, gkamp1L
aOutL oscil gkamp1L, 440, 1
outs aOutL, aOutL
endin
</CsInstruments>
<CsScore>
f1 0 4096 10 1 3 7 1 3
73 di 109

i1 0 20
</CsScore>
</CsoundSynthesizer>

74 di 109

Csound e Python
Csound e Python: primo
incontro

Prima o poi, lavorando con cSound nasce l'esigenza di controllare il motore del
sintetizzatore virtuale con degli strumenti software pi sofisticati rispetto ai
semplici opcodes FLTK , ad esempio con un linguaggio di programmazione
come Python.
Python un linguaggio di script multipiattaforma (Windows, Linux,Mac) ad oggetti ed open
source. Il sito ufficiale : www.python.org.
Nel tutorial di cSound presentato, per la sua flessibilit e velocit d'apprendimento, come il
linguaggio principe per interfacciarsi a cSound.
In effetti script Python possono essere utilizzati dentro a strumenti cSound, sfruttando particolari
opcode, oppure per realizzare applicazioni che utilizzano le cSound API.
Nel numero primaverile di cSounds Journal possibile trovare un articolo scritto da Andrs
Cabrera che analizza gli opcode per utlizzare Python dentro a strumenti cSound
http://www.csounds.com/journal/issue6/pythonOpcodes.html
La sottocartella examples delle ultime releases di cSound, ricca di sorgenti python. La maggior
parte di questi, esemplifica come realizzare un'interfaccia grafica per pilotare orchestre cSound.
Quasi tutti gli esempi sono realizzati usando la GUI python standard: Tkinter.
Solo uno, invece, fa uso della libreria wxPython. (http://www.wxpython.org), sviluppata
sulla libreria C++ multipiattaforma wxWidgets (www.wxWidgets.com)
Quindi per incominciare ad usare cSound come modulo Python occorre:

Installare cSound 5.0 o successivo


Installare Python 2.5 o successivo
Installare wxPython per Python 2.5

Usare Csound con Python: moduli


principali

Una volta installati cSound, Python e wxPython il primo problema che dobbiamo risolvere nello

75 di 109

scrivere il nostro sorgente Python :


Quali packages dobbiamo importare?
Il package principale per l'uso di Csound in Python : csnd. Questo package contiene il wrapper
Python per richiamare all'interno dei nostri script le Csound API.
Se abbiamo istallato wxPython e desideriamo pilotare Csound tramite un'interfaccia grafica fatta di
finestre, controlli e menu, dovremo allora importare anche il package wx.
Infine, se vogliamo temporizzare dei comandi, ad esempio far eseguire una certa istruzione Csound
ad un determinato punto dell'esecuzione della nostra partitura, allora sar opportuno importare
anche la libreria threading
In definitiva il nostro script tipicamente inizier con le seguenti istruzione d'importazione:
import csnd
import wx
import threading

PyGame per joystick e


joypad

Un'altra libreria Python da inserire nella nostra cassetta degli attrezzi la


libreria pyGame. Questa libreria, dal nostro punto di vista, pu servirci per
trasformare joystick, joypad, tastiera e mouse in formidabili strumenti per
il controllo delle nostre elaborazioni
http://www.pygame.org

wxPython e pyGame a
confronto

Nello scegliere quale libreria grafica adottare per le nostre applicazioni meglio soffermarci un
attimo sulle differenze principali tra le due librerie prese in esame:
wxPython e pyGame.

76 di 109

wxPython una libreria progettata per realizzare applicazioni con GUI tradizionale: finestre con
menu e controlli vari.
Il punto di debolezza attuale di questa libreria una gestione degli eventi da tastiera piuttosto
lacunosa. Ad esempio, su sistema operativo windows xp, la libreria mostra diversi bugs fastidiosi.
Il punto di forza invece, la facilit con cui possibile creare menu, pulsanti e la gestione dei
relativi eventi (mouse incluso).
pyGame invece una libreria per la realizzazione di giochi in ambiente Python. Il suo punto di
debolezza sta nel fatto che non affatto pensata per realizzare GUI tradionali. Il suo punto di forza
consiste nella facilit di gestione di puntatori di input quali i tradizionali mouse e tastiera ma anche
joistick e joypad.

Programmare joypad e tastiera con


pyGame

Il joypad pu tornare utile anche come controller per pilotare le elaborazioni di Csound. Nella
sezione download ho pubblicato un semplice esempio che illustra come raggiungere questo scopo.
Innanzitutto dobbiamo importare i moduli principali di pyGame.
from pygame.locals import *
from pygame import *
Quindi iniziare la fase di inizializzazione. La visualizzazione di una finestra pyGame essenziale
per ricevere gli input da tastiera.
pygame.init()
pygame.mouse.set_visible(0)
pygame.display.set_mode((400,50))
pygame.display.flip()
Inizializzare i joystick rilevati dal sistema
for x in range(joystick.get_count()):
j = joystick.Joystick(x)
print "Joystick %i: " % x + j.get_name()
j.init()
Creare un loop principale di analisi degli eventi in coda.
while 1:
key.getkey()
if key.type == KEYDOWN:
77 di 109

......................
if key.type == JOYBUTTONDOWN:
......................
elif key.type == JOYAXISMOTION:
.....................
elif key.type == JOYHATMOTION:
Analisi che si basa sul metodo getKey definito in guiinput.py (incluso nell'esempio)
def getkey(self):
for e in event.get():
self.type = e.type
#print self.type
# KEYBOARD
if e.type == KEYDOWN:
self.value =int(e.key)
elif e.type == JOYBUTTONDOWN:
self.value = int(e.dict['button'])
elif e.type == JOYHATMOTION:
self.value1 = float(e.dict['value'][0])
self.value2 = float(e.dict['value'][1])
# JOYAXIS
elif e.type == JOYAXISMOTION:
self.subtype = str(e.dict["axis"])
self.value = float(e.dict['value'])
Il tutto termina con le consuete operazioni di pulizia
pygame.display.flip()
pygame.quit()
sys.exit()

Il modulo
pySerial

Un altro modulo python che pu tornarci utile nell'interfacciarci con Csound il modulo pyserial
http://pyserial.sourceforge.net/
Questo modulo ci permette di leggere e scrivere verso la porta seriale. In particolare mi tornato
utile per iniziare a leggere il flusso dati proveniente da un sistema di sensori come lo USB78 di 109

microSystem
http://infusionsystems.com

Esplorare il modulo
csnd

Per approfondire la conoscenza delle API cSound accessibili tramite il modulo csnd, opportuno
ripassare le istruzioni Python che ci permettono di investigare il contenuto di un modulo
Innanzitutto occorre importare il modulo da esplorare
import csnd
La funzione dir elenca tutti i metodi e gli attributi del parametro su cui viene applicata
print dir(csnd)
print dir(csnd.CsoundPerformanceThread)
Attraverso la funzione dir si arriva cos ad ottenere un elenco di tutte gli oggetti, le costanti, le
funzioni accessibili a partire dal modulo csnd.
Per avere delle informazioni dettagliate sui singoli metodi si pu usare l'attributo __doc__. Questo
attributo presente in ogni oggetto Python.
E' fondamentale per raggiungere immediatamente la firma di un metodo.
print csnd.CsoundPerformanceThread.Pause.__doc__
>>>
Pause(self)

La variabile d'ambiente PYTHONPATH


(windows)

Se si rendere visibile una cartella contenente dei moduli (librerie) Python, occorre settare la
variabile PYTHONPATH
Per settare questa variabile in Windows Xp, occorre seguire queste indicazioni:
Pannello di controllo > Sistema > scheda Avanzate > pulsante Variabili d'Ambiente > Variabili di
sistema > Aggiunta o modifica della variabile PYTHONPATH con valore il percorso scelto. I

79 di 109

diversi valori devono essere separati da un ";".


C:\Programmi\Csound\bin;C:\Documents and
Settings\Administrator\Documenti\Python\csound;C:\Documents and
Settings\Administrator\Documenti\CSound\Anatrofobia

La classe
cSoundPerformanceThread

Per l'uso di cSound in tempo reale occorre che venga eseguito in un thread separato. La classe
CsoundPerformanceThread, come indica il suo nome, ha il compito di creare un apposito thread
per l'esecuzione di cSound.
Dopo aver creato un'istanza di questa classe sar possibile avviare, mettere in pausa, stoppare
l'esecuzione di una partitura Csound eseguita dall'orchestra corrispondente.
Vediamo un esempio di uso del Perfomance Thread di cSound
Il nostro script Python deve importare, come al solito, il modulo csnd.
import csnd
Occorre creare un oggetto cSound e, ad esempio, compilare un file csd.
self.csound = csnd.CppSound()
self.csound.Compile("Gretchen.csd")
Quindi far incominciare la performance.
self.perf = csnd.CsoundPerformanceThread(self.csound)
self.perf.Play()
Durante la performance sar possibile far eseguire alle nostre orchestre particolari eventi tramite
l'istruzione InputMessage
self.perf.InputMessage("i%d 0 %f %f %f %f %f %f" % ((nButton+1), duration,
self.dur_attack[nButton -1],self.dur_decay[nButton -1],self.dur_sustain[nButton
-1],self.dur_release[nButton -1],delay))
L'istruzione InputMessage ci permette di far eseguire "al volo" alla nostra orchestra degli eventi
Csound. Il tutto in tempo reale.

80 di 109

Un sistema di macro per i files


csd

Csound prevede due sistemi di macro: per i files orchestra e i files partitura. Attualmente non
per possibile definire delle macro a livello di sezione CsOptions.
In questo articolo presento una classe Python che permette d'implementare macro anche a livello
di CsOptions.
Lo scopo quindi quello di poter scrivere all'interno del nostro codice csd, una sintassi come
questa:
<CsoundSynthesizer>
<CsOptions>
$CsOptions
</CsOptions>
<CsInstruments>
Ho quindi definito la classe CSDfile nel modulo mod_csd.py.
Il codice significativo l'ho inserito nel costruttore:
class CSDfile:
def __init__( self, filenameIn, filenameOut,configFile,separatore ):
f = open( configFile, "r" )
self.filenameOut = filenameOut
lista = f.readlines()
dizionario = {}
for linea in lista:
nuovachiave = linea.split( separatore )
if len( nuovachiave ) == 2:
dizionario[ nuovachiave[0].strip() ] = nuovachiave[1].strip()
f.close()
f = open( filenameIn, "r" )
lista = f.readlines()
for k, v in dizionario.items():
for i in range(len(lista)):
lista[i]=lista[i].replace(k,v)
f = open( filenameOut, "w" )
f.writelines(lista)
f.close()

81 di 109

Nel file principale python richiamo il costruttore passandogli gli opportuni parametri.
filenameIn: Il file csd da elaborare contenente le macro da esplodere
filenameOut: Il nuovo file csd risultato finale dell'elaborazione
configFile: Il file di configurazione contenenete la definizione delle macro
separatore: Il separatore utilizzato nell'elenco delle definizioni delle macro.
csdFile = CSDfile("csd/Pad_percussion1.csd", "csd/temp.csd","conf/percussionPad.con","=")
csound.Compile("csd/temp.csd")
Il file di configurazione potr contenere, ad esempio, le seguenti righe:
$CsOptions=-b320 -B640 -odac4 -iadc4 -m0 -M1
$ictlno1=1
$ichan1=1
$ictlno2=1
$ichan2=1
$nota1=69
$nota2=71

L'opcode chnset e l'istruzione


GetChannel

Python e Csound possono comunicare facilmente tra loro. La comunicazione


avviene attraverso i cosiddetti canali (Bus) software. In particolare, grazie
all'opcode cSound chnset e all'API GetChannel possibile passare delle
variabili dal server CSound al client Python (o altro front-end). In questo
modo viene creato un canale di comunicazione (lettura e scrittura) tra Csound
e Python.
Durante l'esecuzione di uno strumento cSound pu tornare utile passare il valore di una varibile ad
un programma di controllo o semplicemente ad un'interfaccia grafica. L'opcode che permette
questo chnset. Questo opcode prende due parametri.
Il primo parametro rappresenta il valore della variabile, che si vuole passare; il secondo la stringaetichetta (in pratica il nome della variabile di comunicazione).
chnset icounter, "counter3"
Per leggere il valore della variabile passata da Csound all'interno di Python, necessario importare
il modulo csnd. Il valore della variabile cSound viene letto tramite il metodo GetChannel,
dell'oggetto csound, che prende come parametro l'etichetta assegnata.
try:
self.counters[nButton -1] = self.csound.GetChannel("counter%d" % b);
tc = self.textcounters[nButton -1]
82 di 109

tc.SetLabel("%d" % self.counters[nButton -1]);


except:
print "Error GetChannel"

Alcune considerazioni sull'opcode


chnset

Prima di continuare ad analizzare le altre API di comunicazione tra Csound e Python, opportuno
soffermarci ancora sull'opcode chnset.
Il manuale di Csound elenca quattro "firme" per l'opcode chnset.
chnset ival, Sname
chnset kval, Sname
chnset aval, Sname
chnset Sval, Sname
Le quattro sintassi differiscono in base al tipo della prima variabile. Quindi possibile passare
attraverso il bus di comunicazione variabili d'inizializzazione, variabili di controllo, variabili audio,
stringhe.
Analizziamo nel dettaglio l'opcode chnset con variabile di controllo, partendo ancora da un
esempio.
a1 = asig1 + asig2
gkGain rms a1
if gkGain > iSoglia then
kTrig=1
else
kTrig=0
endif
chnset kTrig, "Triggered"
In questo codice il mio scopo di "avvisare" il programma Python che sta pilotando Csound, ogni
volta che il valore rms del segnale audio (gkGain ) supera una certa soglia (iSoglia). In particolare,
se la soglia viene superata la variabile di canale "Triggered" viene posta ad 1, altrimenti continua a
valere 0. Voglio cos che il programma Python venga avvisato continuamente, in base alla
frequenza di controllo.
Ora vediamo un errore, che anch'io ingenuamente avevo commesso.
a1 = asig1 + asig2
gkGain rms a1
83 di 109

if gkGain > iSoglia then


chnset 1, "Triggered"
else
chnset 0, "Triggered"
endif
Il codice stato riscritto. Addirittura pi compatto. Non viene usata la variabile kTrig. Sorge per
un problema: il programma Python non viene pi avvisato correttamente quando la soglia viene
superata. Come mai?
Il motivo semplice, usando delle costanti nell'opcode chnset, l'opcode viene eseguito solo in fase
di inizializzazione (e quindi una volta sola).
In conclusione se vogliamo che il nostro opcode sia eseguito continuamente, non possibile
assegnare a chnset una costante come valore del primo argomento.

L'opcode chnget ed il modulo Python


csnd

In questo articolo vediamo una classe Python che utilizza il modulo csnd e un'orchestra csound che
adopera l'opcode chnget.
L'esempio illustra un possibile upgrade della nostra Loop-station (battezzata Faust loop-station
). L'esempio illustrato scaricabile dalla sezione download.
Occorre innanzitutto importare nel nostro script Python il modulo csound csnd,
contenente le API cSound
import csnd
Quindi occorre istanziare (ad esempio nel costruttore della nostra classe) un
oggetto cSound e compilare il file csd di riferimento,
self.csound = csnd.CppSound()
self.csound.Compile("faust.csd")
Infine bisogna far partire in un Thread dedicato il processo cSound.
self.performanceThread = csnd.CsoundPerformanceThread(self.csound)
self.performanceThread.Play()
A questo punto cSound in esecuzione!
Se vogliamo passare dei parametri dalla nostra interfaccia Python all'orchestra
cSound possiamo utilizzare quello che nella documentazione cSound
chiamato software bus
84 di 109

Da una parte del nostro canale software vi cSound, dall'altra vi Python.


L'istruzione Python per inviare dati nel canale SetChannel. Prende due
argomenti: il nome del canale ed il valore da passare.
Mentre la nostra orchestra in esecuzione quindi possibile modificarne dei
parametri interagendo con la GUI Python.
self.mute = 0
self.csound.SetChannel("mute", self.mute)
L'istruzione da utilizzare nell'orchestra cSound chnget. E' un istruzione che legge, in base alla
frequenza del tipo della variabile di output, il valore del canale del software bus. Nell'esempio
seguente l'opcode chnget legge alla frequenza di controllo, il valore dal canale mute e lo assegna
alla variabile globale gkMute, responsabile del muting degli strumenti cSound della loop station
gkMute chnget "mute"

Creare un lettore di campioni in Python e


Csound

In questo articolo vediamo un esempio di classe Python, che permette di caricare in una Combobox
un elenco di nomi di files audio con estensione data e quindi di laniciare l'esecuzione
dell'opportuno strumento Csound.
Lo strumento Csound potr contenere un'istruzione tipo diskin, ma soprattutto dovr assegnare ad
una variabile data (Ssample) il nome del file passato come parametro dal programma Python

instr 2
.....
if gkMute == 1 kgoto ESCI
Ssample = p4
.......

Passiamo ad analizzare la classe Python.


Particolarmente importanti sono gli ultimi parametri passati al costruttore:
path (il percorso contenente i files audio), ext (l'estensione dei files audio), perf (l'istanza della
classe CsoundPerformanceThread ), instr (il numero di strumento Csound che dovr essere
85 di 109

eseguito, ogni volta che l'utente sceglier un nuovo campione)


La classe molto semplice.
Visualizza in una combo i files audio presenti nella cartella SSDIR (caricando solo quelli con
opportune estensioni).
Ogni volta che l'utente seleziona una voce dalla combo,viene eseguita una nota dello strumento
instr con durata casuale.
import utilities
import os
import random
from wxPython.wx import *
import wx

class SamplesCtrl:
def __init__(self, panel, id_Combo, point,size, path,ext,perf,instr):
self.samplesList =[]
for filename in os.listdir(path):
if filename.find(ext)>-1:
self.samplesList.append(filename)
self.Mod = []
self.panel = panel
self.instr = instr
self.perf = perf
self.cb = wx.ComboBox(
self.panel, id_Combo, self.samplesList[0], point,size,self.samplesList,
wx.CB_DROPDOWN
)
self.panel.Bind(wx.EVT_TEXT, self.EvtText, self.cb)
def EvtText(self, evt):
sample = str(evt.GetString())
durata = random.sample([120, 180, 240, 120, 180, 240], 1)
s = "i%d 0 %f \"%s\"" % (self.instr, durata[0],sample )
self.perf.InputMessage(s)
evt.Skip()

Ecco infine una chiamata del costruttore della classe


cb = SamplesCtrl(self.panel, 500,(980, 320),
(-1, -1),"C:\Documents and
Settings\Administrator\Documenti\CSound\Audio",".wav",self.perf,2)
86 di 109

Subclassing del controllo


wxSlider

In questo articolo presento un esempio di personalizzazione del controllo wxSlider della libreria
wxPython con l'obiettivo di creare un componente specializzato nella comunicazione con cSound.
La tecnica adottata quella del subclassing.
Ho innanzitutto derivato il mio wxMediaSlider dal wxSlider. Ho quindi realizzato un costruttore
ad hoc, con un maggior numero di parametri.
Al nuovo costruttore (__init) viene passato l'ggetto cSound (csndObj), il nome della variabile da
utilizzare nel canale software (varName), il fattore di divisione con cui dividere il valore attuale
del controllo per poi passarlo a Csound (nDiv).
Ogni volta che l'utente modifica il valore dello slider, viene inviato un messaggio al server cSound
con variabile varName e valore GetValue()/nDiv. In questo modo la classe che conterr il
wxMediaSlider non dovr pi di preoccuparsi di alcuni noiosi dettagli implementativi.
La classe wxMediaSlider sovrascrive anche il metodo SetValue. In pratica ogni volta che verr
richiamato questo metodo, lo Slider non solo aggiorner la sua interfaccia grafica, ma invier anche
un messaggio a cSound.
In definitiva al wxSlider stata aggiunta una seconda modalit di output del proprio valore
memorizzato. Oltre alla visualizzazione il wxMediaSlider aggiorna anche la vista del server
cSound sul proprio valore memorizzato.
Riporto il codice di questa semplice tecnica di subclassing.
from wxPython.wx import *
import wx
import csnd
class wxMediaSlider(wxSlider):
def __init__(self, parent, ID, defaultValue, minValue, maxValue, position,size,style,
csndObj,varName,nDiv):
wx.Slider.__init__(self, parent, ID, defaultValue, minValue, maxValue, position,size,style)
self.csndObj = csndObj
self.varName = varName
self.nDiv = nDiv
self.__SetValue(defaultValue)
self.SetTickFreq(2, 1)
EVT_SLIDER(self, ID, self.OnSliderMove)
def __SetValue(self,value):
87 di 109

d = value / self.nDiv
self.csndObj.SetChannel(self.varName, d)
def SetValue(self,value):
wx.Slider.SetValue(self,value)
self.__SetValue(value)
def OnSliderMove(self, event):
self.__SetValue(self.GetValue())
Ecco un esempio d'uso della classe appena definita:
l = wxMediaSlider(self.panel, 20 + i, 0, 0, 6000, (2 + ((i-1) *200), 340),
(140,50),wxSL_HORIZONTAL | wxSL_LABELS,self.csound,"volume%d" % (i + 1 ),1000.0)

Una classe Python per grafici in tempo


reale

La classe Python che riporto in questo articolo un semplice visualizzatore grafico di dati cangianti
nel tempo. Ad esempio, mi tornata utile per visualizzare il valore attuale di un controller Midi.

Il visualizzatore rappresenta graficamente gli ultimi n valori ricevuti dalla classe in base ad una
logica First In First Out (FIFO). Inoltre visualizza in una casella di testo l'ultimo valore in ingresso
(Es. 175.83) e l'etichetta di approssimazione pi consona (F3).

88 di 109

from wxPython.wx import *


from ReadConfig import *
import wx
MAX_F = 2.0
SPACE = 30
MAX_PUNTI = 10
#Class for istograms drawing
class GraphPanel(wx.Panel):
def __init__(self, parent, pos, size, pen, title, pMin, pMax, config_file,sep):
wx.Panel.__init__(self, parent,333, pos, size, wx.WANTS_CHARS)
self.ID =100
self.pen = pen
self.Max = pMax
self.Min = pMin
r = ReadConfig(config_file,sep)
self.dizionario = r.getDizionario()
#Resizing buttons and static text
panelSize = self.GetSize()
self.height = panelSize[1]
self.width = panelSize[0]
self.bottom = SPACE
self.top = self.bottom
self.Msg=wx.StaticText(self, -1, title, (0, self.height - SPACE / 2))
font = wx.Font(14, wx.SWISS, wx.NORMAL, wx.NORMAL)
self.Msg.SetFont(font)
self.punti =[]
self.Bind(wx.EVT_PAINT, self.OnPaint)
def getRightLabel(self, Y):
best_value = -1
best_label = ""
for k, v in self.dizionario.items():
if(best_value == -1):
best_value = abs(float(v)- Y)
best_label = k
else:
if abs(float(v)- Y)< best_value :
best_value = abs(float(v)- Y)
best_label = k
return (best_label,best_value)

def AddValue(self,Y):
if (Y >= self.Min and Y <= self.Max):
H = self.Max - self.Min
89 di 109

h = self.height - (self.top + self.bottom)


modulo = Y * h / H
y = self.top + h - modulo
s = self.getRightLabel(Y)
self.Msg.SetLabel(" Value: %.2f - Label:%s" % (Y,s[0]))
self.punti.append(wx.Point(self.GetSize().GetWidth(),y))
if len(self.punti)> MAX_PUNTI:
self.punti.pop(0)
w = self.width / (MAX_PUNTI - 1)
for i in range(0,len(self.punti)):
self.punti[len(self.punti) - (i + 1)].x = self.width - w * i
#print self.punti[len(self.punti) - (i + 1)].y
self.Refresh()
def OnPaint(self, evt):
dc = wx.PaintDC(self)
self.PrepareDC(dc)
try:
gc = wx.GraphicsContext.Create(dc)
except NotImplementedError:
dc.DrawText("This build of wxPython does not support the wx.GraphicsContext "
"family of classes.",
25, 25)
return
font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
font.SetWeight(wx.BOLD)
gc.SetFont(font)
path = gc.CreatePath()
start=0
s = self.GetSize()
h= self.height
w = s.GetWidth()
path.AddRectangle(0, self.top, w-1, h-(self.top + self.bottom))
gc.PushState()
gc.SetPen(wx.Pen("green", 5))
gc.SetBrush(wx.Brush("black"))
for label, PathFunc in [("StrokePath", gc.StrokePath),
("FillPath", gc.FillPath),
("DrawPath", gc.DrawPath)]:
if "wxGTK" in wx.PlatformInfo:
w, h = dc.GetTextExtent(label) # NYI in Cairo context
else:
w, h = gc.GetTextExtent(label)
PathFunc(path)
90 di 109

gc.PopState()
#istograms drawing
path2 = gc.CreatePath()
start=0
if len(self.punti)>0:
path2.MoveToPoint(self.punti[0].x, self.punti[0].y)
for i in range(1,len(self.punti)):
path2.AddLineToPoint(self.punti[i].x, self.punti[i].y)
gc.PushState()
gc.SetPen(wx.Pen(self.pen, 5))
for label, PathFunc in [("StrokePath", gc.StrokePath),
("FillPath", gc.FillPath),
("DrawPath", gc.DrawPath)]:
if "wxGTK" in wx.PlatformInfo:
w, h = dc.GetTextExtent(label) # NYI in Cairo context
else:
w, h = gc.GetTextExtent(label)
PathFunc(path2)
gc.PopState()

91 di 109

Composizione algoritmica e
tempo reale

Nel tutorial, Composizione algoritmica, ci soffermeremo principalmente su tutte quelle tecniche


informatiche che possono essere d'aiuto, non tanto alla composizione musicale in genere, ma alla
cosiddetta composizione istantanea. In altre parole, l'obiettivo quello di fornire alcuni strumenti
per cercare di risolvere il problema principale del musicista elettronico interessato all'elaborazione
del suono in tempo reale: come gestire la modifica contemporanea di pi parametri durante la
performance secondo determinate scelte estetiche im modo pratico, flessibile ed intelligente?

La composizione algoritmica applicata all'elaborazione del suono in tempo reale trova principale
motivazione nel fatto che durante una performance, il musicista ha il tempo di pilotare soltanto un
limitato numero di parametri. Molti aspetti dell'esecuzione devono essere cos necessariamente
delegati alla macchina.
Solo grazie ad algoritmi intelligenti il musicista potr sfruttare pienamente lo strumento che ha tra
le mani: il computer.
Nel preparare una performance il musicista deve cos farsi, almeno idealmente, programmatore.
Le forme musicali che verranno eseguite durante il live, saranno sempre il frutto dell'interazione tra
musicista e programmi ( anche e soprattutto di composizione automatica).
I programmi che il musicista realizzer o assembler definirinno alcuni dei confini della sua
estetica.
Chiramente tali algoritmi in nessun modo sostituiscono l'uso da parte del musicista di particolari
"controlli" ed interfacce fisiche adeguate per interagire con la macchina, ma ne sono l'inevitabile
completamento.

Una classe per la gestione di pattern di


accenti

Ho realizzato la classe PatternCtrl partendo da questo problema esecutivo:


Mi son ritrovato a campionare, durante una performace, un breve frammento sonoro, e quindi a
mandarlo in loop. Ovviamente durante l'esecuzione del loop il frammento veniva eseguito sempre
in maniera identica. Ho quindi voluto creare una classe per applicare al loop una sequenza di

92 di 109

accenti, in modo da renderlo pi vivo e meno monotono.


Ho deciso di memorizzare la sequenza degli accenti in un file e di salvare tutti i file in un'unica
cartella.
Ogni file composto da sole tre righe:

riga di accenti per il canale sinistro

riga di accenti per il canale destro

modalit di lettura dei valori.

Se la terza riga contiene il simbolo ">" i valori verranno letti in sequenza, se il simbolo contenuto
una "r" i valori verranno letti "randomicamente".
Ogni riga di accenti costituita da una sequenza di numeri. Ogni numero un fattore di
moltiplicazione da applicarsi al volume del frammento.
L'esempio 1 quindi rappresenta una sequenza del tipo: accento forte, accento debole, accento forte,
accento debole.
Esempio 1
1.0 0.1 1.0 0.1
1.0 0.2 1.0 0.3
>
Esempio 2
1.0 0.0 0.5 2.0 1.0 0.7 0.2 0.0 0.8
1.0 0.0 0.7 0.8 1.0 0.3 1.5 1.0 0.0
r
I nomi dei possibili pattern di accenti vengono visualizzati in una casella combinata. La casella
viene popolata con i nomi dei files presenti nella directory passata come argomento (path) al
costruttore della classe.
cb = PatternCtrl(self.panel, 500,( 10 + ((i-1) *195), 420),
(-1, -1),os.getcwd() + "\pattern")
La classe si occupa cos di leggere i files dei pattern di accenti, visualizzarne i nomi nella combo,
infine e soprattutto offrire all'esterno della classe il valore dell'accento corrente.
from math import floor
import utilities
import os
import random
from wxPython.wx import *
import wx

93 di 109

class PatternCtrl:
def __init__(self, panel, id_Combo, point,size, path):
self.panList = os.listdir(path)
i=0
self.panL = []
self.panR = []
self.Mod = []
self.R_Counter=0
for fileName in self.panList:
fn = fileName.split(".")
t= path + "\\" + fileName
f = open(t,'rb')
lines =f.readlines()
l = lines[0]
l = l.strip()
x = l.split()
self.panL.append(x)
l = lines[1]
l = l.strip()
x = l.split()
self.panR.append(x)
l = lines[2]
l = l.strip()
self.Mod.append(l)
self.panList[i] =fn[0]
i=i+1
self.panel = panel
self.cb = wx.ComboBox(
self.panel, id_Combo, self.panList[0], point,size,self.panList, wx.CB_DROPDOWN
)
def getIndex(self,name):
for i in range(0,len(self.panList)):
if self.panList[i]==name:
return i
return -1
def getPanValue(self):
i = self.getIndex(self.cb.GetValue())
if self.Mod[i]=="r" or self.Mod[i]=="R":
x = random.sample(self.panL[i],1)
y = random.sample(self.panR[i],1)
return [float(x[0]),float(y[0])]
if self.Mod[i]==">":
self.R_Counter = self.R_Counter + 1
if self.R_Counter == len(self.panL[i]):
self.R_Counter = 0
l = self.panL[i]
94 di 109

r = self.panR[i]
#print "ok"
return [float(l[self.R_Counter]),float(r[self.R_Counter])]
return [1.0,1.0]

Modificare pattern di accenti tramite


istogrammi

Questo articolo presenta un componente grafico per visualizzare nella forma di istogrammi un
pattern di accenti, seguendo la formalizzazione gi presentata.

L'esempio completo presente nella sezione download.


Attraverso i due pulsanti ADD e REMOVE possibile aggiungere o rimuovere un rettangolo dal
grafico. Ogni volta che viene aggiunto un rettangolo, tutti i rettangoli gi presenti vengono
ridimensionati.
Cliccando con il pulsante sinistro del mouse nell'area di disegno, viene ridimensionato il
rettangolo selezionato.
Le stringhe di accenti , ad esempio "1.0 2.0 0.0 1.0", possono essere utilizzate per caricare in un
colpo solo i rettangoli del grafico. Il valore 2.0 il valore massimo consentito, mentre quello
minimo 0.0.
Grazie ad un metodo della classe possibile esportare in formato stringa l'istogramma disegnato.
Ho realizzato la classe per permettere ad un utente di visualizzare e modificare in tempo reale una
sequenza di accenti. Ogni rettangolo un accento. L'altezza del rettangolo rappresenta la forza
95 di 109

dell'accento.
from wxPython.wx import *
import wx
MAX_F = 2.0
SPACE = 10
#Class for istograms drawing
class IstoPanel(wx.Panel):
def __init__(self, parent, pos, size, env, pen, brush, title):
wx.Panel.__init__(self, parent,333, pos, size, wx.WANTS_CHARS)
self.ID =100
self.pen = pen
self.brush = brush
#Add Button
self.ID_BUTTON_ADD = self.ID
self.ID=self.ID + 1
self.buttonInsert = wx.Button(self, self.ID_BUTTON_ADD , "ADD", (20, 20))
EVT_BUTTON(self, self.ID_BUTTON_ADD, self.OnClickButtonAdd)
#Remove Button
self.ID_BUTTON_REMOVE = self.ID
self.ID=self.ID + 1
self.buttonRemove = wx.Button(self, self.ID_BUTTON_REMOVE , "REMOVE", (100,
20))
EVT_BUTTON(self, self.ID_BUTTON_REMOVE, self.OnClickButtonRemove)
#Resizing buttons and static text
panelSize = self.GetSize()
self.height = panelSize[1]
buttonSize = self.buttonInsert.GetSize()
self.buttonInsert.SetPosition((0, self.height - self.buttonInsert.GetSize().GetHeight() +
SPACE / 2))
self.buttonRemove.SetPosition((buttonSize.GetWidth() + SPACE, self.height self.buttonInsert.GetSize().GetHeight() + SPACE / 2))
self.bottom = self.buttonInsert.GetSize().GetHeight()
self.top = self.bottom
x = self.buttonRemove.GetPosition()
x =x[0] + self.buttonRemove.GetSize().GetWidth() + SPACE
wx.StaticText(self, -1, title, (x, self.height - self.buttonInsert.GetSize().GetHeight() +
SPACE / 2))
self.rettangoli =[]
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
def OnClickButtonAdd(self, event):
w = self.GetSize().GetWidth()
96 di 109

if len(self.rettangoli)==0:
rw = w
else:
rw = int(w / (len(self.rettangoli) + 1))
i=0
for i in range(0,len(self.rettangoli)):
self.rettangoli[i].x = i * rw
self.rettangoli[i].width = rw
if len(self.rettangoli) > 0:
i=i+1
self.rettangoli.append (wxRect(rw * i,self.top,rw,self.height - (self.top + self.bottom)))
self.Refresh()
def OnClickButtonRemove(self, event):
if len(self.rettangoli)>0:
self.rettangoli.pop()
w = self.GetSize().GetWidth()
if len(self.rettangoli)==0:
rw = w
else:
rw = int(w / (len(self.rettangoli)))
i=0
for i in range(0,len(self.rettangoli)):
self.rettangoli[i].x = i * rw
self.rettangoli[i].width = rw
if len(self.rettangoli) > 0:
i=i+1
self.Refresh()
def LoadRects(self,lista):
w = self.GetSize().GetWidth()
self.rettangoli =[]
if len(lista)==0:
rw = w
else:
rw = int(w / len(lista))
i=0
for l in lista:
r = float(l.strip())
h = r * (self.height - (self.top + self.bottom)) / MAX_F
top = (self.height - self.top) - h
self.rettangoli.append (wxRect(rw * i,top,rw,h))
i= i + 1

97 di 109

self.Refresh()
def Load(self, Str):
lista = Str.split(" ")
self.LoadRects(lista)
def Get(self):
ris = ""
for r in self.rettangoli:
h = r.height * MAX_F / (self.height - (self.top + self.bottom))
ris = ris + ("%.1f " % h)
ris = ris.strip()
return ris
def OnLeftDown(self, event):
x = event.GetX()
y = event.GetY()
if y >= self.top and y <= (self.height - self.bottom) :
if len(self.rettangoli) >0:
w = self.rettangoli[0].width
i = int(x / w)
if i < len(self.rettangoli):
self.rettangoli[i].y= y
self.rettangoli[i].height = self.height - (self.bottom) - y
self.Refresh()

def OnPaint(self, evt):


dc = wx.PaintDC(self)
self.PrepareDC(dc)
try:
gc = wx.GraphicsContext.Create(dc)
except NotImplementedError:
dc.DrawText("This build of wxPython does not support the wx.GraphicsContext "
"family of classes.",
25, 25)
return
font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
font.SetWeight(wx.BOLD)
gc.SetFont(font)
path = gc.CreatePath()
start=0
s = self.GetSize()
h= self.height
98 di 109

w = s.GetWidth()
path.AddRectangle(0, self.top, w-1, h-(self.top + self.bottom))
gc.PushState()
gc.SetPen(wx.Pen("green", 5))
gc.SetBrush(wx.Brush("black"))
for label, PathFunc in [("StrokePath", gc.StrokePath),
("FillPath", gc.FillPath),
("DrawPath", gc.DrawPath)]:
if "wxGTK" in wx.PlatformInfo:
w, h = dc.GetTextExtent(label) # NYI in Cairo context
else:
w, h = gc.GetTextExtent(label)
PathFunc(path)
gc.PopState()
#istograms drawing
path2 = gc.CreatePath()
for r in self.rettangoli:
path2.AddRectangle(r.x, r.y, r.width, r.height)
gc.PushState()
gc.SetPen(wx.Pen(self.pen, 5))
gc.SetBrush(wx.Brush(self.brush))
for label, PathFunc in [("StrokePath", gc.StrokePath),
("FillPath", gc.FillPath),
("DrawPath", gc.DrawPath)]:
if "wxGTK" in wx.PlatformInfo:
w, h = dc.GetTextExtent(label)
else:
w, h = gc.GetTextExtent(label)
PathFunc(path2)
gc.PopState()

Generazione di motivi musicali con catene di


Markov

Esiste una fiorente letteratura su come utizzare una catena di Markov per generare motivi musicali,

99 di 109

melodie o semplici strutture sonore.

Senza entrare nei dettagli, una catena di Markov pu essere pensata come un grafo orientato
e pesato.
Dal nostro punto di vista pu essere anche vista come una particolare macchina a stati finiti. I nodi
formalizzano gli stati, le freccie le probabilit di passaggio da uno stato ad un altro. In effetti ogni
nodo collegato almeno ad un altro tramite una freccia con un numero che ne indica il peso, ossia
la probabilit di passaggio al nodo successivo. Nessun nodo pu essere isolato.
Osservando la figura si pu notare come il nodo H sia collegato al nodo E con peso/probabilit del
100%. Il nodo L, invece, legato sia a se stesso che al nodo O con un peso/probabilit del 50%.
I nodi possono rappresentare semplici note con durata, frequenza, timbro
specifici, oppure qualsiasi altro oggetto sonoro. Ad esempio se due note
hanno stessa frequenza, timbro e durata potranno essere rappresentate dallo
stesso nodo.
La catena pu avere un nodo iniziale oppure il primo nodo pu essere scelto
casulamente.
Da un nodo si pu passare soltanto ai nodi collegati direttamente. Cos dal
nodo H si passer sempre e comunque al nodo E. Per esempio dalla nota
cSound 8.03 eseguita dallo strumento 1 con durata 1 sec. si potr passare
sempre e solo alla nota denotata da E con la sua specifica articolazione e
timbro. Ancora dal nodo E si passare con una probabilit del 33% a "L", del
33% a "_", del 33% a "R".
A questo punto si potranno ottenere con
strutture: "HER","HEL" oppure "HE_"

la

stessa

probabilit

tre

Il formalismo per la sua semplicit permette di modellare solo strutture


musicali molto semplici, dato che ogni stato dipende interamente soltanto
dallo stato precedente.

100 di 109

Nei prossimi articoli vedremo alcune implementazioni di catene di Markov in


Python e cSound.

Rappresentare una catena di Markov con un file


XML

In questo articolo vediamo come rappresentare una catena di Markov con un file XML.
Il nodo principale il tag <MARKOV_CHAIN>.
Un nodo della catena rappresentato dal tag <NODE ...>, il quale possiede 4 attributi obbligatori:
NAME, OCTAVE, PITCH, DURATION, che formalizzano le principali propriet di una nota. Per
convenzione se il valore dell'attributo OCTAVE uguale a 0, la nota rappresentata in realt una
pausa.
Gli archi che escono dal nodo sono rappresentati dai tag <LINK ...>. I tag LINK hanno due
attributi: NODE, che rappresenta il nome del nodo di arrivo e WEIGTH che rappresenta il peso
associato all'arco.
Esempio1
<?xml version="1.0" ?>
<MARKOV_CHAIN>
<NODES_LIST>
<NODE NAME="Do3_1" OCTAVE="3" PITCH="0" DURATION="1">
<NODES_LINK>
<LINK NODE="Do3_1" WEIGTH="0.2" />
<LINK NODE="Do4_2" WEIGTH="0.2" />
<LINK NODE="Do4_1" WEIGTH="0.2" />
<LINK NODE="MIB6_2" WEIGTH="0.4" />
</NODES_LINK>
</NODE>
<NODE NAME="Do4_1" OCTAVE="3" PITCH="0" DURATION="1">
<NODES_LINK>
<LINK NODE="Do3_1" WEIGTH="0.2" />
<LINK NODE="Do4_2" WEIGTH="0.3" />
<LINK NODE="MIB6_2" WEIGTH="0.5" />
</NODES_LINK>
</NODE>
<NODE NAME="Do4_2" OCTAVE="4" PITCH="0" DURATION="0.5">
<NODES_LINK>
<LINK NODE="Do4_2" WEIGTH="0.5" />
<LINK NODE="Do6_1" WEIGTH="0.5" />
</NODES_LINK>
</NODE>
101 di 109

<NODE NAME="Do6_1" OCTAVE="6" PITCH="0" DURATION="1.0">


<NODES_LINK>
<LINK NODE="Do4_2" WEIGTH="0.4" />
<LINK NODE="MIB6_1" WEIGTH="0.25" />
<LINK NODE="PAU_1" WEIGTH="0.25" />
<LINK NODE="PAU_1" WEIGTH="0.2" />
</NODES_LINK>
</NODE>
<NODE NAME="MIB6_1" OCTAVE="6" PITCH="3" DURATION="1.0">
<NODES_LINK>
<LINK NODE="Do4_2" WEIGTH="0.2" />
<LINK NODE="MIB6_1" WEIGTH="0.2" />
<LINK NODE="Do6_1" WEIGTH="0.2" />
<LINK NODE="PAU_1" WEIGTH="0.2" />
<LINK NODE="SOL6_1" WEIGTH="0.1" />
<LINK NODE="MIB6_2" WEIGTH="0.1" />
</NODES_LINK>
</NODE>
<NODE NAME="SOL6_1" OCTAVE="6" PITCH="8" DURATION="1.0">
<NODES_LINK>
<LINK NODE="Do4_2" WEIGTH="0.2" />
<LINK NODE="MIB6_1" WEIGTH="0.2" />
<LINK NODE="SOL6_1" WEIGTH="0.2" />
<LINK NODE="PAU_1" WEIGTH="0.2" />
<LINK NODE="MIB6_2" WEIGTH="0.2" />
</NODES_LINK>
</NODE>
<NODE NAME="MIB6_2" OCTAVE="6" PITCH="3" DURATION="0.5">
<NODES_LINK>
<LINK NODE="MIB6_2" WEIGTH="0.25" />
<LINK NODE="MIB6_1" WEIGTH="0.25" />
<LINK NODE="Do6_1" WEIGTH="0.25" />
<LINK NODE="PAU_1" WEIGTH="0.25" />
</NODES_LINK>
</NODE>
<NODE NAME="PAU_1" OCTAVE="0" PITCH="0" DURATION="1.0">
<NODES_LINK>
<LINK NODE="Do4_2" WEIGTH="0.25" />
<LINK NODE="Do6_1" WEIGTH="0.25" />
<LINK NODE="PAU_1" WEIGTH="0.5" />
</NODES_LINK>
</NODE>
</NODES_LIST>
</MARKOV_CHAIN>
Esempio2
<?xml version="1.0" ?>
<MARKOV_CHAIN>
<NODES_LIST>
102 di 109

<NODE NAME="SOL6_1" OCTAVE="6" PITCH="8" DURATION="1.0">


<NODES_LINK>
<LINK NODE="SOL6_1" WEIGTH="0.4" />
<LINK NODE="PAU_1" WEIGTH="0.2" />
<LINK NODE="RE7_2" WEIGTH="0.4" />
</NODES_LINK>
</NODE>
<NODE NAME="SOL6_4" OCTAVE="6" PITCH="8" DURATION="0.25">
<NODES_LINK>
<LINK NODE="SOL6_1" WEIGTH="0.2" />
<LINK NODE="SOL6_4" WEIGTH="0.4" />
<LINK NODE="PAU_1" WEIGTH="0.2" />
<LINK NODE="RE7_2" WEIGTH="0.2" />
</NODES_LINK>
</NODE>
<NODE NAME="RE7_2" OCTAVE="7" PITCH="2" DURATION="0.5">
<NODES_LINK>
<LINK NODE="SOL6_1" WEIGTH="0.4" />
<LINK NODE="PAU_1" WEIGTH="0.2" />
<LINK NODE="RE7_2" WEIGTH="0.2" />
<LINK NODE="SOL6_4" WEIGTH="0.2" />
</NODES_LINK>
</NODE>
<NODE NAME="PAU_1" OCTAVE="0" PITCH="0" DURATION="1.0">
<NODES_LINK>
<LINK NODE="SOL6_1" WEIGTH="0.2" />
<LINK NODE="PAU_1" WEIGTH="0.4" />
<LINK NODE="RE7_2" WEIGTH="0.4" />
</NODES_LINK>
</NODE>
</NODES_LIST>
</MARKOV_CHAIN>

Passaggio da un range di valori ad un altro con l'interpolazione


lineare

Conoscere la soluzione a questo problema nella composizione assistita dal


computer pu tornare utile ogni volta che si desidera tradurre un valore
relativo ad un determinato range, in un altro che rientra per in un range pi
piccolo o pi grande.
La soluzione non altro che l'applicazione della nota formula dell'interpolazione lineare.
In particolare x0 e x1 rappresentano gli estremi della gamma di partenza (estremi del segmento
103 di 109

sull'asse X); y0 e y1 rappresentano gli estremi della gamma di arrivo; x il valore che si desidera
tradurre; y il valore che si desidera trovare

Il problema pu essere rappresentato in un asse cartesiano in questo modo: dato un segmento


con estremi (x0,y0) (x1,y1) trovare l'ordinata y conoscendone l'ascissa x.

In Python la formula pu essere cos tradotta


def linear_interpolation(x, xMin, xMax, yMin, yMax):
a = (x - xMin) / (xMax - xMin)
b = yMax - yMin
return a * b + yMin
print linear_interpolation(3.0,1.0,4.0,3.0,9.0)
>>> 7.0
Una tra le tante notevoli applicazioni di questo algoritmo consiste nella traduzione del valore x di
un controllo MIDI (0 - 127) in un valore y di range qualsiasi , come per esempio la durata di un
delay con gamma da 1 a 10 secondi.
Bibliografia
Musimathics vol. 1 di Garteh Loy
Wikipedia Linear Interpolation

104 di 109

Permutazioni o disposizioni senza


ripetizione

Fin dalle mie prime esperieze d'informatica musicale mi sono imbattuto nelle permutazioni: ad
esempio quando scrissi uno dei miei primi programmi C, che doveva trovare tutti i possibili accordi
eseguibili su uno strumento a corde, quali chitarra o basso elettrico.
Per permutazione si intende una disposizione di elementi ma senza ripetizione

In altre parole, una permutazione un modo di combinare n oggetti distinti scambiandoli di


posizione, come nell'anagrammare una parola (WIKIPEDIA).
La formula sopra riportata ci ricorda che dati n elementi, il numero di permutazioni n!
Molti concetti musicali tradizionali, come ad esempio quello di rivolto di un accordo, possono
essere ricondotti a quello di permutazione. Tipicamente l'insieme di tutte le permutazioni
rappresenta l'universo su cui si applicano specifiche regole di preferenza, che hanno il ruolo di
selezionare solo quelle disposizioni che si conformano ai nostri disegni estetico-compositivi

Random
walk

Immaginiamo una persona ubriaca, che ad ogni passo non sappia cosa fare... andare avanti o
indietro?
Ecco, il random walk un algoritmo, stupido, evidentemente
, che permette di scegliere in
quale direzione compiere il prossimo passo della nostra camminata...
Il Random walk si utilizza tipicamente per leggere i valori di una matrice o di una lista a 2 o a n
dimensioni, o per compiere aleatoriamente una qualsiasi scelta. La matrice contiene tutti i valori
del dominio d'interesse (durata dei paramtri di un effetto, serie di altezze, possibili valori
d'ampiezza ecc...). La distribuzione delle scelte che si otterr sar comunque non uniforme, ma avr
delle densit note, dipendenti dal valore di partenza, da quello minimo e massimo, dal numero
degli elementi.
L'algoritmo si applica ad una valore attuale (ad esempio un indice di un Array). Tramite un numero
pseudo casuale si determina se il valore attuale deve essere incrementato o decrementato di un
certo passo. Il nuovo valore sar sempre incluso tra una soglia massima e una soglia minima, che
saranno anche i due valori su cui l'agoritmo potr eventualmente insistere.
Riporto una possibile implementazione in Python. Questa funzione usata per determinare i valori

105 di 109

di due wxSpinCtrl (durata di un delay e di un contatore )


def random_walk(ActualValue, MinValue, MaxValue, Step):
n = random.sample([0,1],1)
if (n[0] == 1):
result = ActualValue + Step
if result > MaxValue:
result = MaxValue
else:
result = ActualValue - Step
if result < MinValue:
result = MinValue
return result
# Esempio d'uso
if self.m_random:
self.spindelays[nButton -1].SetValue(utilities.random_walk(self.spindelays[nButton
-1].GetValue(), MIN_DELAY, MAX_DELAY, 5))
self.spincounters[nButton
-1].SetValue(utilities.random_walk(self.spincounters[nButton -1].GetValue(), MIN_COUNTER,
MAX_COUNTER, 5))
Bibliografia
Automated Music Composition - Phil Winsor
Musimathics - the matematical foundations of music (volume 1) - Gareth Loy - The Mit Press

Disposizioni con
ripetizione

Ripassiamo il concetto di: disposizione con ripetizione.


Per esemplificare il concetto supponiamo di partire dalla seguente serie di 4 note SK={Do3, Do4,
Mi3, Sol4} e proviamo a chiederci quanti motivi di 6 note (Ad Es. Do3, Do4, Mi3, Sol4 Do3, Do4}
possiamo ottenere partendo dalla serie data.
In generale il problema che ci interessa pu essere cos espresso
Siano S1, S2, S3....Sr, r insiemi ognuno di n1,n2,n3....nr oggetti distinti e si consideri il prodotto
cartesiano
Pr = S1 x S2 x ...... x Sr = { (s1,........,sr): s1 in S1 , ........sr in Sr }
Quante r-uple Pr contiene? Ovvero quanti sono gli allineamenti che si possono formare prendendo
106 di 109

un oggetto da S1, un oggetto da S2... un oggetto da Sr? Poich si pu scegliere s1 in n1 modi


distinti, s2 in n2 modi distinti..... sr in nr modi distinti, il numero complessivo degli allineamenti
possibili sar dato da
n1 x n2 x ...... nr
Nel caso speciale in cui S1 = S2 =... Sr il risultato sar nr.

Ritornando al nostro problema di partenza la soluzione sar data da:


4 * 4 * 4 * 4 * 4 * 4 = 46

Funzione di conversione di una nota nella sua frequenza


corrispondente

Come si sa il concetto di frequenza un concetto fisico-matematico, mentre il


concetto di "nota" o "tono" un concetto legato alla sfera psico-percettiva. La
traduzione di un concetto nel suo corrispondente implica un certo grado di
approssimazione. In ogni caso, pu tornare particolarmente utile avere a
disposizone tra le proprie funzioni, una che si occupi della traduzioni di una
nota qualsiasi nella sua corrispondente rappresentazione in cicli per secondo.
La funzione cpsch, che si occupa di questa traduzione, stata scritta in python e corrisponde
all'omonimo opcode csound. A differenza di quest'ultimo, per, la cpsch proposta prende sei
parametri, di cui due obbligatori: Octave e Note, che indicano il numero di ottava e il
numero dell'intervallo pi piccolo della scala di riferimento (0....n).
Gli altri quattro parametri individuano il sistema di coordinate in cui la coppia (Ottava,Nota)
assume il suo corretto significato: la frequenza di riferimento, il numero di intervalli uguali in cui
divisa l'ottava, il numero di ottava ed il numero di intervallo in cui si traduce la frequenza di
riferimento.
La funzione stata implementata partendo dalle seguenti osservazioni:

La traduzione di un tono nella corrispondente rappresentazione in cicli per secondo


presuppone che il tono venga identificato in maniera univoca
Un tono pu venir identificato con diversi sistemi di coordinate. La funzione identifica un
tono in base ad una scala ottenuta tramite temperamento equabile.
107 di 109

La suddivisione dell'ottava in dodici parti uguali una delle possibili


suddivisioni "equabili"dell'ottava
La frequenza di riferimento 440.0 corrispondente al octave-point-pitch-class cSound 8.09,
una delle possibili frequenze di riferimento
Se un tono ha frequenza Fr, l'ottava il tono identificato dalla seguente espressione: Fr * (2
** 1)
Una frequenza pu quindi essere rappresentata da numero di ottava (v) e da un numero di
tono entro l'ottava (k), ottenuto dalla divisione in parti uguali della stessa (d)
F(k,v)= Fr * 2**v + k/d

def cpspch(Octave, Note, OctaveDivision=12.0, RefFreq=440.0, OctaveRefNumber=8,


NoteRefNumber=9):
return RefFreq * (2.0 ** ((Octave - OctaveRefNumber) + (Note NoteRefNumber)/OctaveDivision))
print cpspch(8,9)#----->-440.0

Una classe per il calcolo delle permutazioni di una serie


di note

In questo articolo presento una classe Python per il calcolo di tutte le possibili permutazioni di una
serie di note.

La serie rappresentata da una lista di coppie. Ogni coppia (ottava,nota) traduce in un formato
computazionalmente pi comodo il solito octave-point-pitch-class di cSound.
Il risultato ottenuto in formato lista di liste.
def findPermutations(self, p_l, p_lp):
if type(p_l) is NoneType:
return
if (len(p_l)==0):
return
if (len(p_l)==1):
p_lp.append(p_l[0])
self.ris.append(p_lp)
else:
for i in range(0,len(p_l)):
lp=[]
lp.extend(p_lp)
lp.append(p_l[i])
108 di 109

l=[]
l=p_l[0:i]
l.extend(p_l[(i+1):len(p_l)])
self.findPermutations(l,lp)

def getPermutations(self):
self.ris = []
lp=[]
self.findPermutations(self.S,lp)
return self.ris
Per utilizzare la classe prima la si istanzia, passando al costruttore la serie da permutare. In seguito
si chiama il metodo getPermutations, che ritorna il risultato desiderato. Il lavoro vero e proprio
effettuato dal metodo findPermutations.
L'algoritmo segue una logica ricorsiva:

La permutazione di una lista vuota uguale alla lista vuota


La permutazione di una lista di un solo elemento uguale all'elemento stesso
Se la lista comprende n > 1 elementi, le sue permutazioni saranno uguali alle permutazioni
delle liste con n-1 elementi, concatenando ad esse nella posizione i-esima l'elemento
sottratto

p = Permutations([(8,0),(9,0),(7,5)])
k = p.getPermutations()
print k
>>>
[[(8, 0), (9, 0), (7, 5)], [(8, 0), (7, 5), (9, 0)], [(9, 0), (8, 0), (7, 5)], [(9, 0), (7, 5), (8, 0)], [(7, 5), (8,
0), (9, 0)], [(7, 5), (9, 0), (8, 0)]]

La classe completa pu essere scaricata dalla sezione download.

109 di 109