git.s-ol.nu alive / a5f75cf
lib: update midi Updated luartmidi module with support for virtual ports and JACK s-ol 6 months ago
4 changed file(s) with 178 addition(s) and 69 deletion(s). Raw diff Collapse all Expand all
1616 - [socket][socket]: `luarocks install luasocket`
1717 - [system][system]: `luarocks install luasystem`
1818 - [losc][losc]: `luarocks install losc` (optional)
19 - [lua-rtmidi][rtmidi]: `luarocks install
20 https://raw.githubusercontent.com/s-ol/lua-rtmidi/master/lua-rtmidi-dev-1.rockspec` (optional)
19 - [lua-rtmidi][rtmidi]: `luarocks install lua-rtmidi` (optional)
2120 - [busted][busted]: `luarocks install busted` (optional, for tests)
2221 - [discount][discount]: `luarocks install discount` (optional, for docs)
2322 - [ldoc][ldoc]: `luarocks install
0 import Constant, T, Struct, Op, Input, T, Error, const from require 'alv.base'
0 import Constant, T, Array, Struct, Op, Input, T, Error, const from require 'alv.base'
11 import RtMidiIn, RtMidiOut, RtMidi from require 'luartmidi'
22
33 bit = if _VERSION == 'Lua 5.4'
2626
2727 rMIDI = {v,k for k,v in pairs MIDI}
2828
29 find_port = (Klass, name) ->
30 with Klass RtMidi.Api.UNIX_JACK
31 id = nil
32 for port=1, \getportcount!
33 if name == \getportname port
34 id = port
35 break
36
37 \openport id
29 get_port_names = (port) ->
30 [port\getportname i for i=1, port\getportcount!]
31
32 find_port = (Klass, label, connect) ->
33 port = Klass "alv", RtMidi.Api.UNIX_JACK
34 names = get_port_names port
35
36 if connect == ''
37 port\openvirtualport label
38 return port
39
40 -- first exact matches
41 for i, name in ipairs names
42 if name == connect
43 port\openport i, label
44 return port, name
45
46 -- then pattern matches
47 for i, name in ipairs names
48 if name\match connect
49 port\openport i
50 return port, name
51
52 port\openvirtualport label
53 port
3854
3955 class InPort
40 new: (@name) =>
41 @port = find_port RtMidiIn, @name
56 new: (@name, connect) =>
57 @port, @connect = find_port RtMidiIn, @name, connect
4258 @msgs = {}
4359
4460 poll: =>
5066 status = MIDI[rshift status, 4]
5167 { :status, :chan, :a, :b }
5268
53 __tostring: => "[#{@name}]"
54 __tojson: => string.format '%q', tostring @
69 __tostring: => if @connect then "#{@name}@#{@connect}" else @name
5570
5671 class OutPort
57 new: (@name) =>
58 @port = find_port RtMidiOut, @name
72 new: (@name, connect) =>
73 @port, @connect = find_port RtMidiOut, @name, connect
5974
6075 send: (status, chan, a, b) =>
6176 if 'string' == type 'status'
6277 status = bor (lshift rMIDI[status], 4), chan
6378 @port\sendmessage status, a, b
6479
65 __tostring: => "[#{@name}]"
66 __tojson: => string.format '%q', tostring @
80 __tostring: => if @connect then "#{@name}@#{@connect}" else @name
6781
6882 class PortOp extends Op
6983 setup: (inputs) =>
7084 super inputs
7185
72 { :inp, :out } = @inputs
73
74 type = if inp and out
86 { :name, :inp, :out } = @inputs
87
88 type = if inp != nil and out != nil
7589 Struct in: T['midi/in'], out: T['midi/out']
76 elseif inp
90 elseif inp != nil
7791 T['midi/in']
78 elseif out
92 elseif out != nil
7993 T['midi/out']
8094 else
8195 error "no port opened"
8498 @setup_out '~', type
8599
86100 tick: =>
87 if @inputs.inp and @inputs.inp\dirty!
88 @state.inp = InPort @inputs.inp!
89
90 if @inputs.out and @inputs.out\dirty!
91 @state.out = OutPort @inputs.out!
92
93 { :inp, :out } = @state
94 @out\set if inp and out
95 { 'in': inp, :out }
101 { :name, :inp, :out } = @unwrap_all!
102
103 if inp and @inputs.inp\dirty!
104 @state.inp = InPort name, inp
105
106 if out and @inputs.out\dirty!
107 @state.out = OutPort name, out
108
109 @out\set if @state.inp and @state.out
110 { 'in': @state.inp, out: @state.out }
96111 else
97 inp or out
112 @state.inp or @state.out
113
114 port_names = Constant.meta
115 meta:
116 name: 'port-names'
117 summary: "Get all MIDI port names."
118 examples: { '(midi/port-names direction)' }
119 description: '
120 `direction` can be either `"in"` or `"out".
121 Returns an array of strings.'
122
123 value: class extends Op
124 setup: (inputs) =>
125 dir = const.str\match inputs
126 super {}
127
128 dir = dir.result!
129 assert dir == "in" or dir == "out", Error 'argument', "'dir' has to be either 'in' or 'out'."
130
131 Klass = if dir == "in" then RtMidiIn else RtMidiOut
132 port = Klass "alv", RtMidi.Api.UNIX_JACK
133 names = get_port_names port
134
135 Type = Array #names, T.str
136
137 @setup_out '~', Type, names
98138
99139 input = Constant.meta
100140 meta:
101141 name: 'input'
102142 summary: "Create a MIDI input port."
103 examples: { '(midi/input name)' }
143 examples: { '(midi/input name [port])' }
144 desciprtion: "
145 Create a MIDI input port called `name` and optionally connect
146 it to an existing output `port`.
147 `name` and `port` are both str= results.
148 Use [midi/port-names][] to find valid values for `port`.
149
150 `port` can either be the exact name of an existing port,
151 or a [Lua pattern](https://www.lua.org/pil/20.2.html)."
104152
105153 value: class extends PortOp
106154 setup: (inputs) =>
107 name = const.str\match inputs
108 super inp: Input.hot name
155 { name, connect } = (const.str * 2)\match inputs
156 super
157 name: Input.hot name
158 inp: Input.hot connect or Constant.str ''
109159
110160 poll: =>
111161 @.out!\poll!
115165 meta:
116166 name: 'output'
117167 summary: "Create a MIDI output port."
118 examples: { '(midi/output name)' }
168 examples: { '(midi/output name [port])' }
169 desciprtion: "
170 Create a MIDI output port called `name` and optionally connect
171 it to an existing input `port`.
172 `name` and `port` are both str= results.
173 Use [midi/port-names][] to find valid values for `port`.
174
175 `port` can either be the exact name of an existing port,
176 or a [Lua pattern](https://www.lua.org/pil/20.2.html)."
119177
120178 value: class extends PortOp
121179 setup: (inputs) =>
122 name = const.str\match inputs
123 super out: Input.hot name
180 { name, connect } = (const.str * 2)\match inputs
181 super
182 name: Input.hot name
183 out: Input.hot connect or Constant.str ''
124184
125185 port = Constant.meta
126186 meta:
127187 name: 'port'
128188 summary: "Create a bidirectional MIDI port."
129 examples: { '(midi/port name)' }
189 examples: { '(midi/port name [in] [out])' }
190 desciprtion: "
191 Create a bidirectional MIDI port called `name` and optionally connect
192 it to the existing output port `in` and input port `out`.
193
194 `name`, `in` and `out` are all str= results.
195 Use [midi/port-names][] to find valid values for `in` and `out`.
196 `in` and `out` can either be the exact name of an existing port,
197 or a [Lua pattern](https://www.lua.org/pil/20.2.html)."
130198
131199 value: class extends PortOp
132200 setup: (inputs) =>
133 { inp, out } = (const.str + const.str)\match inputs
201 { name, inp, out } = (const.str * 3)\match inputs
134202 super
135 inp: Input.hot inp
136 out: Input.hot out
203 name: Input.hot name
204 inp: Input.hot inp or Constant.str ''
205 out: Input.hot out or Constant.str ''
137206
138207 poll: =>
139208 @.out!.in\poll!
158227 :input
159228 :output
160229 :port
230 :port_names
161231 :apply_range
162232 :bit
163233 }
00 import Constant, Op, Input, T, Struct, sig, evt from require 'alv.base'
1 import input, output, port, apply_range from require 'alv-lib._midi'
1 import input, output, port, port_names, apply_range from require 'alv-lib._midi'
22 import monotime from require 'system'
33
44 gate = Constant.meta
5151 examples: { '(midi/trig [port] note [chan])' }
5252
5353 value: class extends Op
54 pattern = -sig['midi/in'] + sig.num -sig.num
54 pattern = -sig['midi/in'] + sig.num + -sig.num
5555 setup: (inputs, scope) =>
5656 { port, note, chan } = pattern\match inputs
5757 @out = T.bang\mk_evt!
7171 if msg.a == note! and (chan! == -1 or msg.chan == chan!)
7272 if msg.status == 'note-on'
7373 internal.result\set true
74 return true
75
76 false
77
78 tick: =>
79 @out\set @inputs.internal!
80
81 trigs = Constant.meta
82 meta:
83 name: 'trigs'
84 summary: "`bang`s from note-on messages."
85 examples: { '(midi/trigs [port] [chan])' }
86
87 value: class extends Op
88 pattern = -sig['midi/in'] + -sig.num
89 setup: (inputs, scope) =>
90 { port, chan } = pattern\match inputs
91 @out = T.num\mk_evt!
92 super
93 port: Input.cold port or scope\get '*midi*'
94 chan: Input.cold chan or Constant.num -1
95
96 internal: Input.hot T.num\mk_evt!
97
98 poll: =>
99 { :port, :chan, :internal } = @inputs
100
101 msgs = port!.msgs
102 for i = #msgs, 1, -1
103 msg = msgs[i]
104 if (chan! == -1 or msg.chan == chan!)
105 if msg.status == 'note-on'
106 internal.result\set msg.a
74107 return true
75108
76109 false
199232 :input
200233 :output
201234 :port
235 'port-names': port_names
202236
203237 :gate
204238 :trig
239 :trigs
205240 :cc
206241 'send-notes': send_notes
1616 version = "0.2.0-1";
1717
1818 knownRockspec = (pkgs.fetchurl {
19 url = "mirror://luarocks//${pname}-${version}.rockspec";
20 sha256 = "AzDZV9u6V71YNJFBfj3cR1COjFFWhGmsJkGsUMErSZs=";
19 url = "mirror://luarocks/${pname}-${version}.rockspec";
20 hash = "sha256-AzDZV9u6V71YNJFBfj3cR1COjFFWhGmsJkGsUMErSZs=";
2121 }).outPath;
2222
2323 src = pkgs.fetchFromGitHub {
2424 owner = "osch";
2525 repo = pname;
2626 rev = "v0.2.0";
27 sha256 = "PamppWdV3cQMDK+t2V09/cNRskGuRNeuyvUODmopLaQ=";
27 hash = "sha256-PamppWdV3cQMDK+t2V09/cNRskGuRNeuyvUODmopLaQ=";
2828 };
2929 propagatedBuildInputs = [ lua ];
3030
4040 version = "0.2-2";
4141
4242 src = pkgs.fetchurl {
43 url = "mirror://luarocks//${pname}-${version}.src.rock";
44 sha256 = "Dp3bKIG4swrD4+1NNtRTgyj68Di2cSUlh1r7Z2Rkzn0=";
43 url = "mirror://luarocks/${pname}-${version}.src.rock";
44 hash = "sha256-Dp3bKIG4swrD4+1NNtRTgyj68Di2cSUlh1r7Z2Rkzn0=";
4545 };
4646 postUnpack = "sourceRoot=$sourceRoot/luarocks-fetch-gitrec-0.2";
4747
5959 version = "0.2-1";
6060
6161 src = pkgs.fetchurl {
62 url = "mirror://luarocks//${pname}-${version}.src.rock";
63 sha256 = "fD31FruqVriMecFcvSV4W7JRia38+bg7j3T5k5pFZec=";
62 url = "mirror://luarocks/${pname}-${version}.src.rock";
63 hash = "sha256-fD31FruqVriMecFcvSV4W7JRia38+bg7j3T5k5pFZec=";
6464 };
6565 postUnpack = "sourceRoot=$sourceRoot/lua-fltk4lua";
6666 buildInputs = with pkgs; [ fltk libjpeg ];
7878 version = "1.0.0-1";
7979
8080 src = pkgs.fetchurl {
81 url = "mirror://luarocks//${pname}-${version}.src.rock";
82 sha256 = "MArhj51V1awF5k2zToFYEXpS2c6o8bnNDn4wLhooHos=";
81 url = "mirror://luarocks/${pname}-${version}.src.rock";
82 hash = "sha256-MArhj51V1awF5k2zToFYEXpS2c6o8bnNDn4wLhooHos=";
8383 };
8484 postUnpack = "sourceRoot=$sourceRoot/losc";
8585
9898 version = "0.4-1";
9999
100100 knownRockspec = (pkgs.fetchurl {
101 url = https://luarocks.org/discount-0.4-1.rockspec;
102 sha256 = "0mc2mwkprf8li2v91vga77rwi0xhv989nxshi66z2d45lbl1dcpd";
101 url = mirror://luarocks/discount-0.4-1.rockspec;
102 hash = "sha256-7bIW6KKFNPGNiVB3m1DasIPI8znq7ZC2iBS5fCevglU=";
103103 }).outPath;
104104
105105 src = pkgs.fetchurl {
106 url = https://craigbarnes.gitlab.io/dist/lua-discount/lua-discount-0.4.tar.gz;
107 sha256 = "1bfyrxjr26gbahawdynlbp48ma01gyd3b6xbljvxb2aavvfywc9m";
106 url = https://craigbarnes.gitlab.io/dist/lua-discount/lua-discount-0.4.tar.gz;
107 hash = "sha256-NTHu3d5KidW3pKubNZp/AaiKyF3U+sYVVOsZkWXP3q0=";
108108 };
109109
110110 buildInputs = [ pkgs.discount ];
122122 version = "scm-2";
123123
124124 knownRockspec = (pkgs.fetchurl {
125 url = "mirror://luarocks//${pname}-${version}.rockspec";
126 sha256 = "PHQhpQPfmlPhwIXoce5WZ+eoARmSecy1ac7Bfu4zg38=";
125 url = "mirror://luarocks/${pname}-${version}.rockspec";
126 hash = "sha256-PHQhpQPfmlPhwIXoce5WZ+eoARmSecy1ac7Bfu4zg38=";
127127 }).outPath;
128128
129129 src = pkgs.fetchFromGitHub {
130130 owner = "s-ol";
131131 repo = "LDoc";
132132 rev = "moonscript";
133 sha256 = "3jieGp9++cWtLMKccP+xqrtdCiNG/9BYZlHmH1l8XV8=";
133 hash = "sha256-3jieGp9++cWtLMKccP+xqrtdCiNG/9BYZlHmH1l8XV8=";
134134 };
135135 propagatedBuildInputs = with luaPkgs; [
136136 lua penlight markdown
145145
146146 lua-rtmidi = luaPkgs.buildLuarocksPackage rec {
147147 pname = "lua-rtmidi";
148 version = "dev-1";
149
148 version = "1.0.0-1";
149
150 # src = pkgs.fetchurl {
151 # url = "mirror://luarocks/${pname}-${version}.src.rock";
152 # hash = "sha256-DmSfrQRX8oziH+vvwq3KIdvjTX7P4zeKc6NeTygoU3A=";
153 # };
150154 src = pkgs.fetchFromGitHub {
151155 owner = "s-ol";
152156 repo = "lua-rtmidi";
153 rev = "master";
154 sha256 = "iXckraQZf6smWlxD27ktBEFKNXLzzsZFpzx2MLRQJVM=";
155 };
157 rev = "v1.0.0";
158 hash = "sha256-DmSfrQRX8oziH+vvwq3KIdvjTX7P4zeKc6NeTygoU3A=";
159 };
160
156161 buildInputs = with pkgs; [ stdenv.cc.cc.lib ];
157 propagatedBuildInputs = with pkgs; [ lua alsa-lib pipewire.jack ];
162 propagatedBuildInputs = with pkgs; [ lua alsa-lib libjack2 ];
158163
159164 meta = {
160165 homepage = "https://github.com/s-ol/lua-rtmidi";