diff options
Diffstat (limited to 'lib/midi/launchctl.moon')
| -rw-r--r-- | lib/midi/launchctl.moon | 210 |
1 files changed, 109 insertions, 101 deletions
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 |
