retrojs - escrevendo músicas da era 8-bits com javascript e web audio api
Post on 29-Nov-2014
2.512 Views
Preview:
DESCRIPTION
TRANSCRIPT
RETROJSParty like it's 1983
@shiota 2013
OH HAI!slideshare.net/eshiota
github.com/eshiota@shiota
+ +
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.
Web Audio API
// Vendor prefixedvar context = new webkitAudioContext();
context.createOscillator() context.destination
connect()
var oscillator = context.createOscillator();
oscillator.connect(context.destination);
frequência
duração
oscillator.frequency.value = 780;
oscillator.start(0);oscillator.stop(context.currentTime + 0.5);
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. =)
Voltando ao assunto: challenge accepted, né? =)
o projeto
&
?
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/
primeira ideia
= 60
oscillator.frequency.value = 391;oscillator.start(0);oscillator.stop(context.currentTime + 1);
= 60
setTimeout(function () { oscillator.frequency.value = 391; oscillator.start(0); oscillator.stop(context.currentTime + 1);}, 1000);
= 60
setTimeout(function () { oscillator.frequency.value = 391; oscillator.start(0); oscillator.stop(context.currentTime + 1);}, 2000);
problemasmanter track do tempooscillator tem vida curtaimpraticável de escrever
soluçãocriar notação musicalcriar loop de execuçãocriar estrutura para lidar com tracks e notas
notação musical
&
?
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/
{ "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.
[ "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?
"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.
"G5.4"
frequência (783)
duração (1/4)
"G5.4D"
frequência (783)
duração (1/4 + 1/8)
"-.4" duração (1/4)
Pausas são representadas com um "-".
criando o loop
conceitodividir a música nas menores marcações possíveis, e usar como marcação para iniciar as notas
&
?
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/
semibreve1
=semínima
1/4colcheia
1/8
=semínima
1/4semicolcheia
1/16
=semínima
1/4fusa1/32
=semínima
1/4semifusa
1/64
= 60
=semínima
1/4semifusa
1/64
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
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.
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.
tracks múltiplos
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.
dificuldades e adaptações no caminho
oscillator tem vida curtacada nota é uma nova instância
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).
notações não planejadasnotas pontuadas, tercinas, acordes
estrutura adaptávelnovos instrumentos, controles modificáveis
futuro
melhorar performance
mais instrumentos, usando samples
melhorias de interface
keep having fun =)
https://github.com/eshiota/retro-audio-js
Mas e o mario?
E nessa hora, foi tocado o tema do Mario completo, apenas com JavaScript. Achievement unlocked. ;D
thanks!slideshare.net/eshiota
github.com/eshiota@shiota
top related