RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

60
RETROJS Party like it's 1983 @shiota 2013

description

Os navegadores modernos oferecem APIs que muitas vezes nem chegamos a conhecer e utilizar no dia-a-dia. Um exemplo é a API de Web Audio, que permite reproduzir e criar sons no browser utilizando apenas código JavaScript. Para estudá-la (e me divertir um pouco), resolvi bolar uma maneira de escrever partituras simples em formato JSON e conseguir reproduzi-las no navegador. O resultado disso foi o RetroJS: um experimento de Web Audio, com um feeling nostálgico da era 8-bits. Neste talk, vou explicar como transformei notações musicais em strings, e strings em música.

Transcript of RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

Page 1: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

RETROJSParty like it's 1983

@shiota 2013

Page 2: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

OH HAI!slideshare.net/eshiota

github.com/eshiota@shiota

Page 3: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

+ +

Page 4: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

Tudo começou na palestra do @almirfilho no OlhóSEO em Floripa sobre Web Audio API. O @fnando falou "Cara, dá pra fazer o JavaScript tocar o tema do Mario, imagina que foda?". Challenge accepted.

Page 5: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

Web Audio API

Page 6: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

// Vendor prefixedvar context = new webkitAudioContext();

Page 7: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

context.createOscillator() context.destination

connect()

Page 8: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

var oscillator = context.createOscillator();

oscillator.connect(context.destination);

Page 9: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

frequência

duração

Page 10: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

oscillator.frequency.value = 780;

oscillator.start(0);oscillator.stop(context.currentTime + 0.5);

Page 11: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API
Page 12: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

about me

Estudei piano dos 8 aos 15 anos. Sou apaixonado por música clássica, e gosto de ler partituras. Nada como juntar um hobby antigo com uma paixão. =)

Page 13: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

Voltando ao assunto: challenge accepted, né? =)

Page 14: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

o projeto

Page 15: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

&

?

44

44Piano

Allegro q»™ººœœ# œœ ‰

Jœœ ‰ œœ œœ ‰

œ œ ‰ Jœ ‰ œ œ ‰

Jœœœ ‰ Œ jœ ‰ Œ

Ó Jœ ‰ Œ

&

?

..

..

A3 jœœ ‰ ‰ jœœ Œ jœœ‰

Jœ ‰ ‰ Jœ Œ jœ ‰

‰ œœ ‰ œœ ‰ œœbb œœ ‰

‰ œ ‰ œ ‰ œb œ ‰

œœœœ œœ J

œœ ‰ œœ œœ3

œ œ œ Jœ ‰ œœ

3

‰ œœ ‰ œœ œœ œœ Œ

‰ œ ‰ œ œ œ Œ

&

?

7 jœœ ‰ ‰ jœœ Œ jœœ‰

Jœ ‰ ‰ Jœ Œ jœ ‰

‰ œœ ‰ œœ ‰ œœbb œœ ‰

‰ œ ‰ œ ‰ œb œ ‰

œœœœ œœ J

œœ ‰ œœ œœ3

œ œ œ Jœ ‰ œœ

3

‰ œœ ‰ œœ œœ œœ Œ

‰ œ ‰ œ œ œ Œ

&

?

B11

Œ œœ œœ## œœnn œœ# ‰ Jœœ

jœ ‰ ‰ Jœ Œ Jœ ‰

‰ œœ# œœ œœn ‰ œœ œœœœ

Jœ ‰ ‰ Jœ œ ‰ œ ‰

Œ œœ œœ## œœnn œœ# ‰ Jœœ

jœ ‰ ‰ Jœ Œ œ œ

‰œœœ ‰ œœœ J

œœœ ‰ Œ

Ó Œ Jœ ‰

Overworld ThemeFrom Super Mario Bros.

Koji KondoTranscribed by BLUESCD

http://www.gamemusicthemes.com/

Page 16: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

primeira ideia

Page 17: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

= 60

oscillator.frequency.value = 391;oscillator.start(0);oscillator.stop(context.currentTime + 1);

Page 18: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

= 60

setTimeout(function () { oscillator.frequency.value = 391; oscillator.start(0); oscillator.stop(context.currentTime + 1);}, 1000);

Page 19: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

= 60

setTimeout(function () { oscillator.frequency.value = 391; oscillator.start(0); oscillator.stop(context.currentTime + 1);}, 2000);

Page 20: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

problemasmanter track do tempooscillator tem vida curtaimpraticável de escrever

Page 21: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

soluçãocriar notação musicalcriar loop de execuçãocriar estrutura para lidar com tracks e notas

Page 22: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

notação musical

Page 23: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

&

?

44

44Piano

Allegro q»™ººœœ# œœ ‰

Jœœ ‰ œœ œœ ‰

œ œ ‰ Jœ ‰ œ œ ‰

Jœœœ ‰ Œ jœ ‰ Œ

Ó Jœ ‰ Œ

&

?

..

..

A3 jœœ ‰ ‰ jœœ Œ jœœ‰

Jœ ‰ ‰ Jœ Œ jœ ‰

‰ œœ ‰ œœ ‰ œœbb œœ ‰

‰ œ ‰ œ ‰ œb œ ‰

œœœœ œœ J

œœ ‰ œœ œœ3

œ œ œ Jœ ‰ œœ

3

‰ œœ ‰ œœ œœ œœ Œ

‰ œ ‰ œ œ œ Œ

&

?

7 jœœ ‰ ‰ jœœ Œ jœœ‰

Jœ ‰ ‰ Jœ Œ jœ ‰

‰ œœ ‰ œœ ‰ œœbb œœ ‰

‰ œ ‰ œ ‰ œb œ ‰

œœœœ œœ J

œœ ‰ œœ œœ3

œ œ œ Jœ ‰ œœ

3

‰ œœ ‰ œœ œœ œœ Œ

‰ œ ‰ œ œ œ Œ

&

?

B11

Œ œœ œœ## œœnn œœ# ‰ Jœœ

jœ ‰ ‰ Jœ Œ Jœ ‰

‰ œœ# œœ œœn ‰ œœ œœœœ

Jœ ‰ ‰ Jœ œ ‰ œ ‰

Œ œœ œœ## œœnn œœ# ‰ Jœœ

jœ ‰ ‰ Jœ Œ œ œ

‰œœœ ‰ œœœ J

œœœ ‰ Œ

Ó Œ Jœ ‰

Overworld ThemeFrom Super Mario Bros.

Koji KondoTranscribed by BLUESCD

http://www.gamemusicthemes.com/

Page 24: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

{ "title" : "Imperial March", "tempo" : 120, "time_signature" : "4/4", "score" : [ { "instrument" : "oscillator-square", "volume" : 0.5, "sheet" : [ "G.8D", "-.16", "G.8D", "-.16", "G.8D", "-.16", "Eb.8D", "Bb.16", "G.8D", "-.16", "Eb.8D", "Bb.16", "G.4", "-.4" ] } ]}

Uma partitura, bem simplificada, tem o título, tempo, assinatura de tempo, e as notas. A implementação em JSON que bolei ficou assim.

Page 25: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

[ "G.8D", "-.16", "G.8D", "-.16", "G.8D", "-.16", "Eb.8D", "Bb.16", "G.8D", "-.16", "Eb.8D", "Bb.16", "G.4", "-.4"]

Uma música é um array de notas. Mas como é a sintaxe dessas notas?

Page 26: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

"G.4"

frequência (391)

duração (1/4)

Uma função `getFrequency` interpreta a nota e retorna a frequência, dada uma fórmula matemática.

Page 27: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

"G5.4"

frequência (783)

duração (1/4)

Page 28: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

"G5.4D"

frequência (783)

duração (1/4 + 1/8)

Page 29: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

"-.4" duração (1/4)

Pausas são representadas com um "-".

Page 30: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

criando o loop

Page 31: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

conceitodividir a música nas menores marcações possíveis, e usar como marcação para iniciar as notas

Page 32: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

&

?

44

44Piano

Allegro q»™ººœœ# œœ ‰

Jœœ ‰ œœ œœ ‰

œ œ ‰ Jœ ‰ œ œ ‰

Jœœœ ‰ Œ jœ ‰ Œ

Ó Jœ ‰ Œ

&

?

..

..

A3 jœœ ‰ ‰ jœœ Œ jœœ‰

Jœ ‰ ‰ Jœ Œ jœ ‰

‰ œœ ‰ œœ ‰ œœbb œœ ‰

‰ œ ‰ œ ‰ œb œ ‰

œœœœ œœ J

œœ ‰ œœ œœ3

œ œ œ Jœ ‰ œœ

3

‰ œœ ‰ œœ œœ œœ Œ

‰ œ ‰ œ œ œ Œ

&

?

7 jœœ ‰ ‰ jœœ Œ jœœ‰

Jœ ‰ ‰ Jœ Œ jœ ‰

‰ œœ ‰ œœ ‰ œœbb œœ ‰

‰ œ ‰ œ ‰ œb œ ‰

œœœœ œœ J

œœ ‰ œœ œœ3

œ œ œ Jœ ‰ œœ

3

‰ œœ ‰ œœ œœ œœ Œ

‰ œ ‰ œ œ œ Œ

&

?

B11

Œ œœ œœ## œœnn œœ# ‰ Jœœ

jœ ‰ ‰ Jœ Œ Jœ ‰

‰ œœ# œœ œœn ‰ œœ œœœœ

Jœ ‰ ‰ Jœ œ ‰ œ ‰

Œ œœ œœ## œœnn œœ# ‰ Jœœ

jœ ‰ ‰ Jœ Œ œ œ

‰œœœ ‰ œœœ J

œœœ ‰ Œ

Ó Œ Jœ ‰

Overworld ThemeFrom Super Mario Bros.

Koji KondoTranscribed by BLUESCD

http://www.gamemusicthemes.com/

Page 33: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

semibreve1

Page 34: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

=semínima

1/4colcheia

1/8

Page 35: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

=semínima

1/4semicolcheia

1/16

Page 36: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

=semínima

1/4fusa1/32

Page 37: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

=semínima

1/4semifusa

1/64

Page 38: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

= 60

Page 39: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

=semínima

1/4semifusa

1/64

Page 40: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

1000ms = 16 cycles de 62.5ms

Se uma música tem 60 bpm, uma semínima (uma "batida") tem um segundo. Uma semínima tem 16 semifusas, então tem 16 ciclos. Cada ciclo, portanto, tem 1000/16 = 62.5ms

Page 41: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

parsedTrack["0"] = new Note("C.4");parsedTrack["16"] = new Note("D.4");parsedTrack["32"] = new Note("E.4");parsedTrack["64"] = new Note("F.4");

Tracks são hashes que contêm como índice o ciclo, e a nota que deve ser tocada nesse ciclo.

Page 42: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

parsedTrack["0"] = new Note("C.4");parsedTrack["16"] = new Note("D.4");parsedTrack["32"] = new Note("E.4");parsedTrack["64"] = new Note("F.4");

var cycleDuration = 62.5 , currentCycle = 0;

function renderCycle () { parsedTrack[currentCycle].play()

currentCycle = currentCycle + 1;

setTimeout(renderCycle, cycleDuration);};

Uma loop incrementa os ciclos e checa se há notas a serem tocadas ali.

Page 43: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API
Page 44: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

tracks múltiplos

Page 45: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

parsedTrack0["0"] = new Note("C.4");parsedTrack0["16"] = new Note("D.4");parsedTrack0["32"] = new Note("E.4");parsedTrack0["64"] = new Note("F.4");

parsedTrack1["0"] = new Note("G.4");parsedTrack1["16"] = new Note("A.4");

tracks[0] = parsedTrack0;tracks[1] = parsedTrack1;

var cycleDuration = 62.5 , currentCycle = 0;

function renderCycle () { for (var i = 0, l = tracks.length; i < l; i++) { tracks[i][currentCycle].play(); }

currentCycle = currentCycle + 1;

setTimeout(renderCycle, cycleDuration);};

Se o parâmetro de indexação de uma nota na música é o mesmo entre todos os tracks, é fácil fazer músicas com múltiplos tracks.

Page 46: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API
Page 47: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

dificuldades e adaptações no caminho

Page 48: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

oscillator tem vida curtacada nota é uma nova instância

Page 49: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

quartifusas (1/128)performance ficou baixa

Com múltiplos tracks, executar ciclos tomando uma nota quartifusa (1/128) de duração como base ficou muito pesado. Tive que voltar para uma semifusa (1/64).

Page 50: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

notações não planejadasnotas pontuadas, tercinas, acordes

Page 51: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

estrutura adaptávelnovos instrumentos, controles modificáveis

Page 52: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

futuro

Page 53: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

melhorar performance

Page 54: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

mais instrumentos, usando samples

Page 55: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

melhorias de interface

Page 56: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

keep having fun =)

Page 57: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

https://github.com/eshiota/retro-audio-js

Page 58: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

Mas e o mario?

Page 59: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

E nessa hora, foi tocado o tema do Mario completo, apenas com JavaScript. Achievement unlocked. ;D

Page 60: RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API

thanks!slideshare.net/eshiota

github.com/eshiota@shiota