/taller-tonejs

Primary LanguageJavaScriptMIT LicenseMIT

Taller de iniciación a ToneJS

Introducción

Hace poco he ayudado a montar el CoderDojo de Carabanchel, que es un club de programación donde niños y niñas de entre 7 y 17 años aprenden a programar ayudados por mentores. Nos reunimos los sábados por la tarde, y yo intento ir siempre que puedo con mis dos hijas. Además, a veces preparo talleres. Al principio preparé un taller de p5js, que es una librería de JavaScript para crear arte interactivo en el navegador que gustó bastante, y ahora he preparado un taller de ToneJS, una librería JavaScript para crear música interactiva en el navegador. Este último taller está muy relacionado con un artículo que escribí hace tiempo en dónde explicaba cómo programar la música de Star Wars con Gibber.

Ejemplo 1 (una nota)

Este es el código más básico para crear un botón que al pulsarlo haga sonar una nota, en este caso un DO, en el navegador:

<!DOCTYPE html>
<html>
  <head>
    <title>ToneJS - 01 una nota</title>
    <script src="../lib/Tone.js"></script>
  </head>

  <body>
    <button id="do">UNA NOTA</button>
  </body>

  <script type="text/javascript">
    const synth = new Tone.Synth().toMaster();
    Tone.Transport.start();

    document.querySelector("#do")
      .addEventListener("click", async () => {
        synth.triggerAttackRelease("C4", "4n");
    });
  </script>
</html>

01-una-nota.html.

En este punto hay que remarcar que las notas se ponen en el estilo anglosajón:

  • DO=C
  • RE=D
  • MI=E
  • FA=F
  • SOL=G
  • LA=A
  • SI=B

El número que sigue a la nota hace referencia a la octava (ya sea esta más grave o más aguda).

Ejemplo 2 (piano con botones)

A continuación, parte del código para hacer una especie de piano con botones:

<!DOCTYPE html>
<html>
  <head>
    <title>ToneJS - 02 varias notas</title>
    <script src="../lib/Tone.js"></script>
  </head>

  <body>
    <button id="do">DO</button>
    <button id="re">RE</button>
    ...
  </body>

  <script type="text/javascript">
    const synth = new Tone.Synth().toMaster();
    Tone.Transport.start();

    document.querySelector("#do")
      .addEventListener("click", async () => {
        synth.triggerAttackRelease("C4", "4n");
    });

    document.querySelector("#re")
      .addEventListener("click", async () => {
        synth.triggerAttackRelease("D4", "4n");
    });

    ...
  </script>
</html>

02-varias-notas.html.

Ejemplo 03 (escala)

A continuación mostramos el código para que suene una escala:

<!DOCTYPE html>
<html>
  <head>
    <title>ToneJS - 03 escala</title>
    <script src="../lib/Tone.js"></script>
  </head>

  <body>
    <button id="escala">ESCALA</button>
  </body>

  <script type="text/javascript">
    const synth = new Tone.Synth().toMaster();
    Tone.Transport.start();

    document.querySelector("#escala")
      .addEventListener("click", async () => {
        synth.triggerAttackRelease("C4", "8n", 1);
        synth.triggerAttackRelease("D4", "8n", 2);
        synth.triggerAttackRelease("E4", "8n", 3);
        synth.triggerAttackRelease("F4", "8n", 4);
        synth.triggerAttackRelease("G4", "8n", 5);
        synth.triggerAttackRelease("A4", "8n", 6);
        synth.triggerAttackRelease("B4", "8n", 7);
        synth.triggerAttackRelease("C5", "8n", 8);
    });
  </script>
</html>

03-escala.html.

Ejemplo 4 (varias notas con duraciones diferentes)

Ahora hacemos algo un poco más elaborado utilizamos 2 arrays: uno para las notas y otro para las duraciones de las notas.

Aquí hay que remarcar que para los tiempos hay que tener en cuenta que:

  • 1n hace referencia a una redonda (4 tiempos)
  • 2n hace referencia a una blanca (2 tiempos)
  • 4n hace referencia a una negra (1 tiempo)
  • 8n hace referencia a una corchea (0,5 tiempos)
  • 16n hace referencia a una semicorchea (0,25 tiempos)

Teniendo en cuenta esto, a continuación el código para hacer una escala con diferentes tiempos:

<!DOCTYPE html>
<html>
  <head>
    <title>ToneJS - 04 notas</title>
    <script src="../lib/Tone.js"></script>
    <script src="../lib/Rhythm.js"></script>
  </head>

  <body>
    <button id="notas">NOTAS</button>
  </body>

  <script type="text/javascript">
    var synth = new Tone.Synth().toMaster();

    document.querySelector("#notas").addEventListener("click", async () => {

      var notas = [
        "C4","D4","E4","F4","G4","A4","B4","C5"];
      var duraciones = [
        "2n","4n","8n","16n","16n","8n","4n","2n"];

      var cancion = Rhythm.mergeDurationsAndPitch(duraciones, notas);

      var part = new Tone.Part(function(time, value){
        console.log(value.note + " " + value.duration);
        synth.triggerAttackRelease(value.note, value.duration, time);
      }, cancion );

      part.start(0);
      Tone.Transport.start();
    });
  </script>
</html>

04-notas.html.

Ejemplo 05 (cumpleaños feliz)

Ahora vamos a coger una partitura sencilla, la del cumpleaños feliz:

Y la codificamos con ToneJS:

<!DOCTYPE html>
<html>
  <head>
    <title>ToneJS - 05 cumpleaños feliz</title>
    <script src="../lib/Tone.js"></script>
    <script src="../lib/Rhythm.js"></script>
  </head>

  <body>
    <button id="notas">CUMPLEAÑOS FELIZ</button>
  </body>

  <script type="text/javascript">
    var synth = new Tone.Synth().toMaster();

    document.querySelector("#notas").addEventListener("click", async () => {

      var notas = [
        "C4", "C4",
        "D4", "C4", "F4",
        "E4", "C4", "C4",
        "D4", "C4", "G4",
        "F4", "C4", "C4",
        "C5", "A4", "F4",
        "E4", "D4", "Bb4", "Bb4",
        "A4", "F4", "G4",
        "F4"];
      var duraciones = [
        "8n", "8n",
        "4n", "4n", "4n",
        "2n", "8n", "8n",
        "4n", "4n", "4n",
        "2n", "8n", "8n",
        "4n", "4n", "4n",
        "4n", "4n", "8n", "8n",
        "4n", "4n", "4n",
        "2n"];

      var cancion = Rhythm.mergeDurationsAndPitch(duraciones, notas);

      var part = new Tone.Part(function(time, value){
        console.log(time + " " + value.note + " " + value.duration);
        synth.triggerAttackRelease(value.note, value.duration, time);
      }, cancion );

      part.start(0);
      Tone.Transport.start();
    });
  </script>
</html>

05-cumpleaños.html.

Ejemplo 06 (Star Wars)

Y para terminar, hacemos lo mismo con la partitura de Star Wars:

Aquí hay que tener en cuenta que los trisillos se codifican con una t, en vez de con una n (ejemplo 8t). Y para los puntillos hay que disminuuir su número (ejemplo 3n).

<!DOCTYPE html>
<html>
  <head>
    <title>ToneJS - 06 Star Wars</title>
    <script src="../lib/Tone.js"></script>
    <script src="../lib/Rhythm.js"></script>
  </head>

  <body>
    <button id="notas">Star Wars</button>
  </body>

  <script type="text/javascript">
    var synth = new Tone.Synth().toMaster();

    document.querySelector("#notas").addEventListener("click", async () => {

      var notas = [
        "F3", "C4",
        "Bb3", "A3", "G3", "F4", "C4",
        "Bb3", "A3", "G3", "F4", "C4",
        "Bb3", "A3", "Bb3", "G3", "C3", "C3", "C3",
        "F3", "C4",
        "Bb3", "A3", "G3", "F4", "C4",
        "Bb3", "A3", "Bb3", "G3", "C3", "C3",
        "D3", "D3", "Bb3", "A3", "G3", "F3",
        "F3", "G3", "A3", "G3", "D3", "E3", "C3", "C3",
        "D3", "D3", "Bb3", "A3", "G3", "F3",
        "C4", "G3", "G3", "C3", "C3",
        "D3", "D3", "Bb3", "A3", "G3", "F3",
        "F3", "G3", "A3", "G3", "D3", "E3", "C4", "C4",
        "F4", "F3",
        "C4", "C3", "C3", "C3",
        "F3", "C4",
        "Bb3", "A3", "G3", "F4", "C4",
        "Bb3", "A3", "G3", "F4", "C4",
        "Bb3", "A3", "Bb3", "G3", "C3", "C3", "C3",
        "F3", "C4",
        "Bb3", "A3", "G3", "F4", "C4",
        "Bb3", "A3", "G3", "F4", "C4",
        "Bb3", "A3", "Bb3", "G3", "C3", "C3", "C3",
        "F4", "F4", "F4", "F4", "F4"];
      var duraciones = [
        "2n", "2n",
        "8t", "8t", "8t", "2n", "4n",
        "8t", "8t", "8t", "2n", "4n",
        "8t", "8t", "8t", "2n", "8t", "8t", "8t",
        "2n", "2n",
        "8t", "8t", "8t", "2n", "4n",
        "8t", "8t", "8t", "2n", "8n", "8n",
        "3n", "8n", "8n", "8n", "8n", "8n",
        "8t", "8t", "8t", "8n", "8n", "4n", "8n", "8n",
        "3n", "8n", "8n", "8n", "8n", "8n",
        "8n", "8n", "2n", "8n", "8n",
        "3n", "8n", "8n", "8n", "8n", "8n",
        "8t", "8t", "8t", "8n", "8n", "4n", "8n", "8n",
        "2n", "2n",
        "1n", "8t", "8t", "8t",
        "2n", "2n",
        "8t", "8t", "8t", "2n", "4n",
        "8t", "8t", "8t", "2n", "4n",
        "8t", "8t", "8t", "2n", "8t", "8t", "8t",
        "2n", "2n",
        "8t", "8t", "8t", "2n", "4n",
        "8t", "8t", "8t", "2n", "4n",
        "8t", "8t", "8t", "2n", "8t", "8t", "8t",
        "4n", "8t", "8t", "8t", "4n"];

      var cancion = Rhythm.mergeDurationsAndPitch(duraciones, notas);

      var part = new Tone.Part(function(time, value){
        console.log(time + " " + value.note + " " + value.duration);
        synth.triggerAttackRelease(value.note, value.duration, time);
      }, cancion );

      part.start(0);
      Tone.Transport.start();
    });
  </script>
</html>

06-starwars.html.

Recursos