aboutsummaryrefslogtreecommitdiffstats
path: root/lib/midi
diff options
context:
space:
mode:
Diffstat (limited to 'lib/midi')
-rw-r--r--lib/midi/core.moon70
-rw-r--r--lib/midi/launchctl.moon210
2 files changed, 150 insertions, 130 deletions
diff --git a/lib/midi/core.moon b/lib/midi/core.moon
index c437259..4986811 100644
--- a/lib/midi/core.moon
+++ b/lib/midi/core.moon
@@ -1,4 +1,4 @@
-import IO, Op, Registry, Input, Error, match from require 'core.base'
+import Value, IO, Op, Registry, Input, Error, match from require 'core.base'
import RtMidiIn, RtMidiOut, RtMidi from require 'luartmidi'
bit = do
@@ -67,34 +67,46 @@ class PortOp extends Op
out = out and find_port RtMidiOut, out!
@out\set MidiPort inp, out
-class input extends PortOp
- @doc: "(midi/input name) - create a MIDI input port"
-
- setup: (inputs) =>
- { name } = match 'str', inputs
- super name: Input.value name
-
- tick: => super @inputs.name
-
-class output extends PortOp
- @doc: "(midi/output name) - create a MIDI output port"
-
- setup: (inputs) =>
- { name } = match 'str', inputs
- super name: Input.value name
-
- tick: => super nil, @inputs.name
-
-class inout extends PortOp
- @doc: "(midi/inout inname outname) - create a bidirectional MIDI port"
-
- setup: (inputs) =>
- { inp, out } = match 'str str', inputs
- super
- inp: Input.value inp
- out: Input.value out
-
- tick: => super @inputs.inp, @inputs.out
+input = Value.meta
+ meta:
+ name: 'input'
+ summary: "Create a MIDI input port."
+ examples: { '(midi/input name)' }
+
+ value: class extends PortOp
+ setup: (inputs) =>
+ { name } = match 'str', inputs
+ super name: Input.value name
+
+ tick: => super @inputs.name
+
+output = Value.meta
+ meta:
+ name: 'output'
+ summary: "Create a MIDI output port."
+ examples: { '(midi/output name)' }
+
+ value: class extends PortOp
+ setup: (inputs) =>
+ { name } = match 'str', inputs
+ super name: Input.value name
+
+ tick: => super nil, @inputs.name
+
+inout = Value.meta
+ meta:
+ name: 'inout'
+ summary: "Create a bidirectional MIDI port."
+ examples: { '(midi/inout name)' }
+
+ value: class extends PortOp
+ setup: (inputs) =>
+ { inp, out } = match 'str str', inputs
+ super
+ inp: Input.value inp
+ out: Input.value out
+
+ tick: => super @inputs.inp, @inputs.out
apply_range = (range, val) ->
if range\type! == 'str'
diff --git a/lib/midi/launchctl.moon b/lib/midi/launchctl.moon
index 1084f66..37ccb82 100644
--- a/lib/midi/launchctl.moon
+++ b/lib/midi/launchctl.moon
@@ -5,9 +5,12 @@ import bor, lshift from bit
unpack or= table.unpack
color = (r, g) -> bit.bor 12, r, (bit.lshift g, 4)
-class cc_seq extends Op
- @doc: "(launctl/cc-seq port i start chan [steps [range]]) - CC-Sequencer
-
+cc_seq = Value.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.
@@ -19,104 +22,109 @@ range can be one of:
- 'deg' [ 0 - 360[
- (num) [ 0 - num["
- new: => super 'num'
-
- setup: (inputs) =>
- { port, i, start,
- chan, steps, range } = match 'midi/port num num num num? any?', inputs
-
- super
- port: Input.io port
- i: Input.value i
- start: Input.value start
- chan: Input.value chan
- steps: Input.value steps or Value.num 8
- range: Input.value range or Value.str 'uni'
-
- if not @out\unwrap!
- @out\set 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!\receive!
- 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]
-
-class gate_seq extends Op
- @doc: "(launctl/gate-seq port i start chan [steps]) - Gate-Sequencer
-
-returns true or false for the i-th step steps (buttons starting from start).
-steps defaults to 8."
-
- new: =>
- super 'bool', false
- @state = {}
-
- setup: (inputs) =>
- { port, i, start, chan, steps } = match 'midi/port num num num num?', inputs
-
- super
- port: Input.io port
- i: Input.value i
- start: Input.value start
- chan: Input.value chan
- steps: Input.value steps or Value.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) =>
- { :port, :start, :chan } = @unwrap_all!
- port\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!\receive!
- 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]
+ value: class extends Op
+ new: => super 'num'
+
+ setup: (inputs) =>
+ { port, i, start,
+ chan, steps, range } = match 'midi/port num num num num? any?', inputs
+
+ super
+ port: Input.io port
+ i: Input.value i
+ start: Input.value start
+ chan: Input.value chan
+ steps: Input.value steps or Value.num 8
+ range: Input.value range or Value.str 'uni'
+
+ if not @out\unwrap!
+ @out\set 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!\receive!
+ 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 = Value.meta
+ meta:
+ name: 'gate-seq'
+ summary: "MIDI Gate-Sequencer."
+ examples: { '(launchctl/gate-seq port i start chan [steps])' }
+ description: "
+returns `true` or `false` for the `i`-th note-button (MIDI-notes starting from
+`start`). `steps` defaults to 8."
+
+ value: class extends Op
+ new: =>
+ super 'bool', false
+ @state = {}
+
+ setup: (inputs) =>
+ { port, i, start, chan, steps } = match 'midi/port num num num num?', inputs
+
+ super
+ port: Input.io port
+ i: Input.value i
+ start: Input.value start
+ chan: Input.value chan
+ steps: Input.value steps or Value.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) =>
+ { :port, :start, :chan } = @unwrap_all!
+ port\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!\receive!
+ 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]
{
'gate-seq': gate_seq