55
WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria informatica Modulo M00002 Progetto di diploma Anno 2018 Data 11 dicembre 2018

WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

WebSocket Symphony Orchestra

Studente/i

Stefano Motti

Relatore

Nicola Rizzo

Correlatore

Giancarlo Corti

Committente

Nicola Rizzo

Corso di laurea

Ingegneria informatica

Modulo

M00002 Progetto di diploma

Anno

2018

Data

11 dicembre 2018

Page 2: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria
Page 3: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

i

Indice

Abstract 1

Progetto Assegnato 3

Introduzione 5

1 Stato dell’arte 7

2 Struttura generale 9

2.1 Producer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.2 Dispatcher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.3 Consumer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

3 Metodologia di sviluppo 13

4 Producer 15

4.1 Connessione al dispatcher . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

4.1.1 Gestione touch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

4.2 Produzione singola nota . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

4.2.1 Stato della connessione con il server . . . . . . . . . . . . . . . . . . . 18

4.3 Selezione nota musicale e strumento . . . . . . . . . . . . . . . . . . . . . . 19

4.3.1 Stabilire connessione . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

4.3.2 Selezionare nota . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

4.3.3 Selezionare strumento . . . . . . . . . . . . . . . . . . . . . . . . . . 20

4.3.4 Controllo lunghezza nota con touch . . . . . . . . . . . . . . . . . . . 20

4.3.5 Sensore di prossimità . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

4.4 Produzione di una melodia . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

4.4.1 IP server dinamico . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

4.4.2 Nuovo protocollo di comunicazione . . . . . . . . . . . . . . . . . . . . 24

4.5 Polifonia 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

4.5.1 Produzione melodia nota per nota . . . . . . . . . . . . . . . . . . . . 25

4.5.2 CarillonSocket con canone . . . . . . . . . . . . . . . . . . . . . . . . 26

WebSocket Symphony Orchestra

Page 4: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

ii INDICE

4.5.3 Costruzione di un ID univoco . . . . . . . . . . . . . . . . . . . . . . . 26

4.5.4 Feedback dal consumer . . . . . . . . . . . . . . . . . . . . . . . . . . 27

4.6 Polifonia 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

5 Dispatcher 29

5.1 Connessione con producer(s) . . . . . . . . . . . . . . . . . . . . . . . . . . 29

5.1.1 DispatcherLogger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

5.1.2 Classe WebSocketServer . . . . . . . . . . . . . . . . . . . . . . . . . 32

5.2 Comunicazione verso il consumer . . . . . . . . . . . . . . . . . . . . . . . . 33

5.2.1 Tabella dei producer collegati . . . . . . . . . . . . . . . . . . . . . . . 33

5.3 Comunicazione nota, strumento o comando . . . . . . . . . . . . . . . . . . . 34

5.4 Comunicazione melodia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

5.4.1 DispatcherEmitter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

5.4.2 ConsumerEmitter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36

5.4.3 Comunicazione indirizzo IP al producer . . . . . . . . . . . . . . . . . 36

5.5 Comunicazione polifonia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

5.5.1 Comunicazione preloading . . . . . . . . . . . . . . . . . . . . . . . . 37

5.6 Deploy dispatcher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

6 Consumer 39

6.1 Introduzione a Tone.js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39

6.2 Riproduzione di una nota . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

6.2.1 Riproduzione nota nel consumer . . . . . . . . . . . . . . . . . . . . . 41

6.2.2 Visualizzazione stato della connessione con il dispatcher . . . . . . . . 41

6.2.3 Visualizzazione operazioni del consumer . . . . . . . . . . . . . . . . 42

6.3 Riproduzione nota con strumento selezionato . . . . . . . . . . . . . . . . . . 42

6.3.1 Selezione nota . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

6.3.2 Selezione strumento . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

6.4 Riproduzione melodia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

6.4.1 Riproduzione singola nota . . . . . . . . . . . . . . . . . . . . . . . . 45

6.4.2 Mappatura note e strumenti . . . . . . . . . . . . . . . . . . . . . . . . 45

6.5 Riproduzione polifonia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

6.6 Deploy consumer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

7 Conclusioni 47

WebSocket Symphony Orchestra

Page 5: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

iii

Elenco delle figure

2.1 Architettura del progetto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

3.1 Processo di sviluppo software SCRUM . . . . . . . . . . . . . . . . . . . . . 13

4.1 Layout producer prodotto dall’IDE Android Studio . . . . . . . . . . . . . . . . 15

4.2 Panoramica SocketClient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

4.3 Codice che gestisce i tentativi di connessione . . . . . . . . . . . . . . . . . . 18

4.4 Codice che gestisce gli eventi del sensore di prossimità . . . . . . . . . . . . 21

4.5 Spartito Fra Martino . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

4.6 Estratto dello spartito dell’Aria sulla quarta corda . . . . . . . . . . . . . . . . 27

5.1 Prima implementazione della classe ListenerServer . . . . . . . . . . . . . . 30

5.2 Prima implementazione del DispatcherLogger . . . . . . . . . . . . . . . . . . 31

5.3 Costruzione del SocketIOServer . . . . . . . . . . . . . . . . . . . . . . . . . 32

5.4 Metodo in WebSocketServer che comunica con il dispatcherLogger . . . . . . 32

5.5 Tabella che rappresenta i producer connessi . . . . . . . . . . . . . . . . . . 33

6.1 Meotodo che riproduce la nota . . . . . . . . . . . . . . . . . . . . . . . . . . 41

6.2 Logica del bottone che mostra lo stato della connessione tra consumer e

dispatcher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

6.3 Metodo che riproduce la nota . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

6.4 Metodo che riproduce una melodia . . . . . . . . . . . . . . . . . . . . . . . . 44

WebSocket Symphony Orchestra

Page 6: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

iv ELENCO DELLE FIGURE

WebSocket Symphony Orchestra

Page 7: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

1

Abstract

Il progetto presenta un architettura divisa in tre componenti principali, ognuno dei quali ha

un compito preciso all’interno del ciclo di vita dell’applicazione. L’utente utilizzando un’ap-

plicazione android per smartphone è in grado di produrre delle note musicali utilizzando il

touchscreen del device oppure il sensore di prossimità. Inoltre è in grado di produrre due

melodie: Fra Martino e l’Aria sulla quarta corda di Bach. Le note vengono trasmesse ad un

server centrale con il protocollo socket e dal server sono trasmesse ad una pagina web tra-

mite protocollo websocket. Nella pagina web le note sono riprodotte in tempo reale rispetto

alle azioni che l’utente compie sul suo smartphone. Il sistema supporta la connessione di

più dispositivi che producono note, in questo mdo si può ottenere l’effetto di un orchestra

dove gli strumenti sono dei device collegati alla rete locale.

WebSocket Symphony Orchestra

Page 8: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

2 Abstract

WebSocket Symphony Orchestra

Page 9: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

3

Progetto Assegnato

Descrizione

Il progetto prevede la scrittura di un server che, ricevuti in ingresso alcuni parametri distintivi,

permetta ai client connessi di richiedere l’esecuzione di note musicali specifiche.

I client potranno essere dispositivi mobili, tablet o altri oggetti in grado di connettersi al server

usando il protocollo websocket e potranno usare tutti i sensori disponibili (prossimità, tocco,

accelerometri...) per decidere quando effettuare le richieste.

Le note verranno eseguite, almeno in un primo momento, utilizzando le tecnologie web

disponibili nei browser di ultima generazione (Web Audio)

Compiti

Lo studente dovrà occuparsi della scrittura del server, dell’esecutore vero e proprio di suoni

e di almeno un client che faccia da strumento musicale.

La comunicazione sarà bidirezionale in modo da permettere l’esecuzione automatica in mo-

dalità "rullo di piano", con dei feedback anche sul client (per esempio in caso di tastiera

virtuale, i tasti dovranno apparire premuti nel momento dell’esecuzione)

Obbiettivi

Ottenere il sistema descritto in modo tale che la latenza sia tanto bassa in modo da permet-

tere l’esecuzione di almeno un motivo elementare.

Il server dovrà inoltre permettere l’esecuzione contemporanea di più note e quindi di polifo-

nia

WebSocket Symphony Orchestra

Page 10: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

4 Progetto Assegnato

WebSocket Symphony Orchestra

Page 11: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

5

Introduzione

Nel primo capitolo si fa un introduzione sulle tecnologie presenti al giorno d’oggi che pos-

sono essere utilizzate all’interno del progetto. Si analizzano le applicazioni che riproducono

canzoni e musica più in generale, si passa attraverso applicazioni web che permettono di

comporre melodie nota per nota fino ad arrivare a parlare degli strumenti di più basso livello

che permettono di riprodurre suoni. Infine viene definito il concetto di realtime che il progetto

deve rispettare e vengono analizzate, anche in questo caso, le tecnologie già presenti e che

probabilmente verranno utilizzate.

Nel secondo capitolo viene presentata la struttura generale del progetto, esso si svilup-

perà diviso in tre componenti principali: un producer che, usato dall’utente, ha il compito di

produrre note musicali e melodie. Un dispatcher che rappresenta l’elemento centrale dell’ar-

chitettura, quello che mette in comunicazione producer e consumer. E infine un consumer

che il componente che riproduce i suoni.

Nel terzo capitolo viene spiegata la metodologia scrum come metodologia per sviluppare il

progetto. Si presentano le caratteristiche principali e i punti forte che fanno preferire questa

ad altre metodologie.

Nel quarto capitolo si parla più nello specifico del componente producer. Si analizzano

tutte le funzionalità implementate durante lo sviluppo del software in ordine cronologico e le

classi, i metodi e i meccanismi creati per raggiungere tali funzionalità.

Nel quinto capitolo viene trattato lo sviluppo del componente dispatcher. Come nel caso del

producer vengono analizzate le funzionalità raggiunte durante lo sviluppo software in ordine

cronologico ponendo una particolare attenzione alle classi, ai metodi e ai meccanismi che

sono stati adoperati per raggiungere tali funzionalità.

Nel sesto capitolo l’attenzione si sposta sull’ultimo componente rimasto, il consumer. Ana-

logamente ai componenti precedenti si sono analizzate le funzionalità che sono state imple-

mentate e le funzioni più importanti. Si spiega anche la struttura messa in piedi per gestire

le dipendenze all’interno del componente.

Nell’ultimo capitolo vengono esposti i risultati ottenuti e vengono trattate le conclusioni

riguardo al progetto.

WebSocket Symphony Orchestra

Page 12: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

6 Introduzione

WebSocket Symphony Orchestra

Page 13: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

7

Capitolo 1

Stato dell’arte

Al giorno d’oggi, nel web si trovano molte applicazioni che permettono di produrre e riprodur-

re musica in generale, nel particolare queste danno la possibilità all’utente sia di riprodurre

canzoni o melodie intere, sia di produrre una singola nota, sia di comporre una propria me-

lodia nota per nota. Le maggiori applicazioni che danno la possibilità di ascoltare intere

melodie (Spotify, Google Play Music e Youtube in primis) prima di riprodurle devono scari-

care megabyte di dati. Approfondendo, invece, il tema di produrre note o melodie nel web si

trovano diversi strumenti che permettono di comporre melodie e che mettono a disposizione

strumenti ed effetti per ogni genere e gusto (Caustic 3 e GarageBand per citare i più famosi).

Queste sì permettono di produrre musica ma ad alto livello, e si tratta di applicazioni che

producono e riproducono note solo al proprio interno: cioè non usano un riproduttore ester-

no e non hanno bisogno del web per svolgere il proprio compito. Continuando la ricerca

di strumenti che permettano di produrre note musicali si trovano le cosiddette "Web Audio

API"; queste sono state concepite con lo scopo di colmare il vuoto che solo parzialmente

ha riempito il tag HTML <audio> grazie al quale si ha la possibilità di riprodurre un audio in

streaming o in locale. Le Web Audio API sono relativamente giovani nel web: la prima rac-

comandazione a riguardo, scritta dal W3C (World Wide Web Consortium), è datata 20111

ma è solo dal 2015 che tutti i browser le supportano2. Nello specifico le Web Audio API

sono delle Application Programming Interface JavaScript di basso livello per l’elaborazione

e la sintetizzazione di file audio in applicazioni web. Queste API permettono di manipolare

file audio esistenti o qualsiasi sorgente sonora e di produrre un suono da zero. Per fare

ciò utilizzano degli oggetti detti "AudioNode" che sono utilizzati principalmente per tre scopi:

produrre, filtrare o riprodurre un suono; questi AudioNode possono essere combinati in qual-

siasi modo per ottenere il risultato desiderato. Nel caso del progetto "Websocket Symphony

Orchestra" non è stato necessario utilizzare delle API di così basso livello ma si è optato

per un framework come Tone.js3 che fornisce funzionalità di scheduling avanzato, sintetiz-

1https://www.w3.org/TR/webaudio/2https://caniuse.com/#searchw̄eb%20audio3https://github.com/Tonejs/Tone.js

WebSocket Symphony Orchestra

Page 14: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

8 Stato dell’arte

zatori e effetti, e astrazioni musicali intuitive basate sulle Web Audio API. Questa scelta è

stata fatta anche perché la sua architettura è pensata per essere familiare sia ai musicisti

che ai programmatori audio. Tone.js offre funzioni DAW (Digital Audio Workstation) comu-

ni come un trasporto globale per lo scheduling di eventi, sintetizzatori e effetti predefiniti;

per i programmatori offre invece blocchi ad alte prestazioni e bassa latenza, e moduli DSP

per la costruzione di propri sintetizzatori, effetti o segnali di controllo complessi. Oltre alla

produzione di suoni il progetto prevede che un sistema distribuito lavori in realtime: cioè

che un componente qualsiasi dell’applicazione risponda agli eventi creati dagli altri appena

l’evento è scatenato. In questo caso quando l’utente produce una nota con un device la

nota è riprodotta immediatamente dal riproduttore collegato. Qualcosa di simile è stato fatto

in alcuni giochi per console come "Guitar Hero" in cui il giocatore utilizzava un joystick a

forma di chitarra e il suo scopo era schiacciare il pulsante giusto nel momento giusto per

suonare correttamente la canzone. La limitazione con questo strumento è lo scarso numero

di note (massimo 5) e strumenti (è stata prodotta un’altra versione che permette di usare

una batteria) a disposizione. Quindi per ottenere l’effetto di realtime nel nostro sistema si ha

bisogno di mezzi di comunicazione che assicurino bassa latenza e alte prestazioni. In que-

sta direzione si muove il protocollo di comunicazione Websocket, protocollo standardizzato

dall’IETF come RFC64554 e le sua API sono standardizzate dal consorzio W3C. Questa

tecnologia web fornisce canali di comunicazione full-duplex attraverso un singola connes-

sione con protocollo TCP (Trasmission Control Protocol): ciò significa che posso stabilire tra

due macchine una connessione tramite un singolo canale di comunicazione e che attraver-

so quest’ultimo si può comunicare in entrambe le direzioni con la sicurezza che i dati inviati

siano consegnati integralmente grazie al protocollo TCP. All’interno di questo contesto ho

scelto "Websocket Symphony Orchestra" come lavoro di tesi perché si tratta di un progetto

che parla di musica, argomento del quale sono molto appassionato e che vivo quotidiana-

mente come semplice ascoltatore, e comunicazione realtime nel web, un argomento che

associato alla musica mi ha affascinato per le potenzialità che potrebbero essere scoperte.

4https://it.wikipedia.org/wiki/WebSocket

WebSocket Symphony Orchestra

Page 15: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

9

Capitolo 2

Struttura generale

Il progetto sin dall’inizio è stato suddiviso in tre parti indipendenti l’una dall’altra: così facen-

do la progettazione è avanzata parallelamente su tutte e tre le parti. La struttura prende

spunto dal Producer-Consumer pattern. Quest’ultimo descrive un’architettura nella quale

troviamo a monte un "producer", il quale ha il compito di produrre dati, nel mezzo un buffer,

nel quale vengono depositati i dati in attesa di essere processati, e a valle un "consumer", il

quale deve processare i dati contenuti nel buffer. Come è facile intuire in questa architettura

posso avere un numero indefinito di producer, con l’unica condizione di non produrre dati se

il buffer è pieno, e un numero indefinito di consumer, con la condizione che non richiedano

dati se il buffer è vuoto. Da questa struttura base si è costruita l’architettura del progetto:

come producer si è creata un’applicazione android che fosse in grado di collegarsi ad un

server e comunicare i dati che è capace di produrre; come consumer si è creata una pagina

web in grado di processare i dati in arrivo. Al posto di avere un buffer che immagazzina dati

troviamo un server che ha il solo compito di trasmettere i dati in arrivo dal/i producer verso

il/i consumer collegati.

Figura 2.1: Architettura del progetto

WebSocket Symphony Orchestra

Page 16: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

10 Struttura generale

2.1 Producer

Nello sviluppo del progetto è stato necessario sviluppare un’applicazione android che fun-

gesse da producer. Ma andando con ordine elenchiamo le funzionalità che ha questa

applicazione:

• stabilire un collegamento con il server/dispatcher

• produrre dei dati ricavandoli dai sensori presenti (touch, prossimità, accelerometro,

...)

• produrre un motivetto elementare come un "rullo di piano"

• inviare i dati secondo un protocollo leggibile al consumer

Ottenute queste funzionalità all’interno della architettura completa non c’è nessuna differen-

za tra un’applicazione android o ios o di qualsiasi altro sistema operativo per device mobili.

Si parla di device mobili e non solo di smartphone perché anche, per esempio, i tablet ri-

spondono ai requisiti richiesti. Ho scelto di sviluppare su android per un semplice motivo,

perché possiedo uno smartphone android e ho potuto utilizzarlo sin da subito, e sempre,

per testare il funzionamento dell’applicazione descritta.

2.2 Dispatcher

Il dispatcher è l’elemento centrale in questa architettura e ad esso sono richieste queste

funzionalità:

• supportare la connessione di più producer

• inoltrare i dati verso il/i consumer

• avere una bassa latenza nell’inoltrare i dati

• registrare le operazioni che svolge

Anche se mette in collegamento producer e consumer è indipendente dalle altre compo-

nenti: i messaggi che arrivano dal producer sono mostrati all’utente nella pagina di log delle

operazioni e inoltrati al consumer che esegue le operazioni scritte nel messaggio. Il dispat-

cher in realtà non si interessa dei dati che riceve e inoltra, ma si interessa di garantire le

massime performance nel sistema.

2.3 Consumer

Il consumer è la parte finale dell’architettura ed è quella che ci fa apprezzare il lavoro svolto

dalle altre componenti; da esso ci si aspetta la seguente funzionalità:

WebSocket Symphony Orchestra

Page 17: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

11

• eseguire le operazioni secondo il tipo di dato ricevuto

Questo componente è relativamente semplice: il suo compito è di processare i dati che gli

vengono inviati dal dispatcher. In pratica a seconda del messaggio che riceve deve essere

in grado di riprodurre delle note musicali.

WebSocket Symphony Orchestra

Page 18: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

12 Struttura generale

WebSocket Symphony Orchestra

Page 19: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

13

Capitolo 3

Metodologia di sviluppo

Figura 3.1: Processo di sviluppo software SCRUM

Come metodologia di lavoro è stato usato il modello agile SCRUM. Questo permette di ge-

stire il ciclo di sviluppo del software in modo iterativo e incrementale. Così facendo un ciclo

di lavoro dura un periodo di tempo fissato che può variare da 1 settimana fino a un mese.

Questo ciclo è chiamato sprint. In questo progetto si è deciso che la durata di uno sprint

fosse di 2 settimane. Durante questo periodo gli sviluppatori implementano una o più fun-

zionalità utente, o anche user story, in modo da ottenere entro fine sprint una versione del

software potenzialmente completa e funzionante. Ogni user story ha un valore definito in

termini di story points che è deciso dal gruppo di lavoro, o team: gli story points rappre-

sentano la valutazione del tempo che, in teoria, uno sviluppatore impeiega per risolvere il

problema in relazione alla sua complessità. Inizialmente è impossibile dare una valutazione

precisa in questi termini perché ogni sviluppatore ha le proprie capacità, però già dopo i pri-

mi sprint il processo di valutazione diventa più preciso. Tutte le user story individuate sono

messe in un "contenitore", o product backlog, dal quale ad ogni sprint sono estratte e mes-

WebSocket Symphony Orchestra

Page 20: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

14 Metodologia di sviluppo

se nello sprint backlog. Qui le user story sono suddivise ulteriormente in feature, e queste

in semplici toDo; questo modus operandi aiuta gli sviluppatori a realizzare (relativamente)

piccole porzioni di codice che messe insieme creano un software funzionate. Per mettere in

pratica questa metodologia è stata utilizzata la piattaforma di TI-EDU SCM, o Source code

management, nella quale è possibile impostare le caratteristiche del modello agile come la

durata degli sprint, definire il contenuto di product backlog e configurare il contenuto degli

sprint.

WebSocket Symphony Orchestra

Page 21: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

15

Capitolo 4

Producer

Dopo aver introdotto la struttura del progetto in generale, ora si entra più nel dettaglio

analizzando le singole componenti per funzionalità acquisite durante l’implementazione del

componente.

Il compito principale di questo componente è quello di produrre delle note musicali, o me-

glio è quello di produrre dei messaggi che interpretati dal consumer riproducano delle note

musicali.

4.1 Connessione al dispatcher

La prima funzionalità implementata è stata quella di poter stabilire una connessione tra

producer e dispatcher. Per fare ciò innanzitutto è stato necessario creare un’applicazione

android basilare. Questa prima versione divideva lo schermo in due parti distinte:

• PARTE SUPERIORE, che è la parte interattiva dell’applicazione

• PARTE INFERIORE, che è la parte in cui visualizzare il log delle operazioni

Figura 4.1: Layout producer prodotto dall’IDE Android Studio

Per creare una connessione tra producer e dispather si è usata la classe "Socket", classe

messa a disposizione da java nel package "java.net". Prima di parlare di implementazione

WebSocket Symphony Orchestra

Page 22: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

16 Producer

bisogna tenere conto che un socket è fondamentalmente una coppia di numeri che rap-

presentano le porte attraverso le quali due computer, che hanno i ruoli di client e server

(rispettivamente producer e dispatcher), comunicano. Per poter stabilire questa connes-

sione è necessario che il client conosca l’indirizzo IP1 del server e la porta2. In questo

momento dell’implementazione queste informazioni sono state scritte direttamente nel co-

dice sorgente ma è una scelta non funzionale perché ogni volta che si cambia rete bisogna

cambiare l’indirizzo IP. La porta del server che si è scelto usare per comunicare è la 9999,

mentre la porta del producer è scelta in modo automatico dal sistema operativo tra quel-

le disponibili al momento. Per utilizzare la connessione e contemporaneamente interagire

con l’applicazione è necessario utilizzare una classe che ha il compito di far comunicare il

client e il server e che non processi sul thread principale. Questa classe è stata chiama-

ta SocketClient ed estende AsyncTask<>. AsyncTask è un classe ausiliaria della classe

Thread che mette a disposizione android nel suo package android.os. Questa permette di

eseguire operazioni in background, cioè non sul thread della User Interface (UI), e pubbli-

care i propri risultati sulla UI senza doversi preoccupare di sincronizzazione o altri problemi

di programmazione multithreading. Estendendo questa classe si deve sovrascrivere il me-

todo doInBackground() nel quale si trova il codice che esegue il thread. L’altro metodo

sovrascritto è onProgressUpdate() il quale è l’unico modo per interagire con la UI, cioè

pubblicare i log delle operazioni svolte.

Figura 4.2: Panoramica SocketClient

A livello pratico il thread stabilisce la connessione (socket.connect()), iniziallizza i buffer

che il socket usa per leggere i messaggi dal server (BufferedReader in) e scrivere i messag-

gi per il server (PrintWriter out). Dopodiché legge il messaggio di benvenuto del server (in

questo modo si verifica che la connessione è avvenuta con successo) e inizia il ciclo while

1Etichetta numerica che identifica univocamente un dispositivo collegato a una rete informatica2Numero da 0 a 65535 che identifica la porta su cui è in ascolto il server. I valori da 0 a 1024 sono riservati

e non utilizzabili

WebSocket Symphony Orchestra

Page 23: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

17

(while (!closed && message != null)) responsabile della comunicazione da client verso

server. Questo ciclo ha come parametri di controllo una variabile booleana che permette

di interrompere dalla UI e una condizione sulla stringa che deve mandare al server. Ogni

volta che si modifica questa stringa (sempre dalla UI) l’istanza della classe SocketClient

invia il messaggio al server. Quando l’applicazione termina l’esecuzione o l’utente decide

di sospendere la connessione l’istanza comunica al server che ha terminato l’esecuzione

(out.println(getTimeStamp() + "Background thread finished!")) e chiude il socket. In

questo momento dello sviluppo software la connessione viene aperta al momento dell’aper-

tura dell’applicazione stessa. Questo modo di procedere non è ottimale ma verrà modificato

nelle prossime iterazioni.

4.1.1 Gestione touch

Raggiunto questo punto è stata implementata la "callback" onTouchEvent, ovvero quel me-

todo che viene chiamato dal sistema operativo quando un determinato evento si è verificato.

Questa callback accetta come parametro un oggetto di tipo "MotionEvent" il quale contiene

tutte le caratteristiche del tocco sul schermo del device. Si deve tenere presente che ogni

volta che si tocca lo schermo di un qualsiasi device android non vengono prodotti, come

si potrebbe pensare semplicemente, solo gli eventi di inizio_tocco e fine_tocco, ma molti

altri eventi che inconsapevolmente produce l’utente al momento del tocco. Bisogna tenere

conto che lo schermo dei dispositivi odierni ha milioni di pixel e che nel momento in cui si

tocca lo schermo stesso si stanno toccando molti più pixel che uno solo. Inoltre con un

normale tocco vengono prodotti oltre agli eventi di inizio e fine, anche eventi che rappresen-

tano lo scorrimento del dito su più pixel; questo è molto utile nel caso in cui l’applicazione

deve saper riconoscere dei movimenti preimpostati (le cosiddette "gesture") per reagire di

conseguenza, come nel caso di giochi che associano a dei movimenti delle determinate

azioni. Ma questo non rappresenta la nostra situazione e quindi ci si è limitati a gestire

gli eventi ACTION_DOWN e ACTION_UP: questi rappresentano gli eventi che corrispondo al

momento in cui comincio a toccare lo schermo (ACTION_DOWN) e al momento in cui smetto

di toccarlo (ACTION_UP). A questo punto dell’implementazione, agli eventi appena descritti

l’applicazione eseguiva semplicemente dei log nella textview3 in modo da poter verificare

che fossero gestiti correttamente. La textview occupa la PARTE INFERIORE dello schermo e

si può riconoscerla sia dal titolo che dal colore di sfondo (giallo) che è stato utilizzato.

4.2 Produzione singola nota

Durante il secondo sprint è stato scelto di implementare la funzionalità di produrre una nota

utilizzando il sensore touch del device. Per fare ciò la callback che gestisce il tocco sullo

schermo è stata modificata per produrre il messaggio "L’utente ha toccato il dispositivo!!".3elemento del layout android predisposto a mostrare testo modificabile

WebSocket Symphony Orchestra

Page 24: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

18 Producer

Questo messaggio viene settato in un campo dell’istanza di SocketClient che sta eseguen-

do in background e verrà inviato al server che a questo punto dello sviluppo interpreterà il

messaggio. Infine è stato aggiunto che ogni messaggio di log prodotto dal producer con-

tenesse il timestamp4 del momento in cui l’azione loggata fosse avvenuta: in questo modo

si può verificare la latenza della rete confrontando questo valore con quello prodotto sul

server, o sul consumer. La differenza tra i valori del timestamp è nell’ordine dei centesimi di

secondo.

4.2.1 Stato della connessione con il server

Si è deciso inoltre che è opportuno che il producer non si collegasse la server automatica-

mente all’avvio dell’applicazione ma che fosse l’utente a decidere quando connettersi e che

il producer visualizzi lo stato della connessione con il server. In questo modo è possibile

gestire più efficientemente la connessione e i problemi che possono crearsi. Per prima cosa

è stato creato un bottone visualizzabile nella pagina principale dell’applicazione che contie-

ne la stringa "OFF" ed è di colore rosso per comunicare all’utente che la connessione non

è attiva. A questo bottone è stata aggiunta la callback che risponde al tocco sul bottone:

questa funzione ha il compito di cercare di stabilire la connessione con il server. E inoltre è

stato aggiunto un pezzo di codice che evita di bloccare l’applicazione nel caso in cui il server

sia offline e l’applicazione cerchi continuamente di connettersi. Il codice riprotato in figura

Figura 4.3: Codice che gestisce i tentativi di connessione

4.3 è quello che gestisce i tentativi di connessione del producer al server. Viene sfruttato il

metodo connect() messo a disposizione dalla classe Socket che accetta come parametri

l’indirizzo del server, come InetSocketAddress, e opzionalmente un tempo massimo entro

il quale connettersi. Scaduto tale tempo il metodo produce un’eccezione che viene gestita

comunicando all’utente che è impossibile al momento connettersi e che verrà effettuato un

altro tentativo più tardi. É stato deciso un numero massimo di tentativi, o meglio un tempo

massimo entro il quale se la connessione non è stabilita si interrompono tutti i tentativi di

connessione: questo tempo è di un minuto (MAXtimeout = 60) e si effettuano tentativi ogni 5

secondi (Thread.sleep(5000) ). In caso che la connessione sia stata stabilita con successo4Valore numerico che rappresenta data e ora del momento in cui è calcolato

WebSocket Symphony Orchestra

Page 25: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

19

il bottone cambierà la propria stringa in "ON" ed il suo colore in verde, e la sua funzione non

cercherà di stabilire la connessione ma di interromperla andando a modificare il valore del

campo closed in true.

4.3 Selezione nota musicale e strumento

Per il terzo sprint è stato deciso di poter dare all’utente la possibilità di selezionare quale

nota produrre e con quale strumento riprodurla. Per fare ciò è stato aggiunto all’applicazione

un menù che contenesse le azioni che un utente si aspetta di poter effettuare. Tali azioni

sono:

• stabilire una nuova connessione

• selezionare la nota musicale

• selezionare lo strumento musicale

4.3.1 Stabilire connessione

Per poter stabilire una connessione con il server a livello di codice non si sono fatte grosse

modifiche: il bottone con cui prima si faceva questa azione è stato deresponsabilizzato e ha

solo la funzione di visualizzare lo stato della connessione attraverso i colori rosso e verde.

La voce del menù invece crea un’istanza della classe SocketClient con la quale si stabilisce

la connessione con il server.

4.3.2 Selezionare nota

Questa voce del menù apre una lista di note dalla quale l’utente può selezionare la nota che

desidera. Le note presentate sono scritte con la notazione anglosassone: le note classiche

DO, RE, MI, FA SOL, LA e SI sono anche rappresentate dalle lettere, rispettivamente, C, D,

E, F, G, A e B. Oltre alle note cosiddette "naturali", cioè senza alterazioni, è possibile sele-

zionare le altre cinque note che completano un’ottava5, ovvero A#6, C#, D#, F# e G#. Infine

ad ogni nota è associato un numero che indica in quale ottava riprodurre la stessa, e le

ottave rappresentate sono 7 (0 - 6). A livello di codice questo è stato realizzato con l’aggiun-

ta di tre classi Note, NoteFragment e MyNoteRecyclerViewAdapter, che rispettivamente

rappresentano una singola nota nell’elenco, l’elenco delle note in un nuovo fragment7 e ge-

stiscono l’interazione tra il contenitore di elementi di una lista (NoteFragment) e gli elementi

contenuti (Note). Queste tre classi sono state prodotte dall’IDE con File->New->Fragment-

>Fragment(List) con un esempio funzionante composto da DummyItem. Il codice che è

5Intervallo di 8 note posizionate a frequenza diversa nella scala musicale6La diesis7Un comportamento o una porzione di UI nella Activity principale

WebSocket Symphony Orchestra

Page 26: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

20 Producer

stato prodotto automaticamente evidenzia le parti in cui dev’essere modificato a seconda

delle esigenze degli oggetti da rappresentare. Dopo che è stata selezionata una nota viene

prodotto il messaggio: timestamp/origine/NOTE:nota. Per origine si intende la classe che

produce il timestamp, quindi la classe che che ha effettuato l’azione. Il messaggio prodotto

è passato all’istanza della classe SocketClient che lo invierà via socket al server.

4.3.3 Selezionare strumento

Analogamente a quello che è stato fatto per le note, sono state create le stesse classi

che gestiscono la selezione dello strumento; gli strumenti disponibili sono: Basso elettrico,

Fagotto, Violoncello, Clarinetto, Contrabbasso, Flauto, Corno francese, Chitarra acustica,

Chitarra elettrica, Chitarra acustica con corde di nylon, Armonio, Arpa, Organo, Piano, Sas-

sofono, Trombone, Tromba, Tuba, Violino e Xilofono. Questa volta il messaggio prodotto

contiene la strumento con questa notazione: "timestamp/origine/INSTRUMENT:strumento".

4.3.4 Controllo lunghezza nota con touch

Durante questa iterazione si è voluto anche raggiungere l’obiettivo di controllare la lunghez-

za di riproduzione delle note come succede con uno strumento reale in cui il musicista

decide per quanto tempo riprodurre la nota. L’idea di base è quella di utilizzare il touch

come un tasto che finché è premuto la nota viene riprodotta, mentre quando viene rila-

sciato la nota smette di essere riprodotta. Per fare ciò sono stati introdotti nuovi messaggi

che identificano queste azioni: TOUCH_START e TOUCH_END. Questi messaggi, che sono

prodotti rispettivamente quando inizio a toccare lo schermo e quando smetto di toccarlo,

sono inviati al server tramite l’istanza della classe SocketClient sempre con il protocollo

"timestamp/origine/TOUCH_START/END".

4.3.5 Sensore di prossimità

L’ultima funzionalità che è stata introdotta in questo terzo sprint è stata l’utilizzo del sensore

di prossimità per la produzione di note e per il controllo della lunghezza di riproduzione della

nota stessa. Innanzitutto bisogna tenere presente che il sensore di prossimità non è pre-

sente su tutti i dispositivi, anche perché è un componente hardware. Proprio perché si parla

di un compoente hardaware le diverse versioni posso funzionare in modo differente a se-

conda del tipo di tecnologie che sono state usate per implementarlo. Nella guida di Android

Developers8 si avvertono i programmatori dei due tipi di sensori di prossimità esistenti:

• sensore continuo, ovvero restituisce la distanza dal sensore entro un range

• sensore discreto, ovvero restituisce due valori numerici che equivalgono a true o false

8https://developer.android.com/guide/

WebSocket Symphony Orchestra

Page 27: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

21

Dopo aver constatato che il sensore sul device utilizzato per il progetto è di tipo discreto e

che restituisce due valori numerici (0.0 e 8.0) che indicano se un oggetto è vicino o lontano

si è potuto procedere ad utilizzarlo per produrre delle note. Come è facile ipotizzare l’utilizzo

di questo tipo di sensore è molto simile al comportamento del touch: produco un messag-

gio che identifica quando cominciare a riprodurre la nota e uno per stopparla. Per poter

utilizzare il sensore, a livello di codice, bisogna che la MainActivity implementi l’interfaccia

SensorEventListener per poter catturare gli eventi prodotti dai sensori. Questa interfaccia

è generica, nel senso che è possibile ricevere eventi da qualsiasi sensore presente sul devi-

ce a patto che questi sensori siano ottenuti dal SensorManager e che vengano registrati per

ottenere gli eventi. Ciò a livello di codice si ottiene così: Nel metodo onSensorChanged si

Figura 4.4: Codice che gestisce gli eventi del sensore di prossimità

riceve l’evento che è prodotto dal sensore e da questo si può estrapolare che tipo di evento

è. In questo specifico caso si controlla la distanza che il sensore calcola e se è minore della

metà del massimo valore rilevabile (if (distance < (proximitySensor.getMaximumRange()

/ 2))) si produce il messaggio PROXIMITY_START, in caso contrario il messaggio prodotto è

PROXIMITY_STOP. Fare un controllo del genere evita di fare una distinzione tra i due tipi

di sensori di prossimità che si possono avere, riducendoli essenzialmente ad un sensore

discreto. I messaggi prodotti sono inviati come nel caso del touch.

WebSocket Symphony Orchestra

Page 28: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

22 Producer

4.4 Produzione di una melodia

Nel quarto sprint è stato deciso di implementare la funzionalità "carillon", cioè di produrre

una melodia preimpostata. Prima di poter produrre una melodia preimpostata è necessario

trovare una melodia e tradurla in un linguaggio compatibile con il consumer che deve ripro-

durla. La melodia scelta è "Fra Martino" suonata con un pianoforte. Dallo spartito musicale

Figura 4.5: Spartito Fra Martino

si è passati al solfeggio delle note, cioè a leggere le note dallo spartito come DO-RE-MI

etc, fino alla traduzione in note anglosassoni. Dopodiché ad ogni nota così tradotta è stata

aggiunta l’ottava in cui riprodurre la nota sotto forma di numero da 0 a 6 (coerentemente

alla lista da cui si può selezionare la nota singola). Infine ad ogni nota è stato associato

per quanto tempo riprodurre la nota, anche questo parametro è espresso come numero se-

guendo questa regola: DURATA [1 = 4/4; 2 = 2/4; 4 = 1/4; 8 = 1/8; 16 = 1/16; ...] Il numero

prima dell’uguale è quello che identifica la durata all’interno dell’applicazione, il rapporto a

destra dell’uguale indica il rapporto della durata della nota riferito al metro con cui è scritto

lo spartito. Con questo modo di leggere uno spartito , lo spartito di "Fra Marino" è stato

tradotto e salvato in un file:

INSTRUMENT:piano

MELODY:C3-4;D3-4;E3-4;C3-4;C3-4;D3-4;E3-4;C3-4;E3-4;F3-4;G3-2;E3-4;F3-4;G3-2;G3-8;A3-

8;G3-8;F3-8;E3-4;C3-4;G3-8;A3-8;G3-8;F3-8;E3-4;C3-4;D3-4;G2-4;C3-2;D3-4;G2-4;C3-2

La prima riga di questo file riporta lo strumento con cui si vuole riprodurre la melodia,

la seconda riga riporta la serie di note con tutte le informazioni necessarie alla riprodu-

zione secondo il protocollo "NotaOttava-Durata" e sono separate le une dalle altre da un

punto e virgola. Il file contenente queste informazioni per poter essere letto dall’applica-

zione dev’essere messo in una cartella speciale chiamata "raw", all’interno della cartel-

la che contiene tutte le risorse dell’applicazione chiamata "res". Se non fosse in questa

posizione del fileSystem l’applicazione dovrebbe avere i permessi per poter leggere dalla

memoria del dispositivo e inoltre l’applicazione dovrebbe sapere dove si trova il file all’in-

terno della memoria. Invece, in questo modo, è possibili riferirsi al file attraverso il suo

WebSocket Symphony Orchestra

Page 29: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

23

id e in più farsi dare una "stream" per poter leggere il file (InputStream inputStream =

res.openRawResource(R.raw.fra_martino)). Per semplificare il codice si è creata una

classe ad hoc per leggere questo tipo di file ed è stata chiamata CarillonFileReaderHel-

per. Questa classe espone un solo metodo (readFile(String fileName, Resources res)

che restituisce un oggetto della classe CarillonMessage. Questo tipo di oggetto possiede

tre campi:

• String fileName, in cui viene riportato il nome della melodia letta, è un parametro del

metodo

• String instrument, in cui è riportato lo strumento con il quale riprodurre la melodia

• String[] melody, in cui un elemento è "NotaOttava-Durata"

Questa classe espone oltre ai relativi "getter" e "setter" un metodo toJsonString() che scri-

ve una stringa nel formato JSON9. Questo perché la stringa in formato JSON è il messaggio

che viene inviato inviato al server sempre tramite l’istnaza della classe SocketClient. Que-

sta funzionalità è messa a disposizione dell’utente come nuova voce del menù: Produci

Carillon.

4.4.1 IP server dinamico

Usare un indirizzo IP scritto manualmente nel codice per connettersi con il server non è mai

stata un’idea funzionale, quindi è stato creato un meccanismo grazie al quale l’applicazio-

ne producer possa ottenere dinamicamente l’indirizzo IP del server. Questo "meccanismo"

sfrutta un altro protocollo di comunicazione in rete, ovvero il protocollo UDP10. Attraverso

questo l’applicazione chiede a tutti i dispositivi connessi alla rete (broadcasting), su una spe-

cifica porta, se sono il server che sta cercando; quando il server riceve il messaggio questo

risponde all’applicazione con un altro messaggio. Grazie a questo scambio di messaggi e al

protocollo UDP è possibile ottenere l’indirizzo IP del server. Questo meccanismo, così co-

me è stato spiegato, è messo in funzione dalla classe DiscoverServerIPThread. Quest’ul-

tima estende AsyncTask perché deve processare in background rispetto alla MainActivity,

e quando ottiene la risposta dal server restituisce un valore di ritorno che è l’IP del server.

Un’istanza di questa classe è creata quando viene selezionata la voce del menù "Nuova

connessione" e viene immediatamente "messa al lavoro". Appena termina l’esecuzione e

restituisce l’IP questo è utilizzato per stabilire la connessione con il server.

9JSON, acronimo di JavaScript Object Notation, è un formato adatto all’interscambio di dati fra applicazioniclient/server

10User Data Protocol

WebSocket Symphony Orchestra

Page 30: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

24 Producer

4.4.2 Nuovo protocollo di comunicazione

Ricapitolando, i messaggi che vengono trasmessi al server sono di due tipi allo stato attuale

di implementazione:

• CarillonMessage, per trasmettere una melodia intera da riprodurre

• stringa contente "TOUCH_START/STOP" per produrre e fermare una nota usando il

touch

• stringa contente "PROXIMITY_START/STOP" per produrre e fermare una nota usan-

do il sensore di prossimità

A livello di server questo implica che è il server stesso che deve capire di quale genere di

messaggio si tratta e comportarsi di conseguenza. Quindi per facilitare il lavoro del server si

è deciso di cambiare il modo di comunicare dal producer al server. Si è deciso di creare una

struttura di comunicazione che fosse compatibile con i messaggi che attualmente vengono

prodotti dal producer e che liberi il server dall’elaborazione di tali messaggi. Per ottenere

ciò è stata introdotta una nuova classe Message che contiene i seguenti campi:

• String note, cioè una stringa che contiene la nota selezionata

• String instrument, cioè una stringa contente lo strumento selezionato

• String id, cioè una stringa contente l’id univoco dell’istanza di Message

• String command, cioè una stringa che contiene o "PLAY" o "STOP"

Inoltre questa classe espone "getter" e "setter" per ogni campo e il metodo toJsonString,

già descritto per la classe CarillonMessage. Utilizzando questa classe i messaggi prodotti

utilizzando il touch o il sensore di prossimità diventano, a livello di codice, lo stesso tipo di

messaggio. Nella pratica quando si seleziona una nota questa viene salvata nell’istanza

della classe Message, quando si seleziona uno strumento anch’esso è salvato nell’istanza

della classe Message, quando si tocca il touch o ci si al sensore di prossimità viene settato

il campo command con "PLAY" e il campo con un id univoco creato dalla combinazione del

MAC address11 del device più il timestamp e il messaggio trascritto in forma JSON viene

inviato al server. In modo analogo quando si smette di toccare il touch o ci si allontana

dal sensore di prossimità il campo command è settato con il valore "STOP" e nuovamente

inviato al server. Si noti che durante il ciclo di vita dell’applicazione quando si produce una

singola nota viene utilizzata un’unica istanza della classe Message, la quale è modificata

ogni volta che l’utente seleziona una nuova nota o un nuovo strumento, e ogni volta che

produce la nota e la ferma.

11Codice di 48 bit assegnato in modo univoco dal produttore ad ogni scheda di rete ethernet o wireless almondo

WebSocket Symphony Orchestra

Page 31: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

25

4.5 Polifonia 1

A livello di producer ha poco senso parlare di polifonia se la si intende per il suo significa-

to di ascoltare più suoni diversi contemporaneamente, ma ha senso se la si intende come

produrre più di una nota nello stesso momento. Ma prima di discutere dell’implementazione

della polifonia nel producer è necessario parlare della produzione di una singola melodia:

così com’è l’implementazione il messaggio prodotto contiene l’intera melodia ed è preoccu-

pazione del consumer riprodurla ma non è il risultato che si vuole ottenere. In realtà l’unico

compito che dovrebbe eseguire il consumer è eseguire i comandi che vengono prodotti dal

producer e gli unici comandi che il producer può produrre sono "PLAY" e "STOP".

4.5.1 Produzione melodia nota per nota

A questo punto la logica di produzione di una melodia viene completamente stravolta per-

ché è il producer stesso che deve mandare i messaggi nel momento giusto seguendo la

melodia scritta nel file, cioè deve produrre il messaggio di "PLAY" di una nota e dopo il tem-

po che deve durare quella nota il messaggio di "STOP" e subito quello di "PLAY" della nota

successiva, e così via. Per fare ciò è stata scritta una nuova classe, CarillonSocket, il cui

compito è quello di produrre i messaggi necessari per riprodurre la melodia correttamente.

Questa estende AsyncTask, quindi si tratta di un thread che esegue in background le pro-

prie operazioni. A livello pratico ogni istanza di questa classe apre un nuovo socket verso il

server perché in questo modo si evita di dover dipendere da un solo socket per inviare tutti

i messaggi (ipoteticamente molti anche nello stesso momento se si pensa ad un’orchestra)

e quindi avere un traffico sulla rete distribuito su diversi canali di comunicazione. La scelta

di aprire un nuovo socket per comunicare una melodia al server si è resa necessaria dopo

aver testato empiricamente12 i risultati ottenuti con l’implementazione che utilizzava solo un

canale per inviare i messaggi; i test facevano notare come la soluzione con un solo canale

aperto producesse degli errori nella riproduzione e tra i vari motivi c’era il fatto che i mes-

saggi arrivassero nel momento sbagliato. Ciò era dovuto alla cooperazione di più thread

che parallelamente settavano il messaggio da inviare al server e non c’era nessuna assi-

curazione che il messaggio venisse mandato nel momento corretto. Con l’uso di un nuovo

socket per ogni melodia questo problema non sorge e gli unici responsabili di errori nella

produzione della melodia sono lo scheduler del sistema android che gestisce l’esecuzione

dei thread e il traffico della rete su cui il sistema comunica. Dopo aver aperto la nuova con-

nessione al server l’istanza di CarillonSocket all’interno di un ciclo estrae le informazioni

di ogni singola nota dall’oggetto CarillonMessage e crea un nuovo oggetto Message con

il comando "PLAY" per inviare le informazioni al server e riprodurre la nota. L’informazione

riguardante la durata della nota è utilizzata per "mettere a dormire" il thread in modo da

aspettare il tempo giusto prima di inviare lo stesso messaggio inviato precedentemente solo12Praticamente ascoltare la melodia riprodotta

WebSocket Symphony Orchestra

Page 32: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

26 Producer

con il comando "STOP". La durata non è utilizzata così come si trova scritta ma viene elabo-

rata per trasformarla in un intervallo di tempo in secondi attraverso la funzione toSecond().

Al termine del ciclo il lavoro del thread termina chiudendo il socket che ha utilizzato.

4.5.2 CarillonSocket con canone

Per raggiungere l’obiettivo di produrre una polifonia in questo sprint si è deciso di pro-

durre "Fra Martino" con un canone: cioè di produrre due melodie identiche di cui la se-

conda inizia dopo un certo numero di note della prima. Questo risultato è ottenuto con

l’ultimo parametro che accetta il costruttore della classe CarillonSocket, ovvero il para-

metro che inizializza il campo canon e che rappresenta il numero di note dopo le quali

far partire la stessa melodia. Per produrre la seconda volta la stessa melodia viene det-

to alla MainActivity di istanziare e far partire una nuova istanza di CarillonSocket (con

canon = -1 per non ripetere ulteriormente la melodia). Il passaggio attraverso l’activity

principale dell’applicazione è necessario per il corretto funzionamento del sistema opera-

tivo android, altrimenti l’applicazione si arresta producendo un errore interno. Infatti an-

droid permette solo all’Activity principale di creare e far eseguire nuovi thread; inoltre sem-

pre android obbliga gli sviluppatori ad utilizzare "Esecutore" per eseguire più di due th-

read (uno è la MainActivity, l’altro è SocketClient) alla volta correttamente: carillonSoc-

ket.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR). Nello specifico TH-

READ_POOL_EXECUTOR è un contenitore di thread che permette l’esecuzione in paral-

lelo, al contrario di SERIAL_EXECUTOR che esegue in modo ordinato e seriale. L’utente

può utilizzare questa funzionalità selezionando dal menù la voce "Produci polifonia".

4.5.3 Costruzione di un ID univoco

Ogni nota prodotta per poter essere correttamente riprodotta dal consumer necessità di ave-

re un ID che sia univoco all’interno del sistema: fino a questo momento l’ID consiste in una

stringa che è costruita concatenando una stringa che contiene il MAC address del device

ad una stringa che contiene il timestamp. Questo però non è più sufficiente per assicurare

l’univocità dell’ID perché se si pensa che in questo momento ci sono due thread che stanno

eseguendo (idealmente) in parallelo e che stanno producendo la stessa melodia potrebbe

capitare di produrre due note nello stesso istante. Per evitare che si creino problemi nella

riproduzione è stata modificata la costruzione dell’ID: si tratta sempre di una stringa otte-

nuta concatenando clientNumber13, MAC address, timestamp e strumento con cui voglio

riprodurre la nota. Questa costruzione assicura che anche se due o più thread producono

la stessa nota nello stesso momento avranno comunque sia un ID diverso.

13numero progressivo che il server comunica ai client al momento della connessione

WebSocket Symphony Orchestra

Page 33: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

27

4.5.4 Feedback dal consumer

In seguito ad alcune considerazioni riguardo al consumer e alle risorse che deve avere

a disposizione per poter eseguire senza errori i comandi che lo raggiungeranno è stato

introdotto un messaggio che è prodotto dal consumer e mandato al producer. Il messaggio

che arriva al consumer è Preloading terminato ed è il segnale che il sistema ha caricato

tutte le risorse necessarie e aspetta messaggi dal producer. Il producer prima dell’arrivo di

questo messaggio non è in grado di produrre alcuna nota per evitare errori nel consumer.

L’utente può sapere quando può produrre le note guardando il colore del bottone in alto a

sinistra dell’applicazione. Questo bottone prima aveva solo il compito di dare un feedback

sullo stato della connessione tra producer e server, ora il colore verde significa sia che la

connessione è stata stabilita, sia che il consumer è pronto per l’esecuzione.

4.6 Polifonia 2

Durante l’ultima iterazione si è deciso di introdurre una nuova melodia per verificare il cor-

retto funzionamento della polifonia sia a livello di producer che a livello di consumer. La

melodia scelta è "Aria sulla quarta corda", cioè la trasposizione del violinista tedesco Au-

gust Wilhelmj dell’Aria della terza Suite per orchestra in re maggiore di Bach (BWV 1068).

Come fatto per "Fra Martino" il primo passo è stato tradurre lo spartito in un file leggibile

Figura 4.6: Estratto dello spartito dell’Aria sulla quarta corda

e interpretabile dall’applicazione. Questa volta però le melodie sono 2 diverse e suonabili

con due strumenti diversi: la prima riga è suonata solitamente con un violino, la seconda

riportando note solitamente più basse è suonata con un violoncello. Inoltre in questo spar-

tito compaiono le "legature di valore", ovvero quei tratti che uniscono alcuno note, come nel

caso delle prime tre note nella prima riga dello spartito. Queste legature di valore significano

WebSocket Symphony Orchestra

Page 34: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

28 Producer

che le note dovrebbero essere suonate come un’unica nota, cioè non dovrebbe sentirsi lo

stacco tra una e l’altra, ma all’interno del protocollo che si utilizza per tradurre lo spartito

non esiste nessun modo per tradurre questo tipo di informazione. L’unica alternativa sa-

rebbe quella di riprodurre un’unica nota con lunghezza uguale alla somma delle lunghezze

delle note legate, ma questo non è possibile perché si stanno utilizzando numeri interi per

rappresentare la lunghezza delle note. Quindi il file risulterà così:

INSTRUMENT1:violin

MELODY1:F#5-1;F#5-1;F#5-4;B5-8;G5-8;E5-8;D5-8;C#5-8;D5-8;C#5-2;B4-8;A4-4;A4-8;A5-

1;A5-8;F#5-8;C5-8;B4-8;E5-8;D#5-8;A5-8;G5-8;G5-1;G5-8;E5-8;B4-8;A4-8;D5-8;C#5-8;G5-

8;F#5-8;F#5-2;F#5-4;G#5-8;A5-8;D5-4;D5-16;E5-16;F#5-8;F#5-8;E5-8;E5-8;D5-8;C#5-8;B4-

8;B4-16;C#5-16;D5-8;D5-4;C#5-8;B4-8;A4-1

INSTRUMENT2:cello

MELODY2:D3-4;D4-4;C#4-4;C#3-4;B2-4;B3-4;A3-4;A2-4;G2-4;G3-4;G#3-4;G#2-4;A2-4;A3-

4;G3-4;G2-4;F#2-4;F#3-4;E3-4;E2-4;D#2-4;D#3-4;B2-4;B3-4;E2-4;E3-4;D3-4;D2-4;C#2-4;C#3-

4;A2-4;A3-4;D3-4;D4-4;C#4-4;C#3-4;B2-4;B3-4;G#3-4;E3-4;A3-4;D3-4;E3-4;E2-4;A2-8;B2-

8;C#3-8;D3-8;E3-8;G3-8;F#3-8;E3-8

Dopodiché è stata creata una nuova classe, PolyphonicFileReader, che ha il compito di

leggere il file ed estrarre le due melodie separate. Le singole melodie sono salvate in oggetti

di tipo CarillonMessagge e ordinati all’interno di un array. A questo punto, coerentemente

con quanto fatto prima, ogni melodia deve essere prodotta in un thread ma così facendo

sorge il problema che un thread comincia ad eseguire prima dell’altro. Per risolvere ciò è

stato utilizzato lo strumento di sincronizzazione messo a disposizione da java CyclicBarrier.

Quest’ultimo può essere paragonato all’arbitro della gara dei cento metri piani: mette ad

aspettare i thread (che sono gli sprinter) finché non sono tutti arrivati allo stesso punto

dell’esecuzione e questo punto li lascia eseguire. Il numero di thread che fa aspettare è un

parametro che viene passato al costruttore e come dice il nome questo oggetto può essere

riutilizzato più volte. I thread vengono fermati dopo aver concluso le operazioni preliminari

come stabilire la connessione, inizializzare i buffer di input e output e prima di cominciare la

produzione delle note. Tutto questo permette di produrre la melodia polifonica correttamente

(a meno di latenze sulla rete) metricamente parlando.

WebSocket Symphony Orchestra

Page 35: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

29

Capitolo 5

Dispatcher

Il dispatcher in questa architettura è l’elemento centrale, quello che permette la comunica-

zione tra il producer e il consumer. La sua funzione principale è quella di inoltrare i messaggi

prodotti da uno o più producer e indirizzarli verso il consumer. Visto le sua funzionalità all’in-

terno del sistema questo componente deve assicurare alte performance in termini di velocità

di inoltro dei messaggi per permettere la definizione di sistema realtime. Si è scelto di im-

plementare questo componente con il linguaggio di programmazione Java principalmente

perché possiede tutti gli strumenti necessari per costruire questo genere di applicazione,

perché è stato il linguaggio di programmazione di riferimento durante il mio ciclo di studi

e perché garantisce buone performance riguardo alla comunicazione via socket. Analo-

gamente al producer, in questo capitolo si analizzeranno le funzionalità acquisite durante

l’implementazione.

5.1 Connessione con producer(s)

La prima funzionalità implementata è stata stabilire una connessione con un producer e

come naturale conseguenza la possibilità di supportare più connessioni con eventuali più

producer. Per fare ciò sono state create due classi: ListenerServer e ListenerThread. La

prima è la classe principale, quella che inizializza tutti gli oggetti e che permette di mettere

in funzione il server. Tra gli oggetti che inizializza il più importante è un ServerSocket che

è un’implementazione java di un server socket, il quale aspetta delle richieste in arrivo sul-

la rete sulla porta specificata al momento della costruzione (ServerSocket listener = new

ServerSocket(listenerPortNumber)). La porta specificata è la 9999 ed è la stessa che

il producer deve specificare quando vuole connettersi al server. Essenzialmente l’oggetto

listener ha solo il compito di aspettare richieste di connessione e lo fa attraverso il meto-

do accept(); questo metodo blocca l’esecuzione del programma finché non stabilisce una

connessione e restituisce il socket aperto attraverso il quale producer e dispatcher possono

comunicare. Il socket che ha ritornato è poi utilizzato per creare un’istanza di ListenerTh-

WebSocket Symphony Orchestra

Page 36: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

30 Dispatcher

read, il quale come dice il nome è un thread che si mette in ascolto sul socket. Il ciclo di

vita di questo thread comprende una fase iniziale in cui inizializza i buffer di input e output

(BufferedReader e PrintWriter) per comunicare attraverso il socket e invia un messaggio

di benvenuto al producer per comunicare due informazioni: il numero progressivo che iden-

tifica il producer e che la connessione è stata stabilita con successo. Dopodiché il thread

entra in un ciclo while che ha il compito di ascoltare i messaggi che produce e invia il pro-

ducer. String input = in.readLine() è il modo in cui i messaggi vengono letti: se il valore

della stringa ottenuta è null oppure "." il ciclo si interrompe e il thread chiude la connessione

socket e termina la sua esecuzione. Si svolge questa doppia verifica sulla stringa perché

si vogliono intercettare il caso in cui la connessione è caduta (caso null) oppure il caso in

cui il producer voglia interrompere la comunicazione e quindi invia un messaggio specifi-

co (".") per comunicarlo al dispatcher. Con queste due classi è stato possibile creare un

server multithread che supportasse la connessione di più producer contemporaneamente.

Le modifiche al codice sono state minime: infatti è bastato introdurre un ciclo While(true)

che aspetta nuove connessioni, e quando un nuovo producer si collega viene istanziato un

nuovo ListenerThread.

Figura 5.1: Prima implementazione della classe ListenerServer

5.1.1 DispatcherLogger

In un server multithread è assolutamente necessario avere un sistema per controllare le

operazioni che sono state svolte: in questo modo si ha maggiormente sotto controllo il ser-

ver stesso ed possibile scoprire e trovare più velocemente eventuali errori. Il sistema di

controllo implementato è una pagina web statica in cui vengono stampate tutte le operazio-

ni che il server compie. Quindi si è reso necessario introdurre un nuovo componente nel

sistema che prende il nome di DispatcherLogger. Per fare ciò si è utilizzato il framework

javascript Vue.js: questo è dedicato alla realizzazione di interfacce web reattive che sfrutta-

WebSocket Symphony Orchestra

Page 37: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

31

no il dual-binding tra modello e vista1. Una particolarità di Vue sta nel fatto che è possibile

programmare un componente in tutte le sue parti, cioè struttura (HTML), stile (CSS) e logica

(Javascript), nello stesso file. Queste componenti possono essere combinate e riutilizzate

allo scopo di creare applicazioni web. La scelta di utilizzare un framework del genere è stata

principalmente per la familiarità già acquisita durante un altro progetto; ma oltre a questo

mette a disposizione del programmatore un modo molto semplice per aggiornare i dati e

visualizzarli sulla pagina. Infatti grazie al data-binding, cioè al meccanismo che associa

Figura 5.2: Prima implementazione del DispatcherLogger

dati a elementi dell’interfaccia utente, è necessario solo aggiornare la variabile logger per

mostrare all’utente i log che arrivano dal dispatcher. All’interno del tag <script> si trova la

proprietà sockets: questa è un’implementazione di Socket.IO per Vue che rende molto più

semplice gestire le connessioni tramite websocket. Andando con ordine, Socket.IO è una

libreria javascript per applicazioni web realtime che permette una comunicazione bidirezio-

nale tra web client e server. Per utilizzare questa libreria è stata prima di tutto installata

nel progetto attraverso il package manager "npm"; a livello di codice bisogna inizializzare

una variabile che si mette in ascolto su una determinata porta (SocketIstance = socke-

tio(’http://localhost:5560’)). Infine è necessario dire a Vue di utilizzare quella variabile

(Vue.use(VueSocketIO, SocketIstance)) per permettere a tutti i componenti ".vue" di rice-

vere eventi tramite websocket. Socket.IO mette a disposizione del programmatore un siste-

ma di multiplexing grazie ai "namespace"2: cioè sulla stessa connessione socket è possibile

mettersi in ascolto solo di alcuni eventi che sono specificati da delle stringhe e questi eventi

1https://www.html.it/pag/63947/vue-js-unintroduzione/2https://github.com/socketio/socket.io-protocol

WebSocket Symphony Orchestra

Page 38: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

32 Dispatcher

sono chiamati, appunto, namespace. Con questo meccanismo al server basta specificare il

namespace corretto per assicurarsi che i dati che vuole trasmettere sia correttamente instra-

dati. Inoltre Socket.IO permette di inviare qualsiasi tipo di dato: dai tipi primitivi agli oggetti

più complessi. Facendo riferimento alla figura 5.2 si è utilizzato il namespace dispatchLog

per ricevere e gestire gli eventi di log dal server: in questo caso il tipo di dato ricevuto è un

stringa ed è mostrata sull’interfaccia utente così come è stata composta lato dispatcher.

5.1.2 Classe WebSocketServer

Il DispatcherLogger nell’architettura di progetto ha il ruolo di web client, mentre il ruolo di

server lo ricopre la classe WebSocketServer all’interno del dispatcher. Questa classe ha

il compito di inviare i messaggi dal dispatcher ai web client che sono in ascolto tramite il

meccanismo dei namespace. La classe WebSocketServer è un contenitore dell’oggetto

SocketIOServer, un’implementazione java del server Socket.IO basata su "Netty". Netty

è un framework per applicazioni di rete event-driven asincroni per un rapido sviluppo del

protocollo server & client che mantiene delle performance elevate3. SocketIOServer neces-

sita di conoscere l’indirizzo sul quale aprire una connessione websocket: questo indirizzo è

costruito in un oggetto di tipo Configuration come si può vedere nella figura 5.3. La porta

sulla quale viene aperta la connessione websocket tra dispatcher e dispatcherLogger è la

5560 ed è specificata nella classe principale all’interno della variabile dispatcherLogger-

PortNumber. L’istanza della classe SocketIOServer così creata è passata come parametro

Figura 5.3: Costruzione del SocketIOServer

al costruttore della classe WebSocketServer; al momento della creazione, dopo aver ini-

zializzato i propri campi il server è fatto partire con il metodo start(). L’istanza della classe

WebSocketServer è passato come parametro al momento della costruzione di tutte le istan-

ze di ListenerThread perché è l’oggetto tramite il quale il dispatcher comunica con il proprio

dispatcherLogger. Per comunicare è stato scritto il metodo sendDispatchLog che accetta

Figura 5.4: Metodo in WebSocketServer che comunica con il dispatcherLogger

come parametro una stringa. Questo metodo emette sul websocket un evento con il name-

space "dispatchLog" e i dati trasmessi sono la stringa contenente il messaggio da loggare.

3https://netty.io/

WebSocket Symphony Orchestra

Page 39: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

33

Tutti i metodi scritti in questa classe avranno una struttura simile al metodo riportato in figura

5.4, l’unica differenza è il tipo del parametro che accettano.

5.2 Comunicazione verso il consumer

Nel secondo sprint si è voluta implementare la funzionalità di riprodurre una nota preimpo-

stata: l’utente utilizzando il producer vuole poter ascoltare una nota musicale. Il dispatcher

in questa funzionalità ha il compito di inoltrare il messaggio che riceve attraverso il socket

aperto con il producer verso il consumer. Per comunicare con il consumer il dispatcher

apre una nuova connessione websocket utilizzando un’altra istanza della classe WebSoc-

ketServer: il numero di porta scelto per questo socket è 5570. Così come nel caso del

dispatcherLogger, questa istanza di WebSocketServer è passata come parametro al co-

struttore di ListenerThread ed è l’unico mezzo di comunicazione verso il consumer. Al-

l’interno del ciclo while che "ascolta" i messaggi del producer è stato scritto un controllo:

if(input.contains("L’utente ha toccato il dispositivo!!")). Se si verifica questa condizio-

ne viene fatta la chiamata consumerWSS.reproduceNote(). Questo metodo della classe

WebSocketServer emette un evento sulla connessione websocket verso il consumer usando

il namespace "screenTouch" e i dati trasmessi sono la stringa "C6"4.

5.2.1 Tabella dei producer collegati

In un sistema che mette in collegamento uno o più producer con un server si rende neces-

sario che il server sappia quali producer siano collegati e quali si siano scollegati. Per fare

ciò nel dispatcher è stata creata una lista che contiene tutti le istanze di ListenerThread

create. Ma per mostrare all’utente quali producer siano o meno connessi è stata aggiunta

nel dispatcherLogger una tabella che contiene il numero progressivo che identifica il pro-

ducer e un valore booleano che rappresenta lo stato della connessione (true = connesso,

false = disconnesso). La tabella è stata realizzata con Bootstrap-Vue. Bootstrap-Vue è un

Figura 5.5: Tabella che rappresenta i producer connessi

4Equivale al DO nella sesta ottava

WebSocket Symphony Orchestra

Page 40: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

34 Dispatcher

progetto che permette di utilizzare Bootstrap con le funzionalità di data-binding che met-

te a disposizione Vue per i propri componenti. Questo progetto fornisce dei tag speciali,

molto simili a quelli che si è abituati a utilizzare con Bootstrap, che permettono, tra le al-

tre componenti, di creare una tabella configurandone stile e contenuti. La linea di codice

<b-table striped hover :items="items" :field="fieldss"></b-table> è quella che permet-

te di creare la tabella: la proprietà :field è quella che permette di specificare i titoli delle

colonne nella tabella mentre la proprietà :item è quella che permette di aggiungere nuove

righe nella tabella. Entrambe queste proprietà sono collegate a delle variabili che rispet-

tivamente contengono un array di stringhe che danno il titolo di ogni colonna nella tabella

(fieldss) e un array inizialmente vuoto che verrà riempito da oggetti JSON in cui la chiave

è il titolo della colonna e il valore è ciò che viene mostrato nella tabella (items). Grazie

a Vue è possibile modificare il valore di queste due variabili per modificare i valori visua-

lizzati sull’interfaccia utente. Nella classe ListenerServer quando un producer si collega

viene fatta la chiamata dispatcherWebSocketServer.addClient(clientNumber). Questo

metodo emette un evento sul websocket aperto con il dispatcherLogger con il namespa-

ce "newClient" e i dati trasmessi sono il numero progressivo che identifica il producer. Il

dispatcherLogger quando riceve questo messaggio aggiunge una nuova riga alla tabella:

this.items.push(ClientNumber: clientNumber, Connected: true). Quando un produ-

cer si disconnette è l’istanza di ListenerThread associata che fa la chiamata dispatcher-

WSS.sendToDispatcherClientDisconnected(clientNumber). Questo metodo emette un

evento sul websocket aperto con il dispatcherLogger con il namespace "clientDisconnected"

e i dati trasmessi sono il numero che identifica il producer. La chiamata a questo metodo è

l’ultima operazione che il listenerThread esegue prima di terminare l’esecuzione. Nel dispat-

cherLogger il numero serve per trovare l’elemento all’interno dell’array items e aggiornare

il valore associato alla chiave "Connected" in false.

5.3 Comunicazione nota, strumento o comando

Durante la terza iterazione è stata data la possibilità all’utente di poter selezionare quale

nota riprodurre e con quale strumento riprodurla. Il dispatcher in questa funzionalità ha

il compito di riconoscere quale genere di messaggio l’utente ha prodotto e inoltrare nel

modo corretto le informazioni al consumer. Il dispatcher deve riconoscere se nel messaggio

è contenuto la nota, lo strumento oppure un comando di riproduzione o di stop. Nella

classe ListenreThread, per non appesantire eccessivamente il codice all’interno del ciclo

while, è stato scritto un metodo che ha il compito di controllare il contenuto del messaggio.

Nel seguente elenco si descrivono il controllo e il metodo invocato sull’istanza della classe

WebSocketServer che ha stabilito la connessione websocket con il consumer:

• if (input.contains("INSTRUMENT:")), con il namespace "setInstrument" è inviata

una stringa contenente lo strumento selezionato

WebSocket Symphony Orchestra

Page 41: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

35

• if (input.contains("NOTE:")), con il namespace "setNote" è inviata una stringa con-

tenente la nota selezionata

• if (input.contains("TOUCH_START") || input.contains("PROXIMITY_START")), con

il namespace "playDefaultNote" è inviata la stringa "PLAY"

• if (input.contains("TOUCH_END") || input.contains("PROXIMITY_STOP")), con il

namespace "stopNote" è inviata la stringa "STOP"

5.4 Comunicazione melodia

Nel quarto sprint all’utente è stata aggiunta la funzionalità di riprodurre una melodia preim-

postata. Il dispatcher in questa funzionalità ha il compito di comunicare al consumer i mes-

saggi che riceve dal producer e di loggare questi messaggi sul dispatcherLogger. Rispetto

all’iterazione precedente è stato introdotto un protocollo di comunicazione tra producer, di-

spatcher e consumer che evitasse al dispatcher il compito di riconoscere se il messaggio

contenesse una nota, uno strumento o un comando. Questo nuovo protocollo prevede che

il producer produca due tipi di messaggi:

• Message, contenente nota selezionata, strumento selezionato, ID che identifica la

nota riprodotta e comando "PLAY" o "STOP"

• CarillonMessage, contenente nome della melodia, strumento con cui riprodurla, ar-

ray i cui elementi sono coppie "NotaOttava-Durata"

Entrambi questi tipi di messaggi sono inviati in una stringa scritta in formato JSON. All’inter-

no del ciclo while che ascolta i messaggi del producer ogni messaggio prodotto dall’utente

è loggato sul dispatcherLogger tramite la classe DispatcherEmitter, e tranne il messag-

gio iniziale prodotto dal producer (if (!input.contains("Connected!!"))) ogni messaggio è

inoltrato al consumer usando la classe ConsumerEmitter.

5.4.1 DispatcherEmitter

DispatcherEmitter è una classe che implementa l’interfaccia Runnable, cioè è obbligata a

sovrascrivere il metodo run() che è il metodo eseguito all’interno di un thread. Al costruttore

sono passati come parametri una stringa contenente il messaggio da loggare e l’istanza

di WebSocketServer con il websocket aperto verso il dispatcherLogger. Il thread creato

con questa classe effettua la chiamata dispatcherWSS.sendDispatchLog(data) dove la

variabile data è un stringa ottenuta concatenando il timestamp e il messaggio passato nel

costruttore.

WebSocket Symphony Orchestra

Page 42: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

36 Dispatcher

5.4.2 ConsumerEmitter

ConsumerEmitter, come la precedente, implementa l’interfaccia Runnable. La differenza

sta nel metodo run(): il messaggio prima di essere inviato è utilizzato per creare un oggetto

di tipo JSONObject. A seconda se il messaggio da inviare contenga una singola nota (Mes-

sage) o una melodia (CarillonMessage) vengono fatte le chiamate rispettivametne ai meto-

di consumerWSS.forwardObject(object) e consumerWSS.forwardCarillon(object). Il

primo metodo emette un evento sul websocket aperto verso il consumer con il namespa-

ce "forward" mentre il secondo emette un evento con il namespace "carillon". Entrambi

trasmettono l’oggetto di tipo JSONObject creato.

5.4.3 Comunicazione indirizzo IP al producer

Per implementare il meccanismo che comunica al producer che vuole collegarsi al dispat-

cher l’indirizzo IP del dispatcher stesso è stata creata una nuova classe: IPCommunicator.

Questa classe implementa l’interfaccia Runnable e l’unica istanza creata è creata nella clas-

se principale per poter eseguire il thread che si mette in ascolto su un socket aperto sulla

porta 8500 con il protocollo UDP. Il protocollo UDP è necessario perché permette di riceve-

re messaggi attraverso un socket che non specifica un IP: infatti si utilizza il meccanismo di

broadcasting. Cioè il producer collegato alla rete invia un messaggio a tutti gli indirizzi IP

sulla rete (broadcast) e l’istanza di IPCommunicator che resta in ascolto quando riceve un

messaggio controlla che arrivi da un producer e gli risponde. Grazie alla risposta del dispat-

cher il producer può ottenere l’indirizzo IP con cui aprire un socket usando il protocollo TCP.

A livello di codice l’esecuzione di questa classe consiste in un ciclo while che aspetta l’arrivo

di messaggi: ciò avviene con la chiamata al metodo socket.receive(packetReceived). La

variabile socket rappresenta il socket UDP che ascolta sulla porta 8500 e il metodo invo-

cato blocca l’esecuzione del programma finché un messaggio non è arrivato. Il messaggio

arrivato è immagazzinato nella variabile packetReceived di tipo DatagramPacket; questo

oggetto oltre a contenere un buffer da cui è possibile ottenere il messaggio contiene anche

l’indirizzo IP della sorgente del messaggio. Il messaggio è convertito in una stringa e vie-

ne fatto il controllo if (clientMessage.equals("SONO_UN_CLIENT")) per verificare che sia

stato un producer del progetto Websocket Symphony Orchestra e non un altro dispositivo

connesso alla rete. A questo messaggio il dispatcher risponde con una stringa che contie-

ne "SONO_IL_SERVER" ed è inviato al producer in un oggetto di tipo DatagramPacket in

modo che il producer possa ottenere l’indirizzo IP del dispatcher. Questo thread termina la

sua esecuzione quando termina l’esecuzione del dispatcher.

WebSocket Symphony Orchestra

Page 43: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

37

5.5 Comunicazione polifonia

Nella quinta iterazione è stata aggiunta la funzionalità di riprodurre una melodia polifoni-

ca, cioè di riprodurre più di un suono nello stesso istante di tempo. Il dispatcher per ot-

tenere questa funzionalità ha il compito di inoltrare i messaggi che contengono le note

al consumer. Non sono state aggiunte nuove classi o scritti nuovi metodi per ottenere il

comportamento desiderato, anzi è stato semplificato ulteriormente il protocollo di comuni-

cazione. Ora l’unico messaggio che viene prodotto dall’utente è solo di tipo Message e

nella classe ConsumerEmitter è stato eliminato il controllo che riconosceva tra Message e

CarillonMessage.

5.5.1 Comunicazione preloading

A causa della libreria utilizzata nel consumer è necessario che gli strumenti per riprodurre

le note vengano caricati correttamente e questa operazione occupa per un po’ di tempo il

consumer. Quando questo caricamento è terminato il consumer invia un messaggio verso

il dispatcher che a sua volta lo inoltra al producer. Questo messaggio che si muove nel-

la direzione opposta rispetto a tutti gli altri è gestito all’interno del dispatcher con le classi

WebSocketServer e ListenerThread. Nella prima classe è stato aggiunto un metodo che

ascolta sulla connessione websocket con il consumer un evento con namespace "Preloa-

dingTerminato". Associato a questo evento è inviato un valore booleano che è utilizzato per

inizializzare un campo della classe: this.preloading = aBoolean. Nella seconda classe è

stato scritto un nuovo ciclo while (prima di quello che si mette in ascolto sul socket del pro-

ducer) che aspetta che il valore della variabile diventi true per poter comunicare al producer

che può cominciare a produrre messaggi.

5.6 Deploy dispatcher

Durante l’ultimo sprint la funzionalità introdotta è stata riprodurre una nuova melodia; il di-

spatcher è già in grado di svolgere questo compito dall’iterazione precedente. Invece, come

descritto nel capitolo Metodologia di sviluppo, l’applicazione in ogni momento deve poter

essere messa in produzione. Per fare questo l’applicazione non deve più dipendere dall’IDE

di sviluppo utilizzato ma deve poter essere eseguibile come un qualsiasi programma. Per

quanto riguarda il dispatcherLogger il suo codice è stato compilato in modo da ottenere un

file .HTML che ne descriva la struttura, un file .js che ne gestisca la logica, un file .css che

ne descriva lo stile e una cartella con le risorse utilizzate (immagini). Questi file sono stati

utilizzati per pubblicare la pagina web che è il dispatcherLogger in rete locale utilizzando

XAMPP. XAMPP è un software open-source sviluppato da Apache Friends che utilizza tra

le altre cose un Apache HTTP Server ed è capace di interpretare pagine web dinamiche5.5https://en.wikipedia.org/wiki/XAMPP

WebSocket Symphony Orchestra

Page 44: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

38 Dispatcher

Il dispatcherLogger è raggiungibile all’indirizzo "localhost:8082/index1.html". Per quanto ri-

guarda il dispatcher è stato compilato il codice java ed è stato ottenuto un file .jar. Questo

file è eseguibile da linea di comando con java -jar nome_file.jar e mette in funzione il server

con tutte le funzionalità implementate.

WebSocket Symphony Orchestra

Page 45: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

39

Capitolo 6

Consumer

Il consumer nell’architettura del progetto il componente finale, il suo compito è quello di ri-

produrre le note che l’utente ha prodotto utilizzando il producer. Questo componente è stato

implementato con una pagina web statica e le sue funzionalità sono state implementate

utilizzando principalmente il linguaggio di programmazione javascript. All’interno di questo

componente si è utilizzata la libreria Tone.js come libreria di alto livello per sfruttare le Web

Audio API. Come i componenti precedenti, in questo capitolo si analizzeranno le funzionalità

che sono state acquisite durante lo sviluppo del progetto.

6.1 Introduzione a Tone.js

Prima di parlare delle funzionalità del consumer è bene introdurre alcuni concetti che riguar-

dano la libreria sulla quale sono state implementate tali funzionalità: Tone.js. Tone mette a

disposizione del programmatore dei sintetizzatori artificiali per riprodurre i suoni all’interno di

una pagina web, e come esempio viene riportato l’unico sintetizzatore artificiale che è stato

utilizzato durante lo sviluppo del progetto: var synth = new Tone.Synth().toMaster(). Ana-

lizzando la linea di codice viene chiamato il costruttore dell’oggetto Synth che rappresenta

un sintetizzatore base con un singolo inviluppo e un singolo oscillatore. Questo oggetto per

poter riprodurre suoni deve essere collegato all’output sonoro principale e ciò è fatto con

la chiamata al metodo toMaster(). Ogni oggetto che riproduce suoni in Tone per poterli

riprodurre deve fare la chiamata al proprio metodo toMaster(). Con l’oggetto appena co-

struito è possibile riprodurre qualsiasi nota con una durata specificata con la chiamata al

metodo synth.triggerAttackRelease(’C4’, ’8n’). Questo metodo accetta come primo pa-

rametro la nota musicale espressa in notazione anglosassone (o con la frequenza) e come

secondo parametro la durata della nota. Questo parametro è esprimibile in secondi, in BPM

(Battiti Per Minuto), in Herz o in PPQ (Pulse Per Quarter). triggerAttackRelease è un me-

todo che in realtà unisce due altri metodi che servono uno per iniziare a riprodurre una nota

(triggerAttack(note)) e una per fermare la riproduzione di tale nota (triggerRelease(note)).

WebSocket Symphony Orchestra

Page 46: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

40 Consumer

Questi due metodi possono essere separati e utilizzati in parti diverse del codice per irpro-

durre una nota di durata variabile per esempio. Tone inoltre permette di creare uno stru-

mento musicale personalizzato per riprodurre le note: cioè fornendo ad un oggetto di tipo

Instrument una configurazione specifica e dei campioni di suoni di uno strumento musicale

è possibile riprodurre le note musicali con una chitarra o un pianoforte o qualsiasi altro stru-

mento musicale. L’interfaccia messa a disposizione da Tone per la classe Instrument è del

tutto simile a quella di Synth: i metodi toMaster() e triggerAttackRelease() sono ancora

disponibili. Con questa breve introduzione è stato spiegato come è possibile utilizzare Tone

all’interno di una pagina web e i principali metodi che sono stati usati.

6.2 Riproduzione di una nota

Lo sviluppo del consumer è iniziato nel secondo sprint quando si è aggiunta la funzionalità

di riprodurre una singola nota preimpostata. In questa funzionalità il consumer ha il com-

pito di ricevere un messaggio dal dispatcher e riprodurre la nota contenuta nel messaggio

utilizzando il framework Tone.js. Questo componente è stato costruito utilizzando Webpack.

Webpack è un "module bundler" per applicazioni javascript, cioè ha la funzione di unire i

moduli che compongono un progetto in un singolo file nell’ordine corretto. Nella pratica si

occupa di gestire le dipendenze al posto del programmatore fornendogli molti vantaggi du-

rante lo sviluppo. Per funzionare Webpack necessità di un file di "entry point", cioè il primo

file da cui parte per risolvere le dipendenze in modo ricorsivo, e di informazioni riguardo

l’output1. Tali informazioni sono il nome del file di output e la cartella di destinazione. Que-

ste informazioni sono scritte in un file di configurazione chiamato "webpack.config.js". Per

utilizzare webpack è necessario installarlo con "npm" nella cartella del componente. Il co-

mando sulla command line per installarlo è: npm install webpack webpack-cli –save-dev.

Oltre a webpack è stata installata anche la commnad line di webpack in modo da avere la

possibilità di eseguire il progetto da linea di comando. Dopo l’installazione bisogna costruire

la struttura di cartelle e file che compongono il progetto: una cartella "dist" che rappresen-

ta la destinazione dei file compilati, una cartella "src" che contiene i file sorgenti javascript

compilabili, una cartella "style" che contiene i fogli di stile css e una cartella "risorse" che

contiene risorse come immagini e file audio utilizzati nell’applicazione web. Per costruire

questo genere di progetto ho seguito la guida ufficiale di webpack2. In questa iterazione

è stato creato il file HTML che rappresenta la struttura della pagina web e il file "index.js"

che rappresenta l’entry point. In quest’ultimo file viene aperto il websocket che ascolta sul-

la porta 5570: let socket = io(’http://localhost:5570’) dove la variabile io rappresenta il

socket.io-client importato in questa pagina. Come nel caso del dispatcherLogger anche

il consumer utilizza l’implementazione client di Socket.IO, e per riprodurre la nota musicale

1http://webappfromzero.com/2018/04/01/webpack-cose-e-come-funziona/2https://webpack.js.org/guides/getting-started/

WebSocket Symphony Orchestra

Page 47: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

41

si mette in ascolto dell’evento con namespace "screenTouch" e si aspetta di ricevere co-

me dato una nota musicale scritta in notazione anglosassone (A,B,C,D,E,F o G) seguita

dall’ottava in cui riprodurla. Come si vede in figura 6.1, quando il messaggio che contie-

Figura 6.1: Meotodo che riproduce la nota

ne la nota inviato dal dispatcher arriva al consumer essa viene riprodotta per 3 secondi:

synth.triggerAttackRelease(note,3);

6.2.1 Riproduzione nota nel consumer

In questa iterazione è stato implementato anche un meccanismo che permette di riprodurre

una nota cliccando su un bottone all’interno della pagina web del consumer. Questa funzio-

nalità, successivamente eliminata, è stata implementata per familiarizzare con il framwork

Tone.js e per prendere confidenza con gli strumenti che mette a disposizione. Per fare ciò

sono stati creati dei bottoni nel file HTML con dei valori che rappresentano una nota musi-

cale. Nel file js associato alla pagina web, al momento della creazione, a questi bottoni sono

associate due funzioni, una per il click e una per il rilascio: la prima legge il valore del bot-

tone e riproduce la nota (synth.triggerAttack(e.target.textContent);) mentre la seconda

termina la riproduzione della nota (synth.triggerRelease();)

6.2.2 Visualizzazione stato della connessione con il dispatcher

Per visualizzare lo stato della connessione tra il dispatcher e il consumer è stato creato un

bottone nella pagina web. Questo bottone si colora di verde quando il dispatcher si collega

per la prima volta al consumer; quando la connessione termina, cioè il dispatcher è offline, il

colore del bottone diventa rosso. Questa logica è implementata nei metodi riportati in figura

6.2.

Figura 6.2: Logica del bottone che mostra lo stato della connessione tra consumer edispatcher

WebSocket Symphony Orchestra

Page 48: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

42 Consumer

6.2.3 Visualizzazione operazioni del consumer

Così come per gli altri componenti nell’architettura anche per il consumer è stato implemen-

tato un modo per visualizzare le operazioni che sono svolte nel ciclo di vita del consumer

stesso. Per fare la pagina web è stata divisa in due colonne con il sistema di griglie di

Bootstrap e una di queste è stata predisposta a contenere i messaggi di log prodotti dal

consumer. Con una funzione chiamata logging(text) il consumer può stampare a schermo

le operazioni che svolge e l’utente può vedere se le operazioni svolte sono corrette.

6.3 Riproduzione nota con strumento selezionato

Nel terzo sprint la funzionalità introdotta è quella di poter riprodurre una nota con lo strumen-

to selezionato controllandone la durata con il producer. Il consumer in questa funzionalità ha

il compito di riprodurre e stoppare la nota che l’utente ha selezionato quando il messaggio,

rispettivamente di "PLAY" e "STOP", sono arrivati al consumer. Per questo motivo sul web-

socket aperto verso il dispatcher sono stati aggiunti due nuovi metodi che sono in ascolto

degli eventi associati, rispettivamente, ai namespace "playDefaultNote" e "stopNote". Il pri-

mo di questi quando il messaggio arriva controlla che nel consumer siano state inizializzate

le variabile che rappresentano la nota selezionata e lo strumento selezionato dall’utente. Se

entrambe le variabili sono inizializzate la nota è riprodotta continuamente finché il messag-

gio di stop non arriva. Se non è stata selezionata la nota ma solo lo strumento il consumer

riproduce la nota di default "C6" con lo strumento selezionato. Se nessuna delle due va-

riabili è inizializzata il consumer riproduce con l’oggetto Synth la nota di default "C6" per 1

secondo. Nella figura 6.3 si può vedere che per controllare la lunghezza della nota non sono

Figura 6.3: Metodo che riproduce la nota

stati utilizzati i metodi triggerAttack e triggerRelease ma è stato utilizzato un altro oggetto

di Tone: Transport. Questo oggetto permette di usare la funzione passata come parametro

nella chiamata a Tone.Trasport.scheduleRepeat() all’interno di un loop: in questo modo la

nota continua ad essere riprodotta finché quando arriva il messaggio di stop si fa la chiama-

WebSocket Symphony Orchestra

Page 49: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

43

ta Tone.Transport.clear(id). Il parametro passato alla funzione contiene un Id univoco che

rappresenta la nota che sta riproducendo Transport all’interno del suo loop ed è necessario

salvare questa informazione per poter sospendere la riproduzione correttamente.

6.3.1 Selezione nota

Quando l’utente ha selezionato la nota il producer produce un messaggio che contiene

l’informazione che riguarda la nota. Questo messaggio è inviato al consumer dal dispatcher

sul websocket aperto associandolo al namespace "setNote". La funzione che è in ascolto di

questo evento mostra a schermo la nota scelta e salva il valore nella variabile noteSelected.

Questa variabile è utilizzata dal consumer per riprodurre una nota quando l’utente produce

il messaggio di play.

6.3.2 Selezione strumento

Quando l’utente ha selezionato lo strumento il producer produce un messagio che contiene

l’informazione che riguarda lo strumento. Questo messaggio è inviato al consumer sul web-

socket aperto con il dispatcher associandolo al namespace "setInstrument". La funzione che

è in ascolto di questo evento oltre a mostrare a schermo lo strumento selezionato, costrui-

sce un oggetto di tipo Tone.Sampler. Questo oggetto è un estensione di Tone.Instrument

ed è in grado di interpolare automaticamente tra un gruppo di campioni registrati. A livello

di codice nel momento della costruzione a questo oggetto sono passati come parametro dei

campioni sonori che rappresentano una nota riprodotta con un determinato strumento. Que-

sto oggetto che espone metodi come triggerAttackRelease(), quando deve riprodurre una

determinata nota che è nel gruppo di campioni sonori che possiede utilizza Tone.Player; se

invece non è tra questi re-intona3 un campione automaticamente e lo riproduce. Per utilizza-

re gli strumenti musicali è stato importato il progetto di github "tonejs-instrument"4. Questo

progetto consiste in un file javascript che fornisce allo sviluppatore l’oggetto SampleLibrary

con il quale poter facilmente caricare i campioni di un strumento e ottenere il riproduttore

di suoni usando come parametro il nome dello strumento stesso. Ma il lavoro maggiore in

questo progetto è stato registrare i campioni degli strumenti e raccoglierli in una cartella.

Sono stati raccolti campioni degli strumenti: Basso elettrico,Fagotto, Violoncello, Clarinetto,

Contrabbasso, Flauto, Corno francese, Chitarra acustica, Chitarra elettrica, Chitarra acusti-

ca con corde di nylon, Armonio, Arpa, Organo, Piano, Sassofono, Trombone, Tromba, Tuba,

Violino e Xilofono.

3repitching4https://github.com/nbrosowsky/tonejs-instruments

WebSocket Symphony Orchestra

Page 50: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

44 Consumer

6.4 Riproduzione melodia

Durante la quarta iterazione è stata aggiunta la funzionalità di riprodurre una melodia pre-

impostata e il consumer in questa funzionalità ha il compito di riprodurre una melodia leg-

gendo le note da un messaggio e riproducendole con il metro corretto. Il messaggio da

cui deve leggere la melodia è un oggeto JSON le cui chiavi contengono il nome della me-

lodia (fileName), lo strumento con cui riprodurla (instrument) e un array di oggetti JSON

in cui ogni elemento è una nota è la sua durata. Questo messaggio è inviato tramite

websocket ed è associato all’evento con namespace "carillon". Nel metodo rappresen-

Figura 6.4: Metodo che riproduce una melodia

tato in figura 6.4 si può notare che dopo alcune operazioni preliminari che servono per

eliminare la melodia riprodotta precedentemente si fa la chiamata let ins = mapWrap-

per.getInstrumentValue(carillonMessage.instrument). Nella variabile ins è salvato lo

strumento con cui riprodurre la melodia e mapWrapper è, tra le altre cose, un contenito-

re degli strumenti utilizzabili nel consumer. Dopodiché con ciclo for le note e le rispettive

durate sono salvate in un altro che array che salva l’informazione dell’istante di tempo in

cui riprodurre la note. Quest’ultimo array è utilizzato per costruire un oggetto di tipo To-

ne.Part che è una collezione di oggetti di tipo Tone.Event, i quali possono essere riprodotti,

stoppati e ripetuti come se fossero un evento singolo. La riproduzione inizia con la chia-

mata part.start(0) e il parametro "0" indica il ritardo con il quale cominciare a riprodurre la

melodia, in questo caso subito.

WebSocket Symphony Orchestra

Page 51: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

45

6.4.1 Riproduzione singola nota

In questo quarto sprint è stato cambiato il protocollo di comunicazione, ora al consumer

arrivano solo due tipi di messaggi: uno che contiene una melodia e uno che contiene una

singola nota. Entrambi i messaggi sono oggetti JSON dai quali in javascript è facile leggere

i valori delle chiavi. Per quanto riguarda il messaggio che contiene una singola nota questo

è inviato sul websocket aperto tra dispatcher e consumer ed è associato al namespace "for-

ward". L’oggetto JSON contiene le informazioni riguardo la nota da riprodurre (note), lo stru-

mento con cui riprodurla (instrument), l’id univoco che rappresenta la nota (id) e il comando

di play o stop. Il metodo che riceve questo messaggio prima di tutto distingue il comando

play dal comando stop. Nel primo caso viene ottenuto lo strumento in modo analogo alla

riproduzione di un melodia, vengono mostrati a schermo nota e strumento, l’id è salvata nel

contenitore mapWrapper con la chiamata mapWrapper.insertIdPair(messageObject.id,

instr) e la variabile instr, che rappresenta lo strumento, è utilizzata per riprodurre la nota

con triggerAttack. Nel caso stop viene ottenuto lo strumento associato all’id del messag-

gio dal contenitore mapWrapper e viene chiamato il metodo triggerRelease. La coppia

id:strumento è infine rimossa dal contenitore. Con questo meccanismo non è più il consu-

mer a controllare in modo diretto la durata della nota da riprodurre ma esegue solo i comandi

che sono prodotti dall’utente sul producer.

6.4.2 Mappatura note e strumenti

In seguito al cambiamento nel protocollo di comunicazione si è reso necessario che i cam-

pioni audio degli strumenti fossero caricati prima che qualsiasi tipo di messaggio arrivi al

consumer. Questa operazione è svolta nel metodo che gestisce il momento in cui la connes-

sione websocket tra dispatcher e consumer viene stabilita (socket.on(’connect’, function

() {...}): all’interno di un ciclo for che itera su un array di stringhe che rappresentano gli stru-

menti vengono costruiti tutti gli strumenti, vengono collegati al master output e salvati in una

mappa con la coppia chiave:valore composta da nome_strumento:Tone.Sampler; mapW-

rapper è il contenitore di questa mappa e di un’altra mappa che associa id_nota:Tone.Sampler.

La prima mappa serve al consumer per salvare lo strumento e utilizzarlo quando si vuole

riprodurre una nota. La seconda invece serve per associare l’id della nota che si sta ripro-

ducendo allo strumento che la riproduce: così facendo quando arriva il messaggio di stop il

consumer recupera lo strumento che sta riproducendo il suono e lo interrompe.

6.5 Riproduzione polifonia

Nel quinto sprint all’utente è stata data la funzionalità di riprodurre una melodia polifonica e

il consumer ha il compito di riprodurre e gestire più di una nota contemporaneamente. Per

fare ciò non si è dovuto scrivere nessuna riga di codice aggiuntiva perché il contenitore ma-

WebSocket Symphony Orchestra

Page 52: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

46 Consumer

pWrapper associando l’id della nota allo strumento che la riproduce permette al consumer

di far partire e stoppare la nota corretta. Il problema della polifonia, per quanto riguarda

il consumer, è stato risolto inconsapevolmente già nell’iterazione precedente quando ogni

strumento inizializzato è collegato al master output.

6.6 Deploy consumer

Nella sesta iterazione, come nel caso del dispatcher, non è stata aggiunta alcuna funziona-

lità che interessasse il codice del consumer e, analogamente al dispatcherLogger, il codice

del consumer è stato compilato per pubblicare la pagina web in rete locale con XAMPP. Il

consumer è raggiungibile all’indirizzo "localhost:8082/index1.html".

WebSocket Symphony Orchestra

Page 53: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

47

Capitolo 7

Conclusioni

L’applicazione sviluppata risponde a tutti i gli obbiettivi fissati nella scheda di progetto. Il

sistema allo stato attuale presenta una latenza tanto bassa da permettere di controllare in

realtime la durata di una nota e di riprodurre un melodia le cui note sono prodotte dall’utente

con uno smartphone collegato in rete locale. Inoltre è possibile riprodurre un melodia po-

lifonica, cioè nello stesso istante è possibile ascoltare due note suonate con due strumenti

diversi. Per quanto riguarda le tre componenti da implementare bisogna fare il collegamento

tra i nomi scritti nella scheda di progetto e i nomi utilizzati nello sviluppo dell’applicazione: il

server ha preso il nome di dispatcher, l’esecutore di suoni si chiama consumer e il client che

faccia da strumento musicale è chiamato producer. Queste componenti sono indipendenti

le une dalle altre: basti pensare che nell’iterazione 6 è stata aggiunta una nuova funzionalità

e due componenti su tre non hanno subito modifiche. Di seguito una breve descrizione dei

risultati ottenuti componente per componente:

• Dispatcher Il dispatcher è il componente centrale che mette in comunicazioni i pro-

ducer al consumer. É in grado di aprire connessioni con uno o più producer usando il

protocollo socket e si connette al consumer utilizzando il protocollo websocket.

• Consumer Il consumer è il componente che è responsabile di riprodurre i suoni e si

collega al dispatcher usando il protocollo websocket. Consiste in un’applicazione web

che interpreta i messaggi che riceve dal dispatcher per riprodurre una o più note con

diversi strumenti.

• Producer Il producer è componente che interpreta lo strumento musicale, l’utente

può riprodurre note musicali utilizzando un producer come strumento musicale. Es-

so si collega al dispatcher utilizzando il protocollo socket e nella pratica consiste in

un’applicazione sviluppata in android per smartphone.

La comunicazione tra le componenti è bidirezionale grazie ai protocolli socket e websoc-

ket; infatti sia per quanto riguarda la connessione tra producer e dispatcher quando le due

componenti aprono una connessione entrambi inviano dei messaggi all’altra componente.

WebSocket Symphony Orchestra

Page 54: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

48 Conclusioni

Questo succede anche nella connessione tra consumer e dispatcher. Infine la durante il

ciclo di vita del sistema ci sono i messaggi che rappresentano la nota da riprodurre che ven-

gono prodotti dal producer e inviati al consumer, e c’è un messaggio che il consumer invia

al producer per permettergli di produrre le note. L’unico compito che non è stato portato a

termine è il feedback sul producer quando una nota è riprodotta.

WebSocket Symphony Orchestra

Page 55: WebSocket Symphony Orchestra · WebSocket Symphony Orchestra Studente/i Stefano Motti Relatore Nicola Rizzo Correlatore Giancarlo Corti Committente Nicola Rizzo Corso di laurea Ingegneria

49

Bibliografia

https://www.w3.org/TR/webaudio/

https://caniuse.com/#search=web%20audio

https://github.com/Tonejs/Tone.js

https://it.wikipedia.org/wiki/WebSocket

https://developer.android.com/

https://www.html.it/pag/63947/vue-js-unintroduzione/

https://github.com/socketio/socket.io-protocol

https://netty.io/

https://en.wikipedia.org/wiki/XAMPP

http://webappfromzero.com/2018/04/01/webpack-cose-e-come-funziona/

https://webpack.js.org/guides/getting-started/

https://github.com/nbrosowsky/tonejs-instruments

https://developer.android.com/

https://tonejs.github.io/

https://socket.io/

https://www.wikihow.it/Leggere-la-Musica

WebSocket Symphony Orchestra