Amygdala Web

Riccardo Bazzoni - 04/02/2021
Amygdala Cover 3

Partendo dal progetto Amygdala, presentato nel 2016, abbiamo realizzato un prototipo per rendere accessibile il cuore dell'installazione attraverso una pagina web disponibile su Amygdala Web v0.1.

Uno dei motivi che ci ha spinto alla realizzazione di questo adattamento è stato il desiderio di creare un’esperienza che fosse fruibile da remoto e che l'utente potesse fare direttamente dal proprio browser. Un tentativo per creare un senso di interconnessione e superare le limitazioni imposte durante i periodi di lockdown causati dalla pandemia COVID-19 che hanno segnato la fase storica che stiamo attraversando.
Dal punto di vista tecnologico, abbiamo svolto alcune ricerche rispetto allo stato dell'arte per quanto riguarda lo sviluppo e l'integrazione di audio generativo all'interno del mondo web. Parallelamente, abbiamo inserito all'interno della pagina anche una parte grafica generativa che potesse in un qualche modo ricalcare le orme dell'installazione originale, seppur in maniera diversa.
La realizzazione di Amygdala Web si è sviluppata quindi in due fasi, rispettivamente di ricerca e di sviluppo.

Amygdala Web GIFT V3

RICERCA
In una prima fase di ricerca abbiamo studiato alcune tecnologie analizzando caratteristiche e criticità di frameworks e librerie in grado di creare contenuti audio, tra cui PureData, Max/MSP, Tone/Js, P5/Js. La scelta finale è stata Tone, un framework per la creazione di musica interattiva all’interno del browser. Tra tutte le tecnologie analizzate, questo framework è risultato essere il migliore per la sua flessibilità e funzionalità. Tone utilizza un sistema di programmazione avanzata, basata sull’API WEB Audio (sistema per il controllo dell’audio nel WEB) ed è in grado di creare suoni, effetti e astrazioni musicali complesse, sfruttando tutto il potenziale del linguaggio JavaScript.
Per la parte visiva (e in generale per la creazione della pagina web all'interno della quale gira il sistema) abbiamo scelto di usare la libreria javascript open source P5Js in quanto ambiente ideale per lo sviluppo di audio con ToneJS.
Infine abbiamo ricreato il motore di Amygdala partendo dall’algoritmo di sentiment analysis basato sulla libreria open source sviluppata da Uroš Krčadinac (An Open Source Library for Sentence-Based Emotion Recognition, IEEE Transactions on Affective Computing 4(3): 312-325, 2013), che ci permette di estrapolare il trend emotivo prevalente dai tweet che analizziamo. A questo abbiamo aggiunto l'analisi emozionale di notizie pubblicate sul web grazie al servizio GDelt che fornisce un tono emozionale (positivo o negativo) in base alle notizie pubblicate nel mondo in tempo reale.

Amygdala Web Cover 1920 CloseUP 2 0000703

AUDIO 
La parte audio di Amygdala Web si basa su un'idea di contrappunto libero, in cui quattro voci si intrecciano melodicamente e ritmicamente, muovendosi su progressioni di accordi che ne definiscono l’aspetto armonico e l’intervallo tra ogni voce, creando un flusso polifonico avvolgente e in continua trasformazione. Tutto il sistema audio è interamente realizzato con il framework ToneJs e viene generato in tempo reale, utilizzando i testi dei tweet e la loro analisi emotiva. I testi provenienti da Twitter vengono convertiti da formato ASCII in binario, creando sequenze numeriche in cui i valori uguali ad 1, corrispondono all’esecuzione di note, mentre i valori uguali a 0, corrispondono a pause.

TWEET TEXT: Amygdala 
ASCII: 97 109 121 103 100 97 108 97 10
Binary: 1 1 0 0 0 0 1 1 1 0 1 1 0 1 1 1 1 1 0 0 1 1 1 0 0 1 1 1 1 1 0 0 1 0 0 ...

Le note vengono estratte e ricavate da gruppi di accordi estesi oltre la forma di triade, estrapolati da intervalli che costituiscono la struttura di scale e modi musicali.

Amygdala Web Cover Grid Music 02 1920 Bianco 2


Creazione e lettura array accordi

var note = [0, 2, 4, 5, 7, 9, 11, 12]; //Ionian or Major
var chordNotes = [0, 2, 4, 5, 7, 9, 11, 12, 14, 16, 17, 19, 21, 23, 24, 26, 28, 29, 31, 33, 35, 36];
var firstVoice = note[grado];
var secondVoice = chordNotes[grado + 2];
var threeVoice = chordNotes[grado + 4]; 
var fourVoice = chordNotes[grado + 6]; 
var fiveVoice = chordNotes[grado + 8]; 
var sixVoice = chordNotes[grado + 12]; 
chord = [tone + firstVoice, tone + secondVoice, tone + threeVoice, tone + fourVoice]; 
var gradoProgression = [0, 3, 4];  let noteVoiceOne = chord[Math.floor(Math.random() * chord.length)];
var midiToFreq = Tone.Frequency(noteVoiceOne, "midi").transpose(transposition + 24); 

Utilizzando il sistema di Sentiment Analysis le emozioni vengono associate a una scala o ad un modo musicale per esprimere una sensazione emotiva, sfruttando l’intrinseca natura espressiva data dalla loro struttura intervallare.


Scale, Modi & Emozioni

Amygdala Web Cover Grid Music 1921 Bianco 608

Per quanto riguarda l’aspetto timbrico, ogni voce è costituita da un oscillatore che emette una semplice onda triangolare. Ogni oscillatore ha un suo generatore di inviluppo che varia in maniera aleatoria i valori ADSR per differenziare nel tempo la struttura del suono. Sono presenti anche alcuni campionatori granulari che manipolano suoni, creando micro loop e rumori, intonando il loro pitch sulle note in esecuzione. Per differenziare ed enfatizzare maggiormente l’aspetto di “indipendenza” ogni strumento ha un suo tempo di lettura, innescando così parametri casuali che modellano suono, effetti sonori e variano l’aspetto esecutivo.

Inizializzazione Synth

oscVoice1 = new Tone.Synth().connect(pingPongVoice1).connect(pannerVoice1).connect(meter);
oscVoice1.oscillator.type = 'triangle';
oscVoice1.volume.value = -20;
oscVoice1.toMaster();

 
Inizializzazione campionatore granulare

grain1 = new Tone.GrainPlayer("./FluteC.mp3").connect(pingPongVoice1).connect(pannerGrain1).connect(meter);
Tone.Buffer.on('load', function() {
grain1.start();
});
grain1.loop = true;
grain1.overlap = 0.1;
grain1.playbackRate = 0.1;
grain1.volume.value = -10;
grain1.toMaster();


Trigger Eventi

function repeatVoice1(time) {
var timeInt = Math.floor(time);
readNote = (timeInt % binaryText.length);
var binary = binaryText[readNote];
if (binary == 1) {
let noteVoiceOne = chord[Math.floor(Math.random() * chord.length)];
var midiToFreq = Tone.Frequency(noteVoiceOne, "midi").transpose(transposition + 24);
oscVoice1.triggerAttackRelease(midiToFreq, 10 + Math.floor(Math.random() * 100));
oscVoice1.envelope.attack = 5 + (Math.floor(Math.random() * 1000) / 100.);
oscVoice1.envelope.decay = 0.1 + (Math.floor(Math.random() * 100) / 100.);
oscVoice1.envelope.sustain = 0.1;
oscVoice1.envelope.release = 2;
pingPongVoice1.delayTime.value = 1 + Math.floor(Math.random() * 2000);
}
}

 

VISUAL
L'immaginario visivo è legato ad un'idea di memoria e tempo: solchi grafici vengono impressi sullo schermo, cambiando aspetto e colore, sulla base delle variazioni emotive nel mondo. Con il passare del tempo le scie passate si allontanano da noi, dissolvendosi e lasciando spazio a nuovi tracciati che descrivono il presente.
Tecnicamente la generazione dei percorsi avviene sovrascrivendo nel tempo una texture attraverso flussi di particelle che, seguendo un campo vettoriale in continua mutazione, vanno a disegnare delle scie. Periodicamente al contenuto della texture viene applicato un blur e un'attenuazione sul canale alpha in modo da creare un effetto di dissolvenza nel tempo. Nel frattempo continuano a nascere nuovi tracciati più netti e definiti ad indicare la freschezza di quelle emozioni.

Amygdala Web Cover Grid 960 Campo Vettoriale Bianco 0000824

Il colore utilizzato è in relazione alle emozioni estratte dai tweet, ogni emozione genera un colore, visualizzando così le variazioni emotive e mantenendo il loro “ricordo” che sfuma e si disperde lentamente nel tempo.

Amygdala Web Cover Grid 1920 Texture Bianco 0000815

Gestione colore particelle

var totalEmotion = emotionFactor[6]*100.0;
var percentageID = float(particleId%totalEmotion)/float(totalEmotion);
if
(percentageID < emotionFactor[0]){
stroke(col[0] - 47 , col[1] - 79, col[2] - 252, this.alpha * particleColor); //Happiness
}else if
(percentageID < emotionFactor[0]+emotionFactor[1]){
stroke(col[0] - 81, col[1] - 30, col[2] - 57, this.alpha*particleColor ); //Sadness
}else if
(percentageID < emotionFactor[0]+emotionFactor[1]+emotionFactor[2]){
stroke(col[0] - 106, col[1] - 219, col[2] - 230,this.alpha * particleColor ); //Fear
}else if
(percentageID < emotionFactor[0]+emotionFactor[1]+emotionFactor[2]+emotionFactor[3]){
stroke(col[0] - 187, col[1] - 94, col[2] - 113,this.alpha * particleColor ); //Anger
}else if
(percentageID<emotionFactor[0]+emotionFactor[1]+emotionFactor[2]+emotionFactor[3]+emotionFactor[4]){
stroke(col[0] - 55, col[1] - 240, col[2] - 119, this.alpha * particleColor );//Disgust
}else{
stroke(col[0] - 248, col[1] - 156, col[2] - 181,this.alpha * particleColor); //Surprise
}
strokeWeight(particleStroke * this.stroke );
line(this.pos.x, this.pos.y, this.prevPos.x, this.prevPos.y);
this.updatePrev();

API
Per la ricezione dei Tweet e l'estrazione dell'emozione predominante abbiamo creato un web service che mette a disposizione delle APIs (Application Programming Interface). Nello specifico, il server interroga le API di Twitter per ricevere parte dei tweets che vengono pubblicati nel mondo in ogni momento, vi applica l'algoritmo di Sentiment Analysis e infine traduce questi dati in visualizzazioni grafiche attraverso un'API sviluppata ad-hoc.