Last active
August 29, 2015 14:00
-
-
Save dtinth/11080149 to your computer and use it in GitHub Desktop.
Do You Hear the People Sing?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
### | |
# DO YOU HEAR THE PEOPLE SING? (Uplifting Mix) | |
# version 1.3 (clearer kick sound) | |
# | |
# Converted from CoffeeScript | |
# Source: https://gist.github.com/11080149 | |
# Usage: coffee -bcp file.coffee | |
# | |
# Original from Les Miserables | |
# (http://www.youtube.com/watch?v=QngGvHTOKh4) | |
# Inspired by DUHearThePeopleSing | |
# (http://studio.substack.net/DUHearThePeopleSing(v1.1)?time=1397899959659) | |
# Remixed and coded by Thai Pangsakulyanont | |
# (https://github.com/dtinth) | |
### | |
### | |
# Major constants | |
### | |
BPM = 142 | |
### | |
# The music itself... | |
### | |
music = -> | |
Instrument = | |
kick: do -> | |
click = pipeline(Note.drop(12, 140)).to(Osc.sin).gain(0.4) | |
drop = pipeline(Note.drop(5, 20)).to(Osc.sin).gain(0.3) | |
sub = pipeline(Note.drop(12, 12)).to(Osc.sin).gain(0.6) | |
mix(click, drop, sub) | |
snare: do -> | |
combine( | |
combine(Osc.random, Value.approach(1, 0, 3), Filter.gain), | |
Value.approach(0.4, 0.001, 10), | |
Filter.Lowpass() | |
) | |
hat: do -> | |
combine(Osc.random, Value.approach(1, 0, 24), Filter.gain) | |
phat: mix( | |
pipeline((t) -> t * 1.006).to(Osc.sawtooth).gain(0.3) | |
pipeline((t) -> t * 1.003).to(Osc.sawtooth).gain(0.3) | |
pipeline((t) -> t * 1).to(Osc.sawtooth).gain(0.4) | |
pipeline((t) -> t / 1.003).to(Osc.sawtooth).gain(0.3) | |
pipeline((t) -> t / 1.006).to(Osc.sawtooth).gain(0.3) | |
) | |
Instrument.supersaw = mix( | |
pipeline(Instrument.phat).gain(0.6) | |
pipeline((t) -> t / 2).to(Instrument.phat).gain(0.4) | |
) | |
line = (text, transpose, transform) -> | |
notes = (MidiNote.lookup(c) + transpose for c in text.split(' ')) | |
(MidiNote.toFrequency(c) for c in transform(notes)) | |
convert = (array, transpose, transform) -> | |
result = (line(c, transpose, transform) for c in array) | |
.reduce(((a, b) -> a.concat(b)), []) | |
return result | |
Notes = | |
melody: Note.step(convert [ | |
'sol Re RE Sol Sol' | |
'sol Re MI MI RE' | |
'do sol DO DO RE' | |
'do sol MI MI FA' | |
'mi ti SOL SOL SOL' | |
'mi ti MI RE DO' | |
'fa Do Ti Ti La' | |
'fa Do Ti Ti DO' | |
'Do sol Sol Sol Sol' | |
'ti sol La Sol Fa' | |
'mi la Mi Mi Sol' | |
'mi la DO DO MI' | |
're la RE RE DI' | |
're la RE RE La' | |
're sol DO DO Ti' | |
're sol Ti Ti DO' | |
'sol Re RE Sol Sol' | |
'sol Re MI MI RE' | |
'do sol DO DO RE' | |
'do sol MI MI FA' | |
'mi ti SOL SOL SOL' | |
'mi ti MI RE DO' | |
'fa Do Ti Ti La' | |
'fa Do Ti Ti DO' | |
'Do sol Sol Sol Sol' | |
'ti sol La Sol Fa' | |
'mi la Mi Mi Sol' | |
'mi la DO DO MI' | |
're la RE DI RE' | |
'sol Re FA FA Ti' | |
'do sol DO DO DO' | |
'do sol DO DO DO' | |
'do sol DO DO DO' | |
'ti mi Mi Mi Mi' | |
'la mi La La Si' | |
'la mi La La Ti' | |
'la mi DO DO Ti' | |
'la mi La La DO' | |
'ti mi Ti Ti La' | |
'ti mi Sol Sol La' | |
'ti mi Ti Ti Ti' | |
'ti mi Ti Ti DO' | |
're la RE RE DO' | |
're la Ti Ti DO' | |
're la RE RE DO' | |
're la Ti Ti RE' | |
'la mi DO DO Ti' | |
'la mi La La Ti' | |
'la mi DO DO DO' | |
'sol mi DO DO La' | |
'fa Do DO Ti La' | |
'fa Do DO Ti La' | |
'fi Do DO Ti La' | |
'fi Do DO Ti DO' | |
'sol Re RE RE RE' | |
'sol Re RE RE RE' | |
], 48 + 1, ([a, b, c, d, e]) -> [c, a, b, d, a, b, e, a]) | |
bass: Note.step(convert [ | |
'sol', 'sol', | |
'Do', 'Do', 'Mi', 'Mi', 'Fa', 'Fa', 'Do', 'ti', | |
'la', 'la', 'Re', 'Re', 'sol', 'sol', 'sol', 'sol', | |
'Do', 'Do', 'Mi', 'Mi', 'Fa', 'Fa', 'Do', 'ti', | |
'la', 'la', 'Re', 'sol', 'Do', 'Do', 'Do', 'mi', | |
'la', 'la', 'la', 'la', 'mi', 'mi', 'mi', 'mi', | |
'Re', 'Re', 'Re', 'Re', 'la', 'la', 'la', 'sol', | |
'fa', 'fa', 'fi', 'fi', 'sol', 'sol' | |
], 24 + 1, ([a]) -> [a - 12, a, a + 12, a, a - 12, a + 12, a, a + 12]) | |
kick = pipeline(loopEvery 1 * BEAT).to(Instrument.kick) | |
snare = pipeline((t) -> t + 3 * BEAT).to(loopEvery 2 * BEAT).to(Instrument.snare) | |
hat = pipeline((t) -> t + 0.5 * BEAT).to(loopEvery 1 * BEAT).to(Instrument.hat) | |
arp = combine( | |
pipeline(Notes.melody).to(Instrument.supersaw), | |
pipeline(loopEvery 1 * STEP).to(Value.approach(0.8, 0.01, 8)), | |
Filter.Lowpass() | |
) | |
bass = combine( | |
pipeline(Notes.bass).to(Instrument.supersaw), | |
pipeline(loopEvery 1 * STEP).to(Value.approach(0.5, 0.0001, 30)), | |
Filter.Lowpass() | |
) | |
arpMixed = pipeline(arp).gain(0.4) | |
delay = (t) -> t + (STEP * (Notes.melody.steps - 3)) | |
arpMixedDelayed = pipeline(delay).to(arpMixed).gain(0.2) | |
arpMixedDelayedDelayed = pipeline(delay).to(arpMixedDelayedDelayed).gain(0.5) | |
main = mix( | |
pipeline(snare).gain(0.7), | |
kick, | |
pipeline(hat).gain(0.3), | |
pipeline((t) -> t + 3 * STEP).to(hat).gain(0.1), | |
arpMixed, | |
arpMixedDelayed, | |
pipeline(bass).gain(0.3)) | |
return main | |
### | |
# Other constants... | |
### | |
PI = Math.PI | |
BEAT = 60 / BPM | |
STEP = BEAT / 4 | |
### | |
# Define units, so we can use them as unit(1) | |
### | |
unit = (value) -> (x) -> x * value | |
beat = unit(BEAT) | |
step = unit(STEP) | |
### | |
# The oscillators. These oscilators receive the number of rotations. | |
### | |
pipeline = (source) -> | |
f = (t) -> source(t) | |
f.to = (g) -> pipeline((t) -> g(f(t))) | |
f.gain = (gain) -> pipeline((t) -> f(t) * gain) | |
return f | |
combine = (f, g, h) -> | |
throw new Error("f must be a function") if typeof f != 'function' | |
throw new Error("g must be a function") if typeof g != 'function' | |
throw new Error("h must be a function") if typeof h != 'function' | |
(t) -> h(f(t), g(t)) | |
mix = (sources...) -> | |
return (t) -> sources.reduce(((a, source) -> a + source(t)), 0) | |
loopEvery = (loopLength) -> (time) -> time % loopLength | |
Osc = | |
sin: (x) -> Math.sin(x * 2*PI) | |
sawtooth: (x) -> (x % 1) * 2 - 1 | |
random: (x) -> Math.random() * 2 - 1 | |
Note = | |
### | |
# A frequency drop... | |
# Don't know from which frequency to which frequency though; | |
# I am not a mathematician! | |
# | |
# a : Frequency multiplier | |
# b : Drop speed | |
### | |
drop: (a, b) -> (t) -> (1 - Math.exp(-t * b)) * a | |
freq: (f) -> (t) -> f * t | |
step: (frequencies) -> | |
length = frequencies.length | |
result = (t) -> | |
c = (t / STEP) % length | |
i = Math.floor(c) | |
it = t - i * STEP | |
(frequencies[i] * t) | |
result.steps = length | |
return result | |
MidiNote = | |
lookup: do -> | |
NOTE_NAMES = 'do di re ri mi fa fi sol si la li ti | |
Do Di Re Ri Mi Fa Fi Sol Si La Li Ti | |
DO DI RE RI MI FA FI SOL SI LA LI TI'.split(/\s+/) | |
return (name) -> | |
NOTE_NAMES.indexOf(name) | |
toFrequency: (c) -> 440 * Math.pow(2, (c - 69) / 12) | |
Value = | |
approach: (s, f, b) -> (t) -> s + (1 - Math.exp(-t * b)) * (f - s) | |
Filter = | |
gain: (signal, volume) -> signal * volume | |
Lowpass: () -> | |
current = 0 | |
(signal, factor) -> | |
current += (signal - current) * factor | |
### | |
# Logging facilities.... | |
### | |
log = do -> | |
last = 0 | |
(args...) -> | |
now = new Date().getTime() | |
if now - last > 1000 | |
console.log(args...) | |
last = now | |
args[0] | |
return music() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi I made DUHearThePeopleSing
I do love your remix version....it's awesome ...