Moisés Gabriel Cachay Tello
Creator, destructor.
* 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:
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?
La Música y el Código
¡Escúchame mundo!
440 Hz
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 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
S
T
S
La Música y el Código
Tonos y Semitonos
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
La Música y el Código
Escala Mayor
T T S T T T S
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
T S T T S T T
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
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
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
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
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
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
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
#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:
Contacto:
By Moisés Gabriel Cachay Tello
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.