voicemeeter_api_ruby 4.4.3 → 4.6.0

Sign up to get free protection for your applications and to get access to all the features.
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