voicemeeter_api_ruby 2.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 28ea13d4f9276d77a39c3edb392132cf026d6cb5fd6425c13a1ede4e2d6f9589
4
+ data.tar.gz: fcc60c1caa213fa159031a2b066f233a0c44872769c5827857708ff3d3531083
5
+ SHA512:
6
+ metadata.gz: be2142be5a1e2ad1857877f96d435ec912c036ec61a6107bf53ebf5e7f0246391d4e42c17a89aab288981b6c5fac197c44331b3086eaa64dfc7ed86568f4cabd
7
+ data.tar.gz: 286a5397a410123a5d2fb9795267aa885955bfcfa3dc81b80382b896b06d2648328df723aa2872918436943c8c0f9f543be90a0de5ab6dd5547dc1432b33292b
data/lib/base.rb ADDED
@@ -0,0 +1,129 @@
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 pdirty
52
+ return vmr_pdirty&.nonzero?
53
+ end
54
+
55
+ def mdirty
56
+ return vmr_mdirty&.nonzero?
57
+ end
58
+
59
+ def clear_polling
60
+ while self.pdirty || self.mdirty
61
+ end
62
+ end
63
+
64
+ def polling(func)
65
+ MAX_POLLS.times do
66
+ break if func.include?('param') && !self.pdirty
67
+ break if func.include?('macro') && !self.mdirty
68
+ sleep(DELAY)
69
+ end
70
+ end
71
+
72
+ def retval=(values)
73
+ """ Writer validation for CAPI calls """
74
+ retval, func = *values
75
+ raise CAPIErrors.new(retval, func) if retval&.nonzero?
76
+
77
+ @retval = retval
78
+ end
79
+
80
+ def run_as(func, *args)
81
+ val = send('vmr_' + func, *args)
82
+ sleep(DELAY * 20) if func.include? 'set_param'
83
+ sleep(DELAY * 50) if func.include? 'macro_set'
84
+
85
+ self.retval = [val, func]
86
+ end
87
+ end
88
+
89
+ module Define_Version
90
+ include Base
91
+
92
+ def define_version(kind)
93
+ case kind
94
+ when "basic"
95
+ self.properties = {
96
+ :name => kind,
97
+ :exe => "voicemeeter.exe"
98
+ }
99
+ self.layout = {
100
+ :strip => {:p_in => 2, :v_in=> 1},
101
+ :bus => {:p_out => 1, :v_out=> 1},
102
+ :vban => {:instream => 4, :outstream => 4},
103
+ :mb => 70,
104
+ }
105
+ when "banana"
106
+ self.properties = {
107
+ :name => kind,
108
+ :exe => "voicemeeterpro.exe"
109
+ }
110
+ self.layout = {
111
+ :strip => {:p_in => 3, :v_in=> 2},
112
+ :bus => {:p_out => 3, :v_out=> 2},
113
+ :vban => {:instream => 8, :outstream => 8},
114
+ :mb => 70,
115
+ }
116
+ when "potato"
117
+ self.properties = {
118
+ :name => kind,
119
+ :exe => "voicemeeter8#{OS_BITS == 64 ? "x64" : ""}.exe"
120
+ }
121
+ self.layout = {
122
+ :strip => {:p_in => 5, :v_in=> 3},
123
+ :bus => {:p_out => 5, :v_out=> 3},
124
+ :vban => {:instream => 8, :outstream => 8},
125
+ :mb => 70,
126
+ }
127
+ end
128
+ end
129
+ end
data/lib/bus.rb ADDED
@@ -0,0 +1,31 @@
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
data/lib/button.rb ADDED
@@ -0,0 +1,35 @@
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
+ end
22
+
23
+
24
+ class MacroButton < IMacroButton
25
+ def self.make(remote, num_buttons)
26
+ (0...num_buttons).map do |i|
27
+ MacroButton.new(remote, i)
28
+ end
29
+ end
30
+
31
+ def initialize(remote, i)
32
+ super
33
+ self.make_accessor_macrobutton :state, :stateonly, :trigger
34
+ end
35
+ end
data/lib/channel.rb ADDED
@@ -0,0 +1,25 @@
1
+ require_relative 'meta'
2
+ require_relative 'errors'
3
+
4
+ class IChannel
5
+ include Channel_Meta_Functions
6
+
7
+ attr_accessor :remote, :index
8
+
9
+ def initialize(remote, i)
10
+ self.remote = remote
11
+ self.index = i
12
+ end
13
+
14
+ def getter(param, is_string=false)
15
+ @remote.get_parameter("#{self.cmd}.#{param}", is_string)
16
+ end
17
+
18
+ def setter(param, value)
19
+ @remote.set_parameter("#{self.cmd}.#{param}", value)
20
+ end
21
+
22
+ def cmd
23
+ raise NotImplementedError
24
+ end
25
+ end
data/lib/command.rb ADDED
@@ -0,0 +1,41 @@
1
+ require_relative 'meta'
2
+
3
+
4
+ class ICommand
5
+ include Commands_Meta_Functions
6
+
7
+ attr_accessor :remote
8
+
9
+ def initialize(remote)
10
+ self.remote = remote
11
+ end
12
+
13
+ def setter(param, value)
14
+ @remote.set_parameter("#{self.cmd}.#{param}", value)
15
+ end
16
+
17
+ def cmd
18
+ return "command"
19
+ end
20
+ end
21
+
22
+
23
+ class Command < ICommand
24
+ def initialize(remote)
25
+ super
26
+ self.make_writer_only :show, :restart, :reset, :shutdown
27
+ self.make_writer_bool :showvbanchat, :lock
28
+ end
29
+
30
+ def load(value)
31
+ raise VMRemoteErrros.new("Expected a string") unless value.is_a? String
32
+ self.setter("load", value)
33
+ sleep(0.2)
34
+ end
35
+
36
+ def save(value)
37
+ raise VMRemoteErrros.new("Expected a string") unless value.is_a? String
38
+ self.setter("save", value)
39
+ sleep(0.2)
40
+ end
41
+ end
data/lib/errors.rb ADDED
@@ -0,0 +1,37 @@
1
+ module Errors
2
+ class VMRemoteErrors < StandardError; end
3
+
4
+ class InstallErrors < VMRemoteErrors; end
5
+
6
+ class CAPIErrors < VMRemoteErrors
7
+ attr_accessor :value, :func
8
+
9
+ def initialize(value, func)
10
+ self.value = value
11
+ self.func = func
12
+ end
13
+
14
+ def message
15
+ "When attempting to run function #{@func} the
16
+ C API returned value #{@value}. See documentation for further info"
17
+ end
18
+ end
19
+
20
+ class OutOfBoundsErrors < VMRemoteErrors
21
+ attr_accessor :range
22
+
23
+ def initialize(range)
24
+ self.range = range
25
+ end
26
+
27
+ def message
28
+ if @range.kind_of?(Range)
29
+ "Value error, expected value in range (#{range.first}..#{range.last})"
30
+ elsif @range.kind_of?(Array)
31
+ "Value error, expected one of: #{@range}"
32
+ else
33
+ "Value error, expected #{@range}"
34
+ end
35
+ end
36
+ end
37
+ end
data/lib/inst.rb ADDED
@@ -0,0 +1,40 @@
1
+ require 'win32/registry'
2
+ require 'pathname'
3
+ require_relative 'errors'
4
+
5
+ include Errors
6
+
7
+ BASIC = 1
8
+ BANANA = 2
9
+ POTATO = 3
10
+
11
+ module InstallationFunctions
12
+ def get_arch
13
+ key = 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
14
+ Win32::Registry::HKEY_LOCAL_MACHINE.open(key) do |reg|
15
+ os_bits = reg["PROCESSOR_ARCHITECTURE"]
16
+ if os_bits.include? 64.to_s
17
+ return 64
18
+ end
19
+ return 32
20
+ end
21
+ end
22
+
23
+ def get_vmpath(os_bits)
24
+ vm_key = "VB:Voicemeeter {17359A74-1236-5467}"
25
+ reg_key = "Software#{os_bits == 64 ? "\\WOW6432Node" : ""}\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"
26
+
27
+ Win32::Registry::HKEY_LOCAL_MACHINE.open(reg_key + vm_key) do |reg|
28
+ value = reg["UninstallString"]
29
+
30
+ pn = Pathname.new(value)
31
+ return pn.dirname
32
+ end
33
+ raise InstallErrors.new('Could not get the Voicemeeter path')
34
+ end
35
+
36
+ def vmr_dll=(value)
37
+ raise InstallErrors.new('Could not fetch the dll file') unless value.file?
38
+ @vmr_dll = value
39
+ end
40
+ end
data/lib/meta.rb ADDED
@@ -0,0 +1,242 @@
1
+ require_relative 'errors'
2
+
3
+ module Meta_Functions
4
+ def make_accessor_bool(*params)
5
+ params.each do |param|
6
+ define_singleton_method("#{param}") do
7
+ return !(self.getter("#{param}")).zero?
8
+ end
9
+
10
+ opts = [false, true]
11
+ define_singleton_method("#{param}=") do |value|
12
+ raise OutOfBoundsErrors.new(opts) unless opts.include? value
13
+ self.setter("#{param}", value ? 1 : 0)
14
+ end
15
+ end
16
+ end
17
+
18
+ def make_accessor_int(*params)
19
+ params.each do |param|
20
+ define_singleton_method("#{param}") do
21
+ return self.getter("#{param}").to_i
22
+ end
23
+ define_singleton_method("#{param}=") do |value|
24
+ self.setter("#{param}", value)
25
+ end
26
+ end
27
+ end
28
+
29
+ def make_accessor_float(*params)
30
+ params.each do |param|
31
+ define_singleton_method("#{param}") do
32
+ return self.getter("#{param}")
33
+ end
34
+ define_singleton_method("#{param}=") do |value|
35
+ self.setter("#{param}", value)
36
+ end
37
+ end
38
+ end
39
+
40
+ def make_accessor_string(*params)
41
+ params.each do |param|
42
+ define_singleton_method("#{param}") do
43
+ return self.getter("#{param}", true)
44
+ end
45
+ define_singleton_method("#{param}=") do |value|
46
+ self.setter("#{param}", value)
47
+ end
48
+ end
49
+ end
50
+
51
+ def make_reader_only(*params)
52
+ params.each do |param|
53
+ define_singleton_method("#{param}") do
54
+ return self.getter("#{param}")
55
+ end
56
+ end
57
+ end
58
+
59
+ def make_writer_only(*params)
60
+ params.each do |param|
61
+ define_singleton_method("#{param}=") do |value=1|
62
+ self.setter("#{param}", value)
63
+ end
64
+ end
65
+ end
66
+
67
+ def _make_channel_props(num_A, num_B)
68
+ channels = (1..(num_A + num_B)).map.each do |i|
69
+ i <= num_A ? "A#{i}" : "B#{i - num_A}"
70
+ end
71
+
72
+ self.make_accessor_bool *channels
73
+ end
74
+ end
75
+
76
+
77
+ module Channel_Meta_Functions
78
+ include Meta_Functions
79
+
80
+ def make_accessor_bool(*params)
81
+ params.each do |param|
82
+ cmds = {
83
+ :eq => 'EQ.on',
84
+ }
85
+ if cmds[param] then val = cmds[param] else val = param end
86
+
87
+ define_singleton_method("#{param}") do
88
+ return !(self.getter("#{val}")).zero?
89
+ end
90
+
91
+ opts = [false, true]
92
+ define_singleton_method("#{param}=") do |value|
93
+ raise OutOfBoundsErrors.new(opts) unless opts.include? value
94
+ self.setter("#{val}", value ? 1 : 0)
95
+ end
96
+ end
97
+ end
98
+
99
+ def make_accessor_float(*params)
100
+ params.each do |param|
101
+ define_singleton_method("#{param}") do
102
+ return self.getter("#{param}")
103
+ end
104
+
105
+ opts = {
106
+ :gain => [-60,12],
107
+ :comp => [0,10],
108
+ :gate => [0,10],
109
+ }
110
+ define_singleton_method("#{param}=") do |value|
111
+ raise OutOfBoundsErrors.new(opts[param]) unless value.between? *opts[param]
112
+ self.setter("#{param}", value)
113
+ end
114
+ end
115
+ end
116
+
117
+ def make_accessor_int(*params)
118
+ params.each do |param|
119
+ define_singleton_method("#{param}") do
120
+ return self.getter("#{param}").to_i
121
+ end
122
+
123
+ opts = {
124
+ :limit => (-40..12),
125
+ }
126
+ define_singleton_method("#{param}=") do |value|
127
+ raise OutOfBoundsErrors.new(opts[param]) unless opts[param].member? value
128
+ self.setter("#{param}", value)
129
+ end
130
+ end
131
+ end
132
+
133
+ def make_reader_only(*params)
134
+ params.each do |param|
135
+ cmds = {
136
+ :device => 'device.name',
137
+ :sr => 'device.sr',
138
+ }
139
+ if cmds[param] then val = cmds[param] else val = param end
140
+
141
+ define_singleton_method("#{param}") do
142
+ case param
143
+ when :device
144
+ return self.getter("#{val}", true)
145
+ when :sr
146
+ return self.getter("#{val}", true).to_i
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
152
+
153
+
154
+ module Vban_Meta_Functions
155
+ include Meta_Functions
156
+
157
+ def make_reader_int(*params)
158
+ params.each do |param|
159
+ define_singleton_method("#{param}") do
160
+ case param
161
+ when :bit
162
+ return self.getter("#{param}").to_i == 1 ? 16 : 24
163
+ else
164
+ return self.getter("#{param}").to_i
165
+ end
166
+ end
167
+ end
168
+ end
169
+
170
+ def make_accessor_int(*params)
171
+ params.each do |param|
172
+ define_singleton_method("#{param}") do
173
+ case param
174
+ when :bit
175
+ return self.getter("#{param}").to_i == 1 ? 16 : 24
176
+ else
177
+ return self.getter("#{param}").to_i
178
+ end
179
+ end
180
+
181
+ opts = {
182
+ :sr => [11025, 16000, 22050, 24000, 32000, 44100, 48000,
183
+ 64000, 88200, 96000],
184
+ :channel => (1..8),
185
+ :bit => [16,24],
186
+ :quality => (0..4),
187
+ :route => (0..8),
188
+ }
189
+
190
+ define_singleton_method("#{param}=") do |value|
191
+ raise OutOfBoundsErrors.new(opts[param]) unless opts[param].member? value
192
+ case param
193
+ when :bit
194
+ self.setter("#{param}", value == 16 ? 1 : 2)
195
+ else
196
+ self.setter("#{param}", value)
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end
202
+
203
+
204
+ module MacroButton_Meta_Functions
205
+ def make_accessor_macrobutton(*params)
206
+ params.each do |param|
207
+ mode = {
208
+ :state => 1,
209
+ :stateonly => 2,
210
+ :trigger => 3,
211
+ }
212
+
213
+ define_singleton_method("#{param}") do
214
+ return !(self.getter(mode[param])).zero?
215
+ end
216
+
217
+ opts = [false, true]
218
+ define_singleton_method("#{param}=") do |value|
219
+ raise OutOfBoundsErrors.new(opts[param]) unless opts.include? value
220
+ self.setter(value ? 1 : 0, mode[param])
221
+ end
222
+ end
223
+ end
224
+ end
225
+
226
+ module Commands_Meta_Functions
227
+ include Meta_Functions
228
+ def make_writer_bool(*params)
229
+ params.each do |param|
230
+ cmds = {
231
+ :showvbanchat => 'DialogShow.VBANCHAT',
232
+ }
233
+ if cmds[param] then val = cmds[param] else val = param end
234
+
235
+ opts = [false, true]
236
+ define_singleton_method("#{param}=") do |value|
237
+ raise OutOfBoundsErrors.new(opts[param]) unless opts.include? value
238
+ self.setter("#{val}", value ? 1 : 0)
239
+ end
240
+ end
241
+ end
242
+ end
data/lib/recorder.rb ADDED
@@ -0,0 +1,40 @@
1
+ require_relative 'meta'
2
+
3
+
4
+ class IRecorder
5
+ include Meta_Functions
6
+
7
+ attr_accessor :remote
8
+
9
+ def initialize(remote)
10
+ self.remote = remote
11
+ end
12
+
13
+ def getter(param)
14
+ @remote.get_parameter("#{self.cmd}.#{param}")
15
+ end
16
+
17
+ def setter(param, value)
18
+ @remote.set_parameter("#{self.cmd}.#{param}", value)
19
+ end
20
+
21
+ def cmd
22
+ raise NotImplementedError
23
+ end
24
+ end
25
+
26
+
27
+ class Recorder < IRecorder
28
+ def initialize(remote, layout_bus)
29
+ super(remote)
30
+ self.make_writer_only :play, :stop, :record, :ff, :rew
31
+
32
+ num_A = layout_bus[:p_out]
33
+ num_B = layout_bus[:v_out]
34
+ self._make_channel_props(num_A, num_B)
35
+ end
36
+
37
+ def cmd
38
+ return "recorder"
39
+ end
40
+ end
data/lib/routines.rb ADDED
@@ -0,0 +1,117 @@
1
+ require_relative 'base'
2
+ require_relative 'runvm'
3
+ require_relative 'strip'
4
+ require_relative 'bus'
5
+ require_relative 'button'
6
+ require_relative 'vban'
7
+ require_relative 'command'
8
+ require_relative 'recorder'
9
+
10
+
11
+ class Routines
12
+ """
13
+ define basic behaviours of API functions
14
+ mixin modules
15
+ """
16
+ include Define_Version
17
+ include RunVM
18
+
19
+ attr_accessor :properties, :layout, :strip, :bus, :button, :vban, :command,
20
+ :recorder
21
+
22
+ attr_reader :retval
23
+
24
+ SIZE = 1
25
+ BUFF = 512
26
+
27
+ def initialize(kind)
28
+ define_version(kind)
29
+
30
+ self.strip = Strip.make(self, @layout[:strip], @layout[:bus])
31
+ self.bus = Bus.make(self, @layout[:bus])
32
+ self.button = MacroButton.make(self, @layout[:mb])
33
+ self.vban = Vban.make(self, @layout[:vban])
34
+ self.command = Command.new(self)
35
+ self.recorder = Recorder.new(self, @layout[:bus])
36
+ end
37
+
38
+ def login
39
+ run_as("login")
40
+ clear_polling
41
+
42
+ rescue CAPIErrors => error
43
+ case
44
+ when error.value == 1
45
+ run_voicemeeter
46
+ when error.value < 0
47
+ raise
48
+ end
49
+ end
50
+
51
+ def logout
52
+ clear_polling
53
+ run_as("logout")
54
+ end
55
+
56
+ def get_parameter(name, is_string=false)
57
+ self.polling(__method__.to_s)
58
+
59
+ if is_string
60
+ c_get = FFI::MemoryPointer.new(:string, BUFF, true)
61
+ run_as("get_parameter_string", name, c_get)
62
+ c_get.read_string
63
+ else
64
+ c_get = FFI::MemoryPointer.new(:float, SIZE)
65
+ run_as("get_parameter_float", name, c_get)
66
+ c_get.read_float.round(1)
67
+ end
68
+ end
69
+
70
+ def set_parameter(name, value)
71
+ if value.is_a? String
72
+ run_as("set_parameter_string", name, value)
73
+ else
74
+ run_as("set_parameter_float", name, value.to_f)
75
+ end
76
+ end
77
+
78
+ def macro_getstatus(id, mode)
79
+ self.polling(__method__.to_s)
80
+
81
+ c_get = FFI::MemoryPointer.new(:float, SIZE)
82
+ run_as("macro_getstatus", id, c_get, mode)
83
+ c_get.read_float.to_i
84
+ end
85
+
86
+ def macro_setstatus(id, state, mode)
87
+ run_as("macro_setstatus", id, state, mode)
88
+ end
89
+
90
+ def set_parameter_multi(param_hash)
91
+ param_hash.each do |(key,val)|
92
+ prop, m2, m3, *remaining = key.to_s.split('_')
93
+ if m2.to_i.to_s == m2 then m2 = m2.to_i end
94
+ if m3.to_i.to_s == m3 then m3 = m3.to_i end
95
+
96
+ param_hash[key].each do |(k,v)|
97
+ param = k
98
+ value = v
99
+
100
+ case prop
101
+ when "strip"
102
+ self.strip[m2].send("#{param}=", value)
103
+ when "bus"
104
+ self.bus[m2].send("#{param}=", value)
105
+ when "button"
106
+ self.button[m2].send("#{param}=", value)
107
+ when "vban"
108
+ if m2 == "instream"
109
+ self.vban.instream[m3].send("#{param}=", value)
110
+ else
111
+ self.vban.outstream[m3].send("#{param}=", value)
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
data/lib/runvm.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'open3'
2
+ require_relative 'errors'
3
+ require_relative 'base'
4
+
5
+ module RunVM
6
+ include Base
7
+
8
+ def run_voicemeeter
9
+ if VM_PATH.join(@properties[:exe]).executable?
10
+ exe_path = String(VM_PATH.join(@properties[:exe]))
11
+ else
12
+ raise InstallErrors.new("Could not find Voicemeeter exe file")
13
+ end
14
+
15
+ Open3.popen3(exe_path, '')
16
+ sleep(1)
17
+
18
+ clear_polling
19
+ end
20
+ end
data/lib/strip.rb ADDED
@@ -0,0 +1,49 @@
1
+ require_relative 'channel'
2
+
3
+
4
+ class Strip < IChannel
5
+ attr_reader :num_A, :num_B
6
+
7
+ def self.make(remote, layout_strip, out_channels)
8
+ "
9
+ Factory function for Strip classes.
10
+ "
11
+ p_in = layout_strip[:p_in]
12
+ v_in = layout_strip[:v_in]
13
+ num_A = out_channels[:p_out]
14
+ num_B = out_channels[:v_out]
15
+
16
+ (0...(p_in + v_in)).map do |i|
17
+ i < p_in ? \
18
+ PhysicalStrip.new(remote, i, num_A, num_B) : \
19
+ VirtualStrip.new(remote, i, num_A, num_B)
20
+ end
21
+ end
22
+
23
+ def initialize(remote, i, num_A, num_B)
24
+ super(remote, i)
25
+ self.make_accessor_bool :solo, :mute, :mono
26
+ self.make_accessor_float :gain
27
+ self._make_channel_props(num_A, num_B)
28
+ end
29
+
30
+ def cmd
31
+ return "Strip[#{@index}]"
32
+ end
33
+ end
34
+
35
+ class PhysicalStrip < Strip
36
+ def initialize(remote, i, num_A, num_B)
37
+ super
38
+ self.make_accessor_float :comp, :gate
39
+ self.make_accessor_int :limit
40
+ self.make_reader_only :device, :sr
41
+ end
42
+ end
43
+
44
+ class VirtualStrip < Strip
45
+ def initialize(remote, i, num_A, num_B)
46
+ super
47
+ self.make_accessor_bool :mc, :k
48
+ end
49
+ end
data/lib/vban.rb ADDED
@@ -0,0 +1,92 @@
1
+ require_relative 'meta'
2
+ require_relative 'errors'
3
+
4
+
5
+ class IVban
6
+ include Vban_Meta_Functions
7
+
8
+ attr_accessor :remote, :index
9
+
10
+ def initialize(remote, index)
11
+ self.remote = remote
12
+ self.index = index
13
+ end
14
+
15
+ def getter(param, is_string=false)
16
+ @remote.get_parameter("#{self.cmd}.#{param}", is_string)
17
+ end
18
+
19
+ def setter(param, value)
20
+ @remote.set_parameter("#{self.cmd}.#{param}", value)
21
+ end
22
+
23
+ def cmd
24
+ return "vban.#{self.direction}stream[#{@index}]"
25
+ end
26
+
27
+ def direction
28
+ raise NotImplementedError
29
+ end
30
+ end
31
+
32
+
33
+ class Vban < IVban
34
+ def self.make(remote, vban_streams)
35
+ "
36
+ Factory function for Vban class.
37
+
38
+ Returns a mixin of instream/outstream subclasses
39
+ "
40
+ class << self
41
+ attr_accessor :instream, :outstream, :remote
42
+
43
+ def enable
44
+ @remote.set_parameter("vban.enable", 1)
45
+ end
46
+ def disable
47
+ @remote.set_parameter("vban.enable", 0)
48
+ end
49
+ end
50
+
51
+ self.instream =
52
+ (0...vban_streams[:instream]).map do |i|
53
+ VbanInstream.new(remote, i)
54
+ end
55
+ self.outstream =
56
+ (0...vban_streams[:outstream]).map do |i|
57
+ VbanOutstream.new(remote, i)
58
+ end
59
+
60
+ self.remote = remote
61
+ return self
62
+ end
63
+
64
+ def initialize(remote, i)
65
+ super
66
+ self.make_accessor_bool :on
67
+ self.make_accessor_string :name, :ip
68
+ self.make_accessor_int :quality, :route
69
+ end
70
+ end
71
+
72
+ class VbanInstream < Vban
73
+ def initialize(remote, i)
74
+ super
75
+ self.make_reader_int :sr, :channel, :bit
76
+ end
77
+
78
+ def direction
79
+ return "in"
80
+ end
81
+ end
82
+
83
+ class VbanOutstream < Vban
84
+ def initialize(remote, i)
85
+ super
86
+ self.make_accessor_int :sr, :channel, :bit
87
+ end
88
+
89
+ def direction
90
+ return "out"
91
+ end
92
+ end
data/lib/version.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Voicemeeter_API_Ruby
2
+ VERSION = '2.0.0'
3
+ end
@@ -0,0 +1,30 @@
1
+ require_relative 'routines'
2
+ require_relative 'errors'
3
+
4
+ module Voicemeeter
5
+ class Remote < Routines
6
+ def self.make
7
+ ["basic", "banana", "potato"].to_h do |kind|
8
+ [kind, Remote.new(kind)]
9
+ end
10
+ end
11
+
12
+ def run
13
+ if block_given?
14
+ yield
15
+
16
+ logout
17
+ end
18
+ end
19
+ end
20
+
21
+ def remote(kind)
22
+ _remotes = Remote.make
23
+
24
+ raise VMRemoteErrors.new("Unknown Voicemeeter Kind") unless _remotes[kind]
25
+ _remotes[kind].login
26
+ return _remotes[kind]
27
+ end
28
+
29
+ module_function :remote
30
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: voicemeeter_api_ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ platform: ruby
6
+ authors:
7
+ - onyx_online
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-01-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.9'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.9.10
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.9'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.9.10
33
+ - !ruby/object:Gem::Dependency
34
+ name: rake
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '13.0'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 13.0.3
43
+ type: :development
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '13.0'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 13.0.3
53
+ - !ruby/object:Gem::Dependency
54
+ name: minitest
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '5.14'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 5.14.4
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '5.14'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 5.14.4
73
+ description: A wrapper for Voicemeeter virtual mixer API in Ruby
74
+ email: code@onyxandiris.online
75
+ executables: []
76
+ extensions: []
77
+ extra_rdoc_files: []
78
+ files:
79
+ - lib/base.rb
80
+ - lib/bus.rb
81
+ - lib/button.rb
82
+ - lib/channel.rb
83
+ - lib/command.rb
84
+ - lib/errors.rb
85
+ - lib/inst.rb
86
+ - lib/meta.rb
87
+ - lib/recorder.rb
88
+ - lib/routines.rb
89
+ - lib/runvm.rb
90
+ - lib/strip.rb
91
+ - lib/vban.rb
92
+ - lib/version.rb
93
+ - lib/voicemeeter.rb
94
+ homepage: https://rubygems.org/gems/voicemeeter_api_ruby
95
+ licenses:
96
+ - NGPL
97
+ metadata:
98
+ source_code_uri: https://github.com/onyx-and-iris/voicemeeter-api-ruby.git
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '2.7'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubygems_version: 3.1.4
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: Voicemeeter API wrapper
118
+ test_files: []