Skip to content

Instantly share code, notes, and snippets.

@dtinth
Last active August 29, 2015 14:00
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save dtinth/11080149 to your computer and use it in GitHub Desktop.
Save dtinth/11080149 to your computer and use it in GitHub Desktop.
Do You Hear the People Sing?
###
# 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()
@KC-Liu
Copy link

KC-Liu commented Apr 19, 2014

Hi I made DUHearThePeopleSing
I do love your remix version....it's awesome ...

@dtinth
Copy link
Author

dtinth commented Apr 20, 2014

@KC-Liu Thanks for the comment and your code being the inspiration! :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment