Skip to content

Instantly share code, notes, and snippets.

@peterc
Created February 27, 2012 00:32
Show Gist options
  • Save peterc/1920095 to your computer and use it in GitHub Desktop.
Save peterc/1920095 to your computer and use it in GitHub Desktop.

Revisions

  1. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 5 additions and 2 deletions.
    7 changes: 5 additions & 2 deletions 16step.coffee
    Original file line number Diff line number Diff line change
    @@ -48,7 +48,10 @@ class DrumMachine

    playNote: (note, velocity, duration) ->
    return unless @playing
    console.log "#{note} : #{velocity} : #{duration}ms"
    velocity += Math.floor(Math.random() * 20) - 10
    velocity = 0 if velocity < 0
    velocity = 127 if velocity > 127
    console.log "#{note}\t#{("*" for x in [0..(velocity / 7)]).join('')}"
    @midi.sendMessage [144, @instruments[note], velocity]
    setTimeout =>
    @stopNote note
    @@ -64,7 +67,7 @@ class DrumMachine
    @currentStep++
    @currentStep = 1 if @currentStep == @totalSteps + 1
    clearInterval lp unless @playing
    , this.barDuration() / @totalSteps
    , (this.barDuration() / @totalSteps)

    set: (instrument, steps, velocity = 127) ->
    @steps[step - 1].push [instrument, velocity] for step in steps
  2. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions 16step.coffee
    Original file line number Diff line number Diff line change
    @@ -59,11 +59,11 @@ class DrumMachine

    play: ->
    @playing = true
    @loop = setInterval =>
    lp = setInterval =>
    @playStep @currentStep - 1
    @currentStep++
    @currentStep = 1 if @currentStep == @totalSteps + 1
    clearInterval @loop unless @playing
    clearInterval lp unless @playing
    , this.barDuration() / @totalSteps

    set: (instrument, steps, velocity = 127) ->
    @@ -89,7 +89,7 @@ catch error
    midiOut.openVirtualPort ''

    dm = new DrumMachine(midiOut)
    dm.bpm = 120
    dm.bpm = 96

    # dm.set <instrument>, <step nos> (, <velocity>)
    dm.set 'hihat', [1, 3, 5, 7, 9, 11, 13, 15], 100
  3. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 5 additions and 4 deletions.
    9 changes: 5 additions & 4 deletions 16step.coffee
    Original file line number Diff line number Diff line change
    @@ -29,7 +29,8 @@ class DrumMachine
    @playing = false
    @bpm = 160
    @currentStep = 1
    @steps = ([] for i in [0..15])
    @totalSteps = 16 # changeable for different time signatures
    @steps = ([] for i in [1..64])

    instruments:
    kick: 36
    @@ -61,9 +62,9 @@ class DrumMachine
    @loop = setInterval =>
    @playStep @currentStep - 1
    @currentStep++
    @currentStep = 1 if @currentStep == 17
    @currentStep = 1 if @currentStep == @totalSteps + 1
    clearInterval @loop unless @playing
    , this.barDuration() / 16
    , this.barDuration() / @totalSteps

    set: (instrument, steps, velocity = 127) ->
    @steps[step - 1].push [instrument, velocity] for step in steps
    @@ -88,7 +89,7 @@ catch error
    midiOut.openVirtualPort ''

    dm = new DrumMachine(midiOut)
    dm.bpm = 93
    dm.bpm = 120

    # dm.set <instrument>, <step nos> (, <velocity>)
    dm.set 'hihat', [1, 3, 5, 7, 9, 11, 13, 15], 100
  4. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 16 additions and 0 deletions.
    16 changes: 16 additions & 0 deletions watchr
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    # watchr file to live restart the drum machine when changes
    # are made to the code. Perhaps there's a better way of doing
    # this.. let me know!
    #
    # To use, you need Ruby, gem install watchr, and run
    # watchr <filename of this>

    $running_pid = nil

    watch('.*\.coffee') do |md|
    Process.kill("INT", $running_pid) if $running_pid

    $running_pid = fork do
    exec("coffee", md[0])
    end
    end
  5. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 7 additions and 0 deletions.
    7 changes: 7 additions & 0 deletions 16step.coffee
    Original file line number Diff line number Diff line change
    @@ -34,8 +34,10 @@ class DrumMachine
    instruments:
    kick: 36
    hihat: 42
    clap: 39
    snare: 40
    cowbell: 56
    crash: 49

    barDuration: ->
    60000 / @bpm * 4
    @@ -93,8 +95,13 @@ dm.set 'hihat', [1, 3, 5, 7, 9, 11, 13, 15], 100
    dm.set 'hihat', [2, 4, 6, 8, 10, 12, 14, 16], 39
    dm.set 'kick', [1, 4, 7, 11]
    dm.set 'snare', [5, 13]

    # extra bits added for fun
    dm.set 'cowbell', [2, 4, 7, 12], 20
    dm.set 'cowbell', [3, 5, 8, 13], 80
    dm.set 'crash', [15], 20
    dm.set 'clap', [5, 13], 80
    dm.set 'clap', [16], 50

    dm.play()

  6. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions 16step.coffee
    Original file line number Diff line number Diff line change
    @@ -35,6 +35,7 @@ class DrumMachine
    kick: 36
    hihat: 42
    snare: 40
    cowbell: 56

    barDuration: ->
    60000 / @bpm * 4
    @@ -92,6 +93,8 @@ dm.set 'hihat', [1, 3, 5, 7, 9, 11, 13, 15], 100
    dm.set 'hihat', [2, 4, 6, 8, 10, 12, 14, 16], 39
    dm.set 'kick', [1, 4, 7, 11]
    dm.set 'snare', [5, 13]
    dm.set 'cowbell', [2, 4, 7, 12], 20
    dm.set 'cowbell', [3, 5, 8, 13], 80

    dm.play()

  7. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions 16step.coffee
    Original file line number Diff line number Diff line change
    @@ -19,6 +19,10 @@
    #
    # Yeah, not great OOD for real, but just a fun Sunday night
    # project for now :-)
    #
    # P.S. This is my first CoffeeScript in > 1 year so I have NO IDEA
    # if I'm even vaguely doing it right. But it works. Please leave
    # comments with code improvements to help me learn!

    class DrumMachine
    constructor: (@midi) ->
  8. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions 16step.coffee
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,8 @@
    # Inspired by Giles Bowkett's screencast at
    # http://gilesbowkett.blogspot.com/2012/02/making-music-with-javascript-is-easy.html
    #
    # Screencast demo of this code at http://www.youtube.com/watch?v=qWKkEaKL6DQ
    #
    # Required:
    # node, npm and coffee-script installed
    #
  9. Peter Cooper renamed this gist Feb 27, 2012. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  10. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 15 additions and 15 deletions.
    30 changes: 15 additions & 15 deletions 16beat.coffee
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # Simple 16 beat drum machine experiment with Node and CoffeeScript
    # Simple 16 step drum machine experiment with Node and CoffeeScript
    # by Peter Cooper - @peterc
    #
    # Inspired by Giles Bowkett's screencast at
    @@ -13,7 +13,7 @@
    # create a software instrument (ideally a "drum kit")
    # run this script with "coffee [filename]"
    # ctrl+c to exit
    # customize the drum beat at the footer of this file
    # customize the drum steps at the footer of this file
    #
    # Yeah, not great OOD for real, but just a fun Sunday night
    # project for now :-)
    @@ -22,8 +22,8 @@ class DrumMachine
    constructor: (@midi) ->
    @playing = false
    @bpm = 160
    @currentBeat = 1
    @beats = ([] for i in [0..15])
    @currentStep = 1
    @steps = ([] for i in [0..15])

    instruments:
    kick: 36
    @@ -44,27 +44,27 @@ class DrumMachine
    @stopNote note
    , duration

    playBeat: (beat) ->
    @playNote(note[0], note[1], 40) for note in @beats[beat]
    playStep: (step) ->
    @playNote(note[0], note[1], 40) for note in @steps[step]

    play: ->
    @playing = true
    @loop = setInterval =>
    @playBeat @currentBeat - 1
    @currentBeat++
    @currentBeat = 1 if @currentBeat == 17
    @playStep @currentStep - 1
    @currentStep++
    @currentStep = 1 if @currentStep == 17
    clearInterval @loop unless @playing
    , this.barDuration() / 16

    set: (instrument, beats, velocity = 127) ->
    @beats[beat - 1].push [instrument, velocity] for beat in beats
    set: (instrument, steps, velocity = 127) ->
    @steps[step - 1].push [instrument, velocity] for step in steps

    pause: ->
    @playing = false

    stop: ->
    @pause()
    @currentBeat = 1
    @currentStep = 1
    @midi.sendMessage [252, 0, 0]
    @midi.sendMessage [176, 123, 0]

    @@ -79,13 +79,13 @@ catch error
    midiOut.openVirtualPort ''

    dm = new DrumMachine(midiOut)
    dm.bpm = 240
    dm.bpm = 93

    # dm.set <instrument>, <beat nos> (, <velocity>)
    # dm.set <instrument>, <step nos> (, <velocity>)
    dm.set 'hihat', [1, 3, 5, 7, 9, 11, 13, 15], 100
    dm.set 'hihat', [2, 4, 6, 8, 10, 12, 14, 16], 39
    dm.set 'kick', [1, 4, 7, 11]
    dm.set 'snare', [5, 13, 7, 9, 14, 15]
    dm.set 'snare', [5, 13]

    dm.play()

  11. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions 16beat.coffee
    Original file line number Diff line number Diff line change
    @@ -79,13 +79,13 @@ catch error
    midiOut.openVirtualPort ''

    dm = new DrumMachine(midiOut)
    dm.bpm = 93
    dm.bpm = 240

    # dm.set <instrument>, <beat nos> (, <velocity>)
    dm.set 'kick', [1, 4, 7, 11]
    dm.set 'snare', [5, 13]
    dm.set 'hihat', [1, 3, 5, 7, 9, 11, 13, 15], 100
    dm.set 'hihat', [2, 4, 6, 8, 10, 12, 14, 16], 39
    dm.set 'kick', [1, 4, 7, 11]
    dm.set 'snare', [5, 13, 7, 9, 14, 15]

    dm.play()

  12. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 6 additions and 6 deletions.
    12 changes: 6 additions & 6 deletions 16beat.coffee
    Original file line number Diff line number Diff line change
    @@ -1,22 +1,22 @@
    # Simple 16 beat drum machine experiment with Node and CoffeeScript
    # by Peter Cooper - @peterc
    #
    # Inspired by Giles Bowkett's screencast at
    # http://gilesbowkett.blogspot.com/2012/02/making-music-with-javascript-is-easy.html
    # Inspired by Giles Bowkett's screencast at
    # http://gilesbowkett.blogspot.com/2012/02/making-music-with-javascript-is-easy.html
    #
    # Required:
    # node, npm and coffee-script installed
    #
    # To use:
    # To run:
    # npm install midi
    # run up Garageband
    # create a software instrument (ideally a drum kit)
    # create a software instrument (ideally a "drum kit")
    # run this script with "coffee [filename]"
    # ctrl+c to exit
    # customize the drum beat at the footer of this file
    #
    # Yeah, not great OOD for real, but just a fun Sunday night
    # project for now :-)
    # Yeah, not great OOD for real, but just a fun Sunday night
    # project for now :-)

    class DrumMachine
    constructor: (@midi) ->
  13. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions 16beat.coffee
    Original file line number Diff line number Diff line change
    @@ -14,6 +14,9 @@
    # run this script with "coffee [filename]"
    # ctrl+c to exit
    # customize the drum beat at the footer of this file
    #
    # Yeah, not great OOD for real, but just a fun Sunday night
    # project for now :-)

    class DrumMachine
    constructor: (@midi) ->
  14. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 8 additions and 10 deletions.
    18 changes: 8 additions & 10 deletions 16beat.coffee
    Original file line number Diff line number Diff line change
    @@ -15,16 +15,6 @@
    # ctrl+c to exit
    # customize the drum beat at the footer of this file

    midi = require 'midi'
    midiOut = new midi.output

    try
    midiOut.openPort(0)
    catch error
    midiOut.openVirtualPort ''

    # -----

    class DrumMachine
    constructor: (@midi) ->
    @playing = false
    @@ -77,6 +67,14 @@ class DrumMachine

    # -----

    midi = require 'midi'
    midiOut = new midi.output

    try
    midiOut.openPort(0)
    catch error
    midiOut.openVirtualPort ''

    dm = new DrumMachine(midiOut)
    dm.bpm = 93

  15. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 4 additions and 6 deletions.
    10 changes: 4 additions & 6 deletions 16beat.coffee
    Original file line number Diff line number Diff line change
    @@ -14,16 +14,14 @@
    # run this script with "coffee [filename]"
    # ctrl+c to exit
    # customize the drum beat at the footer of this file
    #
    # Troubleshooter:
    # No sound? Switch the comments around on the midiOut.openVirtualPort lines below.
    # You probably don't have IAC enabled. (Or use Audio MIDI Setup to enable it..)

    midi = require 'midi'
    midiOut = new midi.output

    #midiOut.openVirtualPort '' # use this line if you have problems
    midiOut.openPort(0) # if you have IAC turned on in Audio Midi Setup, this is nicer
    try
    midiOut.openPort(0)
    catch error
    midiOut.openVirtualPort ''

    # -----

  16. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 10 additions and 12 deletions.
    22 changes: 10 additions & 12 deletions 16beat.coffee
    Original file line number Diff line number Diff line change
    @@ -18,10 +18,14 @@
    # Troubleshooter:
    # No sound? Switch the comments around on the midiOut.openVirtualPort lines below.
    # You probably don't have IAC enabled. (Or use Audio MIDI Setup to enable it..)
    #
    # Notes:
    # Yep, this is scrappy and unstructured. Just a bit of fun on a
    # Sunday night :-)

    midi = require 'midi'
    midiOut = new midi.output

    #midiOut.openVirtualPort '' # use this line if you have problems
    midiOut.openPort(0) # if you have IAC turned on in Audio Midi Setup, this is nicer

    # -----

    class DrumMachine
    constructor: (@midi) ->
    @@ -43,7 +47,7 @@ class DrumMachine

    playNote: (note, velocity, duration) ->
    return unless @playing
    console.log "Playing note #{note} at #{velocity} for #{duration}ms"
    console.log "#{note} : #{velocity} : #{duration}ms"
    @midi.sendMessage [144, @instruments[note], velocity]
    setTimeout =>
    @stopNote note
    @@ -73,13 +77,7 @@ class DrumMachine
    @midi.sendMessage [252, 0, 0]
    @midi.sendMessage [176, 123, 0]

    # ----------------------------------------------

    midi = require 'midi'
    midiOut = new midi.output

    #midiOut.openVirtualPort '' # use this line if you have problems
    midiOut.openPort(0) # if you have IAC turned on in Audio Midi Setup, this is nicer
    # -----

    dm = new DrumMachine(midiOut)
    dm.bpm = 93
  17. Peter Cooper revised this gist Feb 27, 2012. 1 changed file with 18 additions and 20 deletions.
    38 changes: 18 additions & 20 deletions 16beat.coffee
    Original file line number Diff line number Diff line change
    @@ -27,6 +27,7 @@ class DrumMachine
    constructor: (@midi) ->
    @playing = false
    @bpm = 160
    @currentBeat = 1
    @beats = ([] for i in [0..15])

    instruments:
    @@ -48,24 +49,27 @@ class DrumMachine
    @stopNote note
    , duration

    playBeat: ->
    @playNote(note[0], note[1], 40) for note in @beats[@currentBeat - 1]
    playBeat: (beat) ->
    @playNote(note[0], note[1], 40) for note in @beats[beat]

    play: ->
    @playing = true
    @currentBeat = 1
    setInterval =>
    @playBeat()
    @loop = setInterval =>
    @playBeat @currentBeat - 1
    @currentBeat++
    @currentBeat = 1 if @currentBeat == 17
    clearInterval @loop unless @playing
    , this.barDuration() / 16


    set: (instrument, beat, velocity = 127) ->
    @beats[beat - 1].push [instrument, velocity]
    set: (instrument, beats, velocity = 127) ->
    @beats[beat - 1].push [instrument, velocity] for beat in beats

    pause: ->
    @playing = false

    stop: ->
    @playing = false
    @pause()
    @currentBeat = 1
    @midi.sendMessage [252, 0, 0]
    @midi.sendMessage [176, 123, 0]

    @@ -78,19 +82,13 @@ midiOut = new midi.output
    midiOut.openPort(0) # if you have IAC turned on in Audio Midi Setup, this is nicer

    dm = new DrumMachine(midiOut)

    dm.bpm = 93

    dm.set 'kick', 1
    dm.set 'kick', 4
    dm.set 'kick', 7
    dm.set 'kick', 11

    dm.set 'snare', 5
    dm.set 'snare', 13

    dm.set 'hihat', beat, 100 for beat in [1, 3, 5, 7, 9, 11, 13, 15]
    dm.set 'hihat', beat, 39 for beat in [2, 4, 6, 8, 10, 12, 14, 16]
    # dm.set <instrument>, <beat nos> (, <velocity>)
    dm.set 'kick', [1, 4, 7, 11]
    dm.set 'snare', [5, 13]
    dm.set 'hihat', [1, 3, 5, 7, 9, 11, 13, 15], 100
    dm.set 'hihat', [2, 4, 6, 8, 10, 12, 14, 16], 39

    dm.play()

  18. Peter Cooper created this gist Feb 27, 2012.
    99 changes: 99 additions & 0 deletions 16beat.coffee
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,99 @@
    # Simple 16 beat drum machine experiment with Node and CoffeeScript
    # by Peter Cooper - @peterc
    #
    # Inspired by Giles Bowkett's screencast at
    # http://gilesbowkett.blogspot.com/2012/02/making-music-with-javascript-is-easy.html
    #
    # Required:
    # node, npm and coffee-script installed
    #
    # To use:
    # npm install midi
    # run up Garageband
    # create a software instrument (ideally a drum kit)
    # run this script with "coffee [filename]"
    # ctrl+c to exit
    # customize the drum beat at the footer of this file
    #
    # Troubleshooter:
    # No sound? Switch the comments around on the midiOut.openVirtualPort lines below.
    # You probably don't have IAC enabled. (Or use Audio MIDI Setup to enable it..)
    #
    # Notes:
    # Yep, this is scrappy and unstructured. Just a bit of fun on a
    # Sunday night :-)

    class DrumMachine
    constructor: (@midi) ->
    @playing = false
    @bpm = 160
    @beats = ([] for i in [0..15])

    instruments:
    kick: 36
    hihat: 42
    snare: 40

    barDuration: ->
    60000 / @bpm * 4

    stopNote: (note) ->
    @midi.sendMessage [128, note, 0]

    playNote: (note, velocity, duration) ->
    return unless @playing
    console.log "Playing note #{note} at #{velocity} for #{duration}ms"
    @midi.sendMessage [144, @instruments[note], velocity]
    setTimeout =>
    @stopNote note
    , duration

    playBeat: ->
    @playNote(note[0], note[1], 40) for note in @beats[@currentBeat - 1]

    play: ->
    @playing = true
    @currentBeat = 1
    setInterval =>
    @playBeat()
    @currentBeat++
    @currentBeat = 1 if @currentBeat == 17
    , this.barDuration() / 16


    set: (instrument, beat, velocity = 127) ->
    @beats[beat - 1].push [instrument, velocity]

    stop: ->
    @playing = false
    @midi.sendMessage [252, 0, 0]
    @midi.sendMessage [176, 123, 0]

    # ----------------------------------------------

    midi = require 'midi'
    midiOut = new midi.output

    #midiOut.openVirtualPort '' # use this line if you have problems
    midiOut.openPort(0) # if you have IAC turned on in Audio Midi Setup, this is nicer

    dm = new DrumMachine(midiOut)

    dm.bpm = 93

    dm.set 'kick', 1
    dm.set 'kick', 4
    dm.set 'kick', 7
    dm.set 'kick', 11

    dm.set 'snare', 5
    dm.set 'snare', 13

    dm.set 'hihat', beat, 100 for beat in [1, 3, 5, 7, 9, 11, 13, 15]
    dm.set 'hihat', beat, 39 for beat in [2, 4, 6, 8, 10, 12, 14, 16]

    dm.play()

    process.addListener "SIGTERM", ->
    dm.stop
    midiOut.closePort()