Ansal


Il progetto è stato sviluppato durante il corso di CMLS al Politecnico di Milano da me, Alessandro Manattini e Salvatore Benvenuto Zocco. Si pone un pò come la prosecuzione di ciò che avevo implementato qui. E’ anche disponibile un video dimostrativo.


0. Sintesi delle funzionalità

L’obiettivo che ci siamo posti è stato quello di fornire a piccoli gruppi di musicisti uno strumento completo per ampliare le loro possibilità musicale e suonare come se fossero una band completa.

Per raggiungere questo obiettivo, abbiamo implementato i seguenti moduli:

  • MIDI Phase Vocoder Polifonico (JUCE): consente di simulare armonie vocali, arricchendo il panorama musicale.
  • Sintetizzatore Polifonico: offre numerose funzionalità, tra cui la modalità mono, la divisione della tastiera, il filtro passa-basso (LPF), lo spostamento di ottava, lo spostamento di pitch e le sequenze di batteria, che verranno dettagliate in seguito.

Nota: questi due strumenti sono interconnessi. Il Vocoder è accessibile tramite l’interfaccia del Synth, e le note ricevute dal Synth vengono inoltrate al Vocoder. Tale configurazione consente a una singola persona di suonare entrambi gli strumenti “senza sforzo”.

  • Piccola suite di Effetti per Chitarra: utilizza il riconoscimento del pitch per identificare le note fondamentali degli accordi suonati, consentendo a un chitarrista di “raddoppiare” la sua chitarra o di “ suonare chitarra e basso”.

Le funzionalità dei moduli possono essere modificate tramite l’interfaccia grafica o tramite mapping di comandi MIDI, come verrà illustrato in seguito.


1. Modulo Vocoder

Il vocoder implementato in questo progetto è un vocoder polifonico a K voci (dove K è un parametro modificabile nelle variabili private in PluginProcessor) controllato tramite MIDI.

Interfaccia Vocoder

Il funzionamento è il seguente:

  • Ingresso Audio: l’audio entra tramite l’ingresso del microfono nel PluginProcessor. Qui viene normalizzato (utilizzando la classe SimpleCompressor) per garantire un livello stabile del segnale in ingresso.
  • Elaborazione Audio e MIDI: il metodo processBlock legge il buffer audio in ingresso e l’input MIDI. Per ogni nota MIDI letta, attiva una delle K voci e la assegna per elaborare il buffer audio alla frequenza specifica della nota MIDI.
  • Elaborazione delle Voci: ogni voce del vocoder (classe PhaseVoc) elabora il buffer audio utilizzando la seguente formula di “autocorrelazione leaky”: \(R_{l,n} = (1 - k) R_{l,n-1} + k x_n x_{n-l}\) Dove:
    • $R_{l,n}$: autocorrelazione leaky al ritardo $l$ e al tempo $n$.
    • $R_{l,n-1}$: autocorrelazione leaky al ritardo $l$ e al passo temporale precedente $n-1$.
    • $x_n$: segnale in ingresso al tempo $n$.
    • $x_{n-l}$: segnale in ingresso $l$ passi prima di $n$.
    • $k$: costante di leakiness, tipicamente intorno a $0.001$. Questa formula bilancia i valori passati di autocorrelazione con i nuovi dati, permettendo al vocoder di adattarsi ai cambiamenti nel segnale vocale nel tempo.
  • Applicazione dell’Inviluppo: per garantire che le note abbiano un inviluppo gradevole, PhaseVoc applica metodi della classe EnvelopeGenerator all’audio elaborato. Una volta fatto ciò, restituisce il buffer contenente il risultato elaborato a PluginProcessor.
  • Filtraggio Passivo-Alto: prima di emettere l’audio, PluginProcessor applica un filtro passa-alto (classe HighPassFilter) all’audio in uscita per rimuovere le frequenze più basse e migliorare l’intelligibilità dell’audio, se necessario.

I passaggi successivi e la gerarchia delle classi relative all’elaborazione audio sono facilmente deducibili dal seguente diagramma:

Schema del Percorso Audio e delle Dipendenze del Vocoder


2. Modulo Synth

Il modulo synth include numerose funzioni disponibili per l’utente, tutte controllabili sia tramite l’interfaccia grafica che tramite MIDI. Inoltre, il Vocoder descritto nella sezione precedente è integrato all’interno del modulo Synth. Questa configurazione garantisce che le note MIDI utilizzate per suonare il sintetizzatore vengano inoltrate anche al Vocoder, consentendo di modulare la voce con le stesse armonie.

Interfaccia Synth

2.1 Configurazione Hardware del Synth

La configurazione hardware per il modulo synth è la seguente:

Dispositivi di Ingresso MIDI

È possibile modificare e controllare i parametri di sistema utilizzando vari controller MIDI (i dettagli su come ciò avvenga verranno forniti nelle sezioni successive). I dispositivi includono:

  • Tastiera MIDI (Arturia Minilab configurata con questo preset).
  • Pedale sustain.
  • Pedale di controllo del volume (non utilizzato per il controllo del volume).
  • Adattatore da segnale analogico a MIDI (ho utilizzato questo).

Ingresso di Inclinazione della Mano

Il sistema riceve anche input dall’inclinazione della mano del tastierista. Il motivo e il metodo per utilizzare questo input per aiutare nel controllo del sistema verranno spiegati in seguito. I dispositivi hardware necessari sono:

  • Accelerometro: montato su un guanto da indossare durante l’esecuzione (ho utilizzato questo).
  • Arduino Uno: necessario per derivare i dati dell’angolo dalle coordinate dell’accelerometro e interfacciare l’accelerometro con il sistema.

I componenti del sistema sono collegati come illustrato nella figura seguente:

Connessioni hardware


2.2 Funzionalità del Synthesizer

Il sintetizzatore offre ampie opzioni di configurazione e personalizzazione dei parametri. L’elenco delle funzionalità è dettagliato nell’immagine della GUI all’inizio del capitolo Synth e nel diagramma di mapping MIDI fornito di seguito, quindi per brevità non le elencherò nuovamente qui. Mappatura Tasti MIDI

Nei seguenti paragrafi, mi concentrerò sulla descrizione dei suoni disponibili nel synth e su come le impostazioni e i suoni possano essere combinati per creare preset interessanti.

2.2.1 Dettagli delle Patch Sonore

All’interno del synth sono disponibili vari tipi di suoni per ciascuno dei due strumenti, migliorando la versatilità della personalizzazione del suono. Di seguito sono riportate le caratteristiche di ogni patch sonora:

  • Rhodes: RHODES1 e RHODES2 emulano il classico pianoforte elettrico Rhodes utilizzando onde a impulso per creare uno spettro armonico ricco. RHODES1 offre un suono caldo e avvolgente con un inviluppo ADSR e un filtro passa-basso dinamico, arricchito da un effetto chorus, rendendolo perfetto per le texture accordali. RHODES2 offre un’alternativa con un attacco più rapido, un chorus potenziato con un ritardo più lungo e riverbero aggiunto, creando un suono spazioso e immersivo ideale per pad e melodie espressive.
  • Synth per Basso: BASSYN1, BASSYN2, BASSYN3 e BASSIMP coprono un’ampia gamma di suoni di basso. BASSYN1 utilizza LFO per modulare la larghezza dell’impulso e la velocità, risultando in un suono dinamico ed evolvente con panning automatico, adatto agli stili elettronici e pop. BASSYN2 presenta oscillatori a dente di sega leggermente disaccordati combinati con un sub-oscillatore per un suono di basso profondo e potente, con vibrato che aggiunge realismo e un filtro passa-basso che garantisce punchevolezza e chiarezza. BASSYN3 migliora questo design con chorus e leggera distorsione, aggiungendo carattere alla combinazione di oscillatori a dente di sega e sub-oscillatore, ideale per linee di basso distintive. BASSIMP si concentra sulla semplicità con un singolo oscillatore a dente di sega, vibrato e un filtro passa-basso, offrendo un tono di basso pulito e solido perfetto per linee di basso essenziali.
  • Lead e Wave Synth: LEADSCR, TRIWAVE e SAWWAVE sono progettati per una varietà di usi, dalle linee melodiche ai pad e al basso. LEADSCR è pensato per suoni di lead potenti e taglienti con un oscillatore a dente di sega sincronizzato e modulazione dinamica della frequenza, con il cutoff e la risonanza del filtro modulati da inviluppi per una maggiore espressività. TRIWAVE genera un’onda triangolare con distorsione aggiunta, offrendo un tono distintivo controllato da un filtro passa-basso e un inviluppo ADSR, ideale per lead e pad lisci e caldi con un tocco di grana. SAWWAVE produce un’onda a dente di sega classica, nota per il suo contenuto armonico ricco e brillante, con un filtro passa-basso e un inviluppo ADSR che offrono controllo sul timbro e la dinamica, rendendolo versatile per lead, pad e linee di basso.

2.2.2 Dettagli dei Preset

  • Basso Mono, Batteria e Synth: attivando la divisione della tastiera, applicando un basso (spostamento di ottava -1) sulla sezione sinistra e un altro synth sulla sezione destra, è possibile suonare contemporaneamente un basso e un synth. L’impostazione mono sul lato sinistro consente di non preoccuparsi del rilascio del pedale sustain, permettendo al pianista di concentrarsi sul coordinamento del pedale solo con la mano destra. Aggiungendo una sequenza di batteria e mappando la frequenza di taglio del synth della mano destra con il guanto o il pedale, si crea un effetto molto interessante (dimostrazione video).
  • Configurazione simile al Theremin: attivando la mappatura del pitch bend del guanto per entrambi gli strumenti e collegando il controllo y del guanto alla frequenza di taglio del synth superiore e il pedale di controllo alla frequenza di taglio del synth inferiore (spostamento di ottava -1), si ottengono risultati unici (dimostrazione video).
  • Synth Profondo: utilizzando impostazioni simili al primo preset dell’elenco ma rimuovendo la divisione della tastiera, è possibile ottenere questo tipo di effetto.

Nota: la Divisione della Tastiera può essere attivata/disattivata come segue:

  • Cliccando sul pulsante 1 (in alto a sinistra sull’Arturia), viene attivata la modalità “selezione divisione”. In questa modalità, il sistema attende che venga premuto un tasto. Una volta fatto, quel tasto diventa il punto di divisione tra le sezioni sinistra e destra della tastiera.
  • Per rimuovere la divisione della tastiera, premere nuovamente il pulsante 1. Ora, entrambi gli strumenti suoneranno simultaneamente su tutta l’estensione della tastiera.

2.3 Dettagli di Implementazione

Per implementare il sistema, abbiamo mirato a separare le funzionalità in moduli e file distinti il più possibile. Questo approccio garantisce un funzionamento indipendente, migliorando la manutenibilità e la riutilizzabilità del codice. Come mostrato nel diagramma seguente:

  • Moduli Blu: gestiscono la sezione ritmica, trattando gli input MIDI, definendo i suoni da riprodurre e impostando le sequenze di percussioni.
  • Moduli Rossi: gestiscono la gestione delle note MIDI, inclusa l’elaborazione degli input delle note MIDI, la definizione dei suoni del synth e l’inoltro delle note al vocoder.
  • Sezioni Arancioni e Grigie: rappresentano la gestione delle manopole e dei preset. Quando un utente seleziona un nuovo preset, il modulo delle manopole aggiorna tutti i “valori delle manopole” (parametri di sistema), che si propagano a tutti gli altri moduli. Inoltre, il modulo delle manopole gestisce gli input MIDI CC.
  • Modulo Verde: modulo ArduinoAdapter, che riceve i valori di inclinazione della mano e li applica al sistema.
  • Modulo Rosa: modulo OSCCommunication, responsabile della ricezione degli input del mouse dell’utente e dell’aggiornamento della GUI per visualizzare lo stato del sistema sullo schermo.

Schema a Blocchi del Synth


2.4 Interazione con Accelerometro e Arduino

Per quanto riguarda l’implementazione del guanto, la gestione degli input è quasi interamente gestita in SuperCollider. Tuttavia, i dati ricevuti in SuperCollider non sono i dati grezzi a 3 assi dell’accelerometro. L’accelerometro rileva l’accelerazione lungo i tre assi cartesiani, mentre SuperCollider riceve l’accelerazione relativa all’orientamento della mano. Per eseguire questa conversione, abbiamo utilizzato formule tipicamente impiegate per la gestione dell’orientamento dei droni in volo (fonte).


2.5 Comunicazione tra SuperCollider e Processing

Processing crea un’interfaccia grafica (GUI) che consente agli utenti di controllare i parametri sonori, che vengono inviati a SuperCollider tramite il protocollo Open Sound Control (OSC). SuperCollider elabora questi input per produrre audio e può inviare aggiornamenti a Processing per regolazioni dinamiche della GUI. Questa interazione è illustrata nel diagramma seguente:

Diagramma di comunicazione

Di seguito, descriviamo i ruoli di SuperCollider e Processing nella gestione della GUI e nei loro metodi di comunicazione.

2.5.1 Processing

Processing genera la GUI, inclusi pulsanti, cursori e manopole per controllare parametri come volume, filtri passa-basso (LPF), selezione dello strumento, ottave, pedali di controllo e preset. Escludendo le funzioni di inizializzazione e supporto, il codice può essere raggruppato nelle seguenti sezioni principali:

  • Gestione della Comunicazione con SuperCollider:
    • Invio di Messaggi OSC: Il codice gestisce l’invio di messaggi OSC a SuperCollider per comunicare vari parametri. Le funzioni inviano i nomi degli strumenti selezionati, i parametri di controllo come lo stato mono, il volume, la frequenza del filtro passa-basso (LPF), il BPM, il volume del vocoder e lo stato della GUI del Vocoder. Inoltre, inviano le ottave selezionate e i valori dell’accelerometro.
    • Ricezione di Messaggi OSC: Quando vengono ricevuti messaggi OSC da SuperCollider, l’interfaccia grafica viene aggiornata di conseguenza. Ciò include l’aggiornamento di manopole, cursori ed etichette con i valori e gli stati di controllo ricevuti, come i pulsanti mono e GUI.
  • Gestione degli Input Utente: L’interfaccia grafica consente agli utenti di interagire con vari controlli. I pulsanti consentono di cambiare strumenti, ottave, impostazioni del pedale di controllo, accelerometri e preset. Ogni pulsante ha un listener che cambia il colore di sfondo e invia un messaggio OSC a SuperCollider. I cursori e le manopole consentono di regolare parametri come BPM, volume del vocoder, volume generale e frequenze del filtro, inviando i valori selezionati a SuperCollider quando vengono modificati.
  • Aggiornamento della GUI: Il codice aggiorna graficamente l’interfaccia utente in ogni frame, disegnando forme e loghi sulla finestra della GUI.

2.5.2 SuperCollider

In SuperCollider, possiamo suddividere la gestione della comunicazione nelle seguenti sezioni principali:

  • Ricezione di Messaggi OSC: Il codice gestisce la ricezione di messaggi OSC da Processing tramite OSCdef, che definisce vari gestori per elaborare i messaggi ricevuti. Questi gestori aggiornano le variabili corrispondenti in base ai messaggi ricevuti. Gestiscono diversi aspetti come la selezione dello strumento, il controllo mono, il volume, il filtro passa-basso, il BPM della sequenza di batteria, la selezione dell’ottava, la gestione del vocoder, la mappatura del pedale di controllo e del guanto, e la selezione dei preset.
  • Invio di Messaggi OSC: La funzione ~updateGUI invia messaggi OSC a Processing per mantenere aggiornata la GUI. Questa funzione invia informazioni sui volumi degli strumenti, le frequenze di taglio del filtro passa-basso, il preset selezionato, gli strumenti selezionati, lo stato mono, il BPM della sequenza di batteria, lo stato attuale del guanto, il volume del vocoder, lo stato dell’editor del vocoder, la mappatura del pedale di controllo e le ottave selezionate.
  • Routine di Aggiornamento della GUI: La ~guiRoutine assicura che la GUI sia sempre sincronizzata con gli stati attuali dei parametri eseguendo la funzione ~updateGUI ogni 0,1 secondi.

3. Modulo Chitarra

Questo modulo è stato implementato in SuperCollider. L’abbiamo chiamato “Chitarra” perché è così che lo abbiamo utilizzato, ma tecnicamente potrebbe essere utilizzato con qualsiasi segnale in ingresso da un microfono. Abbiamo prestato particolare attenzione alla scelta dell’interfaccia (MMA-A) per garantire una conversione stabile, e del microfono (4099), un supercardioide preciso, entrambi di DPA Microphones.

Interfaccia Chitarra

3.1 Gli Algoritmi

Un buon punto di partenza è stato lo studio dell’UGen SoundIn.ar e del codice trovato negli esempi inclusi nella documentazione di SuperCollider. Per il nostro scopo, abbiamo deciso di avere sempre un ingresso mono e un’uscita stereo (o almeno centrata).

3.1.1 Synth per Basso

L’utilizzo degli UGen Pitch.kr e Amplitude.ar, insieme a SoundIn, consente un tracciamento stabile del segnale in ingresso, che, assegnato come parametro di frequenza a un UGen come SinOsc.ar, genera a sua volta un’uscita stabile e controllabile. Inizialmente, suonando note singole, l’abbiamo accordato dritto (1.0) e per ottave (0.5 più basso, 2.0 più alto), ma abbiamo presto scoperto alcuni effetti interessanti:

  • I coefficienti utilizzati dovevano essere regolati con precisione per compensare la detonazione iniziale delle corde in gioco e il leggero ritardo dell’uscita. Suonando accidentalmente più di una nota, il pitch risultante veniva attribuito alla nota di volume più alto in esecuzione, consentendo così un ingresso polifonico.
  • Quest’ultimo ci ha dato l’idea di ridisegnare l’algoritmo per suonare una linea di basso sintetica insieme ad accordi puliti o arpeggi. L’accordatura dritta è stata regolata a un valore più efficace di 0.994, con l’ottava superiore a 1.985 e quella inferiore a 0.497. Formant.ar è stato sfruttato invece di SinOsc per un risultato più sintetico.
  • Per perfezionare il risultato del basso, abbiamo deciso di aggiungere un tempo di rilascio in Amplitude.ar e di aggiungere un filtro passa-basso dopo il SoundIn per il risultato trattato, da aggiungere all’uscita e bilanciare con accordi e arpeggi dall’ingresso.

3.1.2 Effetti Stereo per Chitarra

Gli effetti di pitch sul mercato (Cori, Flanger, Phaser) trattano invariabilmente l’intero segnale della chitarra, aggiungendo fangosità alle frequenze più basse. Avendo aggiunto il filtro passa-basso (LP) sull’ingresso, ne abbiamo invertito il risultato per presentare i registri bassi intatti al centro dell’uscita, e abbiamo aggiunto un filtro passa-alto (HP) per raccogliere il segnale (registri medi e alti), da detonare ciclicamente da sinistra a destra (L-R). LP e HP sono stati compensati in una configurazione quasi Linkwitz-Riley, per non sovrapporre le bande del segnale. Le detonazioni L-R sono state ottenute regolando due SinOsc ritardati con due argomenti “rate @~0.1” e “depth @~6”, come in questo esempio:

DelayN.ar(highSig, 0.5, SinOsc.kr((rate + 0.3)).exprange(depth*0.012, rate*0.030)*0.1);

Il risultato finale è un Chorus stereo (quasi un Flanger), con un registro basso fermo e pulito al centro dell’immagine. Infine, per la nostra demo, abbiamo implementato un’interfaccia di controllo in cui abbiamo assegnato i tre suoni necessari: Pulito, Chorus e (Pulito con) Basso.

Puoi trovare più info su GitHub.


Angelo Antona, 18 Ottobre 2025