Introducción a la Teoría Musical*

* con Python

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!

frecuencia = 440.0
muestras_por_segundo = 44100
duracion = 1.0

muestras_totales = duracion * muestras_por_segundo

ciclos_por_muestra = frecuencia / muestras_por_segundo
incremento = 2 * math.pi * ciclos_por_muestra
fase = 0

muestras = []
for i in range(int(muestras_totales)):
    muestra = math.sin(fase)
    fase += incremento
    muestras.append(muestra)

La Música y el Código

¡Escúchame mundo!

nombre_archivo = 'a.wav'
archivo = wave.open(nombre_archivo, 'w')
archivo.setparams((1, 2, muestras_por_segundo, 0, 'NONE', 'not compressed'))

valores = []
for muestra in muestras:
    valor_bit = struct.pack('h', muestra * 32767)
    valores.append(valor_bit)

valores_str = ''.join(valores)
archivo.writeframes(valores_str)
archivo.close()

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

frecuencias = [220.0, 440.0, 880.0]
muestras_por_segundo = 44100
duracion = 1.0

muestras_totales = duracion * muestras_por_segundo

muestras = []
for frecuencia in frecuencias:
    ciclos_por_muestra = frecuencia / muestras_por_segundo
    incremento = 2 * math.pi * ciclos_por_muestra
    fase = 0

    for i in range(int(muestras_totales)):
        muestra = math.sin(fase)
        fase += incremento
        muestras.append(muestra)

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

raiz_doceava_de_dos = 2 ** (1.0/12)

actual = 220.0
frecuencias = [actual]
for i in range(12):
    actual *= raiz_doceava_de_dos
    frecuencias.append(actual)

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

TONO = 2
SEMITONO = 1

escala = [TONO, TONO, SEMITONO, TONO, TONO, TONO, SEMITONO]
actual = 0
frecuencias_escala = [frecuencias[0]]
for intervalo in escala:
    actual += intervalo
    frecuencias_escala.append(frecuencias[actual])

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

TONO = 2
SEMITONO = 1

escala = [TONO, SEMITONO, TONO, TONO, SEMITONO, TONO, TONO]
actual = 0
frecuencias_escala = [frecuencias[0]]
for intervalo in escala:
    actual += intervalo
    frecuencias_escala.append(frecuencias[actual])

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

notas = []
modo = [TONO, TONO, SEMITONO, TONO, TONO, TONO, SEMITONO]
inicio = 0

for i in range(8):
    actual = inicio
    frecuencias_modo = [frecuencias[actual]]

    for intervalo in modo:
        actual += intervalo
        frecuencias_modo.append(frecuencias[actual])

    notas += frecuencias_modo
    inicio += modo[0]

    modo = rotate(modo)

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

escala = [TONO, TONO, SEMITONO, TONO, TONO, TONO, SEMITONO]
escala *= 2

notas = [frecuencias[0]]

actual = 0
for grupo in grouper(escala, 2, 0):
    actual += sum(grupo)
    notas.append(frecuencias[actual])

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

muestras = [0 for i in range(int(muestras_totales))]
for frecuencia in notas:
    ciclos_por_muestra = frecuencia / muestras_por_segundo
    incremento = 2 * math.pi * ciclos_por_muestra
    fase = 0

    for i in range(int(muestras_totales)):
        muestras[i] += math.sin(fase)
        fase += incremento

maximo = max([abs(muestra) for muestra in muestras])
multiplicador = 1.0 / maximo
muestras = [multiplicador * muestra for muestra in muestras]

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

inicio = 0
for x in range(8):
    actual = inicio
    notas = [frecuencias[actual]]
    for grupo in grouper(escala, 2, 0):
        actual += sum(grupo)
        notas.append(frecuencias[actual])

    acordes.append(notas)
    inicio += escala[0]

    escala = rotate(escala)

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

I, II, III, IV, V, VI, VII = range(7)

acordes_cancion = (acordes[I], acordes[V], acordes[VI], 
                   acordes[IV], acordes[I])

I V vi VI

La Música y el Código

Progresiones de Acordes

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/musica

Introducción a la Teoría Musical en Python

By Moisés Gabriel Cachay Tello

Introducción a la Teoría Musical en Python

Una breve introducción a la generación de sonido digital 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.

  • 6,135