voicemeeter_api_ruby 4.1.5 → 4.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -1
- data/README.md +24 -5
- data/lib/voicemeeter/base.rb +223 -0
- data/lib/voicemeeter/bus.rb +99 -0
- data/lib/voicemeeter/button.rb +25 -0
- data/lib/voicemeeter/cbindings.rb +126 -0
- data/lib/voicemeeter/command.rb +38 -0
- data/lib/voicemeeter/configs.rb +83 -0
- data/lib/voicemeeter/device.rb +26 -0
- data/lib/voicemeeter/errors.rb +43 -0
- data/lib/voicemeeter/inst.rb +27 -0
- data/lib/voicemeeter/iremote.rb +34 -0
- data/lib/voicemeeter/kinds.rb +79 -0
- data/lib/voicemeeter/meta.rb +251 -0
- data/lib/voicemeeter/mixin.rb +74 -0
- data/lib/voicemeeter/recorder.rb +20 -0
- data/lib/voicemeeter/runvm.rb +31 -0
- data/lib/voicemeeter/strip.rb +124 -0
- data/lib/voicemeeter/vban.rb +80 -0
- data/lib/voicemeeter/version.rb +25 -0
- data/lib/voicemeeter.rb +8 -8
- metadata +20 -19
- data/lib/base.rb +0 -220
- data/lib/bus.rb +0 -105
- data/lib/button.rb +0 -23
- data/lib/cbindings.rb +0 -125
- data/lib/command.rb +0 -36
- data/lib/configs.rb +0 -80
- data/lib/device.rb +0 -24
- data/lib/errors.rb +0 -41
- data/lib/inst.rb +0 -27
- data/lib/iremote.rb +0 -32
- data/lib/kinds.rb +0 -77
- data/lib/meta.rb +0 -275
- data/lib/recorder.rb +0 -20
- data/lib/runvm.rb +0 -29
- data/lib/strip.rb +0 -135
- data/lib/vban.rb +0 -78
- data/lib/version.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfec081c74f1dbdd1b315bd0c3aeaff0b80da1e520b995c584d087f2753cb56e
|
4
|
+
data.tar.gz: 5e40c74ebc5d8aef7f153f278b3737387f43748604d073d35a308fa817a21627
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 189d225992622d19c21d7eb6a3f81e08db74b5b5556b7f8794bcc3fe4c0efe17393fbd6897bae1c869d1b4ebef9eafae1433827a1ecafecb393e0349260bcfb8
|
7
|
+
data.tar.gz: 933d748eb4ca2bcae4081a35c4b3cc9258b08defa79fca143c0caced8ec3c00773c55acc086f71f36c9ede579515dca945dcd26de335ed825dedd8a2529294a3
|
data/CHANGELOG.md
CHANGED
@@ -9,7 +9,24 @@ Before any major/minor/patch is released all unit tests will be run to verify th
|
|
9
9
|
|
10
10
|
## [Unreleased] - These changes have not been added to RubyGems yet
|
11
11
|
|
12
|
-
- [ ]
|
12
|
+
- [ ]
|
13
|
+
|
14
|
+
## [4.3.0] - 2022-07-29
|
15
|
+
|
16
|
+
### Added
|
17
|
+
|
18
|
+
- Mixin module
|
19
|
+
- xy, fx parameters to strip/bus
|
20
|
+
- unit tests for xy, fx
|
21
|
+
- xy, fx to readme
|
22
|
+
- config tests added
|
23
|
+
- gemfile to obs example
|
24
|
+
|
25
|
+
### Changed
|
26
|
+
|
27
|
+
- moved gem files into voicemeeter/ dir
|
28
|
+
- update obs example
|
29
|
+
- using require_relative in case using direct download.
|
13
30
|
|
14
31
|
## [4.1.0] - 2022-07-19
|
15
32
|
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
+
[](https://badge.fury.io/rb/voicemeeter_api_ruby)
|
2
|
+

|
1
3
|
[](https://github.com/onyx-and-iris/voicemeeter-api-ruby/blob/dev/LICENSE)
|
2
4
|
[](https://github.com/prettier/plugin-ruby)
|
3
5
|

|
4
|
-
[](https://badge.fury.io/rb/voicemeeter_api_ruby)
|
5
|
-

|
6
6
|
|
7
7
|
# Ruby Wrapper for Voicemeeter API
|
8
8
|
|
@@ -98,6 +98,20 @@ The following properties are available.
|
|
98
98
|
- `bass`: float, from -12.0 to 12.0
|
99
99
|
- `mid`: float, from -12.0 to 12.0
|
100
100
|
- `treble`: float, from -12.0 to 12.0
|
101
|
+
- `reverb`: float, from 0.0 to 10.0
|
102
|
+
- `delay`: float, from 0.0 to 10.0
|
103
|
+
- `fx1`: float, from 0.0 to 10.0
|
104
|
+
- `fx2`: float, from 0.0 to 10.0
|
105
|
+
- `pan_x`: float, from -0.5 to 0.5
|
106
|
+
- `pan_y`: float, from 0.0 to 1.0
|
107
|
+
- `color_x`: float, from -0.5 to 0.5
|
108
|
+
- `color_y`: float, from 0.0 to 1.0
|
109
|
+
- `fx_x`: float, from -0.5 to 0.5
|
110
|
+
- `fx_y`: float, from 0.0 to 1.0
|
111
|
+
- `postreverb`: boolean
|
112
|
+
- `postdelay`: boolean
|
113
|
+
- `postfx1`: boolean
|
114
|
+
- `postfx2`: boolean
|
101
115
|
|
102
116
|
example:
|
103
117
|
|
@@ -164,6 +178,11 @@ The following properties are available.
|
|
164
178
|
- `label`: string
|
165
179
|
- `device`: string
|
166
180
|
- `sr`: int
|
181
|
+
- `returnreverb`: float, from 0.0 to 10.0
|
182
|
+
- `returndelay`: float, from 0.0 to 10.0
|
183
|
+
- `returnfx1`: float, from 0.0 to 10.0
|
184
|
+
- `returnfx2`: float, from 0.0 to 10.0
|
185
|
+
- `monitor`: boolean
|
167
186
|
|
168
187
|
example:
|
169
188
|
|
@@ -264,10 +283,10 @@ vm.recorder.play
|
|
264
283
|
vm.recorder.stop
|
265
284
|
|
266
285
|
# Enable loop play
|
267
|
-
vm.recorder.loop =
|
286
|
+
vm.recorder.loop = true
|
268
287
|
|
269
288
|
# Disable recorder out channel B2
|
270
|
-
vm.recorder.B2 =
|
289
|
+
vm.recorder.B2 = false
|
271
290
|
|
272
291
|
# filepath as string
|
273
292
|
vm.recorder.load('C:\music\mytune.mp3')
|
@@ -300,7 +319,7 @@ example:
|
|
300
319
|
vm.vban.enable
|
301
320
|
|
302
321
|
# turn on vban instream 0
|
303
|
-
vm.vban.instream[0].on =
|
322
|
+
vm.vban.instream[0].on = true
|
304
323
|
|
305
324
|
# set bit property for outstream 3 to 24
|
306
325
|
vm.vban.outstream[3].bit = 24
|
@@ -0,0 +1,223 @@
|
|
1
|
+
require "observer"
|
2
|
+
|
3
|
+
require_relative "runvm"
|
4
|
+
require_relative "configs"
|
5
|
+
require_relative "errors"
|
6
|
+
|
7
|
+
module Voicemeeter
|
8
|
+
class Base
|
9
|
+
"
|
10
|
+
Base class responsible for wrapping the C Remote API
|
11
|
+
|
12
|
+
Mixin required modules
|
13
|
+
"
|
14
|
+
include Observable
|
15
|
+
include Configs
|
16
|
+
include RunVM
|
17
|
+
|
18
|
+
attr_accessor :strip, :bus, :button, :vban, :command, :recorder, :device
|
19
|
+
attr_accessor :strip_mode
|
20
|
+
|
21
|
+
attr_reader :kind, :p_in, :v_in, :p_out, :v_out, :retval, :cache
|
22
|
+
attr_reader :running, :_strip_comp, :_bus_comp, :delay
|
23
|
+
|
24
|
+
DELAY = 0.001
|
25
|
+
SYNC = false
|
26
|
+
RATELIMIT = 0.033
|
27
|
+
SIZE = 1
|
28
|
+
|
29
|
+
def initialize(kind, **kwargs)
|
30
|
+
@kind = kind
|
31
|
+
@p_in, @v_in = kind.layout[:strip].values
|
32
|
+
@p_out, @v_out = kind.layout[:bus].values
|
33
|
+
@cache = Hash.new
|
34
|
+
@sync = kwargs[:sync] || SYNC
|
35
|
+
@ratelimit = kwargs[:ratelimit] || RATELIMIT
|
36
|
+
@running = false
|
37
|
+
@strip_mode = 0
|
38
|
+
@delay = DELAY
|
39
|
+
end
|
40
|
+
|
41
|
+
def init_thread
|
42
|
+
@running = true
|
43
|
+
@cache["strip_level"], @cache["bus_level"] = _get_levels
|
44
|
+
Thread.new do
|
45
|
+
loop do
|
46
|
+
Thread.stop if !@running
|
47
|
+
if pdirty?
|
48
|
+
changed
|
49
|
+
notify_observers("pdirty")
|
50
|
+
end
|
51
|
+
if mdirty?
|
52
|
+
changed
|
53
|
+
notify_observers("mdirty")
|
54
|
+
end
|
55
|
+
if ldirty?
|
56
|
+
changed
|
57
|
+
@_strip_comp =
|
58
|
+
@cache["strip_level"].map.with_index do |x, i|
|
59
|
+
!(x == @strip_buf[i])
|
60
|
+
end
|
61
|
+
@_bus_comp =
|
62
|
+
@cache["bus_level"].map.with_index { |x, i| !(x == @bus_buf[i]) }
|
63
|
+
@cache["strip_level"] = @strip_buf
|
64
|
+
@cache["bus_level"] = @bus_buf
|
65
|
+
notify_observers("ldirty")
|
66
|
+
end
|
67
|
+
sleep(@ratelimit)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def end_thread
|
73
|
+
@running = false
|
74
|
+
end
|
75
|
+
|
76
|
+
def login
|
77
|
+
@@cdll.call(:login)
|
78
|
+
clear_polling
|
79
|
+
rescue CAPIErrors => error
|
80
|
+
case
|
81
|
+
when error.value == 1
|
82
|
+
self.start(@kind.name)
|
83
|
+
clear_polling
|
84
|
+
when error.value < 0
|
85
|
+
raise
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def logout
|
90
|
+
clear_polling
|
91
|
+
sleep(0.1)
|
92
|
+
@@cdll.call(:logout)
|
93
|
+
end
|
94
|
+
|
95
|
+
def type
|
96
|
+
c_type = FFI::MemoryPointer.new(:long, SIZE)
|
97
|
+
@@cdll.call(:vmtype, c_type)
|
98
|
+
types = { 1 => "basic", 2 => "banana", 3 => "potato" }
|
99
|
+
types[c_type.read_long]
|
100
|
+
end
|
101
|
+
|
102
|
+
def version
|
103
|
+
c_ver = FFI::MemoryPointer.new(:long, SIZE)
|
104
|
+
@@cdll.call(:vmversion, c_ver)
|
105
|
+
v1 = (c_ver.read_long & 0xFF000000) >> 24
|
106
|
+
v2 = (c_ver.read_long & 0x00FF0000) >> 16
|
107
|
+
v3 = (c_ver.read_long & 0x0000FF00) >> 8
|
108
|
+
v4 = c_ver.read_long & 0x000000FF
|
109
|
+
"#{v1}.#{v2}.#{v3}.#{v4}"
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_parameter(name, is_string = false)
|
113
|
+
self.polling("get_parameter", name: name) do
|
114
|
+
if is_string
|
115
|
+
c_get = FFI::MemoryPointer.new(:string, 512, true)
|
116
|
+
@@cdll.call(:get_parameter_string, name, c_get)
|
117
|
+
c_get.read_string
|
118
|
+
else
|
119
|
+
c_get = FFI::MemoryPointer.new(:float, SIZE)
|
120
|
+
@@cdll.call(:get_parameter_float, name, c_get)
|
121
|
+
c_get.read_float.round(1)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def set_parameter(name, value)
|
127
|
+
if value.is_a? String
|
128
|
+
@@cdll.call(:set_parameter_string, name, value)
|
129
|
+
else
|
130
|
+
@@cdll.call(:set_parameter_float, name, value.to_f)
|
131
|
+
end
|
132
|
+
@cache.store(name, value)
|
133
|
+
end
|
134
|
+
|
135
|
+
def get_buttonstatus(id, mode)
|
136
|
+
self.polling("get_buttonstatus", id: id, mode: mode) do
|
137
|
+
c_get = FFI::MemoryPointer.new(:float, SIZE)
|
138
|
+
@@cdll.call(:get_buttonstatus, id, c_get, mode)
|
139
|
+
c_get.read_float.to_i
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def set_buttonstatus(id, state, mode)
|
144
|
+
@@cdll.call(:set_buttonstatus, id, state, mode)
|
145
|
+
@cache.store("mb_#{id}_#{mode}", state)
|
146
|
+
end
|
147
|
+
|
148
|
+
def set_parameter_multi(param_hash)
|
149
|
+
param_hash.each do |(key, val)|
|
150
|
+
prop, m2, m3, *rem = key.to_s.split("_")
|
151
|
+
if m2.to_i.to_s == m2
|
152
|
+
m2 = m2.to_i
|
153
|
+
elsif m3.to_i.to_s == m3
|
154
|
+
m3 = m3.to_i
|
155
|
+
end
|
156
|
+
|
157
|
+
case prop
|
158
|
+
when "strip"
|
159
|
+
self.strip[m2].set_multi(val)
|
160
|
+
when "bus"
|
161
|
+
self.bus[m2].set_multi(val)
|
162
|
+
when "button", "mb"
|
163
|
+
self.button[m2].set_multi(val)
|
164
|
+
when "vban"
|
165
|
+
if %w[instream in].include? m2
|
166
|
+
self.vban.instream[m3].set_multi(val)
|
167
|
+
elsif %w[outstream out].include? m2
|
168
|
+
self.vban.outstream[m3].set_multi(val)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
sleep(DELAY)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def get_level(type, index)
|
176
|
+
c_get = FFI::MemoryPointer.new(:float, SIZE)
|
177
|
+
@@cdll.call(:get_level, type, index, c_get)
|
178
|
+
c_get.read_float
|
179
|
+
end
|
180
|
+
|
181
|
+
def _get_levels
|
182
|
+
[
|
183
|
+
(0...(2 * @p_in + 8 * @v_in)).map { |i| get_level(@strip_mode, i) },
|
184
|
+
(0...(8 * (@p_out + @v_out))).map { |i| get_level(3, i) }
|
185
|
+
]
|
186
|
+
end
|
187
|
+
|
188
|
+
def get_num_devices(direction)
|
189
|
+
unless %w[in out].include? direction
|
190
|
+
raise VMRemoteErrors.new("expected in or out")
|
191
|
+
end
|
192
|
+
if direction == "in"
|
193
|
+
val = @@cdll.call(:get_num_indevices)
|
194
|
+
else
|
195
|
+
val = @@cdll.call(:get_num_outdevices)
|
196
|
+
end
|
197
|
+
val[0]
|
198
|
+
end
|
199
|
+
|
200
|
+
def get_device_description(index, direction)
|
201
|
+
unless %w[in out].include? direction
|
202
|
+
raise VMRemoteErrors.new("expected in or out")
|
203
|
+
end
|
204
|
+
c_type = FFI::MemoryPointer.new(:long, SIZE)
|
205
|
+
c_name = FFI::MemoryPointer.new(:string, 256, true)
|
206
|
+
c_hwid = FFI::MemoryPointer.new(:string, 256, true)
|
207
|
+
if direction == "in"
|
208
|
+
@@cdll.call(:get_desc_indevices, index, c_type, c_name, c_hwid)
|
209
|
+
else
|
210
|
+
@@cdll.call(:get_desc_outdevices, index, c_type, c_name, c_hwid)
|
211
|
+
end
|
212
|
+
[c_name.read_string, c_type.read_long, c_hwid.read_string]
|
213
|
+
end
|
214
|
+
|
215
|
+
alias_method "set_multi", :set_parameter_multi
|
216
|
+
alias_method "apply", :set_parameter_multi
|
217
|
+
alias_method "get", :get_parameter
|
218
|
+
alias_method "set", :set_parameter
|
219
|
+
alias_method "pdirty", :pdirty?
|
220
|
+
alias_method "mdirty", :mdirty?
|
221
|
+
alias_method "ldirty", :ldirty?
|
222
|
+
end
|
223
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require_relative "iremote"
|
2
|
+
|
3
|
+
module Voicemeeter
|
4
|
+
class Bus < IRemote
|
5
|
+
"
|
6
|
+
Concrete Bus class
|
7
|
+
"
|
8
|
+
include Channel_Meta_Functions
|
9
|
+
include Mixin::Fades
|
10
|
+
include Mixin::Return
|
11
|
+
|
12
|
+
attr_accessor :mode, :levels
|
13
|
+
|
14
|
+
def self.make(remote, layout_bus)
|
15
|
+
"
|
16
|
+
Factory function for Bus classes.
|
17
|
+
"
|
18
|
+
p_out, v_out = layout_bus.values
|
19
|
+
(0...(p_out + v_out)).map do |i|
|
20
|
+
i < p_out ? PhysicalBus.new(remote, i) : VirtualBus.new(remote, i)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(remote, i)
|
25
|
+
super
|
26
|
+
self.make_accessor_bool :mute, :mono, :eq, :eq_ab, :sel, :monitor
|
27
|
+
self.make_accessor_float :gain
|
28
|
+
self.make_accessor_string :label
|
29
|
+
|
30
|
+
@mode = BusModes.new(remote, i)
|
31
|
+
@levels = BusLevels.new(remote, i)
|
32
|
+
end
|
33
|
+
|
34
|
+
def identifier
|
35
|
+
"bus[#{@index}]"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class PhysicalBus < Bus
|
40
|
+
def initialize(remote, i)
|
41
|
+
super
|
42
|
+
self.make_reader_only :device, :sr
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class VirtualBus < Bus
|
47
|
+
end
|
48
|
+
|
49
|
+
class BusModes < IRemote
|
50
|
+
include Channel_Meta_Functions
|
51
|
+
|
52
|
+
def initialize(remote, i)
|
53
|
+
super
|
54
|
+
self.make_bus_modes :normal,
|
55
|
+
:amix,
|
56
|
+
:bmix,
|
57
|
+
:repeat,
|
58
|
+
:composite,
|
59
|
+
:tvmix,
|
60
|
+
:upmix21,
|
61
|
+
:upmix41,
|
62
|
+
:upmix61,
|
63
|
+
:centeronly,
|
64
|
+
:lfeonly,
|
65
|
+
:rearonly
|
66
|
+
end
|
67
|
+
|
68
|
+
def identifier
|
69
|
+
"bus[#{@index}].mode"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class BusLevels < IRemote
|
74
|
+
def initialize(remote, i)
|
75
|
+
super
|
76
|
+
@init = i * 8
|
77
|
+
@offset = 8
|
78
|
+
end
|
79
|
+
|
80
|
+
def identifier
|
81
|
+
"bus[#{@index}]"
|
82
|
+
end
|
83
|
+
|
84
|
+
def getter(mode)
|
85
|
+
if @remote.running
|
86
|
+
vals = @remote.cache["bus_level"][@init, @offset]
|
87
|
+
else
|
88
|
+
vals = (@init...@offset).map { |i| @remote.get_level(mode, i) }
|
89
|
+
end
|
90
|
+
vals.map { |x| x > 0 ? (20 * Math.log(x, 10)).round(1) : -200.0 }
|
91
|
+
end
|
92
|
+
|
93
|
+
def all
|
94
|
+
getter(3)
|
95
|
+
end
|
96
|
+
|
97
|
+
def isdirty? = @remote._bus_comp[@init, @offset].any?
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative "iremote"
|
2
|
+
require_relative "meta"
|
3
|
+
|
4
|
+
module Voicemeeter
|
5
|
+
class MacroButton < IRemote
|
6
|
+
include MacroButton_Meta_Functions
|
7
|
+
|
8
|
+
def self.make(remote, num_buttons)
|
9
|
+
(0...num_buttons).map { |i| MacroButton.new(remote, i) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(remote, i)
|
13
|
+
super
|
14
|
+
self.make_accessor_macrobutton :state, :stateonly, :trigger
|
15
|
+
end
|
16
|
+
|
17
|
+
def getter(mode)
|
18
|
+
@remote.get_buttonstatus(@index, mode)
|
19
|
+
end
|
20
|
+
|
21
|
+
def setter(set, mode)
|
22
|
+
@remote.set_buttonstatus(@index, set, mode)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require "ffi"
|
2
|
+
require_relative "inst"
|
3
|
+
|
4
|
+
module Voicemeeter
|
5
|
+
module CBindings
|
6
|
+
"
|
7
|
+
Creates Ruby bindings to the C DLL
|
8
|
+
|
9
|
+
Performs other low level tasks
|
10
|
+
"
|
11
|
+
extend Voicemeeter::InstallationFunctions
|
12
|
+
extend FFI::Library
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
begin
|
17
|
+
OS_BITS = FFI::Platform::CPU.downcase == "x64" ? 64 : 32
|
18
|
+
VM_PATH = get_vmpath(OS_BITS)
|
19
|
+
DLL_NAME = "VoicemeeterRemote#{OS_BITS == 64 ? "64" : ""}.dll"
|
20
|
+
|
21
|
+
self.vm_dll = VM_PATH.join(DLL_NAME)
|
22
|
+
rescue InstallErrors => error
|
23
|
+
puts "ERROR: #{error.message}"
|
24
|
+
raise
|
25
|
+
end
|
26
|
+
|
27
|
+
ffi_lib @vm_dll
|
28
|
+
ffi_convention :stdcall
|
29
|
+
|
30
|
+
attach_function :vm_login, :VBVMR_Login, [], :long
|
31
|
+
attach_function :vm_logout, :VBVMR_Logout, [], :long
|
32
|
+
attach_function :vm_runvm, :VBVMR_RunVoicemeeter, [:long], :long
|
33
|
+
attach_function :vm_vmtype, :VBVMR_GetVoicemeeterType, [:pointer], :long
|
34
|
+
attach_function :vm_vmversion, :VBVMR_GetVoicemeeterVersion, [:pointer], :long
|
35
|
+
|
36
|
+
attach_function :vm_mdirty, :VBVMR_MacroButton_IsDirty, [], :long
|
37
|
+
attach_function :vm_get_buttonstatus,
|
38
|
+
:VBVMR_MacroButton_GetStatus,
|
39
|
+
%i[long pointer long],
|
40
|
+
:long
|
41
|
+
attach_function :vm_set_buttonstatus,
|
42
|
+
:VBVMR_MacroButton_SetStatus,
|
43
|
+
%i[long float long],
|
44
|
+
:long
|
45
|
+
|
46
|
+
attach_function :vm_pdirty, :VBVMR_IsParametersDirty, [], :long
|
47
|
+
attach_function :vm_get_parameter_float,
|
48
|
+
:VBVMR_GetParameterFloat,
|
49
|
+
%i[string pointer],
|
50
|
+
:long
|
51
|
+
attach_function :vm_set_parameter_float,
|
52
|
+
:VBVMR_SetParameterFloat,
|
53
|
+
%i[string float],
|
54
|
+
:long
|
55
|
+
|
56
|
+
attach_function :vm_get_parameter_string,
|
57
|
+
:VBVMR_GetParameterStringA,
|
58
|
+
%i[string pointer],
|
59
|
+
:long
|
60
|
+
attach_function :vm_set_parameter_string,
|
61
|
+
:VBVMR_SetParameterStringA,
|
62
|
+
%i[string string],
|
63
|
+
:long
|
64
|
+
|
65
|
+
attach_function :vm_set_parameter_multi,
|
66
|
+
:VBVMR_SetParameters,
|
67
|
+
[:string],
|
68
|
+
:long
|
69
|
+
|
70
|
+
attach_function :vm_get_level, :VBVMR_GetLevel, %i[long long pointer], :long
|
71
|
+
|
72
|
+
attach_function :vm_get_num_indevices, :VBVMR_Input_GetDeviceNumber, [], :long
|
73
|
+
attach_function :vm_get_desc_indevices,
|
74
|
+
:VBVMR_Input_GetDeviceDescA,
|
75
|
+
%i[long pointer pointer pointer],
|
76
|
+
:long
|
77
|
+
|
78
|
+
attach_function :vm_get_num_outdevices,
|
79
|
+
:VBVMR_Output_GetDeviceNumber,
|
80
|
+
[],
|
81
|
+
:long
|
82
|
+
attach_function :vm_get_desc_outdevices,
|
83
|
+
:VBVMR_Output_GetDeviceDescA,
|
84
|
+
%i[long pointer pointer pointer],
|
85
|
+
:long
|
86
|
+
|
87
|
+
@@cdll =
|
88
|
+
lambda { |func, *args| retval = [send("vm_#{func}", *args), func] }
|
89
|
+
|
90
|
+
def clear_polling = while pdirty? || mdirty?; end
|
91
|
+
|
92
|
+
def polling(func, **kwargs)
|
93
|
+
params = {
|
94
|
+
"get_parameter" => kwargs[:name],
|
95
|
+
"get_buttonstatus" => "mb_#{kwargs[:id]}_#{kwargs[:mode]}"
|
96
|
+
}
|
97
|
+
return @cache.delete(params[func]) if @cache.key? params[func]
|
98
|
+
|
99
|
+
clear_polling if @sync
|
100
|
+
|
101
|
+
yield
|
102
|
+
end
|
103
|
+
|
104
|
+
def retval=(values)
|
105
|
+
" Writer validation for CAPI calls "
|
106
|
+
retval, func = *values
|
107
|
+
unless %i[get_num_indevices get_num_outdevices].include? func
|
108
|
+
raise CAPIErrors.new(retval, func) if retval&.nonzero?
|
109
|
+
end
|
110
|
+
@retval = retval
|
111
|
+
end
|
112
|
+
|
113
|
+
public
|
114
|
+
|
115
|
+
def pdirty? = vm_pdirty&.nonzero?
|
116
|
+
|
117
|
+
def mdirty? = vm_mdirty&.nonzero?
|
118
|
+
|
119
|
+
def ldirty?
|
120
|
+
@strip_buf, @bus_buf = _get_levels
|
121
|
+
return(
|
122
|
+
!(@cache["strip_level"] == @strip_buf && @cache["bus_level"] == @bus_buf)
|
123
|
+
)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative "iremote"
|
2
|
+
require_relative "meta"
|
3
|
+
|
4
|
+
module Voicemeeter
|
5
|
+
class Command < IRemote
|
6
|
+
include Commands_Meta_Functions
|
7
|
+
|
8
|
+
def initialize(remote)
|
9
|
+
super
|
10
|
+
self.make_action_prop :show, :restart, :shutdown
|
11
|
+
self.make_writer_bool :showvbanchat, :lock
|
12
|
+
end
|
13
|
+
|
14
|
+
def identifier
|
15
|
+
:command
|
16
|
+
end
|
17
|
+
|
18
|
+
def hide
|
19
|
+
self.setter("show", 0)
|
20
|
+
end
|
21
|
+
|
22
|
+
def load(value)
|
23
|
+
raise VMRemoteErrors.new("Expected a string") unless value.is_a? String
|
24
|
+
self.setter("load", value)
|
25
|
+
sleep(0.2)
|
26
|
+
end
|
27
|
+
|
28
|
+
def save(value)
|
29
|
+
raise VMRemoteErrors.new("Expected a string") unless value.is_a? String
|
30
|
+
self.setter("save", value)
|
31
|
+
sleep(0.2)
|
32
|
+
end
|
33
|
+
|
34
|
+
def reset
|
35
|
+
@remote.set_config("reset")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require "toml"
|
2
|
+
require_relative "kinds"
|
3
|
+
|
4
|
+
module Voicemeeter
|
5
|
+
module Configs
|
6
|
+
private
|
7
|
+
|
8
|
+
@@configs = Hash.new
|
9
|
+
|
10
|
+
class TOMLStrBuilder
|
11
|
+
def initialize(kind)
|
12
|
+
@p_in, @v_in = kind[:layout][:strip].values
|
13
|
+
@p_out, @v_out = kind[:layout][:bus].values
|
14
|
+
@vs_params =
|
15
|
+
["mute = false", "mono = false", "solo = false", "gain = 0.0"] +
|
16
|
+
(1..@p_out).map { |i| "A#{i} = false" } +
|
17
|
+
(1..@v_out).map { |i| "B#{i} = false" }
|
18
|
+
|
19
|
+
@ps_params = @vs_params + ["comp = 0.0", "gate = 0.0"]
|
20
|
+
@bus_params = ["mono = false", "eq = false", "mute = false"]
|
21
|
+
end
|
22
|
+
|
23
|
+
def build
|
24
|
+
"
|
25
|
+
Builds a TOML script for the parser
|
26
|
+
"
|
27
|
+
@ps = (0...@p_in).map { |i| ["[strip_#{i}]"] + @ps_params }
|
28
|
+
@ps.map! { |a| a.map { |s| s.gsub("B1 = false", "B1 = true") } }
|
29
|
+
@vs =
|
30
|
+
(@p_in...(@p_in + @v_in)).map { |i| ["[strip_#{i}]"] + @vs_params }
|
31
|
+
@vs.map! { |a| a.map { |s| s.gsub("A1 = false", "A1 = true") } }
|
32
|
+
|
33
|
+
@b = (0...(@p_out + @v_out)).map { |i| ["[bus_#{i}]"] + @bus_params }
|
34
|
+
|
35
|
+
[@ps + @vs + @b].join("\n")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def parser(data)
|
40
|
+
TOML::Parser.new(data).parsed
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_configs(kind_id)
|
44
|
+
file_path = File.join(Dir.pwd, "configs", "#{kind_id}")
|
45
|
+
|
46
|
+
if Dir.exist?(file_path)
|
47
|
+
Dir
|
48
|
+
.glob(File.join(file_path, "*.toml"))
|
49
|
+
.to_h do |toml_file|
|
50
|
+
filename = File.basename(toml_file, ".toml")
|
51
|
+
puts "loading config #{kind_id}/#{filename} into memory"
|
52
|
+
[filename, parser(File.read(toml_file))]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def loader
|
58
|
+
if @@configs.empty?
|
59
|
+
builder = TOMLStrBuilder.new(@kind)
|
60
|
+
puts "loading config reset into memory"
|
61
|
+
@@configs["reset"] = parser(builder.build)
|
62
|
+
configs = get_configs(@kind.name.to_s)
|
63
|
+
|
64
|
+
@@configs.merge!(configs) unless configs.nil?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
public
|
69
|
+
|
70
|
+
def set_config(value)
|
71
|
+
loader
|
72
|
+
unless @@configs.key? value
|
73
|
+
raise VMRemoteErrors.new("No profile with name #{value} was loaded")
|
74
|
+
end
|
75
|
+
|
76
|
+
self.send("set_multi", @@configs[value])
|
77
|
+
puts "config #{@kind.name}/#{value} applied!"
|
78
|
+
sleep(@delay)
|
79
|
+
end
|
80
|
+
|
81
|
+
alias_method "apply_config", :set_config
|
82
|
+
end
|
83
|
+
end
|