voicemeeter_api_ruby 4.3.1 → 4.4.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 +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
|