Piano in tasca
L'anno scorso, mentre caricavo sacchi di pellet nella mia caldaia, stavo ragionando su come sfruttare l'orientamento nello spazio del telefono per produrre delle note.
Ho immaginato quindi di avere le note musicali attorno a me, disposte in cerchio, e di poterle suonare sollevando la gamba in direzione della nota scelta.
Piano in tasca
- Url
- https://pianointasca.it/
- Github
- https://github.com/polesello/pianointasca
- Data di uscita
- 1 marzo 2024
- Caratteristiche
- deviceorientation, immagini SVG, audio
- Dispositivi
- Android, iOS, Desktop
- Browser
- Chrome, Firefox, Safari
Il sensore di orientamento è molto preciso e sensibile e l'aggiornamento del dato è molto frequente, quindi risponde immediatamente ad ogni cambiamento. Qui, accedendo con uno smartphone, puoi vedere i valori grezzi dell'orientamento del telefono lungo i tre assi, oltre all'accelerazione, utilizzata dall'app Spaccamuro.
L'angolo in gradi in direzione alfa, cioè quello indicato dalla bussola, indicherà quindi la nota da suonare, mentre l'angolo beta, cioè quello che indica l'orientamento del telefono sull'asse x, scatenerà il suono della nota prescelta.
Schema grafico

Nella versione base a otto note, lo schema che appare è quello rappresentato in figura.
Dovendo gestire un numero variabile di note per poter usare altre disposizioni, non era pensabile di utilizzare un'immagine fissa. I settori circolari vengono quindi creati all'avvio dell'applicazione facendoli disegnare da una funzione Javascript.
L'svg risultante è di questo tipo: un tag path per il settore e un tag text per il nome della nota.
<svg width="360" height="360" viewBox="0 0 360 360">
<g transform="translate(180,180)">
<path d="M -11.480502970952692 -27.716385975338603 L -55.8717811253031 -134.88641174664787 A 146 146 0 0 1 55.871781125303116 -134.88641174664787 L 11.480502970952696 -27.716385975338603 A 30 30 0 0 0 -11.480502970952692 -27.716385975338603" stroke="black" fill="hsl(0, 100%, 70%)" notesound="c4" noteindex="0"></path>
<text x="7.102951435054649e-15" y="-116" text-anchor="middle" dominant-baseline="middle" transform="rotate(0,7.102951435054649e-15,-116)">C</text>
<path d="M 11.480502970952696 -27.716385975338603 L 55.871781125303116 -134.88641174664787 A 146 146 0 0 1 134.88641174664787 -55.87178112530311 L 27.716385975338603 -11.480502970952694 A 30 30 0 0 0 11.480502970952696 -27.716385975338603" stroke="black" fill="hsl(45, 100%, 70%)" notesound="d4" noteindex="1"></path>
<text x="82.02438661763952" y="-82.02438661763951" text-anchor="middle" dominant-baseline="middle" transform="rotate(45,82.02438661763952,-82.02438661763951)">D</text>
</g>
</svg>
la riga che calcola il path vi farà rispolverare le vostre dimenticate lezioni di trigonometria, ma nel dubbio c'è sempre Copilot che ci dà una mano.
Per quanto riguarda il colore dei settori, ho scelto di usare la notazione hsl, che risulta molto comoda quando si vogliono ottenere colori omogenei e uniformemente distribuiti sulla ruota dei colori, poiché il primo parametro è proprio l'angolo in gradi, considerando l'angolo 0° sul rosso.
const sector = `M ${R_MIN * Math.cos(currAngle)} ${R_MIN * Math.sin(currAngle)} L ${R_MAX * Math.cos(currAngle)} ${R_MAX * Math.sin(currAngle)} A ${R_MAX} ${R_MAX} 0 0 1 ${R_MAX * Math.cos(currAngle + sectorAngle)} ${R_MAX * Math.sin(currAngle + sectorAngle)} L ${R_MIN * Math.cos(currAngle + sectorAngle)} ${R_MIN * Math.sin(currAngle + sectorAngle)} A ${R_MIN} ${R_MIN} 0 0 0 ${R_MIN * Math.cos(currAngle)} ${R_MIN * Math.sin(currAngle)}`
Com’è messo il telefono?
Per reagire ad ogni movimento del telefono è necessario rimanere in ascolto dell'evento deviceorientation. La funzione che lo gestisce riceverà in ingresso un evento con tre proprietà chiamate alpha, beta e gamma, che indicano la rotazione in gradi nei tre assi x, y e z.

La proprietà alpha è quella che ci dà l'orientamento della bussola, quella che cambia quando teniamo il telefono appoggiato sul tavolo e lo facciamo girare mantenendolo appoggiato al tavolo. In altre parole, il movimento dato dalla rotazione sull'asse z, cioè l'asse perpendicolare al tavolo.
La proprietà beta ci dà invece la rotazione sull'asse x, ossia la rotazione che avviene quando, tenendo il telefono in tasca, solleviamo o abbassiamo la gamba. Tale valore assume il valore di -90 quando il telefono è verticale con l'altoparlante verso il basso, di zero quando è appoggiato sul tavolo e di 90 quando lo teniamo perfettamente verticale davanti a noi durante un utilizzo normale.
La condizione che fa scatenare il suono della nota è if (event.beta > -30), che considera un angolo di sollevamento della gamba pari ad almeno 30°.
Di seguito le parti più significative della funzione.
window.addEventListener('deviceorientation', updateNote)
function updateNote(event) {
// alpha0 è l'angolo che impostiamo premendo l'omino al centro
let angle = alpha0 - event.alpha
if (angle < 0) angle += 360
// ruota tutto lo schema delle note come fosse il quadrante di una bussola
canvas.setAttribute('transform', 'rotate(' + -angle + ', 180, 180) translate(180,180)')
if (event.beta > -30) {
// suona la nota corrispondente
Come suono?
L'idea iniziale di utilizzare un unico tag <audio> e di sostituire l'attributo src nel momento in cui si sceglie la nota provocava un fastidioso ritardo quando si tentava di cambiare nota molto velocemente, ossia quando si tiene il telefono in mano col braccio teso perpendicolare al corpo e si fa una veloce giravolta.
Ho creato quindi un numero sufficiente di tag audio come il seguente, dedicandone uno ad ogni singola nota, e impostando l'attributo src al momento della creazione dello schema iniziale, senza più bisogno di cambiarlo in futuro.
<audio class="player" src=""></audio>
Dopo la creazione dello schema a otto note, questo è quello che risulta nella pagina.
<audio class="player" src="notes/c4.mp3"></audio>
<audio class="player" src="notes/d4.mp3"></audio>
<audio class="player" src="notes/e4.mp3"></audio>
<audio class="player" src="notes/f4.mp3"></audio>
<audio class="player" src="notes/g4.mp3"></audio>
<audio class="player" src="notes/a5.mp3"></audio>
<audio class="player" src="notes/b5.mp3"></audio>
<audio class="player" src="notes/c5.mp3"></audio>
«Ma io lo voglio usare anche su desktop!»
Le note suonano anche al click, è quindi possibile usare l'applicazione anche su un normale computer desktop, sprovvisto quindi dei sensori di orientamento. Questo porta con sè due vantaggi:
- Si possono suonare anche accordi, grazie al fatto che ogni nota ha a disposizione un tag audio dedicato, che può suonare contemporaneamente agli altri.
- Non c'è bisogno di tentare di infilarsi il computer portatile in tasca, risparmiando così le spese di riparazione dei pantaloni.
Altre particolarità
Nell'istruzioni volevo caratterizzare il punto elenco della lista <ol> mostrandolo in un cerchio. Ho subito abbbandonato l'idea di utilizzare lo stile sullo pseudo elemento ::marker perché supporta pochissime proprietà, e il background-color non è tra queste.
Usando invece le proprietà relative ai contatori CSS ho ottenuto il risultato voluto.
ol {
padding: 0;
margin: 0 0 0 30px;
list-style: none;
counter-reset: instructions;
font-size: 14px;
}
li {
position: relative;
counter-increment: instructions;
margin-bottom: 8px;
}
li::before {
content: counter(instructions);
Usando un contatore automatico possiamo modificare la lista nell'html avendo la garanzia che sarà sempre numerata correttamente.
Ciò viene sfruttato quando, in caso si acceda su dispositivo Android, viene rimossa da Javascript l'istruzione che chiede di dare il consenso all'utilizzo dei sensori di movimento, che viene richiesto solo su dispositivi iOS.
<li class="only-ios">Dai il consenso all’utilizzo dei sensori di movimento</li>
// Android
document.querySelector('.only-ios').style.display = 'none'
«Ma io non so suonare»
È proprio per te che ho creato l'ultima modalità che vedi nel menu a tendina.
«In che altro modo la posso usare?»
Intanto avrai notato che alzare la gamba non è l'unico modo per suonare. Puoi ad esempio impostare una nota mentre sei in piedi e suonarla nel momento esatto in cui ti siedi.
Oppure puoi scatenarti in discoteca selezionando "L'amour toujours" tenendo il telefono in mano col braccio teso e ruotando di 90° in senso orario ad ogni battuta.
Altrimenti puoi procurarti due telefoni, impostarli su due note diverse, infilarne uno per tasca e fare un po' di corsa skip.
Se invece hai un gruppo di amici, disponetevi in fila, impostate una nota diversa a testa e sincronizzatevi in modo da suonare una semplice melodia in cui ogni persona è dedicata a produrre una singola nota al momento giusto.
Se mai qualcuno arrivasse a leggere queste proposte e volesse metterle in pratica, bé, è obbligato a mandarmi il video.
Che ne dici?
Ti invito a segnalarmi le tue osservazioni, apprezzamenti e critiche compilando il form qui sotto o scrivendomi una email a polesello@infofactory.it