voicemeeter_api_ruby 2.0.4 → 4.1.0
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 +309 -0
- data/LICENSE +21 -0
- data/README.md +439 -0
- data/lib/base.rb +182 -135
- data/lib/bus.rb +80 -16
- data/lib/button.rb +10 -29
- data/lib/cbindings.rb +128 -0
- data/lib/command.rb +17 -22
- data/lib/configs.rb +79 -0
- data/lib/device.rb +24 -0
- data/lib/errors.rb +39 -37
- data/lib/inst.rb +10 -17
- data/lib/iremote.rb +30 -0
- data/lib/kinds.rb +77 -0
- data/lib/meta.rb +96 -66
- data/lib/mixin.rb +11 -0
- data/lib/recorder.rb +10 -35
- data/lib/runvm.rb +19 -8
- data/lib/strip.rb +99 -17
- data/lib/vban.rb +47 -75
- data/lib/version.rb +1 -1
- data/lib/voicemeeter.rb +60 -34
- metadata +25 -27
- data/lib/channel.rb +0 -34
- data/lib/routines.rb +0 -123
data/lib/base.rb
CHANGED
@@ -1,171 +1,218 @@
|
|
1
|
-
require '
|
2
|
-
require 'ffi'
|
3
|
-
require_relative 'inst'
|
1
|
+
require 'observer'
|
4
2
|
|
5
|
-
|
3
|
+
require_relative 'runvm'
|
4
|
+
require_relative 'configs'
|
5
|
+
require_relative 'errors'
|
6
6
|
|
7
|
+
class Base
|
8
|
+
'
|
9
|
+
Base class responsible for wrapping the C Remote API
|
7
10
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
Mixin required modules
|
12
|
+
'
|
13
|
+
include Observable
|
14
|
+
include Configs
|
15
|
+
include RunVM
|
13
16
|
|
14
|
-
|
17
|
+
attr_accessor :strip, :bus, :button, :vban, :command, :recorder, :device
|
18
|
+
attr_accessor :strip_mode
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
VM_PATH = get_vmpath(OS_BITS)
|
19
|
-
DLL_NAME = "VoicemeeterRemote#{OS_BITS == 64 ? "64" : ""}.dll"
|
20
|
+
attr_reader :kind, :p_in, :v_in, :p_out, :v_out, :retval, :cache
|
21
|
+
attr_reader :running, :_strip_comp, :_bus_comp
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
DELAY = 0.001
|
24
|
+
SYNC = false
|
25
|
+
RATELIMIT = 0.033
|
26
|
+
SIZE = 1
|
27
|
+
|
28
|
+
def initialize(kind, **kwargs)
|
29
|
+
@kind = kind
|
30
|
+
@p_in, @v_in = kind.layout[:strip].values
|
31
|
+
@p_out, @v_out = kind.layout[:bus].values
|
32
|
+
@cache = Hash.new
|
33
|
+
@sync = kwargs[:sync] || SYNC
|
34
|
+
@ratelimit = kwargs[:ratelimit] || RATELIMIT
|
35
|
+
@running = false
|
36
|
+
@strip_mode = 0
|
25
37
|
end
|
26
38
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
39
|
+
def init_thread
|
40
|
+
@running = true
|
41
|
+
@cache['strip_level'], @cache['bus_level'] = _get_levels
|
42
|
+
Thread.new do
|
43
|
+
loop do
|
44
|
+
Thread.stop if !@running
|
45
|
+
if pdirty?
|
46
|
+
changed
|
47
|
+
notify_observers('pdirty')
|
48
|
+
elsif mdirty?
|
49
|
+
changed
|
50
|
+
notify_observers('mdirty')
|
51
|
+
elsif ldirty?
|
52
|
+
changed
|
53
|
+
@_strip_comp =
|
54
|
+
@cache['strip_level'].map.with_index do |x, i|
|
55
|
+
!(x == @strip_buf[i])
|
56
|
+
end
|
57
|
+
@_bus_comp =
|
58
|
+
@cache['bus_level'].map.with_index do |x, i|
|
59
|
+
!(x == @bus_buf[i])
|
60
|
+
end
|
61
|
+
@cache['strip_level'] = @strip_buf
|
62
|
+
@cache['bus_level'] = @bus_buf
|
63
|
+
notify_observers('ldirty')
|
64
|
+
end
|
65
|
+
sleep(@ratelimit)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
34
69
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
attach_function :vmr_macro_getstatus, :VBVMR_MacroButton_GetStatus, \
|
39
|
-
[:long, :pointer, :long], :long
|
70
|
+
def end_thread
|
71
|
+
@running = false
|
72
|
+
end
|
40
73
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
74
|
+
def login
|
75
|
+
@@cdll.call(:login)
|
76
|
+
clear_polling
|
77
|
+
rescue CAPIErrors => error
|
78
|
+
case
|
79
|
+
when error.value == 1
|
80
|
+
self.start(@kind.name)
|
81
|
+
clear_polling
|
82
|
+
when error.value < 0
|
83
|
+
raise
|
84
|
+
end
|
85
|
+
end
|
46
86
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
87
|
+
def logout
|
88
|
+
clear_polling
|
89
|
+
sleep(0.1)
|
90
|
+
@@cdll.call(:logout)
|
91
|
+
end
|
51
92
|
|
52
|
-
|
53
|
-
|
93
|
+
def type
|
94
|
+
c_type = FFI::MemoryPointer.new(:long, SIZE)
|
95
|
+
@@cdll.call(:vmtype, c_type)
|
96
|
+
types = { 1 => 'basic', 2 => 'banana', 3 => 'potato' }
|
97
|
+
types[c_type.read_long]
|
98
|
+
end
|
54
99
|
|
55
|
-
|
56
|
-
|
100
|
+
def version
|
101
|
+
c_ver = FFI::MemoryPointer.new(:long, SIZE)
|
102
|
+
@@cdll.call(:vmversion, c_ver)
|
103
|
+
v1 = (c_ver.read_long & 0xFF000000) >> 24
|
104
|
+
v2 = (c_ver.read_long & 0x00FF0000) >> 16
|
105
|
+
v3 = (c_ver.read_long & 0x0000FF00) >> 8
|
106
|
+
v4 = c_ver.read_long & 0x000000FF
|
107
|
+
"#{v1}.#{v2}.#{v3}.#{v4}"
|
108
|
+
end
|
57
109
|
|
58
|
-
def
|
59
|
-
|
110
|
+
def get_parameter(name, is_string = false)
|
111
|
+
self.polling('get_parameter', name: name) do
|
112
|
+
if is_string
|
113
|
+
c_get = FFI::MemoryPointer.new(:string, 512, true)
|
114
|
+
@@cdll.call(:get_parameter_string, name, c_get)
|
115
|
+
c_get.read_string
|
116
|
+
else
|
117
|
+
c_get = FFI::MemoryPointer.new(:float, SIZE)
|
118
|
+
@@cdll.call(:get_parameter_float, name, c_get)
|
119
|
+
c_get.read_float.round(1)
|
120
|
+
end
|
121
|
+
end
|
60
122
|
end
|
61
123
|
|
62
|
-
def
|
63
|
-
|
124
|
+
def set_parameter(name, value)
|
125
|
+
if value.is_a? String
|
126
|
+
@@cdll.call(:set_parameter_string, name, value)
|
127
|
+
else
|
128
|
+
@@cdll.call(:set_parameter_float, name, value.to_f)
|
129
|
+
end
|
130
|
+
@cache.store(name, value)
|
64
131
|
end
|
65
132
|
|
66
|
-
|
67
|
-
|
68
|
-
|
133
|
+
def get_buttonstatus(id, mode)
|
134
|
+
self.polling('get_buttonstatus', id: id, mode: mode) do
|
135
|
+
c_get = FFI::MemoryPointer.new(:float, SIZE)
|
136
|
+
@@cdll.call(:get_buttonstatus, id, c_get, mode)
|
137
|
+
c_get.read_float.to_i
|
69
138
|
end
|
70
139
|
end
|
71
140
|
|
72
|
-
def
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
141
|
+
def set_buttonstatus(id, state, mode)
|
142
|
+
@@cdll.call(:set_buttonstatus, id, state, mode)
|
143
|
+
@cache.store("mb_#{id}_#{mode}", state)
|
144
|
+
end
|
145
|
+
|
146
|
+
def set_parameter_multi(param_hash)
|
147
|
+
param_hash.each do |(key, val)|
|
148
|
+
prop, m2, m3, *rem = key.to_s.split('_')
|
149
|
+
if m2.to_i.to_s == m2
|
150
|
+
m2 = m2.to_i
|
151
|
+
elsif m3.to_i.to_s == m3
|
152
|
+
m3 = m3.to_i
|
153
|
+
end
|
154
|
+
|
155
|
+
case prop
|
156
|
+
when 'strip'
|
157
|
+
self.strip[m2].set_multi(val)
|
158
|
+
when 'bus'
|
159
|
+
self.bus[m2].set_multi(val)
|
160
|
+
when 'button', 'mb'
|
161
|
+
self.button[m2].set_multi(val)
|
162
|
+
when 'vban'
|
163
|
+
if %w[instream in].include? m2
|
164
|
+
self.vban.instream[m3].set_multi(val)
|
165
|
+
elsif %w[outstream out].include? m2
|
166
|
+
self.vban.outstream[m3].set_multi(val)
|
82
167
|
end
|
83
|
-
sleep(DELAY)
|
84
|
-
break if @cache[params[func]][1] == false && i == 1
|
85
168
|
end
|
169
|
+
sleep(DELAY)
|
86
170
|
end
|
87
|
-
|
88
|
-
val = yield
|
89
|
-
@cache.store(params[func], [val, false])
|
90
|
-
val
|
91
171
|
end
|
92
172
|
|
93
|
-
def
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
@retval = retval
|
173
|
+
def get_level(type, index)
|
174
|
+
c_get = FFI::MemoryPointer.new(:float, SIZE)
|
175
|
+
@@cdll.call(:get_level, type, index, c_get)
|
176
|
+
c_get.read_float
|
98
177
|
end
|
99
178
|
|
100
|
-
def
|
101
|
-
|
102
|
-
|
103
|
-
|
179
|
+
def _get_levels
|
180
|
+
s = (0...(2 * @p_in + 8 * @v_in)).map { |i| get_level(0, i) }
|
181
|
+
b = (0...(8 * (@p_out + @v_out))).map { |i| get_level(3, i) }
|
182
|
+
[s, b]
|
104
183
|
end
|
105
|
-
end
|
106
184
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
when "basic"
|
116
|
-
@properties = {
|
117
|
-
:name => kind,
|
118
|
-
:exe => "voicemeeter.exe",
|
119
|
-
}
|
120
|
-
@layout = {
|
121
|
-
:strip => {:p_in => 2, :v_in=> 1},
|
122
|
-
:bus => {:p_out => 1, :v_out=> 1},
|
123
|
-
:vban => {:instream => 4, :outstream => 4},
|
124
|
-
:mb => 70,
|
125
|
-
}
|
126
|
-
when "banana"
|
127
|
-
@properties = {
|
128
|
-
:name => kind,
|
129
|
-
:exe => "voicemeeterpro.exe",
|
130
|
-
}
|
131
|
-
@layout = {
|
132
|
-
:strip => {:p_in => 3, :v_in=> 2},
|
133
|
-
:bus => {:p_out => 3, :v_out=> 2},
|
134
|
-
:vban => {:instream => 8, :outstream => 8},
|
135
|
-
:mb => 70,
|
136
|
-
}
|
137
|
-
when "potato"
|
138
|
-
@properties = {
|
139
|
-
:name => kind,
|
140
|
-
:exe => "voicemeeter8#{OS_BITS == 64 ? "x64" : ""}.exe",
|
141
|
-
}
|
142
|
-
@layout = {
|
143
|
-
:strip => {:p_in => 5, :v_in=> 3},
|
144
|
-
:bus => {:p_out => 5, :v_out=> 3},
|
145
|
-
:vban => {:instream => 8, :outstream => 8},
|
146
|
-
:mb => 70,
|
147
|
-
}
|
185
|
+
def get_num_devices(direction)
|
186
|
+
unless %w[in out].include? direction
|
187
|
+
raise VMRemoteErrors.new('expected in or out')
|
188
|
+
end
|
189
|
+
if direction == 'in'
|
190
|
+
val = @@cdll.call(:get_num_indevices)
|
191
|
+
else
|
192
|
+
val = @@cdll.call(:get_num_outdevices)
|
148
193
|
end
|
194
|
+
val[0]
|
149
195
|
end
|
150
|
-
end
|
151
|
-
|
152
196
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
197
|
+
def get_device_description(index, direction)
|
198
|
+
unless %w[in out].include? direction
|
199
|
+
raise VMRemoteErrors.new('expected in or out')
|
200
|
+
end
|
201
|
+
c_type = FFI::MemoryPointer.new(:long, SIZE)
|
202
|
+
c_name = FFI::MemoryPointer.new(:string, 256, true)
|
203
|
+
c_hwid = FFI::MemoryPointer.new(:string, 256, true)
|
204
|
+
if direction == 'in'
|
205
|
+
@@cdll.call(:get_desc_indevices, index, c_type, c_name, c_hwid)
|
206
|
+
else
|
207
|
+
@@cdll.call(:get_desc_outdevices, index, c_type, c_name, c_hwid)
|
163
208
|
end
|
209
|
+
[c_name.read_string, c_type.read_long, c_hwid.read_string]
|
164
210
|
end
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
211
|
+
|
212
|
+
alias_method 'set_multi', :set_parameter_multi
|
213
|
+
alias_method 'get', :get_parameter
|
214
|
+
alias_method 'set', :set_parameter
|
215
|
+
alias_method 'pdirty', :pdirty?
|
216
|
+
alias_method 'mdirty', :mdirty?
|
217
|
+
alias_method 'ldirty', :ldirty?
|
171
218
|
end
|
data/lib/bus.rb
CHANGED
@@ -1,33 +1,97 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative 'iremote'
|
2
|
+
require_relative 'mixin'
|
2
3
|
|
4
|
+
class Bus < IRemote
|
5
|
+
'
|
6
|
+
Concrete Bus class
|
7
|
+
'
|
8
|
+
include Channel_Meta_Functions
|
9
|
+
include Fades
|
10
|
+
|
11
|
+
attr_accessor :mode, :levels
|
3
12
|
|
4
|
-
class Bus < IChannel
|
5
|
-
"""
|
6
|
-
Concrete class for Bus objects
|
7
|
-
"""
|
8
13
|
def self.make(remote, layout_bus)
|
9
|
-
|
14
|
+
'
|
10
15
|
Factory function for Bus classes.
|
11
|
-
|
12
|
-
p_out, v_out = layout_bus.
|
16
|
+
'
|
17
|
+
p_out, v_out = layout_bus.values
|
13
18
|
(0...(p_out + v_out)).map do |i|
|
14
|
-
i < p_out ?
|
15
|
-
PhysicalBus.new(remote, i) : \
|
16
|
-
VirtualBus.new(remote, i)
|
19
|
+
i < p_out ? PhysicalBus.new(remote, i) : VirtualBus.new(remote, i)
|
17
20
|
end
|
18
21
|
end
|
19
22
|
|
20
23
|
def initialize(remote, i)
|
21
24
|
super
|
22
|
-
self.make_accessor_bool :mute, :mono, :eq
|
25
|
+
self.make_accessor_bool :mute, :mono, :eq, :sel
|
23
26
|
self.make_accessor_float :gain
|
24
27
|
self.make_accessor_string :label
|
28
|
+
|
29
|
+
@mode = BusModes.new(remote, i)
|
30
|
+
@levels = BusLevels.new(remote, i)
|
31
|
+
end
|
32
|
+
|
33
|
+
def identifier
|
34
|
+
"bus[#{@index}]"
|
25
35
|
end
|
36
|
+
end
|
26
37
|
|
27
|
-
|
28
|
-
|
38
|
+
class PhysicalBus < Bus
|
39
|
+
def initialize(remote, i)
|
40
|
+
super
|
41
|
+
self.make_reader_only :device, :sr
|
29
42
|
end
|
30
43
|
end
|
31
44
|
|
32
|
-
class
|
33
|
-
|
45
|
+
class VirtualBus < Bus
|
46
|
+
end
|
47
|
+
|
48
|
+
class BusModes < IRemote
|
49
|
+
include Channel_Meta_Functions
|
50
|
+
|
51
|
+
def initialize(remote, i)
|
52
|
+
super
|
53
|
+
self.make_bus_modes :normal,
|
54
|
+
:amix,
|
55
|
+
:bmix,
|
56
|
+
:repeat,
|
57
|
+
:composite,
|
58
|
+
:tvmix,
|
59
|
+
:upmix21,
|
60
|
+
:upmix41,
|
61
|
+
:upmix61,
|
62
|
+
:centeronly,
|
63
|
+
:lfeonly,
|
64
|
+
:rearonly
|
65
|
+
end
|
66
|
+
|
67
|
+
def identifier
|
68
|
+
"bus[#{@index}].mode"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class BusLevels < IRemote
|
73
|
+
def initialize(remote, i)
|
74
|
+
super
|
75
|
+
@init = i * 8
|
76
|
+
@offset = 8
|
77
|
+
end
|
78
|
+
|
79
|
+
def identifier
|
80
|
+
"bus[#{@index}]"
|
81
|
+
end
|
82
|
+
|
83
|
+
def getter(mode)
|
84
|
+
if @remote.running
|
85
|
+
vals = @remote.cache['bus_level'][@init, @offset]
|
86
|
+
else
|
87
|
+
vals = (@init...@offset).map { |i| @remote.get_level(mode, i) }
|
88
|
+
end
|
89
|
+
vals.map { |x| x > 0 ? (20 * Math.log(x, 10)).round(1) : -200.0 }
|
90
|
+
end
|
91
|
+
|
92
|
+
def all
|
93
|
+
getter(3)
|
94
|
+
end
|
95
|
+
|
96
|
+
def isdirty?() = @remote._bus_comp[@init, @offset].any?
|
97
|
+
end
|
data/lib/button.rb
CHANGED
@@ -1,42 +1,23 @@
|
|
1
|
+
require_relative 'iremote'
|
1
2
|
require_relative 'meta'
|
2
3
|
|
3
|
-
|
4
|
-
class IMacroButton
|
4
|
+
class MacroButton < IRemote
|
5
5
|
include MacroButton_Meta_Functions
|
6
6
|
|
7
|
-
|
7
|
+
def self.make(remote, num_buttons)
|
8
|
+
(0...num_buttons).map { |i| MacroButton.new(remote, i) }
|
9
|
+
end
|
8
10
|
|
9
|
-
def initialize(remote,
|
10
|
-
|
11
|
-
self.
|
11
|
+
def initialize(remote, i)
|
12
|
+
super
|
13
|
+
self.make_accessor_macrobutton :state, :stateonly, :trigger
|
12
14
|
end
|
13
15
|
|
14
16
|
def getter(mode)
|
15
|
-
|
17
|
+
@remote.get_buttonstatus(@index, mode)
|
16
18
|
end
|
17
19
|
|
18
20
|
def setter(set, mode)
|
19
|
-
@remote.
|
20
|
-
end
|
21
|
-
|
22
|
-
def set_multi(param_hash)
|
23
|
-
param_hash.each do |(key,val)|
|
24
|
-
self.send("#{key}=", val)
|
25
|
-
end
|
26
|
-
sleep(remote.delay)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
|
31
|
-
class MacroButton < IMacroButton
|
32
|
-
def self.make(remote, num_buttons)
|
33
|
-
(0...num_buttons).map do |i|
|
34
|
-
MacroButton.new(remote, i)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def initialize(remote, i)
|
39
|
-
super
|
40
|
-
self.make_accessor_macrobutton :state, :stateonly, :trigger
|
21
|
+
@remote.set_buttonstatus(@index, set, mode)
|
41
22
|
end
|
42
23
|
end
|
data/lib/cbindings.rb
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
require_relative 'inst'
|
3
|
+
|
4
|
+
include InstallationFunctions
|
5
|
+
|
6
|
+
module CBindings
|
7
|
+
'
|
8
|
+
Creates Ruby bindings to the C DLL
|
9
|
+
|
10
|
+
Performs other low level tasks
|
11
|
+
'
|
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,
|
71
|
+
:VBVMR_GetLevel,
|
72
|
+
%i[long long pointer],
|
73
|
+
:long
|
74
|
+
|
75
|
+
attach_function :vm_get_num_indevices,
|
76
|
+
:VBVMR_Input_GetDeviceNumber, [], :long
|
77
|
+
attach_function :vm_get_desc_indevices,
|
78
|
+
:VBVMR_Input_GetDeviceDescA, %i[long pointer pointer pointer],
|
79
|
+
:long
|
80
|
+
|
81
|
+
attach_function :vm_get_num_outdevices,
|
82
|
+
:VBVMR_Output_GetDeviceNumber, [], :long
|
83
|
+
attach_function :vm_get_desc_outdevices,
|
84
|
+
:VBVMR_Output_GetDeviceDescA, %i[long pointer pointer pointer],
|
85
|
+
:long
|
86
|
+
|
87
|
+
|
88
|
+
@@cdll =
|
89
|
+
lambda do |func, *args|
|
90
|
+
self.retval = [send("vm_#{func}", *args), func]
|
91
|
+
end
|
92
|
+
|
93
|
+
def clear_polling() = while pdirty? || mdirty?; end
|
94
|
+
|
95
|
+
def polling(func, **kwargs)
|
96
|
+
params = {
|
97
|
+
'get_parameter' => kwargs[:name],
|
98
|
+
'get_buttonstatus' => "mb_#{kwargs[:id]}_#{kwargs[:mode]}",
|
99
|
+
}
|
100
|
+
return @cache.delete(params[func]) if @cache.key? params[func]
|
101
|
+
|
102
|
+
clear_polling if @sync
|
103
|
+
|
104
|
+
yield
|
105
|
+
end
|
106
|
+
|
107
|
+
def retval=(values)
|
108
|
+
' Writer validation for CAPI calls '
|
109
|
+
retval, func = *values
|
110
|
+
unless [:get_num_indevices, :get_num_outdevices].include? func
|
111
|
+
raise CAPIErrors.new(retval, func) if retval&.nonzero?
|
112
|
+
end
|
113
|
+
@retval = retval
|
114
|
+
end
|
115
|
+
|
116
|
+
public
|
117
|
+
|
118
|
+
def pdirty?() = vm_pdirty&.nonzero?
|
119
|
+
|
120
|
+
def mdirty?() = vm_mdirty&.nonzero?
|
121
|
+
|
122
|
+
def ldirty?
|
123
|
+
@strip_buf, @bus_buf = _get_levels
|
124
|
+
return !(
|
125
|
+
@cache['strip_level'] == @strip_buf && @cache['bus_level'] == @bus_buf
|
126
|
+
)
|
127
|
+
end
|
128
|
+
end
|