voicemeeter_api_ruby 4.3.1 → 4.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -1
- data/README.md +76 -3
- data/lib/voicemeeter/base.rb +44 -12
- data/lib/voicemeeter/bus.rb +2 -2
- data/lib/voicemeeter/cbindings.rb +6 -1
- data/lib/voicemeeter/event.rb +31 -0
- data/lib/voicemeeter/midi.rb +17 -0
- data/lib/voicemeeter/mixin.rb +3 -1
- data/lib/voicemeeter/strip.rb +2 -2
- data/lib/voicemeeter/version.rb +2 -2
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b5218c12fdf2ff6d99a68ce6ac4e896f8fc213848c17301bbaaf1897b71446b
|
4
|
+
data.tar.gz: 66f1a8e56633c592e9fd78b0188ac5061328e6324dd7b23eaee7077a33228e1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: efab5bb8f17a001f170cbf5f257ff523c1647a42b77dd962f1e95329b38b76ccfd458f5b18f9f66342e544b1e9fd6e1a2c4037a1411309f7a616e3c2b26e2ffc
|
7
|
+
data.tar.gz: b3a47db4e3cfa1f82baa9dfda397be0a0b64fd9fa91d4c483c387c97e99004f47efd8dc06c6fac077feef6f3c92c35d484ee27fd03eb4415b35abd13f928605d
|
data/CHANGELOG.md
CHANGED
@@ -9,7 +9,26 @@ 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
|
+
- [ ] Add midi example
|
13
|
+
|
14
|
+
## [4.4.0] - 2022-08-06
|
15
|
+
|
16
|
+
### Added
|
17
|
+
|
18
|
+
- midi device support added.
|
19
|
+
- pdirty, mdirty, midi, ldirty kwargs added to Remote class. Initialize which events to sub to.
|
20
|
+
- Event class added. Toggle events, get list of currently subscribed.
|
21
|
+
- Voicemeeter.remote added to README in Remote class section.
|
22
|
+
- observer example updated to reflect changes.
|
23
|
+
|
24
|
+
### Changed
|
25
|
+
|
26
|
+
- channel out props for strip/recorder now mixed in.
|
27
|
+
- By default no longer listen for level updates (high volume). Should be enabled explicitly.
|
28
|
+
|
29
|
+
### Fixed
|
30
|
+
|
31
|
+
- bug in strip/bus levels if making capi calls directly.
|
13
32
|
|
14
33
|
## [4.3.0] - 2022-07-29
|
15
34
|
|
data/README.md
CHANGED
@@ -229,7 +229,7 @@ puts vm.bus[0].levels.all
|
|
229
229
|
|
230
230
|
### Strip | Bus
|
231
231
|
|
232
|
-
The following methods are
|
232
|
+
The following methods are available
|
233
233
|
|
234
234
|
- `fadeto(amount, time)`: float, int
|
235
235
|
- `fadeby(amount, time)`: float, int
|
@@ -266,7 +266,7 @@ The following properties accept boolean values.
|
|
266
266
|
- `A1 - A5`: boolean
|
267
267
|
- `B1 - A3`: boolean
|
268
268
|
|
269
|
-
The following methods are
|
269
|
+
The following methods are available
|
270
270
|
|
271
271
|
- `play`
|
272
272
|
- `stop`
|
@@ -356,6 +356,27 @@ example:
|
|
356
356
|
vm.run { (0...vm.device.ins).each { |i| puts vm.device.input(i) } }
|
357
357
|
```
|
358
358
|
|
359
|
+
### Midi
|
360
|
+
|
361
|
+
The following properties are available:
|
362
|
+
|
363
|
+
- `channel`: int, returns the midi channel
|
364
|
+
- `current`: int, returns the current (or most recently pressed) key
|
365
|
+
|
366
|
+
The following methods are available:
|
367
|
+
|
368
|
+
- `get(key)`: int, returns most recent velocity value for a key
|
369
|
+
|
370
|
+
|
371
|
+
example:
|
372
|
+
|
373
|
+
```ruby
|
374
|
+
puts vm.midi.get(12)
|
375
|
+
```
|
376
|
+
|
377
|
+
get may return nil if no value for requested key in midi cache
|
378
|
+
|
379
|
+
|
359
380
|
### Multiple parameters
|
360
381
|
|
361
382
|
- `apply`
|
@@ -411,6 +432,58 @@ will load a config file at mydir/configs/banana/example.toml for Voicemeeter Ban
|
|
411
432
|
|
412
433
|
### Remote class
|
413
434
|
|
435
|
+
#### Voicemeeter.remote
|
436
|
+
|
437
|
+
You may pass the following optional keyword arguments:
|
438
|
+
|
439
|
+
- `sync`: boolean=false, force the getters to wait for dirty parameters to clear. For most cases leave this as false.
|
440
|
+
- `ratelimit`: float=0.033, how often to check for updates in ms.
|
441
|
+
- `pdirty`: boolean=true, parameter updates
|
442
|
+
- `mdirty`: boolean=true, macrobutton updates
|
443
|
+
- `midi`: boolean=true, midi updates
|
444
|
+
- `ldirty`: boolean=false, level updates
|
445
|
+
|
446
|
+
|
447
|
+
#### Event updates
|
448
|
+
|
449
|
+
To receive event updates you should do the following:
|
450
|
+
|
451
|
+
- register your app to receive updates using the `vm.add_observer(observer)` method, where observer is your app.
|
452
|
+
- define an `update(subject)` callback function in your app. The value of subject may be checked for the type of event.
|
453
|
+
|
454
|
+
See `examples/observer` for a demonstration.
|
455
|
+
|
456
|
+
Level updates are considered high volume, by default they are NOT listened for. However, polling them with strip levels and bus levels methods will still work.
|
457
|
+
|
458
|
+
So if you don't wish to receive level updates, or you prefer to handle them yourself simply leave ldirty as default (False).
|
459
|
+
|
460
|
+
Each of the update types may be enabled/disabled separately. Don't use a midi controller? You have the option to disable midi updates.
|
461
|
+
|
462
|
+
example:
|
463
|
+
|
464
|
+
```ruby
|
465
|
+
require 'voicemeeter'
|
466
|
+
# Set updates to occur every 50ms
|
467
|
+
# Listen for level updates but disable midi updates
|
468
|
+
vm = Voicemeeter.remote('banana', ratelimit: 0.05, ldirty: true, midi: false)
|
469
|
+
vm.run { ... }
|
470
|
+
```
|
471
|
+
|
472
|
+
#### `vm.event`
|
473
|
+
|
474
|
+
You may also add/remove event subscriptions as necessary with the Event class.
|
475
|
+
|
476
|
+
example:
|
477
|
+
|
478
|
+
```ruby
|
479
|
+
vm.event.add("ldirty")
|
480
|
+
|
481
|
+
vm.event.remove("pdirty")
|
482
|
+
|
483
|
+
# get a list of currently subscribed
|
484
|
+
p vm.event.get
|
485
|
+
```
|
486
|
+
|
414
487
|
Access to lower level Getters and Setters are provided with these functions:
|
415
488
|
|
416
489
|
- `vm.get(param, string=false)`: For getting the value of any parameter. Set string to true if getting a property value expected to return a string.
|
@@ -429,7 +502,7 @@ vm.set('Strip[4].Label', 'stripname')
|
|
429
502
|
vm.set('Strip[0].Gain', -3.6)
|
430
503
|
```
|
431
504
|
|
432
|
-
#### Voicemeeter
|
505
|
+
#### Voicemeeter.start
|
433
506
|
|
434
507
|
Use this function to start Voicemeeter of a kind independently of Remote class.
|
435
508
|
for example:
|
data/lib/voicemeeter/base.rb
CHANGED
@@ -3,6 +3,8 @@ require "observer"
|
|
3
3
|
require_relative "runvm"
|
4
4
|
require_relative "configs"
|
5
5
|
require_relative "errors"
|
6
|
+
require_relative "event"
|
7
|
+
require_relative "midi"
|
6
8
|
|
7
9
|
module Voicemeeter
|
8
10
|
class Base
|
@@ -15,8 +17,15 @@ module Voicemeeter
|
|
15
17
|
include Configs
|
16
18
|
include RunVM
|
17
19
|
|
18
|
-
attr_accessor :strip,
|
19
|
-
|
20
|
+
attr_accessor :strip,
|
21
|
+
:bus,
|
22
|
+
:button,
|
23
|
+
:vban,
|
24
|
+
:command,
|
25
|
+
:recorder,
|
26
|
+
:device,
|
27
|
+
:midi
|
28
|
+
attr_accessor :strip_mode, :event
|
20
29
|
|
21
30
|
attr_reader :kind, :p_in, :v_in, :p_out, :v_out, :retval, :cache
|
22
31
|
attr_reader :running, :_strip_comp, :_bus_comp, :delay
|
@@ -28,31 +37,38 @@ module Voicemeeter
|
|
28
37
|
|
29
38
|
def initialize(kind, **kwargs)
|
30
39
|
@kind = kind
|
40
|
+
@sync = kwargs.delete(:sync) || SYNC
|
41
|
+
@ratelimit = kwargs.delete(:ratelimit) || RATELIMIT
|
31
42
|
@p_in, @v_in = kind.layout[:strip].values
|
32
43
|
@p_out, @v_out = kind.layout[:bus].values
|
33
|
-
@cache = Hash.new
|
34
|
-
@sync = kwargs[:sync] || SYNC
|
35
|
-
@ratelimit = kwargs[:ratelimit] || RATELIMIT
|
36
44
|
@running = false
|
37
45
|
@strip_mode = 0
|
38
46
|
@delay = DELAY
|
47
|
+
@cache = Hash.new
|
48
|
+
@midi = Midi.new
|
49
|
+
@event = Event.new(**kwargs)
|
39
50
|
end
|
40
51
|
|
41
52
|
def init_thread
|
42
|
-
@
|
53
|
+
puts "Listening for #{@event.get.join(", ")} events"
|
43
54
|
@cache["strip_level"], @cache["bus_level"] = _get_levels
|
55
|
+
@running = true
|
44
56
|
Thread.new do
|
45
57
|
loop do
|
46
58
|
Thread.stop if !@running
|
47
|
-
if pdirty?
|
59
|
+
if @event.pdirty && pdirty?
|
48
60
|
changed
|
49
61
|
notify_observers("pdirty")
|
50
62
|
end
|
51
|
-
if mdirty?
|
63
|
+
if @event.mdirty && mdirty?
|
52
64
|
changed
|
53
65
|
notify_observers("mdirty")
|
54
66
|
end
|
55
|
-
if
|
67
|
+
if @event.midi && get_midi_message
|
68
|
+
changed
|
69
|
+
notify_observers("midi")
|
70
|
+
end
|
71
|
+
if @event.ldirty && ldirty?
|
56
72
|
changed
|
57
73
|
@_strip_comp =
|
58
74
|
@cache["strip_level"].map.with_index do |x, i|
|
@@ -190,11 +206,11 @@ module Voicemeeter
|
|
190
206
|
raise VMRemoteErrors.new("expected in or out")
|
191
207
|
end
|
192
208
|
if direction == "in"
|
193
|
-
|
209
|
+
res = @@cdll.call(:get_num_indevices)
|
194
210
|
else
|
195
|
-
|
211
|
+
res = @@cdll.call(:get_num_outdevices)
|
196
212
|
end
|
197
|
-
|
213
|
+
res[0]
|
198
214
|
end
|
199
215
|
|
200
216
|
def get_device_description(index, direction)
|
@@ -212,6 +228,22 @@ module Voicemeeter
|
|
212
228
|
[c_name.read_string, c_type.read_long, c_hwid.read_string]
|
213
229
|
end
|
214
230
|
|
231
|
+
def get_midi_message
|
232
|
+
c_msg = FFI::MemoryPointer.new(:string, 1024, true)
|
233
|
+
res = @@cdll.call(:get_midi_message, c_msg, 1024)
|
234
|
+
if res[0] > 0
|
235
|
+
vals = c_msg.read_string.bytes
|
236
|
+
vals.each_slice(3) do |ch, key, vel|
|
237
|
+
@midi.channel = ch if @midi.channel.nil? || @midi.channel != ch
|
238
|
+
@midi.current = key.to_i
|
239
|
+
@midi.set(key.to_i, vel.to_i)
|
240
|
+
end
|
241
|
+
elsif res[0] == -1 || res[0] == -2
|
242
|
+
raise CAPIErrors.new("VBVMR_GetMidiMessage returned #{msg[0]}")
|
243
|
+
end
|
244
|
+
res[0] > 0
|
245
|
+
end
|
246
|
+
|
215
247
|
alias_method "set_multi", :set_parameter_multi
|
216
248
|
alias_method "apply", :set_parameter_multi
|
217
249
|
alias_method "get", :get_parameter
|
data/lib/voicemeeter/bus.rb
CHANGED
@@ -82,10 +82,10 @@ module Voicemeeter
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def getter(mode)
|
85
|
-
if @remote.running
|
85
|
+
if @remote.running && @remote.event.ldirty
|
86
86
|
vals = @remote.cache["bus_level"][@init, @offset]
|
87
87
|
else
|
88
|
-
vals = (@init...@offset).map { |i| @remote.get_level(mode, i) }
|
88
|
+
vals = (@init...@init + @offset).map { |i| @remote.get_level(mode, i) }
|
89
89
|
end
|
90
90
|
vals.map { |x| x > 0 ? (20 * Math.log(x, 10)).round(1) : -200.0 }
|
91
91
|
end
|
@@ -84,6 +84,11 @@ module Voicemeeter
|
|
84
84
|
%i[long pointer pointer pointer],
|
85
85
|
:long
|
86
86
|
|
87
|
+
attach_function :vm_get_midi_message,
|
88
|
+
:VBVMR_GetMidiMessage,
|
89
|
+
%i[pointer long],
|
90
|
+
:long
|
91
|
+
|
87
92
|
@@cdll =
|
88
93
|
lambda { |func, *args| retval = [send("vm_#{func}", *args), func] }
|
89
94
|
|
@@ -104,7 +109,7 @@ module Voicemeeter
|
|
104
109
|
def retval=(values)
|
105
110
|
" Writer validation for CAPI calls "
|
106
111
|
retval, func = *values
|
107
|
-
unless %i[get_num_indevices get_num_outdevices].include? func
|
112
|
+
unless %i[get_num_indevices get_num_outdevices get_midi_message].include? func
|
108
113
|
raise CAPIErrors.new(retval, func) if retval&.nonzero?
|
109
114
|
end
|
110
115
|
@retval = retval
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Voicemeeter
|
2
|
+
class Event
|
3
|
+
attr_accessor :pdirty, :mdirty, :midi, :ldirty
|
4
|
+
|
5
|
+
def initialize(pdirty: true, mdirty: true, midi: true, ldirty: false)
|
6
|
+
@pdirty = pdirty
|
7
|
+
@mdirty = mdirty
|
8
|
+
@midi = midi
|
9
|
+
@ldirty = ldirty
|
10
|
+
end
|
11
|
+
|
12
|
+
def info(msg)
|
13
|
+
info_msg = ["#{msg} events", "Now listening for #{get.join(", ")} events"]
|
14
|
+
puts info_msg.join("\n")
|
15
|
+
end
|
16
|
+
|
17
|
+
def get
|
18
|
+
%w[pdirty mdirty midi ldirty].reject { |ev| !send("#{ev}") }
|
19
|
+
end
|
20
|
+
|
21
|
+
def add(event)
|
22
|
+
send("#{event}=", true)
|
23
|
+
info("#{event} added to")
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove(event)
|
27
|
+
send("#{event}=", false)
|
28
|
+
info("#{event} removed from")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/voicemeeter/mixin.rb
CHANGED
@@ -24,8 +24,10 @@ module Voicemeeter
|
|
24
24
|
|
25
25
|
module Outputs
|
26
26
|
include Channel_Meta_Functions
|
27
|
-
|
27
|
+
|
28
|
+
def initialize(*args)
|
28
29
|
super
|
30
|
+
remote, *rem = args
|
29
31
|
num_A, num_B = remote.kind.layout[:bus].values
|
30
32
|
channels =
|
31
33
|
(1..(num_A + num_B)).map do |i|
|
data/lib/voicemeeter/strip.rb
CHANGED
@@ -96,10 +96,10 @@ module Voicemeeter
|
|
96
96
|
end
|
97
97
|
|
98
98
|
def get_level(mode)
|
99
|
-
if @remote.running
|
99
|
+
if @remote.running && @remote.event.ldirty
|
100
100
|
vals = @remote.cache["strip_level"][@init, @offset]
|
101
101
|
else
|
102
|
-
vals = (@init...@offset).map { |i| get_level(mode, i) }
|
102
|
+
vals = (@init...@init + @offset).map { |i| @remote.get_level(mode, i) }
|
103
103
|
end
|
104
104
|
vals.map { |x| x > 0 ? (20 * Math.log(x, 10)).round(1) : -200.0 }
|
105
105
|
end
|
data/lib/voicemeeter/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: voicemeeter_api_ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- onyx_online
|
@@ -93,10 +93,12 @@ files:
|
|
93
93
|
- lib/voicemeeter/configs.rb
|
94
94
|
- lib/voicemeeter/device.rb
|
95
95
|
- lib/voicemeeter/errors.rb
|
96
|
+
- lib/voicemeeter/event.rb
|
96
97
|
- lib/voicemeeter/inst.rb
|
97
98
|
- lib/voicemeeter/iremote.rb
|
98
99
|
- lib/voicemeeter/kinds.rb
|
99
100
|
- lib/voicemeeter/meta.rb
|
101
|
+
- lib/voicemeeter/midi.rb
|
100
102
|
- lib/voicemeeter/mixin.rb
|
101
103
|
- lib/voicemeeter/recorder.rb
|
102
104
|
- lib/voicemeeter/runvm.rb
|