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