Introducción a la Teoría Musical*

* con Javascript + Web Audio API

Puede verse esta presentación online visitando:

El código fuente mostrado aquí puede encontrarse en la siguiente dirección:

La naturaleza del Sonido

¿Qué es el sonido?

El mundo físico

El mundo digital

La naturaleza del Sonido

El mundo Físico

La perturbación de un objeto produce una onda que se propaga a través de un medio (como el aire).

La naturaleza del Sonido

El mundo Físico

Estas ondas tienen ciertas características:

  • Amplitud
  • Frecuencia
  • Longitud
  • Intensidad

La naturaleza del Sonido

El mundo Físico

Las ondas llegan a nuestros oidos tras propagarse y nuestros cerebros las interpretan como 'sonido'.

La naturaleza del Sonido

El mundo Físico

La forma / complejidad de la onda depende del objeto que la produce.

La naturaleza del Sonido

El mundo Digital

En el mundo físico, las ondas son infinitamente densas; en el mundo digital, tenemos espacio limitado. Por tanto guardamos 'muestras' de las ondas.

La naturaleza del Sonido

El mundo Digital

Estas muestras no son más que cantidades numéricas que representan la forma de la onda a lo largo del tiempo.

La naturaleza del Sonido

El mundo Digital

Una cantidad de muestras considerable es necesaria para asegurar la calidad del sonido. Se tiene como estándar 44100 muestras por segundo.

La naturaleza del Sonido

El mundo Digital

Adicionalmente, otro factor en la calidad es la cantidad de bits de cada muestra. Mientras más bits tengamos, el sonido será más fiel al original en amplitud. 16 bits es el estándar actual.

¿Y Ahora qué?

¡Ya podemos trabajar sobre el sonido en forma de código y empezar a hablar sobre música!

La Música y el Código

¿Cuánto sabemos? ¿Cuánto sabremos?

  • Generar un sonido
  • Sonido de frecuencia específica (nota)
  • Notas específicas (escalas)
  • Notas tocadas a la vez (acordes)
  • Acordes consecutivos (canciones)

La Música y el Código

¡Escúchame mundo!

440 Hz

  • Frecuencia fundamental en la música occidental moderna.
  • Musicalmente se le reconoce como 'La' o 'A'.

La Música y el Código

¡Escúchame mundo!

 function getAudioContext() {
   if(!window.audioContext)
     window.audioContext = new AudioContext();
   return window.audioContext;
 }
AudioContext
Source
Effect
Destination

La Música y el Código

¡Escúchame mundo!

  var context = getAudioContext()
  ,      real = new Float32Array([0, 1])
  ,      imaj = new Float32Array([0, 0])
  ,  sinewave = context.createPeriodicWave(real, imaj)
  ,   sineosc = context.createOscillator();

  sineosc.setPeriodicWave(sinewave);
  sineosc.frequency.value = 440;
  sineosc.connect(context.destination);
  sineosc.start(audioContext.currentTime);
  sineosc.stop(audioContext.currentTime + 1);

  log('Context Sample rate: ' + context.sampleRate + 'Hz');
  log('Oscillator frequency: ' + sineosc.frequency.value + 'Hz');
  log('---');

La Música y el Código

Octavas

  • La octava de una nota es aquella que la dobla en frecuencia.
  • La octava superior de una onda de 440Hz es 880Hz y la inferior 220Hz respectivamente.

La Música y el Código

Octavas

  var   context = getAudioContext()
  , frequencies = [220, 440, 880]
  , currentTime = audioContext.currentTime
  ,    duration = 1;

  frequencies.forEach(function(frequency, index) {
    var sineosc = context.createOscillator()
    , startTime = currentTime + (index * duration);
    sineosc.type = 'sine';
    sineosc.frequency.value = frequency;
    sineosc.connect(context.destination);
    sineosc.start(startTime);
    sineosc.stop(startTime + duration);
    sineosc.onended = function(){ log('Finished ' + frequency + 'Hz tone.'); };
  });

  log('Playing octaves: ' + frequencies);

La Música y el Código

Tonos y Semitonos

  • Es el menor intervalo posible en la música occidental.
  • Una tecla adyacente en el piano, un traste adyacente en la guitarra.
  • Dos semitonos hacen un tono.

S

T

S

La Música y el Código

Tonos y Semitonos

  • Entre una nota y su octava, hay 12 semitonos.
  • El semitono siguiente a una frecuencia se obtiene multiplicándola por un número r.
  • r es 12√2 (siguiendo una escala logarítmica en la distribución de las frecuencias)

La Música y el Código

Tonos y Semitonos

  var twelfthRootOfTwo = Math.pow(2, 1/12)
  ,   currentFrequency = 220
  ,        frequencies = [currentFrequency];

  for (var i = 0; i < 12; i++) {
    currentFrequency *= twelfthRootOfTwo;
    frequencies.push(currentFrequency);
  }

La Música y el Código

Escalas

  • Sucesión de notas con cierto sentido.
  • La escala más simple es la cromática (la acabamos de escuchar), aunque parezca carecer de sentido.
  • Las escalas comunes y corrientes tienen 7 notas.

La Música y el Código

Escala Mayor

  • 7 notas específicas.
  • Siguen el patrón:

       T T S T T T S 

  • Tiene un sentido 'alegre'.

T

T

S

T

T

T

S

La Música y el Código

Escala Mayor

  var           TONE = 2
  ,         SEMITONE = 1
  ,            scale = [TONE, TONE, SEMITONE, TONE, TONE, TONE, SEMITONE]
  , currentFrequency = 0
  , scaleFrequencies = [frequencies[0]];

  scale.forEach(function (interval) {
    currentFrequency += interval;
    scaleFrequencies.push(frequencies[currentFrequency]);
  })

La Música y el Código

Escala Menor

  • 7 notas específicas.
  • Siguen el patrón:

       T S T T S T T 

  • Tiene un sentido 'triste', 'vacío'.

T

T

S

T

T

T

S

La Música y el Código

Escala Menor

  var           TONE = 2
  ,         SEMITONE = 1
  ,            scale = [TONE, SEMITONE, TONE, TONE, SEMITONE, TONE, TONE]
  , currentFrequency = 0
  , scaleFrequencies = [frequencies[0]];

  scale.forEach(function (interval) {
    currentFrequency += interval;
    scaleFrequencies.push(frequencies[currentFrequency]);
  })

La Música y el Código

Modos en las Escalas

  • Cada escala tiene una serie de modos.
  • Son rotaciones de la escala Mayor.
  • Existen 7 modos.

La Música y el Código

Modos en las Escalas

  var   notes = []
  ,      mode = [TONE, TONE, SEMITONE, TONE, TONE, TONE, SEMITONE]
  , modeStart = 0;

  for (var i = 0; i < 8; i++) {
    var currentFrequency = modeStart;
    notes.push(frequencies[currentFrequency]);

    mode.forEach(function (interval) {
      currentFrequency += interval;
      notes.push(frequencies[currentFrequency]);
    });

    modeStart += mode[0];
    mode.push(mode.shift());
  }

La Música y el Código

Terceras

  • Son saltos entre notas, medidos en semitonos.
  • Pueden ser menores o mayores.
  • Se saltan 3 y 4 semitonos respectivamente.
  • Puede entenderse también como saltar entre notas de la escala.

La Música y el Código

Terceras

  var          scale = [TONE, TONE, SEMITONE, TONE, TONE, TONE, SEMITONE]
  ,            notes = [frequencies[0]]
  , currentFrequency = 0;

  while(notes.length < 3) {
    var group = scale.splice(0, 2);
    currentFrequency += group[0] + group[1];
    notes.push(frequencies[currentFrequency]);
  }

La Música y el Código

Acordes

  • Son intervalos (normalmente terceras) tocados simultáneamente.
  • Los estos intervalos pertenecen a una escala.

La Música y el Código

Acordes

  notes.forEach(function(frequency, index) {
    var sineosc = context.createOscillator()
    , startTime = currentTime;
    sineosc.type = 'sine';
    sineosc.frequency.value = frequency;
    sineosc.connect(context.destination);
    sineosc.start(startTime);
    sineosc.stop(startTime + duration);
    // ...
  });

La Música y el Código

Escalas de Acordes

  • Pueden generarse varios acordes en base a un escala.
  • El acorde que empieza con la primera nota de la escala se denomina I.
  • Los acordes generados se vuelven menores/mayores automáticamente.

La Música y el Código

Escalas de Acordes

  var   chords = []
  , chordStart = 0;

  for (var i = 0; i < 8; i++) {
    var currentFrequency = chordStart
    ,              notes = [frequencies[currentFrequency]]
    ,         chordScale = scale.slice();

    while(notes.length < 3) {
      var group = chordScale.splice(0, 2);
      currentFrequency += group[0] + group[1];
      notes.push(frequencies[currentFrequency]);
    }

    chords.push(notes);
    chordStart += scale[0];
    scale.push(scale.shift());
  }

La Música y el Código

Progresiones de Acordes

  • Series de acordes (de una escala) sucesivos.
  • Las canciones actuales giran en torno a progresiones conocidas.

La Música y el Código

Progresiones de Acordes

  var I = 0, II = 1, III = 2, IV = 3, V = 4, VI = 5, VII = 6, VIII = 7
  , songChords = [chords[I], chords[V], chords[VI], chords[IV], chords[I]];

I V vi VI

La Música y el Código

Progresiones de Acordes

Epílogo

Abstracciones

Epílogo

Abstracciones

Pyo

from pyo import * 
s = Server().boot()
s.start()

freqs = midiToHz([60 ,64, 67, 60+12, 64+6, 67+12])

rnd = Choice(choice=freqs, freq=[1, 4])
rnd2 = Choice(choice=freqs, freq=[4, 8])
a = SineLoop(freq=[rnd, rnd2], mul=.15).out()

s.gui(locals())

Epílogo

Abstracciones

Rhodey voc => JCRev r => Echo a => Echo b => Echo c => dac;

220.0 => voc.freq;
0.8 => voc.gain;
.8 => r.gain;
.2 => r.mix;
1000::ms => a.max => b.max => c.max;
750::ms => a.delay => b.delay => c.delay;
.50 => a.mix => b.mix => c.mix;

fun void vecho_Shred() {
    0.0 => float decider;
    0.0 => float mix;
    0.0 => float old;
    0.0 => float inc;
    0 => int n;

    while( true ) {
        Math.random2f( 0, 1 ) => decider;
        if( decider < .3 ) 0.0 => mix;
        else if( decider < .6 ) .08 => mix;
        else if( decider < .8 ) .5 => mix;
        else .15 => mix;

        (mix-old)/1000.0 => inc;
        1000 => n;
        while( n-- ) {
            old + inc => old;
            old => a.mix => b.mix => c.mix;
            1::ms => now;
        }
        mix => old;
        Math.random2(2,6)::second => now;
    }
}

spork ~ vecho_Shred();

[ 0, 2, 4, 7, 9 ] @=> int scale[];

while( true ) {
    scale[Math.random2(0,scale.cap()-1)] => int freq;

    Std.mtof( ( 33 + Math.random2(0,1) * 12 + freq ) ) => voc.freq;
    Math.random2f( 0.6, 0.8 ) => voc.noteOn;

    if( Math.randomf() > 0.85 )
    { 1000::ms => now; }
    else if( Math.randomf() > .85 )
    { 500::ms => now; }
    else if( Math.randomf() > .1 )
    { .250::second => now; }
    else {
        0 => int i;
        2 * Math.random2( 1, 3 ) => int pick;
        0 => int pick_dir;
        0.0 => float pluck;

        for( ; i < pick; i++ ) {
            Math.random2f(.4,.6) + i*.035 => pluck;
            pluck + -0.02 * (i * pick_dir) => voc.noteOn;
            !pick_dir => pick_dir;
            250::ms => now;
        }
    }
}

Epílogo

Abstracciones

define :play_bb do |n|
  sample :drum_heavy_kick
  sample :ambi_drone, rate: [0.25, 0.5, 0.125, 1].choose, amp: 0.25 if rand < 0.125
  sample :ambi_lunar_land, rate: [0.5, 0.125, 1, -1, -0.5].choose, amp: 0.25 if rand < 0.125
  sample :loop_amen, attack: 0, release: 0.05, start: 1 - (1.0 / n), rate: [1,1,1,1,1,1,-1].choose
  sleep sample_duration(:loop_amen) / n
end
loop {play_bb([1,2,4,8,16].choose)}

Epílogo

Abstracciones

(ns overtone.examples.compositions.funk
    (:use [overtone.live]))

(definst string [note 60 amp 1.0 dur 0.5 decay 30 coef 0.3 gate 1]
  (let [freq (midicps note)
        noize (* 0.8 (white-noise))
        dly   (/ 1.0 freq)
        plk   (pluck noize gate dly dly decay coef)
        dist  (distort plk)
        filt  (rlpf dist (* 12 freq) 0.6)
        clp   (clip2 filt 0.8)
        reverb (free-verb clp 0.4 0.8 0.2)]
    (* amp (env-gen (perc 0.0001 dur) :action 0) reverb)))

(def snare (sample (freesound-path 26903)))
(def kick (sample (freesound-path 2086)))
(def close-hihat (sample (freesound-path 802)))
(def open-hihat (sample (freesound-path 26657)))


(defn subdivide
    [a b position]
    (+ a (* position (/ (- b a) 4) )))

(defn drums [nome]
    (let [beat (nome)]
        ; hi-hat pattern
        (at (nome beat) (close-hihat))
        (at (nome (+ 1 beat)) (open-hihat))
        (at (nome (+ 2 beat)) (close-hihat))
        (at (nome (+ 3 beat)) (close-hihat))
        (at (nome (+ 4 beat)) (close-hihat))
        (at (nome (+ 5 beat)) (open-hihat))
        (at (nome (+ 6 beat)) (close-hihat))
        (at (nome (+ 7 beat)) (close-hihat))

        ; snare pattern
        (at (nome (+ 2 beat)) (snare))
        (at (subdivide (nome (+ 2 beat)) (nome (+ 4 beat)) 3) (snare))
        (at (subdivide (nome (+ 4 beat)) (nome (+ 6 beat)) 1) (snare))
        (at (nome (+ 6 beat)) (snare))
        (at (subdivide (nome (+ 6 beat)) (nome (+ 8 beat)) 3) (snare))

        ; kick drum pattern
        (at (nome beat) (kick))
        (at (nome (+ 5 beat)) (kick))
        (at (nome (+ 7 beat)) (kick))
        (apply-by (nome (+ 8 beat)) drums nome [])))

(defn bass [nome]
    (let [beat (nome)]
    (at (nome beat) (string 51))
    (at (subdivide (nome beat) (nome (+ 2 beat)) 1) (string 51))
    (at (subdivide (nome beat) (nome (+ 2 beat)) 3) (string 51))
    (at (subdivide (nome (+ beat 1)) (nome (+ 3 beat)) 1) (string 51))
    (at (subdivide (nome (+ beat 1)) (nome (+ 3 beat)) 3) (string 51))
    (at (nome (+ 4 beat)) (string 51))
    (at (subdivide (nome (+ 4 beat)) (nome (+ 6 beat)) 1) (string 49))
    (at (nome (+ 5 beat)) (string 46))
    (at (nome (+ 6 beat)) (string 51))
    (at (subdivide (nome (+ 6 beat)) (nome (+ 8 beat)) 1) (string 49))
    (at (nome (+ 7 beat)) (string 46))
    (at (nome (+ 8 beat)) (string 51))
    (at (nome (+ 12 beat)) (string 51))
    (at (subdivide (nome (+ 12 beat)) (nome (+ 14 beat)) 1) (string 51))
    (apply-by (nome (+ 16 beat)) bass nome [])))

(defn section [nome]
    (drums nome)
    (bass nome))

(def met (metronome (* 100 2)))

(section met)
;; (stop)

Epílogo

Abstracciones

C

#include <stdio.h>

int main() {
    int t;
    for(t=0;;t++) {
        putchar(((t/16)>>t/2*t) & (t/2<<2) | t/4>>2);
    }
}

Final

La presentación puede verse online en cualquier momento accediendo a:

http://slides.com/xpktro/musicajs

Contacto:

https://moises.dev

Introducción a la Teoría Musical con Javascript + Web Audio API

By Moisés Gabriel Cachay Tello

Introducción a la Teoría Musical con Javascript + Web Audio API

Una breve introducción a la generación de sonido digital mediante el Web Audio API y su consecuente aplicación en la programación creativa de música algorítmica. Basado en 'A gentle introduction to music theory in Ruby' de Alex Speller.

  • 1,444