Sviluppare un emulatore del Suzuki Omnichord (parte 2)
Nella prima parte di questa serie ho affrontato la scelta dello stack tecnologico e l'ottimizzazione della latenza.
L'obiettivo sarà quello di creare un emulatore del Suzuki Omnichord per la piattaforma Android.
In questa seconda parte vedremo come sono riuscito a "clonare" il caratteristico suono degli accordi dell'Omnichord.
Come già scritto in precedenza, questa serie di articoli non saranno dei tutorial, ma un'analisi sulle scelte progettuali e sulla risoluzione dei problemi trovati durante il percorso.
Sebbene questi campioni provenissero da modelli differenti, confrontandoli tra loro, penso di aver carpito le caratteristiche comuni che contraddistinguono questo strumento.
È doveroso ringraziare chi ha messo a disposizione gratuitamente questi campioni:
Matt Lim per l’OM-27 link github
Benjamin Dehli per l’OM-84 link github
Devo ammettere che inizialmente non avevo la minima idea su come ricreare questi suoni.
Avrei potuto far suonare i samples e quindi di fatto realizzare un grosso campionatore, ma ho voluto procedere diversamente per 2 motivi:
- l’obiettivo è vendere questa app sul Play Store, e non vorrei che la Suzuki mi facesse causa per l’utilizzo di materiale coperto da copyright;
- il mondo della sintesi sonora software è una per me una novità e mi piacerebbe provare.
Il suono degli accordi era quello che avevo sottovalutato di più e che invece mi ha dato tantissimo filo da torcere.
Partendo dal sample del Do Maggiore, ho provato ad analizzare le armoniche con il Frequency Spectrum Analyzer Meter di Reaper, e inizialmente tutto quello che vedevo era una matassa impossibile da sbrogliare.
Reaper non ha bisogno di presentazioni, ma per i pochi che non lo conoscono è una delle migliori DAW in circolazione.

Quindi, come direbbe il buon Ash Williams, ho provato a battere quell'ammucchiata di armoniche... con la scienza!
Primo tentativo: sintesi additiva
Il primo tentativo è stato quello di usare la Fast Fourier Transform per estrarre le informazioni sulle armoniche, per poi ricrearle con la sintesi additiva.Per la FFT ho utilizzato l’audio editor Audacity che include una comoda funzione che permette di effettuare l’analisi ed esportare un file txt contenente tutto lo spettro armonico.
Ottenuto questo txt, ho poi creato un parser con PHP per estrarre solo le frequenze di picco e creare una struttura dati di base che mi mettesse in relazione queste frequenze con il loro volume.
Sì, per questo tipo di operazioni poco critiche come piccoli parser mi avvalgo del tanto bistrattato PHP, che in questi casi risulta essere utilissimo.
Visto che sto sperimentando e ho bisogno di essere veloce, non ho subito implementato il tutto in C++, ma mi sono avvalso di un potente strumento messo a disposizione sempre su Reaper: ho creato uno script Jesusonic (JSFX) per leggere queste frequenze e sintetizzarle additivamente.
JSFX è un linguaggio di scripting meraviglioso creato dagli autori di Reaper che mi ha permesso di realizzare questi prototipi abbastanza facilmente.
L’approccio inizialmente ha funzionato, ma con diversi problemi.
Primo problema: il suono era troppo statico, poco vivo e privo di dinamicità.
Somigliava al suono di partenza, ma era come se fosse stato freezato.
Ho risolto in parte questo problema randomizzando la fase iniziale per ogni armonica, ma comunque non era sufficiente.
Secondo problema: il consumo di cpu altissimo.
Inizialmente stavo sintetizzando qualcosa come 300 armoniche, per ogni armonica la cpu deve processare una funzione coseno.
Quindi per ogni sample sono circa 300 funzioni coseno. Ogni secondo erano 48000 sample: ovvero circa 14.400.000 funzioni coseno al secondo.
La cosa non era chiaramente sostenibile. Ho provato a modificare il parser PHP per filtrare solo le armoniche al di sopra di una determinata soglia: con la soglia a -60db sono riuscito a ridurre il numero di armoniche a una 30ina.
Con 30 armoniche il suono c’era ancora ed era riconoscibile, ma a questo punto gli mancavano completamente le alte frequenze (dai 5000hz circa in su), e nonostante il numero di operazioni si fosse ridotto drasticamente, il consumo della cpu era ancora molto alto.
Poi mi sono reso conto che gli altri accordi dell’Omnichord non sono ottenuti da un accordo base pitchato in tonalità differenti, ma ogni accordo segue regole proprie e ha voicing differenti.
Avrei quindi dovuto estrarre le armoniche per tutte le 84 combinazioni di accordi ottenibili con l’omnichord, il che sarebbe stato folle, considerando che il risultato comunque non mi soddisfaceva molto.
Chiaramente non poteva essere questa la strada da intraprendere.
Il successo: modellazione sonora, soft clipping e sintesi sottrattiva
A questo punto, armato di Reaper e quella gemma sottovalutata chiamata ReaSynth, su 4 tracce differenti, ho provato a modellare il suono di ogni singola nota.Dopo giornate intere di tentativi falliti, sono riuscito finalmente a trovare una soddisfacente combinazione di forma d'onda / filtri.
Non scriverò qui la "ricetta", ma come qualcun altro ha già scritto su altri blog, il suono di partenza è l'onda quadra. Poi c'è una combinazione di filtri passa alto/basso per ottenere il suono finale.
Nel dominio digitale, quando si parla di onde quadre, bisogna cercare di tenere sotto controllo l'aliasing estremo che potrebbe crearsi.
Ho provato diversi approcci, evitando l'oversampling che potrebbe essere troppo oneroso per le limitate capacità di calcolo degli smartphone (almeno per il mio vecchio Samsung J6).
Alla fine ho sono riuscito a tenere a bada l'aliasing grazie al soft clipping. Non l'ho eliminato del tutto perchè, a giudicare dai sample che ho preso come riferimento, un po' di aliasing è presente anche nello strumento originale (dando per assunto che questo aliasing non sia stato creato dall'interfaccia audio in fase di registrazione).
Insomma sono riuscito ad ottenere un suono quasi indistinguibile dall’originale.
Armato di pazienza, sono riuscito a replicare i voicing di tutte e 84 le combinazioni di accordi ottenibili dall’OM-84.
A questo punto, ho dovuto traslare il tutto in C++, quindi ho dovuto scrivere la funzione che crea l’onda quadra soft-clippata partendo dall’LFO sinusoidale che avevo già scritto in precedenza, Low Pass Filter, High Pass Filter e infine tutta la logica che permette di combinare gli accordi per ottenere le famose 84 combinazioni.
Ho poi creato su Flutter un primissimo prototipo dell’interfaccia grafica, cioè i 36 tasti degli accordi. Bruttina e non definitiva, ma funzionale!
Per adesso tutto funziona a meraviglia. Il progetto inizia a prendere forma.

Nel terzo episodio parlerò del suono più caratteristico, quello per cui tutti si innamorano dell'Omnichord, cioè quello dello strum plate.
È stato inviato e sarà moderato prima della pubblicazione.