aboutsummaryrefslogtreecommitdiffstats
path: root/lib/midi
diff options
context:
space:
mode:
Diffstat (limited to 'lib/midi')
-rw-r--r--lib/midi/core.moon122
-rw-r--r--lib/midi/launchctl.moon194
2 files changed, 0 insertions, 316 deletions
diff --git a/lib/midi/core.moon b/lib/midi/core.moon
deleted file mode 100644
index ddb1e8a..0000000
--- a/lib/midi/core.moon
+++ /dev/null
@@ -1,122 +0,0 @@
-import ValueStream, IOStream, Op, Input, Error, val from require 'alv.base'
-import RtMidiIn, RtMidiOut, RtMidi from require 'luartmidi'
-
-bit = do
- ok, bit = pcall require, 'bit32'
- if ok then bit else require 'bit'
-import band, bor, lshift, rshift from bit
-
-MIDI = {
- [0x9]: 'note-on'
- [0x8]: 'note-off'
-
- [0xa]: 'after-key'
- [0xd]: 'after-channel'
-
- [0xb]: 'control-change'
- [0xe]: 'pitch-bend'
- [0xc]: 'program-change'
-}
-
-rMIDI = {v,k for k,v in pairs MIDI}
-
-find_port = (Klass, name) ->
- with Klass RtMidi.Api.UNIX_JACK
- id = nil
- for port=1, \getportcount!
- if name == \getportname port
- id = port
- break
-
- \openport id
-
-class MidiPort extends IOStream
- new: => super 'midi/port'
-
- setup: (inp, out) =>
- @inp = inp and find_port RtMidiIn, inp
- @out = out and find_port RtMidiOut, out
-
- tick: =>
- return unless @inp
- while true
- delta, bytes = @inp\getmessage!
- break unless delta
-
- { status, a, b } = bytes
- chan = band status, 0xf
- status = MIDI[rshift status, 4]
- @add { :status, :chan, :a, :b }
-
- send: (status, chan, a, b) =>
- assert @out, Error 'type', "#{@} is not an output or bidirectional port"
- if 'string' == type 'status'
- status = bor (lshift rMIDI[status], 4), chan
- @out\sendmessage status, a, b
-
-class PortOp extends Op
- new: (...) =>
- super ...
- @out or= MidiPort!
-
- tick: (inp, out) =>
- { :inp, :out } = @unwrap_all!
- @out\setup inp, out
-
-input = ValueStream.meta
- meta:
- name: 'input'
- summary: "Create a MIDI input port."
- examples: { '(midi/input name)' }
-
- value: class extends PortOp
- setup: (inputs) =>
- name = val.str\match inputs
- super inp: Input.hot name
-
-output = ValueStream.meta
- meta:
- name: 'output'
- summary: "Create a MIDI output port."
- examples: { '(midi/output name)' }
-
- value: class extends PortOp
- setup: (inputs) =>
- name = val.str\match inputs
- super out: Input.hot name
-
-inout = ValueStream.meta
- meta:
- name: 'inout'
- summary: "Create a bidirectional MIDI port."
- examples: { '(midi/inout name)' }
-
- value: class extends PortOp
- setup: (inputs) =>
- { inp, out } = (val.str + val.str)\match inputs
- super
- inp: Input.hot inp
- out: Input.hot out
-
-apply_range = (range, val) ->
- if range\type! == 'str'
- switch range!
- when 'raw' then val
- when 'uni' then val / 128
- when 'bip' then val / 64 - 1
- when 'rad' then val / 64 * math.pi
- when 'deg' then val / 128 * 360
- else
- error Error 'argument', "unknown range '#{range!}'"
- elseif range.type == 'num'
- val / 128 * range!
- else
- error Error 'argument', "range has to be a string or number"
-
-{
- :input
- :output
- :inout
- :apply_range
- :bit
-}
diff --git a/lib/midi/launchctl.moon b/lib/midi/launchctl.moon
deleted file mode 100644
index 42837f0..0000000
--- a/lib/midi/launchctl.moon
+++ /dev/null
@@ -1,194 +0,0 @@
-import ValueStream, EventStream, Op, Input, val, evt from require 'alv.base'
-import apply_range, bit from require 'lib.midi.core'
-import bor, lshift from bit
-
-color = (r, g) -> bit.bor 12, r, (bit.lshift g, 4)
-
-cc_seq = ValueStream.meta
- meta:
- name: 'cc-seq'
- summary: "MIDI CC-Sequencer."
- examples: { '(launchctl/cc-seq [port] i start chan [steps [range]])' }
- description: "
-returns the value for the i-th step steps (buttons starting from start).
-steps defaults to 8.
-
-range can be one of:
-- 'raw' [ 0 - 128[
-- 'uni' [ 0 - 1[ (default)
-- 'bip' [-1 - 1[
-- 'rad' [ 0 - tau[
-- 'deg' [ 0 - 360[
-- (num) [ 0 - num["
-
- value: class extends Op
- num = val.num
- pattern = -evt['midi/port'] + num + num + num + -num + -(val.str + num)
- setup: (inputs, scope) =>
- { port, i, start, chan, steps, range } = pattern\match inputs
-
- super
- port: Input.hot port or scope\get '*ctrl*'
- i: Input.hot i
- start: Input.hot start
- chan: Input.hot chan
- steps: Input.hot steps or ValueStream.num 8
- range: Input.hot range or ValueStream.str 'uni'
-
- @state or= {}
- @out or= ValueStream 'num', apply_range @inputs.range, 0
-
- tick: =>
- { :port, :i, :start, :chan, :steps, :range } = @inputs
-
- if steps\dirty!
- while steps! > #@state
- table.insert @state, 0
- while steps! < #@state
- table.remove @state
-
- curr_i = i! % #@state
- if port\dirty!
- changed = false
- for msg in *port!
- if msg.status == 'control-change' and msg.chan == chan!
- rel_i = msg.a - start!
- if rel_i >= 0 and rel_i < #@state
- @state[rel_i+1] = msg.b
- changed = rel_i == curr_i
- @out\set apply_range range, @state[curr_i+1] if changed
- else
- @out\set apply_range range, @state[curr_i+1]
-
-gate_seq = ValueStream.meta
- meta:
- name: 'gate-seq'
- summary: "MIDI Gate-Sequencer."
- examples: { '(launchctl/gate-seq [port] i start chan [steps])' }
- description: "
-Send `true` or `false` for the `i`-th note-button (MIDI-notes starting from
-`start`). `steps` defaults to 8."
-
- value: class extends Op
- pattern = -evt['midi/port'] + val.num + val.num + val.num + -val.num
- setup: (inputs, scope) =>
- @out or= ValueStream 'bool'
- @state or= {}
- { port, i, start, chan, steps } = pattern\match inputs
-
- super
- port: Input.hot port or scope\get '*ctrl*'
- i: Input.hot i
- start: Input.hot start
- chan: Input.hot chan
- steps: Input.hot steps or ValueStream.num 8
-
- light = (set, active) ->
- set = if set then 'S' else ' '
- active = if active then 'A' else ' '
- color switch set .. active
- when ' ' then 0, 0
- when ' A' then 1, 1
- when 'S ' then 1, 0
- when 'SA' then 3, 1
-
- display: (i, active) =>
- start, chan = @inputs.start!, @inputs.chan!
- @inputs.port.stream\send 'note-on', chan, (start + i), light @state[i+1], active
-
- tick: =>
- { :port, :i, :start, :chan, :steps } = @inputs
-
- if steps\dirty!
- while steps! > #@state
- table.insert @state, false
- while steps! < #@state
- table.remove @state
-
- curr_i = i! % #@state
-
- if port\dirty!
- for msg in *port!
- if msg.status == 'note-on' and msg.chan == chan!
- rel_i = msg.a - start!
- if rel_i >= 0 and rel_i < #@state
- @state[rel_i+1] = not @state[rel_i+1]
- @display rel_i, rel_i == curr_i
-
- if i\dirty!
- prev_i = (curr_i - 1) % #@state
-
- @display curr_i, true
- @display prev_i, false
-
- @out\set @state[curr_i+1]
-
-trig_seq = ValueStream.meta
- meta:
- name: 'trig-seq'
- summary: "MIDI Trigger-Sequencer."
- examples: { '(launchctl/trig-seq [port] i start chan [steps])' }
- description: "
-Send bangs for the `i`-th note-button (MIDI-notes starting from `start`).
-`steps` defaults to 8."
-
- value: class extends Op
- pattern = -evt['midi/port'] + val.num + val.num + val.num + -val.num
- setup: (inputs, scope) =>
- @out or= EventStream 'bang'
- @state or= {}
- { port, i, start, chan, steps } = pattern\match inputs
-
- super
- port: Input.hot port or scope\get '*ctrl*'
- i: Input.hot i
- start: Input.hot start
- chan: Input.hot chan
- steps: Input.hot steps or ValueStream.num 8
-
- light = (set, active) ->
- set = if set then 'S' else ' '
- active = if active then 'A' else ' '
- color switch set .. active
- when ' ' then 0, 0
- when ' A' then 1, 1
- when 'S ' then 1, 0
- when 'SA' then 3, 1
-
- display: (i, active) =>
- start, chan = @inputs.start!, @inputs.chan!
- @inputs.port.stream\send 'note-on', chan, (start + i), light @state[i+1], active
-
- tick: =>
- { :port, :i, :start, :chan, :steps } = @inputs
-
- if steps\dirty!
- while steps! > #@state
- table.insert @state, false
- while steps! < #@state
- table.remove @state
-
- curr_i = i! % #@state
-
- if port\dirty!
- for msg in *port!
- if msg.status == 'note-on' and msg.chan == chan!
- rel_i = msg.a - start!
- if rel_i >= 0 and rel_i < #@state
- @state[rel_i+1] = not @state[rel_i+1]
- @display rel_i, rel_i == curr_i
-
- if i\dirty!
- prev_i = (curr_i - 1) % #@state
-
- @display curr_i, true
- @display prev_i, false
-
- if @state[curr_i+1]
- @out\add true
-
-{
- 'cc-seq': cc_seq
- 'gate-seq': gate_seq
- 'trig-seq': trig_seq
-}