RETROJS
Party 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 Ja...
Web Audio API
// Vendor prefixed
var 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 ...
Voltando ao assunto: challenge accepted, né? =)
o projeto
&
?
4
4
4
4
Piano
Allegro q»™ºº
œ
œ#
œ
œ ‰
J
œ
œ ‰ œ
œ
œ
œ ‰
œ œ ‰
J
œ ‰ œ œ ‰
J
œ
œœ ‰ Œ j
œ ‰ Œ
Ó J
œ ‰ Œ
&
?
..
..
A3
j...
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 +...
= 60
setTimeout(function () {
oscillator.frequency.value = 391;
oscillator.start(0);
oscillator.stop(context.currentTime +...
problemas
manter track do tempo
oscillator tem vida curta
impraticável de escrever
solução
criar notação musical
criar loop de execução
criar estrutura para lidar com tracks e notas
notação musical
&
?
4
4
4
4
Piano
Allegro q»™ºº
œ
œ#
œ
œ ‰
J
œ
œ ‰ œ
œ
œ
œ ‰
œ œ ‰
J
œ ‰ œ œ ‰
J
œ
œœ ‰ Œ j
œ ‰ Œ
Ó J
œ ‰ Œ
&
?
..
..
A3
j...
{
"title" : "Imperial March",
"tempo" : 120,
"time_signature" : "4/4",
"score" : [
{
"instrument" : "oscillator-square",
"...
[
"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...
"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
...
"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
conceito
dividir a música nas menores
marcações possíveis, e usar como
marcação para iniciar as notas
&
?
4
4
4
4
Piano
Allegro q»™ºº
œ
œ#
œ
œ ‰
J
œ
œ ‰ œ
œ
œ
œ ‰
œ œ ‰
J
œ ‰ œ œ ‰
J
œ
œœ ‰ Œ j
œ ‰ Œ
Ó J
œ ‰ Œ
&
?
..
..
A3
j...
semibreve
1
=
semínima
1/4
colcheia
1/8
=
semínima
1/4
semicolcheia
1/16
=
semínima
1/4
fusa
1/32
=
semínima
1/4
semifusa
1/64
= 60
=
semínima
1/4
semifusa
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 sem...
parsedTrack["0"] = new Note("C.4");
parsedTrack["16"] = new Note("D.4");
parsedTrack["32"] = new Note("E.4");
parsedTrack[...
parsedTrack["0"] = new Note("C.4");
parsedTrack["16"] = new Note("D.4");
parsedTrack["32"] = new Note("E.4");
parsedTrack[...
tracks múltiplos
parsedTrack0["0"] = new Note("C.4");
parsedTrack0["16"] = new Note("D.4");
parsedTrack0["32"] = new Note("E.4");
parsedTra...
dificuldades e adaptações
no caminho
oscillator tem vida curta
cada nota é uma nova instância
quartifusas (1/128)
performance ficou baixa
Com múltiplos tracks, executar ciclos tomando uma nota quartifusa (1/128) de du...
notações não planejadas
notas pontuadas, tercinas, acordes
estrutura adaptável
novos 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
RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API
RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API
RetroJS - Escrevendo músicas da era 8-bits com JavaScript e Web Audio API
Upcoming SlideShare
Loading in...5
×

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

2,466

Published on

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.

Published in: Technology
1 Comment
16 Likes
Statistics
Notes
No Downloads
Views
Total Views
2,466
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
34
Comments
1
Likes
16
Embeds 0
No embeds

No notes for slide

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

  1. 1. RETROJS Party like it's 1983 @shiota 2013
  2. 2. OH HAI!slideshare.net/eshiota github.com/eshiota @shiota
  3. 3. + +
  4. 4. 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.
  5. 5. Web Audio API
  6. 6. // Vendor prefixed var context = new webkitAudioContext();
  7. 7. context.createOscillator() context.destination connect()
  8. 8. var oscillator = context.createOscillator(); oscillator.connect(context.destination);
  9. 9. frequência duração
  10. 10. oscillator.frequency.value = 780; oscillator.start(0); oscillator.stop(context.currentTime + 0.5);
  11. 11. 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. =)
  12. 12. Voltando ao assunto: challenge accepted, né? =)
  13. 13. o projeto
  14. 14. & ? 4 4 4 4 Piano Allegro q»™ºº œ œ# œ œ ‰ J œ œ ‰ œ œ œ œ ‰ œ œ ‰ J œ ‰ œ œ ‰ J œ œœ ‰ Œ j œ ‰ Œ Ó J œ ‰ Œ & ? .. .. A3 j œ œ ‰ ‰ j œ œ Œ j œ œ ‰ J œ ‰ ‰ J œ Œ j œ ‰ ‰ œ œ ‰ œ œ ‰ œ œ b b œ œ ‰ ‰ œ ‰ œ ‰ œb œ ‰ œ œ œ œ œ œ J œ œ ‰ œ œ œ œ 3 œ œ œ J œ ‰ œ œ 3 ‰ œ œ ‰ œ œ œ œ œ œ Œ ‰ œ ‰ œ œ œ Œ & ? 7 j œ œ ‰ ‰ j œ œ Œ j œ œ ‰ J œ ‰ ‰ J œ Œ j œ ‰ ‰ œ œ ‰ œ œ ‰ œ œ b b œ œ ‰ ‰ œ ‰ œ ‰ œb œ ‰ œ œ œ œ œ œ J œ œ ‰ œ œ œ œ 3 œ œ œ J œ ‰ œ œ 3 ‰ œ œ ‰ œ œ œ œ œ œ Œ ‰ œ ‰ œ œ œ Œ & ? B11 Œ œœ œœ## œœnn œœ# ‰ J œœ j œ ‰ ‰ J œ Œ J œ ‰ ‰ œœ# œœ œœn ‰ œ œ œ œ œ œ J œ ‰ ‰ J œ œ ‰ œ ‰ Œ œœ œœ## œœnn œœ# ‰ J œœ j œ ‰ ‰ J œ Œ œ œ ‰ œœœ ‰ œœœ J œœœ ‰ Œ Ó Œ J œ ‰ Overworld Theme From Super Mario Bros. Koji Kondo Transcribed by BLUESCD http://www.gamemusicthemes.com/
  15. 15. primeira ideia
  16. 16. = 60 oscillator.frequency.value = 391; oscillator.start(0); oscillator.stop(context.currentTime + 1);
  17. 17. = 60 setTimeout(function () { oscillator.frequency.value = 391; oscillator.start(0); oscillator.stop(context.currentTime + 1); }, 1000);
  18. 18. = 60 setTimeout(function () { oscillator.frequency.value = 391; oscillator.start(0); oscillator.stop(context.currentTime + 1); }, 2000);
  19. 19. problemas manter track do tempo oscillator tem vida curta impraticável de escrever
  20. 20. solução criar notação musical criar loop de execução criar estrutura para lidar com tracks e notas
  21. 21. notação musical
  22. 22. & ? 4 4 4 4 Piano Allegro q»™ºº œ œ# œ œ ‰ J œ œ ‰ œ œ œ œ ‰ œ œ ‰ J œ ‰ œ œ ‰ J œ œœ ‰ Œ j œ ‰ Œ Ó J œ ‰ Œ & ? .. .. A3 j œ œ ‰ ‰ j œ œ Œ j œ œ ‰ J œ ‰ ‰ J œ Œ j œ ‰ ‰ œ œ ‰ œ œ ‰ œ œ b b œ œ ‰ ‰ œ ‰ œ ‰ œb œ ‰ œ œ œ œ œ œ J œ œ ‰ œ œ œ œ 3 œ œ œ J œ ‰ œ œ 3 ‰ œ œ ‰ œ œ œ œ œ œ Œ ‰ œ ‰ œ œ œ Œ Overworld Theme From Super Mario Bros. Koji Kondo Transcribed by BLUESCD http://www.gamemusicthemes.com/
  23. 23. { "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.
  24. 24. [ "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?
  25. 25. "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.
  26. 26. "G5.4" frequência (783) duração (1/4)
  27. 27. "G5.4D" frequência (783) duração (1/4 + 1/8)
  28. 28. "-.4" duração (1/4) Pausas são representadas com um "-".
  29. 29. criando o loop
  30. 30. conceito dividir a música nas menores marcações possíveis, e usar como marcação para iniciar as notas
  31. 31. & ? 4 4 4 4 Piano Allegro q»™ºº œ œ# œ œ ‰ J œ œ ‰ œ œ œ œ ‰ œ œ ‰ J œ ‰ œ œ ‰ J œ œœ ‰ Œ j œ ‰ Œ Ó J œ ‰ Œ & ? .. .. A3 j œ œ ‰ ‰ j œ œ Œ j œ œ ‰ J œ ‰ ‰ J œ Œ j œ ‰ ‰ œ œ ‰ œ œ ‰ œ œ b b œ œ ‰ ‰ œ ‰ œ ‰ œb œ ‰ œ œ œ œ œ œ J œ œ ‰ œ œ œ œ 3 œ œ œ J œ ‰ œ œ 3 ‰ œ œ ‰ œ œ œ œ œ œ Œ ‰ œ ‰ œ œ œ Œ & ? 7 j œ œ ‰ ‰ j œ œ Œ j œ œ ‰ J œ ‰ ‰ J œ Œ j œ ‰ ‰ œ œ ‰ œ œ ‰ œ œ b b œ œ ‰ ‰ œ ‰ œ ‰ œb œ ‰ œ œ œ œ œ œ J œ œ ‰ œ œ œ œ 3 œ œ œ J œ ‰ œ œ 3 ‰ œ œ ‰ œ œ œ œ œ œ Œ ‰ œ ‰ œ œ œ Œ & ? B11 Œ œœ œœ## œœnn œœ# ‰ J œœ j œ ‰ ‰ J œ Œ J œ ‰ ‰ œœ# œœ œœn ‰ œ œ œ œ œ œ J œ ‰ ‰ J œ œ ‰ œ ‰ Œ œœ œœ## œœnn œœ# ‰ J œœ j œ ‰ ‰ J œ Œ œ œ ‰ œœœ ‰ œœœ J œœœ ‰ Œ Ó Œ J œ ‰ Overworld Theme From Super Mario Bros. Koji Kondo Transcribed by BLUESCD http://www.gamemusicthemes.com/
  32. 32. semibreve 1
  33. 33. = semínima 1/4 colcheia 1/8
  34. 34. = semínima 1/4 semicolcheia 1/16
  35. 35. = semínima 1/4 fusa 1/32
  36. 36. = semínima 1/4 semifusa 1/64
  37. 37. = 60
  38. 38. = semínima 1/4 semifusa 1/64
  39. 39. 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
  40. 40. 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.
  41. 41. 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.
  42. 42. tracks múltiplos
  43. 43. 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.
  44. 44. dificuldades e adaptações no caminho
  45. 45. oscillator tem vida curta cada nota é uma nova instância
  46. 46. 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).
  47. 47. notações não planejadas notas pontuadas, tercinas, acordes
  48. 48. estrutura adaptável novos instrumentos, controles modificáveis
  49. 49. futuro
  50. 50. melhorar performance
  51. 51. mais instrumentos, usando samples
  52. 52. melhorias de interface
  53. 53. keep having fun =)
  54. 54. https://github.com/eshiota/retro-audio-js
  55. 55. Mas e o mario?
  56. 56. E nessa hora, foi tocado o tema do Mario completo, apenas com JavaScript. Achievement unlocked. ;D
  57. 57. thanks!slideshare.net/eshiota github.com/eshiota @shiota
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×