Permalink
Browse files

Merge branch 'midi-multi-source'

  • Loading branch information...
eelco committed May 31, 2016
2 parents b9c33da + 3188bfe commit f508b1824ee2d55ef694fd6555a04ca59692f858
Showing with 63 additions and 60 deletions.
  1. +36 −34 framer/MIDIControl.coffee
  2. +27 −26 framer/MIDIInput.coffee
View
@@ -1,53 +1,55 @@
{_} = require "./Underscore"
{_} = require "./Underscore"
{BaseClass} = require "./BaseClass"
{Events} = require "./Events"
{Events} = require "./Events"
{MIDIInput} = require "./MIDIInput"
Events.MIDIControlValueChange = "MIDIControlValueChange"
class MIDIControl extends BaseClass
@define "min", @simpleProperty("min", 0)
@define "max", @simpleProperty("max", 127)
@define "control", @simpleProperty("control", null)
@define "channel", @simpleProperty("channel", null)
# Not supported yet, needs MIDIInput that opens all inputs
# @define "source", @simpleProperty("source", null)
@define "min", @simpleProperty("min", 0)
@define "max", @simpleProperty("max", 127)
@define "control", @simpleProperty("control", null)
@define "channel", @simpleProperty("channel", null)
@define "source", @simpleProperty("source", null)
constructor: (options={}) ->
super options
constructor: (options={}) ->
super options
MIDIInput.enabled = true
MIDIInput.onCommand (timeStamp, data) =>
[b1, b2, b3] = data
MIDIInput.enabled = true
MIDIInput.onCommand (source, timeStamp, data) =>
# Mask the bytes to get the info we want
command = b1 & 0xf0
channel = (b1 & 0x0f) + 1 # 1-16
data1 = b2 & 0x7f
data2 = b3 & 0x7f
[b1, b2, b3] = data
# 0xb0 control change
# 0x90 note on
# 0x80 note off
# Mask the bytes to get the info we want
command = b1 & 0xf0
channel = (b1 & 0x0f) + 1 # 1-16
data1 = b2 & 0x7f
data2 = b3 & 0x7f
return unless command in [0xb0, 0x90, 0x80]
return if @channel? and @channel isnt channel
return if @control? and @control isnt data1
# 0xb0 control change
# 0x90 note on
# 0x80 note off
info =
channel: channel
control: data1
return unless command in [0xb0, 0x90, 0x80]
return if @source? and @source isnt source
return if @channel? and @channel isnt channel
return if @control? and @control isnt data1
if command in [0x90, 0x80]
info = _.defaults info
type: "note"
info =
source: source
channel: channel
control: data1
@emit(Events.MIDIControlValueChange, @_modulate(data2), info)
if command in [0x90, 0x80]
info = _.defaults info
type: "note"
_modulate: (value) ->
Utils.modulate(value, [0, 127], [@min, @max])
@emit(Events.MIDIControlValueChange, @_modulate(data2), info)
onValueChange: (cb) -> @on(Events.MIDIControlValueChange, cb)
_modulate: (value) ->
Utils.modulate(value, [0, 127], [@min, @max])
onValueChange: (cb) -> @on(Events.MIDIControlValueChange, cb)
exports.MIDIControl = MIDIControl
View
@@ -1,42 +1,43 @@
{BaseClass} = require "./BaseClass"
{Events} = require "./Events"
{Events} = require "./Events"
Events.MIDICommand = "midiCommand"
class MIDIInput extends BaseClass
@define "enabled",
get: -> @_input or @_request
set: (value) ->
return unless value != @enabled
return @_requestRejected() if not navigator.requestMIDIAccess
if value
@_request = navigator.requestMIDIAccess().then @_requestResolved, @_requestRejected
else
@_input?.close()
@_request = null
@_input = null
@define "enabled",
get: -> @_inputs?.length or @_request
set: (value) ->
return unless value != @enabled
return @_requestRejected() if not navigator.requestMIDIAccess
if value
@_request = navigator.requestMIDIAccess().then @_requestResolved, @_requestRejected
else
@_inputs?.map close
@_request = null
@_inputs = []
# Success handlers
# Success handlers
_requestResolved: (access) =>
# Pick the last one
access.inputs.forEach (input) =>
@_input = input
@_input.onmidimessage = @_onmidimessage
_requestResolved: (access) =>
@_inputs ?= []
access.inputs.forEach (input) =>
console.log(input)
@_inputs.push input
input.onmidimessage = @_onmidimessage(input.id)
# Failure handlers
# Failure handlers
_requestRejected: (error) =>
throw Error "Requesting MIDI access failed: #{error ? "not supported by browser"}"
_requestRejected: (error) =>
throw Error "Requesting MIDI access failed: #{error ? "not supported by browser"}"
# Event handlers
# Event handlers
_onmidimessage: (message) =>
@emit(Events.MIDICommand, message.timeStamp, message.data)
_onmidimessage: (sourceID) =>
(message) => @emit(Events.MIDICommand, sourceID, message.timeStamp, message.data)
# Event shortcuts
# Event shortcuts
onCommand: (cb) -> @on(Events.MIDICommand, cb)
onCommand: (cb) -> @on(Events.MIDICommand, cb)
exports.MIDIInput = new MIDIInput

0 comments on commit f508b18

Please sign in to comment.