diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-04-14 09:21:00 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-04-14 09:21:00 +0000 |
| commit | 5faab5d81cc5ed36824a52a273e83eb20240cb2e (patch) | |
| tree | dba10fadf4cdad0f5524df642fab83f6310a8574 /lib/midi | |
| parent | move spec out of spec/core (diff) | |
| download | alive-5faab5d81cc5ed36824a52a273e83eb20240cb2e.tar.gz alive-5faab5d81cc5ed36824a52a273e83eb20240cb2e.zip | |
move lib to alv-lib module
Diffstat (limited to 'lib/midi')
| -rw-r--r-- | lib/midi/core.moon | 122 | ||||
| -rw-r--r-- | lib/midi/launchctl.moon | 194 |
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 -} |
