Algo-ritmi

Tutorial e idee su software musicali

Settima Parte: introduzione al VCA

con un commento

Nella terza parte dello schema, la nota midi immagazzinata nella lista creata precedentemente viene divisa di nuovo in pitch e velocity e questi due valori vengono inviati a due parti distinte del “circuito”: il pitch verrà trasformato in una frequenza da inviare all’oscillatore che emetterà il suono desiderato, la velocity verrà utilizzata per gestire l’andamento del volume nel tempo al quale l’oscillatore dovrà suonare, quello che in gergo viene chiamato Envelope Generator (EG) o Voltage Control Amplifier (VCA) nelle macchine analogiche.

VCA

In questo sequencer, che chiamerei “ad impulsi” – in quanto le note suonate sono cortissime (50 ms) – l’EG ha solamente due punti di inviluppo che sono:

1. il tempo che impiega a raggiungere il volume impostato dalla velocity
2. il tempo che impiega una volta raggiunto il volume massimo a tornare a zero

Anche se un po’ impropriamente, questo EG potrebbe essere considerato un “attack/release”, solitamente nei sintetizzatori i punti di inviluppo sono almeno 4: “attack/decay/sustain/release”, per qualche informazione in più su quest’argomento date un’occhiata a questo link: http://www.vintagesynth.com/techniques/faq.shtml alla voce “Envelope (VCA)”.

Ritornando al nostro schema e percorrendolo dall’alto verso il basso, abbiamo dunque la lista in arrivo dall’oggetto receive che viene suddivisa in pitch e velocity dall’oggetto unpack il quale genera in uscita rispettivamente dal primo outlet il pitch e dal secondo la velocity.

Come accennato prima, i due valori seguono a questo punto due strade diverse: il pitch passerà attraverso l’oggetto mtof che lo trasformerà in una frequenza in Hz e lo invierà all’oscillatore (di questo ne parlerò più avanti) mentre il valore della velocity andrà ad alimentare il meccanismo dell’EG.

Prima di procedere è necessario specificare un paio di cose: il volume di un segnale in MSP varia da zero a 1 e le connessioni degli oggetti in MSP trasmettono un segnale e non un valore, consiglio vivamente di leggere il manuale “tutorial and topics” di MSP per comprendere bene questi concetti.

L’ampiezza del segnale (volume) dovrà essere quindi un numero float (a virgola mobile) compreso tra zero e 1, quindi la velocity in arrivo dovrà essere divisa per il valore massimo possibile (127), quindi utilizzerò una divisione: / 127. (Ho scritto un numero float come divisore per avere in uscita un numero float).

Altra cosa importante è che l’EG deve entrare in azione solo nel caso in cui la velocity sia un valore superiore a zero: il controllo in questione è fatto da un gate che apre o chiude l’invio del valore della velocity in base al valore stesso, che deve essere superiore a zero. il confronto viene fatto con l’oggetto >, che restituisce 1 nel caso il confronto sia vero.

Da notare che per fare funzionare correttamente questa parte devo tenere in considerazione la regola di MAX per cui gli inlet sono letti sempre da destra verso sinistra, per cui è importante che l’oggetto > si trovi più spostato verso destra rispetto all’oggetto /, altrimenti il gate si aprirà ma il valore che vi passerà attraverso sarà quello precedente.

Ora che la velocity arriva nel posto giusto al momento giusto, posso implementare la gestione dell’EG utilizzando l’oggetto line~ di MSP che in base ad una lista genera un movimento nel tempo del segnale.

Il messaggio che alimenta la lista in entrata dell’oggetto line~ è così composto: “0, $1 10 0 120″, il che significa “in 10 millisecondi vai da zero a $1 (la velocity passata al messaggio), una volta raggiunto $1, in 120 millisecondi raggiungi zero”. Ecco così ricreato l’effetto di “attack/release”.

Moltiplicando il segnale in uscita da line~ attraverso l’operatore *~ con il segnale audio in arrivo dall’oscillatore, si avrà quindi la modulazione del volume dell’oscillatore nel tempo.

Written by lodevalm

Dicembre 11, 2007 alle 1:37 pm

Sesta Parte: gestire pitch e velocity

lascia un commento »

Il primo blocco della nuova patch non presenta particolari differenze rispetto alla versione precedente:

tempo and matrix

l’unica differenza è l’aggiunta di un messaggio clear, che svuota la griglia del matrixctrl (per informazioni aggiuntive, consiglio di leggere il tutorial numero 3).

La sezione successiva è invece un’implementazione della precedente versione:

column to midi note

La lista binaria composta dall’output della colonna del matrixctrl viene prima rovesciata (questo serve perchè le note partono da basso, mentre invece la lista arriva in ordine dall’alto verso il basso) tramite zl rev, dopo di che viene estratto l’indice che vale 1 (ossia il nostro pitch) tramite zl sub 1. A questo punto se trovo un 1 nella lista, zl sub 1 invierà l’indice a expr che lo somma a 59 per ottenere una nota nell’ottava centrale di una tastiera e contemporaneamente dal suo secondo outlet leggerò 1 (nel caso sia stato trovato il valore ricercato nella lista) o zero (il valore non è stato trovato).

Seguendo il segnale in uscita dal secondo outlet di zl sub 1, vediamo innanzi tutto che l’output viene inviato a un moltiplicatore * 127, questo perchè il valore della velocity ha per convenzione un range che va da 1 (nota suonata pianissimo) a 127 (nota suonata al massimo del suo volume) con il valore zero che esprime un “note off”, ho aggiunto un numberbox che va da 0 a 127 nel secondo inlet della moltiplicazione di modo da poter controllare il valore della velocity. Per esempio selezionando 64, la moltiplicazione darà come risultato 1*64, quindi la velocity sarà la metà.

I due dati rilevanti della nota in uscita da questo blocco sono immagazzinati in una lista attraverso l’oggetto pack. Questo oggetto imposta il numero di inlet in base al numero di argomenti, nel mio caso, gli argomenti sono 2: pitch (nel primo inlet) e velocity (nel secondo inlet) e crea una lista in uscita composta dai relativi valori degli inlet (o degli argomenti).

A questo punto non resta che gestire il “note off”, che ho impostato 50 millisecondi dopo la nota con velocity maggiore a zero, una nota cortissima.

Ho dunque utilizzato l’oggetto pipe, che ritarda l’invio di un numero in arrivo nel primo inlet di un determinato intervallo in millisecondi. L’intervallo è definibile attraverso il suo secondo inlet o come nel mio caso specificandolo come argomento nell’oggetto.

Il “note off” sarà quindi un ritardo della nota suonata con la velocity impostata a zero, per cui pipe è connesso direttamente al primo inlet di pack e gli passerà il pitch dell’ultima nota ricevuta ed al tempo stesso è collegato ad un button che emetterà un bang ad un messaggio che passa zero al secondo inlet di pack, il tutto con un ritardo di 50 millisecondi rispetto all’ultima nota suonata.

A questo punto il gioco è fatto, ho creato un “modulo” che crea una lista composta da due valori che rappresentano una nota midi. Il primo valore è creato in base al pitch ricevuto dal matrixctrl ed il secondo in base alla velocity desiderata (per default 127) tramite il numberbox con l’etichetta “velocity”. Ad ogni nota corrisponde il relativo “note off” che ha un ritardo di 50 millisecondi rispetto alla nota suonata.

Questa lista viene inviata tramite un oggetto send con l’etichetta “seqNote” al prossimo blocco che si occuperà di far suonare la nota midi ricevuta.

Written by lodevalm

Dicembre 10, 2007 alle 2:37 pm

Quinta Parte: Approfondimenti

lascia un commento »

Benchè a questo punto sia possibile emettere numeri interpretabili come note tramite il matrixctrl , se tentate di implementare il precedente tutorial, vi troverete di fronte ad un “binario morto”, perchè per raggiungere l’obiettivo il più rapidamente possibile, ho completamente tralasciato il reale contenuto di una nota midi, concentrandomi solo sull’intonazione.

Infatti, una nota midi è composta non solo dall’intonazione (pitch) ma contiene dentro di se altri due valori che sono il volume al quale la nota deve essere suonata (velocity) ed il canale midi alla quale deve essere suonata (midi channel).

Un ultimo valore, non presente nella struttura dati rappresentata dalla nota midi è la sua durata, questo valore non è direttamente presente, ma è “deducibile”: una nota midi con un determinato pitch e la velocity impostata a 0 viene denominata “note off” ed indica che quella nota è arrivata alla fine della sua durata.

Ancora una volta, trascurerò la durata di esecuzione della nota per semplificare la patch, che è la seguente (cliccare per ingrandire):

sequencer

Mi concentrerò invece su questi due aspetti: pitch (che in realtà non è molto diverso dal tutorial precedente) e velocity, con cui andremo a gestire l’ampiezza (volume) del segnale generato dalla nota.

Come potete vedere, ho suddiviso la patch in blocchi e per facilità di comprensione ho utilizzato due oggetti molto comodi per non finire sepolti dai “cavi” che collegano gli oggetti. Si tratta di send e receive. Questi due oggetti devono avere un parametro che indica il nome della loro connessione, per migliorare la leggibilità della patch ho colorato con lo stesso colore send e receive connessi, per esempio “matrixList” (verde) è la connessione che passa la lista della colonna in uscita dal matrixctrl a zl.

Written by lodevalm

Dicembre 10, 2007 alle 10:28 am

Quarta Parte: un po’ di soddisfazione…

lascia un commento »

A questo punto, il “cuore” del nostro sequencer è concluso.

Giusto per avere un po’ di soddisfazione e per iniziare ad emettere qualche suono, provate a connettere alla nota in uscita dall’oggetto peak quanto segue:

1_3 final

In breve, dall’alto verso il basso:
mtof: trasforma una nota midi in una frequenza
cycle~: emette un’onda sinusoidale intonata con la frequenza in entrata.
Signal level fader: controlla il volume di un segnale
Audio output: invia il segnale al driver audio

Written by lodevalm

Novembre 19, 2007 alle 2:57 pm

Terza Parte: Creare note con matrixctrl

con 2 commenti

tutorial 1_3

In questa parte vedremo come poter generare un numero che rappresenterà l’altezza della nota tramite la lettura di una colonna del matrixctrl.

Prima di impostare il matrixctrl, vediamo come poter visualizzare quale colonna viene letta in un determinato momento.
Per fare questo, ho creato un oggetto route ed impostato 16 outlet, agganciando ad ognuno un button. Per charezza, ne ho colorato uno diversamente (verde) ogni 4, quindi i bottoni 1, 5, 9 e 13 rappresentano ¼ della battuta.
L’oggetto route ridireziona l’input all’outlet corrispondente, nel nostro caso ho impostato come argomenti:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

Questo significa che collegando l’output dall’oggetto tempo nell’input del router (è un numero intero che va da 0 a 15), il bottone che si accenderà sarà corrispondente alla suddivisione corrente.
Per esempio nell’immagine sopra viene passato il numero 6 che quindi sarà ridirezionato al settimo outlet, infatti il settimo bottone è acceso (giallo).

Siamo dunque arrivati al momento di impostare il matrixctrl, che dovrà essere una griglia di 16×12, questo perché sull’asse x avremo l’avanzamento del tempo, mentre sull’asse y la nota da riprodurre.

Una volta disegnato il matrixctrl della dimensione giusta è necessario impostarne le proprietà attraverso l’inspector, di seguito ecco come è settato l’oggetto per il nostro scopo:

matrixctrl inspector

La cosa importante è impostare che solo una cella per colonna può essere accesa, di modo da fornire l’indicazione dell’altezza della nota.

L’output interessante del matrixctrl è la lista di celle corrispondenti a una determinata colonna, dove i valori delle celle possono essere 0 (spento) o 1 (acceso)

La parte più importante da sviluppare è a questo punto come leggere l’output della colonna e trasformarlo in una nota, secondo questa logica:

1. recupero la lista delle celle della colonna corrente

questo avviene tramite la connessione del messaggio [getcolumn $1], dove la variabile passata è il numero della colonna della quale voglio recuperare la lista.
Connettendo quindi l’utput del tempo al messaggio da inviare al matrixctrl, avrò in uscita la lista della colonna.
Nell’esempio della figura sopra, sto chiedendo la lista della colonna 6, considerando che la prima colonna è la colonna 0, avrò in uscita questa lista:
0 0 0 0 0 1 0 0 0 0 0 0
(vedi messaggio in uscita dal matrixctrl dopo l’oggetto [prepend set])

2. inverto la lista

La lista è letta dall’alto verso il basso, quindi gli indici della colonna sono:
1 -> prima riga -> nota B
2 -> seconda riga -> nota A#
3 -> terza riga -> nota A
4 -> quarta riga -> nota G#

11 -> undicesima riga -> nota C#
12 -> dodicesima riga -> nota C

Quindi per avere il corretto valore della nota, devo inverire la lista, di modo che abbia le note espresse come:
C -> nota 1
C# -> nota 2
D -> nota 3
D# -> nota 4
E -> nota 5
F -> nota 6
F# -> nota 7
G -> nota 8
G# -> nota 9
A -> nota 10
A# -> nota 11
B -> nota 12

Per invertire una lista si può usare l’oggetto zl e impostare il parametro rev, in questo modo l’oggetto prende come inlet una lista e la restituisce come outlet rovesciata.

Ricapitolando, nel caso dell’esempio avremo la lista:
0 0 0 0 0 1 0 0 0 0 0 0
che viene rovesciata in:
0 0 0 0 0 0 1 0 0 0 0 0

3. prendo l’indice della lista dove il valore è 1

Ora non mi resta che trovare quale elemento della lista vale 1, questo può essere fatto attraverso un’altra funzione dell’oggetto zl, questa è sub, in questo caso zl sub 1 significa che estrae dalla lista l’indice che corrisponde al valore 1.
Sempre per fare riferimento all’esempio dell’immagine, l’indice estratto è 7, di conseguenza la nota sarà F#.

4. sommo all’indice il numero 59

Tramite l’espressione presente in expr ($i1+59), ottengo il giusto valore della nota, considerando che nell’ottava centrale di una tastiera midi, il C corrisponde a 60, di conseguenza se avessi selezionato l’ultima cella in basso della colonna avrei avuto 59+1, quindi la nota C, mentre nell’esempio ho 59+7 = 66, la nota F# nell’ottava centrale.

5. controllo che la colonna non sia vuota (neanche una nota selezionata)

Resta un’ultimo problema da gestire: come faccio a controllare che la colonna sia vuota?
Se guardate il number box in uscita dall’oggetto zl sub 1, noterete che l’output non torna mai a 0, questo perché l’oggetto non emette output nel caso non trovi neanche una corrispondenza.
Quindi per emettere una nota con il valore 0, nel caso non ci sia neanche una cella selezionata è necessario trovare un’altra strada.
La strada che ho perseguito in questo esempio è tramite l’oggetto peak.
L’oggetto peak emette il valore del primo inlet se questo supera il valore precedente o quello impostato tramite il secondo inlet.
Quindi tramite un button connesso all’output del tempo, imposto ad ogni lettura il valore massimo di peak a 0 e di conseguenza se dalla colonna arriva output, questo sarà superiore a 0 (minimo 60) quindi emetterà la nota desiderata, altrimenti emetterà la nota 0.

Written by lodevalm

Novembre 19, 2007 alle 2:57 pm

Seconda Parte: Inizializzazione della patch

lascia un commento »

Se salvate il progetto e successivamente lo riaprite, noterete che I number box vengono caricati con il loro valore più basso, questo può essere fastidioso e sicuramente è sempre meglio avere il parametro in input uguale al parametro dell’oggetto.
Questo può essere gestito tramite l’oggetto loadbang.

In pratica, quando la patch viene caricata, loadbang emette un bang che può essere utilizzato per mandare messaggi agli oggetti che necessitano un’inizializzazione.
In più è possibile fare doppio click sull’oggetto per riemettere il bang, per cui in qualunque momento  può essere utilizzato per  riportare gli oggetti in una situazione iniziale.

Per chi di voi programma, per esempio in java, lo si può considerare come una chiamata ad un metodo di inizializzazione di una classe, dove la classe è la nostra patch.

loadbang

In questo caso ho impostato i valori iniziali per i due number box: uno a 120 e l’altro a 16, i valori di default per BPM e divisione della misura, di modo da avere “allineati” i parametri iniziali e gli input.

Written by lodevalm

Novembre 14, 2007 alle 2:27 pm

Prima Parte: La gestione del tempo

lascia un commento »

Questo tutorial è veramente semplice, l’ho scritto per chi non ha quasi mai messo mano a questo ambiente di sviluppo, e visto che la mia prima domanda davanti alla pagina bianca è stata: come gestisco il tempo? Ho pensato di inziare da qui.

In questo tutorial imposterò un semplice metronomo/gestore delle misure che successivamente guiderà la griglia del sequencer.

metronome

Il mio oggetto perferito per lagestione del tempo è l’oggetto tempo, perchè ha la stessa interfaccia che viene utilizzata in tutti i software moderni: il tempo è espresso in BPM, la misura può essere suddivisa, cè un moltiplicatore della suddivisione ed ha un inlet che prende come argomento lo start/stop dell’oggetto.

Come output restituisce la divisione corrente (un valore da zero al limite impostato della suddivisione)

Per lo scopo di questo tutorial inizializzerò i parametri con valori di default:
120 1 16.

Questo significa che l’oggetto girerà a 120BPM con una divisione della misura in 16 parti (in pratica una battuta in 16/16).
Il secondo parametro è 1, che è il moltiplicatore della suddivisione (quindi 16×1=16), vi consiglio di giocare con questo parametro per vedere cosa restituisce l’outlet dell’oggetto.

A questo punto non resta che rendere l’oggetto “interattivo”, quindi connetto un toggle al primo inlet, un number box al secondo (gestirà i BPM) ed un altro number box all’ultimo inlet (la suddivisione della battuta).

TIP: è sempre meglio impostare I limiti dei number box, in questo modo si può controllare meglio cosa sta succedendo e prevenire l’invio agli oggetti di valori troppo alti o troppo bassi che non possono essere correttamente interpretati o che possono causare crash del programma (cosa che è molto più semplice di quanto si possa pensare!)

In questo caso ho impostato per il number box dei BPM i valori da 10 a 255 e per il number box responsabile della divisione della battuta i valori da 1 a 16.

Il modo in cui possono essere impostati i valori limite è attraverso la finestra di ispezione dell’oggetto (inspector), accessibile cliccando con il tasto destro sull’oggetto e selezionando “Get Info”.

inspector

Ci sono diversi parametri a disposizione dell’inspector del number box, vi consiglio di fare esperimenti…

L’ultimo oggetto connesso al tempo è un altro number box, che ne riceve l’output.
Questo è utilizzato solo per mostrare il valore in uscita, in questo caso se fate partire ora l’applicazione, cliccando sul toggle che fa partire il tempo, vedrete la divisione corrente, che avanza da 0 a 16 e poi ritorna a 0.

TIP: Personalmente, quando uso number box come display di qualche parametro, solitamente flaggo il parametro “Can’t Change” nell’inspector, in questo modo si può prevenire un cambiamento non voluto all’output dell’oggetto dal quale arriva il valore.

Written by lodevalm

Novembre 14, 2007 alle 2:21 pm

Max/Msp: Creazione di un semplice sequencer

lascia un commento »

In questa serie di tutorial mostrerò come creare un semplicissimo sequencer, alla fine non avrete un clone di Cubase, piuttosto avrete a disposizione qulche concetto utile per la realizzazione di patch più complesse.

Il fruitore di questo tutorial non è ovviamente lo scienziato dell’IRCAM ma qualche inesperto curioso, quindi cercherò di essere il più semplice e chiaro possibile.

Ometterò molte cose per raggiungere in fretta l’obbiettivo, quindi il mio primo consiglio è: se non vi è chiaro cosa fa un oggetto, cliccateci sopra e premete F1.

Written by lodevalm

Novembre 14, 2007 alle 2:05 pm