diff options
Diffstat (limited to 'alv-lib/_midi.moon')
| -rw-r--r-- | alv-lib/_midi.moon | 148 |
1 files changed, 109 insertions, 39 deletions
diff --git a/alv-lib/_midi.moon b/alv-lib/_midi.moon index eb0b742..8e8b507 100644 --- a/alv-lib/_midi.moon +++ b/alv-lib/_midi.moon @@ -1,4 +1,4 @@ -import Constant, T, Struct, Op, Input, T, Error, const from require 'alv.base' +import Constant, T, Array, Struct, Op, Input, T, Error, const from require 'alv.base' import RtMidiIn, RtMidiOut, RtMidi from require 'luartmidi' bit = if _VERSION == 'Lua 5.4' @@ -27,19 +27,35 @@ MIDI = { 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 +get_port_names = (port) -> + [port\getportname i for i=1, port\getportcount!] - \openport id +find_port = (Klass, label, connect) -> + port = Klass "alv", RtMidi.Api.UNIX_JACK + names = get_port_names port + + if connect == '' + port\openvirtualport label + return port + + -- first exact matches + for i, name in ipairs names + if name == connect + port\openport i, label + return port, name + + -- then pattern matches + for i, name in ipairs names + if name\match connect + port\openport i + return port, name + + port\openvirtualport label + port class InPort - new: (@name) => - @port = find_port RtMidiIn, @name + new: (@name, connect) => + @port, @connect = find_port RtMidiIn, @name, connect @msgs = {} poll: => @@ -51,32 +67,30 @@ class InPort status = MIDI[rshift status, 4] { :status, :chan, :a, :b } - __tostring: => "[#{@name}]" - __tojson: => string.format '%q', tostring @ + __tostring: => if @connect then "#{@name}@#{@connect}" else @name class OutPort - new: (@name) => - @port = find_port RtMidiOut, @name + new: (@name, connect) => + @port, @connect = find_port RtMidiOut, @name, connect send: (status, chan, a, b) => if 'string' == type 'status' status = bor (lshift rMIDI[status], 4), chan @port\sendmessage status, a, b - __tostring: => "[#{@name}]" - __tojson: => string.format '%q', tostring @ + __tostring: => if @connect then "#{@name}@#{@connect}" else @name class PortOp extends Op setup: (inputs) => super inputs - { :inp, :out } = @inputs + { :name, :inp, :out } = @inputs - type = if inp and out + type = if inp != nil and out != nil Struct in: T['midi/in'], out: T['midi/out'] - elseif inp + elseif inp != nil T['midi/in'] - elseif out + elseif out != nil T['midi/out'] else error "no port opened" @@ -85,28 +99,64 @@ class PortOp extends Op @setup_out '~', type tick: => - if @inputs.inp and @inputs.inp\dirty! - @state.inp = InPort @inputs.inp! + { :name, :inp, :out } = @unwrap_all! + + if inp and @inputs.inp\dirty! + @state.inp = InPort name, inp - if @inputs.out and @inputs.out\dirty! - @state.out = OutPort @inputs.out! + if out and @inputs.out\dirty! + @state.out = OutPort name, out - { :inp, :out } = @state - @out\set if inp and out - { 'in': inp, :out } + @out\set if @state.inp and @state.out + { 'in': @state.inp, out: @state.out } else - inp or out + @state.inp or @state.out + +port_names = Constant.meta + meta: + name: 'port-names' + summary: "Get all MIDI port names." + examples: { '(midi/port-names direction)' } + description: ' +`direction` can be either `"in"` or `"out". +Returns an array of strings.' + + value: class extends Op + setup: (inputs) => + dir = const.str\match inputs + super {} + + dir = dir.result! + assert dir == "in" or dir == "out", Error 'argument', "'dir' has to be either 'in' or 'out'." + + Klass = if dir == "in" then RtMidiIn else RtMidiOut + port = Klass "alv", RtMidi.Api.UNIX_JACK + names = get_port_names port + + Type = Array #names, T.str + + @setup_out '~', Type, names input = Constant.meta meta: name: 'input' summary: "Create a MIDI input port." - examples: { '(midi/input name)' } + examples: { '(midi/input name [port])' } + desciprtion: " +Create a MIDI input port called `name` and optionally connect +it to an existing output `port`. +`name` and `port` are both str= results. +Use [midi/port-names][] to find valid values for `port`. + +`port` can either be the exact name of an existing port, +or a [Lua pattern](https://www.lua.org/pil/20.2.html)." value: class extends PortOp setup: (inputs) => - name = const.str\match inputs - super inp: Input.hot name + { name, connect } = (const.str * 2)\match inputs + super + name: Input.hot name + inp: Input.hot connect or Constant.str '' poll: => @.out!\poll! @@ -116,25 +166,44 @@ output = Constant.meta meta: name: 'output' summary: "Create a MIDI output port." - examples: { '(midi/output name)' } + examples: { '(midi/output name [port])' } + desciprtion: " +Create a MIDI output port called `name` and optionally connect +it to an existing input `port`. +`name` and `port` are both str= results. +Use [midi/port-names][] to find valid values for `port`. + +`port` can either be the exact name of an existing port, +or a [Lua pattern](https://www.lua.org/pil/20.2.html)." value: class extends PortOp setup: (inputs) => - name = const.str\match inputs - super out: Input.hot name + { name, connect } = (const.str * 2)\match inputs + super + name: Input.hot name + out: Input.hot connect or Constant.str '' port = Constant.meta meta: name: 'port' summary: "Create a bidirectional MIDI port." - examples: { '(midi/port name)' } + examples: { '(midi/port name [in] [out])' } + desciprtion: " +Create a bidirectional MIDI port called `name` and optionally connect +it to the existing output port `in` and input port `out`. + +`name`, `in` and `out` are all str= results. +Use [midi/port-names][] to find valid values for `in` and `out`. +`in` and `out` can either be the exact name of an existing port, +or a [Lua pattern](https://www.lua.org/pil/20.2.html)." value: class extends PortOp setup: (inputs) => - { inp, out } = (const.str + const.str)\match inputs + { name, inp, out } = (const.str * 3)\match inputs super - inp: Input.hot inp - out: Input.hot out + name: Input.hot name + inp: Input.hot inp or Constant.str '' + out: Input.hot out or Constant.str '' poll: => @.out!.in\poll! @@ -159,6 +228,7 @@ apply_range = (range, val) -> :input :output :port + :port_names :apply_range :bit } |
