Car Seat Drum Kit

ed over 8 years ago

# NOTE! This example reimplements a lot of stuff that now exists in the libraries: # https://emcmanus.gitbooks.io/tinyrave-libraries/content/instruments.html # -------------------------------------- Array.prototype.remove = (from, to) -> rest = this.slice((to || from) + 1 || this.length) this.length = if from < 0 then this.length + from else from this.push.apply(this, rest); class Processable constructor: -> @reset() reset: -> @timeOffset = 0 tick: -> @timeOffset += 1 / 44100 isAlive: -> true # -------------------------------------- class ADSR2 extends Processable constructor: (@attackTime=0.2, @decayTime=0.1, @sustainTime=0.0, @releaseTime=0.2, @sustainLevel=0.5) -> super process: (value) -> sample = @getMultiplier() * value @tick() sample getMultiplier: -> if @timeOffset <= @attackTime # attack - linear increase to 1 @timeOffset / @attackTime else if @timeOffset <= @attackTime + @decayTime # decay - linear decrease from 1 to @sustainLevel progress = (@timeOffset - @attackTime) / @decayTime 1 - (progress * (1 - @sustainLevel)) else if @timeOffset <= @attackTime + @decayTime + @sustainTime # sustain @sustainLevel else if @timeOffset <= @attackTime + @decayTime + @sustainTime + @releaseTime # release - linear decrease from @sustainLevel to 0 progress = (@timeOffset - @attackTime - @decayTime - @sustainTime) / @releaseTime @sustainLevel - progress * @sustainLevel else 0 isAlive: -> @timeOffset <= @attackTime + @decayTime + @sustainTime + @releaseTime class ADSR extends Processable constructor: (@processable, @attackTime=0.2, @decayTime=0.1, @sustainTime=0.0, @releaseTime=0.2, @sustainLevel=0.5) -> super process: -> sample = @getMultiplier() * @processable.process() @tick() sample getMultiplier: -> if @timeOffset <= @attackTime # attack - linear increase to 1 @timeOffset / @attackTime else if @timeOffset <= @attackTime + @decayTime # decay - linear decrease from 1 to @sustainLevel progress = (@timeOffset - @attackTime) / @decayTime 1 - (progress * (1 - @sustainLevel)) else if @timeOffset <= @attackTime + @decayTime + @sustainTime # sustain @sustainLevel else if @timeOffset <= @attackTime + @decayTime + @sustainTime + @releaseTime # release - linear decrease from @sustainLevel to 0 progress = (@timeOffset - @attackTime - @decayTime - @sustainTime) / @releaseTime @sustainLevel - progress * @sustainLevel else 0 isAlive: -> @timeOffset <= @attackTime + @decayTime + @sustainTime + @releaseTime # - # Instruments class Drum extends ADSR constructor: (@frequency=60, @sustain=0.3) -> super({ process: => Math.sin @frequency * Math.PI * 2 * Math.pow(@timeOffset, @sustain) }) class SquareDrum extends ADSR constructor: (@frequency=50, @sustain=0.3) -> super({ process: => Math.sin @frequency * Math.PI * 2 * Math.pow(@timeOffset, @sustain) + 0.3 * Math.round(Math.sin @frequency * Math.PI * 2 * Math.pow(@timeOffset, @sustain)) }) class HighHat extends ADSR constructor: -> @trailingSamples = [] super({process: (-> Math.random() * 2 - 1)}, 0.02, 0.03, 0, 0.15, 0.03) lowPass: (value, windowSize=2) -> # (Running average): the poor man's low-pass filter. if @trailingSamples.length == windowSize @trailingSamples.shift() @trailingSamples.push(value) sum = @trailingSamples.reduce (memo, value) -> memo + value sum / @trailingSamples.length highPass: (value, windowSize=2) -> # (Original - running average): the poor man's high-pass filter. value - @lowPass(value, windowSize) process: -> @highPass(super()) class OpenHighHat extends ADSR constructor: -> @trailingSamples = [] super({process: (-> Math.random() * 2 - 1)}, 0.0, 0.0, 0.15, 0.2, 0.8) lowPass: (value, windowSize=2) -> # (Running average): the poor man's low-pass filter. if @trailingSamples.length == windowSize @trailingSamples.shift() @trailingSamples.push(value) sum = @trailingSamples.reduce (memo, value) -> memo + value sum / @trailingSamples.length highPass: (value, windowSize=2) -> # (Original - running average): the poor man's high-pass filter. value - @lowPass(value, windowSize) process: -> @highPass(super()) class SnareDrum extends Processable constructor: -> @trailingSamples = [] @adsr = new ADSR2(0, 0, 0, 0.25, 1) super isAlive: -> @adsr.isAlive() lowPass: (value, windowSize=2) -> # (Running average): the poor man's low-pass filter. if @trailingSamples.length == windowSize @trailingSamples.shift() @trailingSamples.push(value) sum = @trailingSamples.reduce (memo, value) -> memo + value sum / @trailingSamples.length highPass: (value, windowSize=2) -> # (Original - running average): the poor man's high-pass filter. value - @lowPass(value, windowSize) process: -> sample = Math.sin(120 * Math.pow(@timeOffset, 0.05) * 2 * Math.PI) + 0.5 * @lowPass(Math.random() * 2 - 1) @tick() @adsr.process sample class SquareTone extends Processable constructor: (@frequency=440, @length=0.1) -> @trailingSamples = [] @adsr = new ADSR2 @length / 4, @length / 4, @length / 4, @length / 4, 0.7 super isAlive: -> @timeOffset <= @length lowPass: (value, windowSize=2) -> # (Running average): the poor man's low-pass filter. if @trailingSamples.length == windowSize @trailingSamples.shift() @trailingSamples.push(value) sum = @trailingSamples.reduce (memo, value) -> memo + value sum / @trailingSamples.length highPass: (value, windowSize=2) -> # (Original - running average): the poor man's high-pass filter. value - @lowPass(value, windowSize) process: -> sample = Math.sin @frequency * @timeOffset * Math.PI * 2 sample = if sample > 0 1 else -1 @tick() 0.5 * @adsr.process(sample) class Knock extends Processable constructor: (@frequency=440, @length=0.1) -> @adsr = new ADSR2 @length / 4, @length / 4, @length / 4, @length / 4, 0.7 super isAlive: -> @timeOffset <= @length process: -> sample = Math.sin @frequency * @timeOffset * Math.PI * 2 @tick() @adsr.process sample # - class Mixer constructor: (@bpm=110)-> @bps = @bpm / 60 @generators = [] @lastBeat = -1 update: (t, callback) -> currentBeat = Math.floor(t * @bps) if @lastBeat != currentBeat callback(currentBeat) @prune() @lastBeat = currentBeat push: (generator, volume=1) -> @generators.push {'generator': generator, 'volume': volume} process: -> sample = 0 sample += (generator['volume'] * generator['generator'].process()) for generator in @generators sample prune: -> for generator, index in @generators if generator? @generators.remove(index) unless generator['generator'].isAlive() # - mixer = new Mixer 280 buildSample = (t) -> mixer.update t, (beat) -> mixDrums(beat) mixVocals(beat) mixVocals2(beat) 0.2 * mixer.process() mixVocals2 = (beat) -> beat -= 32 # Drums beat -= 64 # Vocals 1 if beat >= 0 beat = beat % 64 if beat == 0 mixer.push new SquareTone(D_4, 0.3) # 3 else if beat == 3 mixer.push new SquareTone(F_4, 0.7) # 5 else if beat == 8 mixer.push new SquareTone(D_4, 0.3) # 2 else if beat == 10 mixer.push new SquareTone(F_4, 0.9) # 6 else if beat == 16 mixer.push new SquareTone(A_SHARP_3, 0.3) # 3 else if beat == 19 mixer.push new SquareTone(D_4, 0.7) # 5 else if beat == 24 mixer.push new SquareTone(A_SHARP_3, 0.3) # 2 else if beat == 26 mixer.push new SquareTone(D_4, 0.9) # 6 else if beat == 32 mixer.push new SquareTone(C_4, 0.3) # 3 else if beat == 35 mixer.push new SquareTone(E_4, 0.7) # 5 else if beat == 40 mixer.push new SquareTone(C_4, 0.3) # 2 else if beat == 42 mixer.push new SquareTone(E_4, 0.9) # 6 else if beat == 48 mixer.push new SquareTone(G_3, 0.3) # 3 else if beat == 51 mixer.push new SquareTone(A_SHARP_3, 0.7) # 5 else if beat == 56 mixer.push new SquareTone(G_3, 0.3) # 2 else if beat == 58 mixer.push new SquareTone(A_SHARP_3, 0.9) # 6 mixVocals = (beat) -> beat -= 32 if beat >= 0 beat = beat % 64 if beat < 16 mixer.push new SquareTone(A_4, 0.1) else if beat < 32 mixer.push new SquareTone(F_4, 0.1) else if beat < 48 mixer.push new SquareTone(G_4, 0.1) else if beat < 64 mixer.push new SquareTone(A_SHARP_4, 0.1) mixDrums = (beat) -> cycles = Math.floor(beat / 8) count = (beat % 16) / 2 # Count is 0-7.5 in increments of 0.5 switch count when 0 mixer.push new HighHat when 1 mixer.push new HighHat when 2 mixer.push new HighHat mixer.push new SnareDrum, 0.4 when 3 mixer.push new HighHat when 4 mixer.push new HighHat when 5 mixer.push new HighHat when 5.5 mixer.push new OpenHighHat when 6.5 mixer.push new HighHat when 7 mixer.push new HighHat # Based on http://www.phy.mtu.edu/~suits/notefreqs.html C_0 = 16.35 C_SHARP_0 = D_FLAT_0 = 17.32 D_0 = 18.35 D_SHARP_0 = E_FLAT_0 = 19.45 E_0 = 20.60 F_0 = 21.83 F_SHARP_0 = G_FLAT_0 = 23.12 G_0 = 24.50 G_SHARP_0 = A_FLAT_0 = 25.96 A_0 = 27.50 A_SHARP_0 = B_FLAT_0 = 29.14 B_0 = 30.87 C_1 = 32.70 C_SHARP_1 = D_FLAT_1 = 34.65 D_1 = 36.71 D_SHARP_1 = E_FLAT_1 = 38.89 E_1 = 41.20 F_1 = 43.65 F_SHARP_1 = G_FLAT_1 = 46.25 G_1 = 49.00 G_SHARP_1 = A_FLAT_1 = 51.91 A_1 = 55.00 A_SHARP_1 = B_FLAT_1 = 58.27 B_1 = 61.74 DEEP_C = C_2 = 65.41 C_SHARP_2 = D_FLAT_2 = 69.30 D_2 = 73.42 D_SHARP_2 = E_FLAT_2 = 77.78 E_2 = 82.41 F_2 = 87.31 F_SHARP_2 = G_FLAT_2 = 92.50 G_2 = 98.00 G_SHARP_2 = A_FLAT_2 = 103.83 A_2 = 110.00 A_SHARP_2 = B_FLAT_2 = 116.54 B_2 = 123.47 TENOR_C = C_3 = 130.81 C_SHARP_3 = D_FLAT_3 = 138.59 D_3 = 146.83 D_SHARP_3 = E_FLAT_3 = 155.56 E_3 = 164.81 F_3 = 174.61 F_SHARP_3 = G_FLAT_3 = 185.00 G_3 = 196.00 G_SHARP_3 = A_FLAT_3 = 207.65 A_3 = 220.00 A_SHARP_3 = B_FLAT_3 = 233.08 B_3 = 246.94 MIDDLE_C = C_4 = 261.63 C_SHARP_4 = D_FLAT_4 = 277.18 D_4 = 293.66 D_SHARP_4 = E_FLAT_4 = 311.13 E_4 = 329.63 F_4 = 349.23 F_SHARP_4 = G_FLAT_4 = 369.99 G_4 = 392.00 G_SHARP_4 = A_FLAT_4 = 415.30 A440 = A_4 = 440.00 A_SHARP_4 = B_FLAT_4 = 466.16 B_4 = 493.88 C_5 = 523.25 C_SHARP_5 = D_FLAT_5 = 554.37 D_5 = 587.33 D_SHARP_5 = E_FLAT_5 = 622.25 E_5 = 659.25 F_5 = 698.46 F_SHARP_5 = G_FLAT_5 = 739.99 G_5 = 783.99 G_SHARP_5 = A_FLAT_5 = 830.61 A_5 = 880.00 A_SHARP_5 = B_FLAT_5 = 932.33 B_5 = 987.77 SOPRANO_C = HIGH_C = C_6 = 1046.50 C_SHARP_6 = D_FLAT_6 = 1108.73 D_6 = 1174.66 D_SHARP_6 = E_FLAT_6 = 1244.51 E_6 = 1318.51 F_6 = 1396.91 F_SHARP_6 = G_FLAT_6 = 1479.98 G_6 = 1567.98 G_SHARP_6 = A_FLAT_6 = 1661.22 A_6 = 1760.00 A_SHARP_6 = B_FLAT_6 = 1864.66 B_6 = 1975.53 DOUBLE_HIGH_C = C_7 = 2093.00 C_SHARP_7 = D_FLAT_7 = 2217.46 D_7 = 2349.32 D_SHARP_7 = E_FLAT_7 = 2489.02 E_7 = 2737.02 F_7 = 2793.83 F_SHARP_7 = G_FLAT_7 = 2959.97 G_7 = 3135.97 G_SHARP_7 = A_FLAT_7 = 3322.44 A_7 = 3520.00 A_SHARP_7 = B_FLAT_7 = 3729.31 B_7 = 3951.07 C_8 = 4186.01 C_SHARP_8 = D_FLAT_8 = 4434.92 D_8 = 4698.63 D_SHARP_8 = E_FLAT_8 = 4988.03 E_8 = 5284.04 F_8 = 5588.65 F_SHARP_8 = G_FLAT_8 = 5919.91 G_8 = 6281.93 G_SHARP_8 = A_FLAT_8 = 6644.88 A_8 = 8040.00 A_SHARP_8 = B_FLAT_8 = 8458.62 B_8 = 8902.13
Coffeescript

00:47 92 plays


Comment on Track

Sign in to comment Or sign up to join the party