voicemeeter_api_ruby 4.4.3 → 4.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 25d30480b41b65b719d0a8f76d87767c3dc9aad60c3074be0ff7d61434368f88
4
- data.tar.gz: 62023ace8700d6ad5fd3e77098661f2e8df7bd5a9bf97a132168b6723dbd38f4
3
+ metadata.gz: 853191cf2f0496441c9db529fb2863f29f769088107e704f779cd3fa602baf4a
4
+ data.tar.gz: ac9610c2aa4bf7a3319dbd7677774b5b52d579970d58412447357e9d67443830
5
5
  SHA512:
6
- metadata.gz: eccdfc9d875372183b18ce1739cf509c91b0a78c98417ec90b6963d8902c66930ca18f99414415040ff1f61654957f7aa073d58faf3d9bd28737ca0d3e4b3736
7
- data.tar.gz: 4132a9c07c9344f7a5b53662dffb4820a91f242a8f34aad0fe55cdc296dc2ee506db220d6a3dfc3b1f95a21a9deeb5c7513cdb86f815d28db750710b4f43e23a
6
+ metadata.gz: 4dddc3aaa0fb7e600c489b0c0773a542447e9ff6fe1e839783b45f8766742a21d1354846daf5a2a3ee08f43ee85fc2272326ed6a696201eaa741f6b5002a1299
7
+ data.tar.gz: ab40474cf35aede927799ce48465a482269345803ec79692ccbe0da6bb082368545000a8622286530c08d9a8764b3e983c91383c89caf603d3432799a6d4fda0
data/CHANGELOG.md CHANGED
@@ -9,7 +9,22 @@ 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
- - [ ] Add midi example
12
+ - [ ]
13
+
14
+ ## [4.6.0] - 2022-10-17
15
+
16
+ ### Added
17
+
18
+ - StripDevice, BusDevice classes.
19
+ - midi example
20
+ - logger module to dependencies.
21
+ - README updated to reflect changes.
22
+
23
+ ### Changed
24
+
25
+ - log level info to examples.
26
+ - bus levels now printed in observer example.
27
+ - Event add/remove methods now accept multiple events.
13
28
 
14
29
  ## [4.4.0] - 2022-08-06
15
30
 
data/README.md CHANGED
@@ -91,8 +91,6 @@ The following properties are available.
91
91
  - `limit`: int, from -40 to 12
92
92
  - `A1 - A5`, `B1 - B3`: boolean
93
93
  - `label`: string
94
- - `device`: string
95
- - `sr`: int
96
94
  - `mc`: boolean
97
95
  - `k`: int, from 0 to 4
98
96
  - `bass`: float, from -12.0 to 12.0
@@ -176,8 +174,6 @@ The following properties are available.
176
174
  - `sel`: boolean
177
175
  - `gain`: float, from -60.0 to 12.0
178
176
  - `label`: string
179
- - `device`: string
180
- - `sr`: int
181
177
  - `returnreverb`: float, from 0.0 to 10.0
182
178
  - `returndelay`: float, from 0.0 to 10.0
183
179
  - `returnfx1`: float, from 0.0 to 10.0
@@ -243,6 +239,24 @@ vm.strip[0].fadeto(-10.3, 1000)
243
239
  vm.bus[3].fadeby(-5.6, 500)
244
240
  ```
245
241
 
242
+ #### Strip.Device | Bus.Device
243
+
244
+ The following properties are available
245
+
246
+ - `name`: str
247
+ - `sr`: int
248
+ - `wdm`: str
249
+ - `ks`: str
250
+ - `mme`: str
251
+ - `asio`: str
252
+
253
+ example:
254
+
255
+ ```ruby
256
+ puts vm.strip[0].device.name
257
+ vm.bus[0].device.asio = "Audient USB Audio ASIO Driver"
258
+ ```
259
+
246
260
  ### Macrobuttons
247
261
 
248
262
  Three modes defined: state, stateonly and trigger.
@@ -428,62 +442,90 @@ vm.run { vm.apply_config('example') }
428
442
 
429
443
  will load a config file at mydir/configs/banana/example.toml for Voicemeeter Banana.
430
444
 
431
- ## `Voicemeeter Module`
445
+ ## Events
432
446
 
433
- ### Remote class
447
+ Level updates are considered high volume, by default they are NOT listened for.
434
448
 
435
- #### Voicemeeter.remote
449
+ Use keyword args `pdirty`, `mdirty`, `midi`, `ldirty` to initialize event updates.
436
450
 
437
- You may pass the following optional keyword arguments:
451
+ example:
438
452
 
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
453
+ ```ruby
454
+ require 'voicemeeter'
455
+ # Set updates to occur every 50ms
456
+ # Listen for level updates but disable midi updates
457
+ vm = Voicemeeter.remote('banana', ratelimit: 0.05, ldirty: true, midi: false)
458
+ vm.run { ... }
459
+ ```
445
460
 
461
+ #### `vm.add_observer`|`vm.delete_observer`
446
462
 
447
- #### Event updates
463
+ Use the add_observer/delete_observer methods to register/deregister an app as an observer.
448
464
 
449
- To receive event updates you should do the following:
465
+ example:
450
466
 
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.
467
+ ```ruby
468
+ # register an app to receive updates
469
+ class App():
470
+ def initialize(vm)
471
+ @vm = vm
472
+ @vm.add_observer(self)
473
+ ...
474
+ ```
453
475
 
454
- See `examples/observer` for a demonstration.
476
+ #### `vm.event`
455
477
 
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.
478
+ Use the event class to toggle updates as necessary.
457
479
 
458
- So if you don't wish to receive level updates, or you prefer to handle them yourself simply leave ldirty as default (False).
480
+ The following properties are available:
459
481
 
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.
482
+ - `pdirty`: boolean
483
+ - `mdirty`: boolean
484
+ - `midi`: boolean
485
+ - `ldirty`: boolean
461
486
 
462
487
  example:
463
488
 
464
489
  ```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 { ... }
490
+ vm.event.ldirty = true
491
+
492
+ vm.event.pdirty = false
470
493
  ```
471
494
 
472
- #### `vm.event`
495
+ Or add, remove an array of events.
473
496
 
474
- You may also add/remove event subscriptions as necessary with the Event class.
497
+ The following methods are available:
498
+
499
+ - `add()`
500
+ - `remove()`
501
+ - `get()`
475
502
 
476
503
  example:
477
504
 
478
505
  ```ruby
479
- vm.event.add("ldirty")
506
+ vm.event.add(%w[pdirty mdirty midi ldirty])
480
507
 
481
- vm.event.remove("pdirty")
508
+ vm.event.remove(%w[pdirty mdirty midi ldirty])
482
509
 
483
510
  # get a list of currently subscribed
484
511
  p vm.event.get
485
512
  ```
486
513
 
514
+ ## `Voicemeeter Module`
515
+
516
+ ### Remote class
517
+
518
+ #### Voicemeeter.remote
519
+
520
+ You may pass the following optional keyword arguments:
521
+
522
+ - `sync`: boolean=false, force the getters to wait for dirty parameters to clear. For most cases leave this as false.
523
+ - `ratelimit`: float=0.033, how often to check for updates in ms.
524
+ - `pdirty`: boolean=true, parameter updates
525
+ - `mdirty`: boolean=true, macrobutton updates
526
+ - `midi`: boolean=true, midi updates
527
+ - `ldirty`: boolean=false, level updates
528
+
487
529
  Access to lower level Getters and Setters are provided with these functions:
488
530
 
489
531
  - `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.
@@ -45,9 +45,14 @@ module Voicemeeter
45
45
  @event = Event.new(**kwargs)
46
46
  end
47
47
 
48
+ def to_s
49
+ "Voicemeeter #{@kind.name.capitalize}"
50
+ end
51
+
48
52
  def login
49
53
  @@cdll.call(:login)
50
54
  clear_polling
55
+ LOGGER.info("Logged into Voiceemeter #{self}")
51
56
  rescue CAPIErrors => error
52
57
  case
53
58
  when error.value == 1
@@ -62,6 +67,7 @@ module Voicemeeter
62
67
  clear_polling
63
68
  sleep(0.1)
64
69
  @@cdll.call(:logout)
70
+ LOGGER.info("Logged out of Voiceemeter #{self}")
65
71
  end
66
72
 
67
73
  def type
@@ -9,7 +9,7 @@ module Voicemeeter
9
9
  include Mixin::Fades
10
10
  include Mixin::Return
11
11
 
12
- attr_accessor :mode, :levels
12
+ attr_accessor :mode, :levels, :device
13
13
 
14
14
  def self.make(remote, layout_bus)
15
15
  "
@@ -39,7 +39,7 @@ module Voicemeeter
39
39
  class PhysicalBus < Bus
40
40
  def initialize(remote, i)
41
41
  super
42
- self.make_reader_only :device, :sr
42
+ @device = BusDevice.new(remote, i)
43
43
  end
44
44
  end
45
45
 
@@ -96,4 +96,18 @@ module Voicemeeter
96
96
 
97
97
  def isdirty? = @remote._bus_comp[@init, @offset].any?
98
98
  end
99
+
100
+ class BusDevice < IRemote
101
+ include Channel_Meta_Functions
102
+
103
+ def initialize(remote, i)
104
+ super
105
+ self.make_reader_only :name, :sr
106
+ self.make_writer_only :wdm, :ks, :mme, :asio
107
+ end
108
+
109
+ def identifier
110
+ "bus[#{@index}].device"
111
+ end
112
+ end
99
113
  end
@@ -31,7 +31,10 @@ module Voicemeeter
31
31
  attach_function :vm_logout, :VBVMR_Logout, [], :long
32
32
  attach_function :vm_runvm, :VBVMR_RunVoicemeeter, [:long], :long
33
33
  attach_function :vm_vmtype, :VBVMR_GetVoicemeeterType, [:pointer], :long
34
- attach_function :vm_vmversion, :VBVMR_GetVoicemeeterVersion, [:pointer], :long
34
+ attach_function :vm_vmversion,
35
+ :VBVMR_GetVoicemeeterVersion,
36
+ [:pointer],
37
+ :long
35
38
 
36
39
  attach_function :vm_mdirty, :VBVMR_MacroButton_IsDirty, [], :long
37
40
  attach_function :vm_get_buttonstatus,
@@ -69,7 +72,10 @@ module Voicemeeter
69
72
 
70
73
  attach_function :vm_get_level, :VBVMR_GetLevel, %i[long long pointer], :long
71
74
 
72
- attach_function :vm_get_num_indevices, :VBVMR_Input_GetDeviceNumber, [], :long
75
+ attach_function :vm_get_num_indevices,
76
+ :VBVMR_Input_GetDeviceNumber,
77
+ [],
78
+ :long
73
79
  attach_function :vm_get_desc_indevices,
74
80
  :VBVMR_Input_GetDeviceDescA,
75
81
  %i[long pointer pointer pointer],
@@ -89,10 +95,7 @@ module Voicemeeter
89
95
  %i[pointer long],
90
96
  :long
91
97
 
92
- @@cdll =
93
- lambda { |func, *args| retval = [send("vm_#{func}", *args), func] }
94
-
95
- def clear_polling = while pdirty? || mdirty?; end
98
+ @@cdll = lambda { |func, *args| retval = [send("vm_#{func}", *args), func] }
96
99
 
97
100
  def polling(func, **kwargs)
98
101
  params = {
@@ -109,7 +112,11 @@ module Voicemeeter
109
112
  def retval=(values)
110
113
  " Writer validation for CAPI calls "
111
114
  retval, func = *values
112
- unless %i[get_num_indevices get_num_outdevices get_midi_message].include? func
115
+ unless %i[
116
+ get_num_indevices
117
+ get_num_outdevices
118
+ get_midi_message
119
+ ].include? func
113
120
  raise CAPIErrors.new(retval, func) if retval&.nonzero?
114
121
  end
115
122
  @retval = retval
@@ -117,6 +124,10 @@ module Voicemeeter
117
124
 
118
125
  public
119
126
 
127
+ def clear_polling =
128
+ while pdirty? || mdirty?
129
+ end
130
+
120
131
  def pdirty? = vm_pdirty&.nonzero?
121
132
 
122
133
  def mdirty? = vm_mdirty&.nonzero?
@@ -124,8 +135,10 @@ module Voicemeeter
124
135
  def ldirty?
125
136
  @strip_buf, @bus_buf = _get_levels
126
137
  return(
127
- !(@cache["strip_level"] == @strip_buf && @cache["bus_level"] == @bus_buf)
138
+ !(
139
+ @cache["strip_level"] == @strip_buf && @cache["bus_level"] == @bus_buf
140
+ )
128
141
  )
129
142
  end
130
143
  end
131
- end
144
+ end
@@ -1,6 +1,6 @@
1
1
  module Voicemeeter
2
2
  class Event
3
- attr_accessor :pdirty, :mdirty, :midi, :ldirty
3
+ attr_reader :pdirty, :mdirty, :midi, :ldirty
4
4
 
5
5
  def initialize(pdirty: true, mdirty: true, midi: true, ldirty: false)
6
6
  @pdirty = pdirty
@@ -13,23 +13,52 @@ module Voicemeeter
13
13
  "#{self.class.name.split("::").last}#{@index}"
14
14
  end
15
15
 
16
- def info(msg)
17
- info_msg = ["#{msg} events", "Now listening for #{get.join(", ")} events"]
18
- puts info_msg.join("\n")
16
+ def info(msg = nil)
17
+ info_msg = msg ? ["#{msg} events."] : []
18
+ if any?
19
+ info_msg += ["Now listening for #{get.join(", ")} events"]
20
+ else
21
+ info_msg += ["Not listening for any events"]
22
+ end
23
+ LOGGER.info(info_msg.join(" "))
24
+ end
25
+
26
+ def pdirty=(val)
27
+ @pdirty = val
28
+ info("pdirty #{val ? "added to" : "removed from"}")
29
+ end
30
+
31
+ def mdirty=(val)
32
+ @mdirty = val
33
+ info("mdirty #{val ? "added to" : "removed from"}")
34
+ end
35
+
36
+ def ldirty=(val)
37
+ @ldirty = val
38
+ info("ldirty #{val ? "added to" : "removed from"}")
39
+ end
40
+
41
+ def midi=(val)
42
+ @midi = val
43
+ info("midi #{val ? "added to" : "removed from"}")
19
44
  end
20
45
 
21
46
  def get
22
47
  %w[pdirty mdirty midi ldirty].reject { |ev| !send("#{ev}") }
23
48
  end
24
49
 
25
- def add(event)
26
- send("#{event}=", true)
27
- info("#{event} added to")
50
+ def any?
51
+ [pdirty, mdirty, midi, ldirty].any?
52
+ end
53
+
54
+ def add(events)
55
+ events = [events] if !events.respond_to? :each
56
+ events.each { |ev| send("#{ev}=", true) }
28
57
  end
29
58
 
30
- def remove(event)
31
- send("#{event}=", false)
32
- info("#{event} removed from")
59
+ def remove(events)
60
+ events = [events] if !events.respond_to? :each
61
+ events.each { |ev| send("#{ev}=", false) }
33
62
  end
34
63
  end
35
64
  end
@@ -114,19 +114,12 @@ module Voicemeeter
114
114
 
115
115
  def make_reader_only(*params)
116
116
  params.each do |param|
117
- cmds = { device: "device.name", sr: "device.sr" }
118
- if cmds.key? param
119
- cmd = cmds[param]
120
- else
121
- cmd = param
122
- end
123
-
124
117
  define_singleton_method("#{param}") do
125
118
  case param
126
- when :device
127
- return self.getter("#{cmd}", true)
119
+ when :name
120
+ return self.getter("#{param}", true)
128
121
  when :sr
129
- return self.getter("#{cmd}").to_i
122
+ return self.getter("#{param}").to_i
130
123
  end
131
124
  end
132
125
  end
@@ -10,7 +10,7 @@ module Voicemeeter
10
10
  include Mixin::Outputs
11
11
  include Mixin::Fades
12
12
 
13
- attr_accessor :gainlayer, :levels
13
+ attr_accessor :gainlayer, :levels, :device
14
14
 
15
15
  def self.make(remote, layout_strip)
16
16
  "
@@ -45,7 +45,8 @@ module Voicemeeter
45
45
  def initialize(remote, i)
46
46
  super
47
47
  self.make_accessor_float :comp, :gate, :audibility
48
- self.make_reader_only :device, :sr
48
+
49
+ @device = StripDevice.new(remote, i)
49
50
  end
50
51
  end
51
52
 
@@ -121,4 +122,18 @@ module Voicemeeter
121
122
 
122
123
  def isdirty? = @remote._strip_comp[@init, @offset].any?
123
124
  end
125
+
126
+ class StripDevice < IRemote
127
+ include Channel_Meta_Functions
128
+
129
+ def initialize(remote, i)
130
+ super
131
+ self.make_reader_only :name, :sr
132
+ self.make_writer_only :wdm, :ks, :mme, :asio
133
+ end
134
+
135
+ def identifier
136
+ "strip[#{@index}].device"
137
+ end
138
+ end
124
139
  end
@@ -7,11 +7,11 @@ module Voicemeeter
7
7
  end
8
8
 
9
9
  def minor
10
- 4
10
+ 6
11
11
  end
12
12
 
13
13
  def patch
14
- 3
14
+ 0
15
15
  end
16
16
 
17
17
  def to_a
@@ -1,7 +1,7 @@
1
1
  module Voicemeeter
2
2
  module Worker
3
3
  def init_worker
4
- puts "Listening for #{@event.get.join(", ")} events"
4
+ LOGGER.info("Listening for #{@event.get.join(", ")} events")
5
5
  @cache["strip_level"], @cache["bus_level"] = _get_levels
6
6
  @running = true
7
7
  Thread.new do
data/lib/voicemeeter.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require "logger"
2
+
1
3
  require_relative "voicemeeter/base"
2
4
  require_relative "voicemeeter/strip"
3
5
  require_relative "voicemeeter/bus"
@@ -7,3 +9,10 @@ require_relative "voicemeeter/command"
7
9
  require_relative "voicemeeter/recorder"
8
10
  require_relative "voicemeeter/device"
9
11
  require_relative "voicemeeter/remote"
12
+
13
+ module Voicemeeter
14
+ include Logger::Severity
15
+
16
+ LOGGER = Logger.new(STDOUT)
17
+ LOGGER.level = WARN
18
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: voicemeeter_api_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.4.3
4
+ version: 4.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - onyx_online
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-05 00:00:00.000000000 Z
11
+ date: 2022-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -58,6 +58,26 @@ dependencies:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
60
  version: 0.1.1
61
+ - !ruby/object:Gem::Dependency
62
+ name: logger
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.5'
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: 1.5.1
71
+ type: :runtime
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - "~>"
76
+ - !ruby/object:Gem::Version
77
+ version: '1.5'
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: 1.5.1
61
81
  - !ruby/object:Gem::Dependency
62
82
  name: rspec
63
83
  requirement: !ruby/object:Gem::Requirement