52 Commits

Author SHA1 Message Date
2ad8118f2c adjust the timings slightly 2023-08-17 00:14:12 +01:00
bc6162cf16 add cmdletbinding to examples for debug, verbose flags
add verbose,debug flags to launch scripts
2023-08-16 16:38:00 +01:00
9b3d9f2250 remove Write-Warning for CAPIErrors.
Allow them to bubble up.
(Might be worth adding a helper function to print stacktrace?)
2023-08-16 16:36:43 +01:00
844eaeabaa ErrorMessage removed from error classes 2023-08-16 15:13:30 +01:00
a78cdf9a99 RunVoicemeeter function added
All CAPIErrors are now logged and rethrown
2023-08-16 15:12:25 +01:00
a40adf27be readme, changelog updated 2023-08-16 03:05:06 +01:00
1397c14522 debug statements added to getters and setters
made some rearrangements to the dot sourcing

ButtonTypes enum added to macrobuttons.ps1

login string now includes version number

Test-RegistryValue added to inst.ps1
2023-08-16 02:52:12 +01:00
ff1bd5e6cc section 3.1.0 added to CHANGELOG
close #4
2023-08-15 15:44:14 +01:00
f480b637eb pester test script added to launch.json
CHANGELOG, README updated
2023-08-14 23:01:38 +01:00
09078d382b make examples and tests runnable if dot sourced 2023-08-14 22:44:09 +01:00
598e0dd647 add launch scripts 2023-08-14 21:45:18 +01:00
72b5ac02d3 adds missing Recorder parameters 2023-08-14 21:43:51 +01:00
a031d25a41 fix range checks 2023-08-14 21:30:32 +01:00
4e9ff66640 rework getters, setters in higher classes 2023-08-12 03:09:23 +01:00
bee52b6541 rename some of the internal classes
RecorderMode class added to Recorder

RunMacrobuttons() and CloseMacrobuttons() added to Special (Command)
2023-08-12 01:40:29 +01:00
5bda43131b upd changelog 2023-08-09 14:44:47 +01:00
1c9c400f12 VBVMR_GetLevel binding added
Get_Level implemented in base.ps1

strip.{PreFader,PostFader,PostMute} methods added

bus.{All} added
2023-08-09 14:16:27 +01:00
aee3430962 fix strip[i].device.name bug
patch bump
2022-12-19 23:19:20 +00:00
47fb880b91 remove tasklist from unreleased 2022-12-19 00:45:13 +00:00
acc078632d add strip.eq/bus.eq example to readme 2022-12-18 18:52:22 +00:00
d48104c4a9 edit changelog 2022-12-18 17:03:47 +00:00
dfebb20c6e add remote sublcasses to changelog 2022-12-18 16:56:47 +00:00
150301c271 add Login() to Remote class.
method chain it in factory functions.
2022-12-18 16:48:28 +00:00
828a9a5731 minor changes. 2022-12-18 04:30:51 +00:00
3b1e469d2d Login refactor.
Return Exit value -2 for multiple login attempts.
2022-12-18 04:29:41 +00:00
3b1bb06c7d Classes for each remote kind added.
They subclass Remote.

Factory functions now return the Remote class of a Kind.

Return Exit value -1 for DLL setup error.
2022-12-18 04:27:55 +00:00
7e1c5616db fix output string 2022-12-17 20:16:02 +00:00
ff4391c6fb add entry/exit functions to readme.
rethrow LoginError exceptions, let the consumer handle it.
2022-12-17 20:10:53 +00:00
3b4185c251 update bus mode tests 2022-12-17 19:33:32 +00:00
deb3da15ea remove constructor annotations 2022-12-17 17:47:42 +00:00
408218ea32 typo fixes 2022-12-17 17:47:27 +00:00
5d1fc9736e md fixes 2022-12-17 17:19:01 +00:00
fed7489ac2 readme, changelog updated 2022-12-17 15:41:18 +00:00
cd7508b823 minor rework 2022-12-17 15:41:02 +00:00
6468270fd0 wdm, ks, mme and asio added to strip.device 2022-12-17 15:40:29 +00:00
42b17a7239 mode class added to Bus.
removed busmodemember meta functions.
2022-12-17 15:40:07 +00:00
714d761af2 update changelog 2022-12-17 02:13:17 +00:00
bb94e9d4e5 update tests to reflect v3 changes 2022-12-17 02:12:32 +00:00
72467a611b enable verbose output in examples
fix host key in obs example readme.
2022-12-17 02:11:00 +00:00
e01d4f134a comp, gate, denoiser, eq, device sections added
appgain|appmute added.

todo. add examples
2022-12-16 19:41:33 +00:00
9074e0d416 add note to close OBS to end script 2022-12-16 18:57:26 +00:00
bc3216bee7 Merge branch 'dev' into add-comp-gate-eq-device 2022-12-16 18:51:00 +00:00
2a476b8ffe start constructing version 3 section in changelog
add to todo list.
2022-12-16 18:41:22 +00:00
fc290ba90c entry/exit functions added 2022-12-16 18:19:35 +00:00
a40e36998c meta functions refactored to use class identifiers 2022-12-16 17:40:47 +00:00
c37b4e0b1b IVban class added
getters/setters moved into IVban

refactored to use identifier()
2022-12-16 17:30:06 +00:00
14c8a54f01 refactored to use identifier() 2022-12-16 17:29:04 +00:00
a642dfd154 getters now return boolean values 2022-12-16 17:27:58 +00:00
ec296059d4 refactored to use identifier() 2022-12-16 17:27:05 +00:00
c999e73e14 IStrip class added.
getters/setters moved into IStrip

Comp, Gate, Denoiser, Eq and Device classes added to PhysicalStrip

AppGain, AppMute methods added to VirtualStrip
2022-12-16 17:24:31 +00:00
d86ad2fe87 IBus class added.
getters/setters moved into IBus

Eq class added to Bus

Device class added to PhysicalBus
2022-12-16 17:18:51 +00:00
62ad51c6b8 examples now using relative import path
obs example now using obs-powershell module. README updated.
2022-12-16 17:16:02 +00:00
23 changed files with 1569 additions and 649 deletions

71
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,71 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "PowerShell: Launch CLI Example",
"type": "PowerShell",
"request": "launch",
"cwd": "${workspaceRoot}/examples/cli",
"script": "${workspaceFolder}/examples/cli/CLI.ps1",
"args": [
"-s",
"\"strip[0].mute\",",
"\"!strip[0].mute\",",
"\"strip[0].mute\",",
"\"bus[2].eq.on=1\",",
"\"command.lock=1\"",
"-Verbose",
"-Debug"
],
"createTemporaryIntegratedConsole": true
},
{
"name": "PowerShell: Launch NextBus Example",
"type": "PowerShell",
"request": "launch",
"cwd": "${workspaceRoot}/examples/nextbus",
"script": "${workspaceFolder}/examples/nextbus/GoTo-NextBus.ps1",
"args": [
"-Verbose",
"-Debug"
],
"createTemporaryIntegratedConsole": true
},
{
"name": "PowerShell: Launch OBS Example",
"type": "PowerShell",
"request": "launch",
"cwd": "${workspaceRoot}/examples/obs",
"script": "${workspaceFolder}/examples/obs/Vm-Obs-Sync.ps1",
"args": [
"-Verbose",
"-Debug"
],
"createTemporaryIntegratedConsole": true
},
{
"name": "PowerShell: Run Pester Tests",
"type": "PowerShell",
"request": "launch",
"cwd": "${workspaceRoot}",
"script": "${workspaceFolder}/tests/pre-commit.ps1",
"args": [],
"createTemporaryIntegratedConsole": true
},
{
"name": "PowerShell: Launch Quick Test",
"type": "PowerShell",
"request": "launch",
"cwd": "${workspaceRoot}",
"script": "${workspaceFolder}/quick.ps1",
"args": [
"-Verbose",
"-Debug"
],
"createTemporaryIntegratedConsole": true
}
]
}

View File

@@ -9,8 +9,54 @@ Before any major/minor/patch is released all test units will be run to verify th
## [Unreleased] These changes have not been added to PSGallery yet ## [Unreleased] These changes have not been added to PSGallery yet
- [x] Implement command.load - [x] Debug statements added to Getters, Setters in higher classes.
- [ ] Implement comp/gate parameters introduced in v3.0.2.8 of the api.
## [3.1.0]
### Added
- Level methods for Strip class implemented. See Strip.levels section in README.
- Level methods for Bus class implemented. See Bus.levels section in README.
- More Recorder commands implemented. See Recorder section in README.
- RunMacrobuttons, CloseMacrobuttons added to Special class
## [3.0.0]
v3 introduces some breaking changes. They are as follows:
- Strip[i].comp now references [Comp] class. (see README for details on settings strip.comp parameters)
- Strip[i].gate now references [Gate] class. (see README for details on settings strip.gate parameters)
- Strip[i].eq now references [Eq] class. (see README for details on settings strip.eq parameters)
- Strip[i].device now references [Device] class. (see README for details on settings strip.device parameters)
- Bus[i].eq now references [Eq] class. (see README for details on settings bus.eq parameters)
- Bus[i].mode now implemented as its own class [Mode]. (see README for details on settings bus.mode parameters)
There are other changes but they should not be breaking.
### Changed
- meta functions refactored, they now use identifier() functions.
- OBS example reworked, now using obs-powershell module.
- Rethrow LoginError for unknown kind exceptions, let the consumer handle it from there.
### Added
- Entry/exit points Connect-Voicemeeter, Disconnect-Voicemeeter added to module.
- Comp, Gate, Denoiser and Eq classes added to PhysicalStrip
- Device class added to PhysicalStrip/PhysicalBus
- AppGain(), AppMute() methods added to VirtualStrip
- eq added to Bus
- interface classes IBus, IStrip and IVban added. getters/setters moved into interface classes.
- RemoteBasic, RemoteBanana and RemotePotato subclasses added.
### Fixed
- Button getters return boolean values.
### Removed
- Bus[i].mode\_{param} members removed. Replaced with Bus[i].mode.{param}
## [2.5.0] - 2022-10-27 ## [2.5.0] - 2022-10-27

266
README.md
View File

@@ -79,6 +79,21 @@ Voicemeeter factory function can be:
- Get-RemoteBanana - Get-RemoteBanana
- Get-RemotePotato - Get-RemotePotato
Added in `v3` you may also use the following entry/exit points:
- Connect-Voicemeeter
- Disconnect-Voicemeeter
`Connect-Voicemeeter` takes a single parameter `Kind`.
for example:
```powershell
$vmr = Connect-Voicemeeter -Kind "potato"
...
Disconnect-Voicemeeter
```
#### `Through the Shell` #### `Through the Shell`
One liners should be run through a subshell, you may pipe the Remote object to a script block, for example: One liners should be run through a subshell, you may pipe the Remote object to a script block, for example:
@@ -109,11 +124,7 @@ The following strip commands are available:
- B1-B3: bool - B1-B3: bool
- limit: int, from -40 to 12 - limit: int, from -40 to 12
- gain: float, from -60.0 to 12.0 - gain: float, from -60.0 to 12.0
- comp: float, from 0.0 to 10.0
- gate: float, from 0.0 to 10.0
- label: string - label: string
- device: string
- sr: int
- reverb: float, from 0.0 to 10.0 - reverb: float, from 0.0 to 10.0
- delay: float, from 0.0 to 10.0 - delay: float, from 0.0 to 10.0
- fx1: float, from 0.0 to 10.0 - fx1: float, from 0.0 to 10.0
@@ -124,15 +135,15 @@ The following strip commands are available:
- color_y: float, from 0.0 to 1.0 - color_y: float, from 0.0 to 1.0
- fx_x: float, from -0.5 to 0.5 - fx_x: float, from -0.5 to 0.5
- fx_y: float, from 0.0 to 1.0 - fx_y: float, from 0.0 to 1.0
- postreverb: boolean - postreverb: bool
- postdelay: boolean - postdelay: bool
- postfx1: boolean - postfx1: bool
- postfx2: boolean - postfx2: bool
- gainlayer0-gainlayer7: float - gainlayer0-gainlayer7: float
for example: for example:
``` ```powershell
$vmr.strip[5].gainlayer1 = -8.3 $vmr.strip[5].gainlayer1 = -8.3
``` ```
@@ -142,35 +153,182 @@ gainlayers defined for Potato version only.
mc, k for virtual strips only. mc, k for virtual strips only.
#### comp
The following strip.comp commands are available:
- knob: float, from 0.0 to 10.0
- gainin: float, from -24.0 to 24.0
- ratio: float, from 1.0 to 8.0
- threshold: float, from -40.0 to -3.0
- attack: float, from 0.0 to 200.0
- release: float, from 0.0 to 5000.0
- knee: float, 0.0 to 1.0
- gainout: float, from -24.0 to 24.0
- makeup: bool
for example:
```powershell
$vmr.strip[3].comp.attack = 8.5
```
#### gate
The following strip.gate commands are available:
- knob: float, from 0.0 to 10.0
- threshold: float, from -60.0 to -10.0
- damping: float, from -60.0 to -10.0
- bpsidechain: int, from 100 to 4000
- attack: float, from 0.0 to 1000.0
- hold: float, from 0.0 to 5000.0
- release: float, from 0.0 to 5000.0
for example:
```powershell
$vmr.strip[3].gate.threshold = -40.5
```
#### denoiser
The following strip.denoiser commands are available:
- knob: float, from 0.0 to 10.0
for example:
```powershell
$vmr.strip[3].denoiser.knob = 5
```
#### AppGain | AppMute
- `AppGain(amount, gain)` : string, float
- `AppMute(amount, mutestate)` : string, bool
for example:
```powershell
$vmr.strip[5].AppGain("Spotify", 0.5)
$vmr.strip[5].AppMute("Spotify", $true)
```
#### levels
The following strip.level commands are available:
- PreFader()
- PostFader()
- PostMute()
for example:
```powershell
$vmr.strip[2].levels.PreFader() -Join ', ' | Write-Host
```
### Bus ### Bus
The following bus commands are available: The following bus commands are available:
- mute: bool - mute: bool
- mono: bool - mono: bool
- eq: bool
- eq_ab: bool
- limit: int, from -40 to 12 - limit: int, from -40 to 12
- gain: float, from -60.0 to 12.0 - gain: float, from -60.0 to 12.0
- label: string - label: string
- device: string
- sr: int
- returnreverb: float, from 0.0 to 10.0 - returnreverb: float, from 0.0 to 10.0
- returndelay: float, from 0.0 to 10.0 - returndelay: float, from 0.0 to 10.0
- returnfx1: float, from 0.0 to 10.0 - returnfx1: float, from 0.0 to 10.0
- returnfx2: float, from 0.0 to 10.0 - returnfx2: float, from 0.0 to 10.0
- mode\_: bool, any of the following:
@('normal', 'amix', 'bmix', 'repeat', 'composite', 'tvmix', 'upmix21',
'upmix41', 'upmix61', 'centeronly', 'lfeonly', 'rearonly')
for example: for example:
```powershell
$vmr.bus[3].returnreverb = 5.7
``` ```
$vmr.bus[3].mode_repeat = $true
#### modes
The following bus.mode members are available:
- normal: bool
- amix: bool
- bmix: bool
- repeat: bool
- composite: bool
- tvmix: bool
- upmix21: bool
- upmix41: bool
- upmix61: bool
- centeronly: bool
- lfeonly: bool
- rearonly: bool
The following bus.mode commands are available:
- Get(): returns the current bus mode.
for example:
```powershell
$vmr.bus[0].mode.centeronly = $true
$vmr.bus[0].mode.Get()
```
#### levels
The following strip.level commands are available:
- All()
for example:
```powershell
$vmr.bus[2].levels.All() -Join ', ' | Write-Host
``` ```
### Strip|Bus ### Strip|Bus
#### device
The following strip.device | bus.device commands are available:
- name: string
- sr: int
- wdm: string
- ks: string
- mme: string
- asio: string
for example:
```powershell
$vmr.strip[0].device.wdm = "Mic|Line|Instrument 1 (Audient EVO4)"
$vmr.bus[0].device.name
```
name, sr are defined as read only.
wdm, ks, mme, asio are defined as write only.
#### eq
The following strip.eq | bus.eq commands are available:
- on: bool
- ab: bool
for example:
```powershell
$vmr.strip[0].eq.on = $true
$vmr.bus[0].eq.ab = $false
```
#### FadeTo | FadeBy
- `FadeTo(amount, time)` : float, int - `FadeTo(amount, time)` : float, int
- `FadeBy(amount, time)` : float, int - `FadeBy(amount, time)` : float, int
@@ -178,7 +336,7 @@ Modify gain to or by the selected amount in db over a time interval in ms.
for example: for example:
``` ```powershell
$vmr.strip[3].FadeTo(-18.7, 1000) $vmr.strip[3].FadeTo(-18.7, 1000)
$vmr.bus[0].FadeBy(-10, 500) $vmr.bus[0].FadeBy(-10, 500)
``` ```
@@ -191,7 +349,7 @@ Three modes defined: state, stateonly and trigger.
- Stateonly does not run associated scripts - Stateonly does not run associated scripts
- Index range (0, 69) - Index range (0, 69)
``` ```powershell
$vmr.button[3].state = $true $vmr.button[3].state = $true
$vmr.button[4].stateonly = $false $vmr.button[4].stateonly = $false
@@ -201,19 +359,19 @@ $vmr.button[5].trigger = $true
### VBAN ### VBAN
- vmr.vban.enable: Toggle VBAN on or off. Accepts a boolean value. - vmr.vban.enable: Toggle VBAN on or off. Accepts a bool value.
For each vban in/out stream the following parameters are defined: For each vban in/out stream the following parameters are defined:
- on: boolean - on: bool
- name: string - name: string
- ip: string - ip: string
- port: int from 1024 - 65535 - port: int, from 1024 - 65535
- sr: int (11025, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000) - sr: in, (11025, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000)
- channel: int from 1 to 8 - channel: int from 1 to 8
- bit: int 16 or 24 - bit: int, 16 or 24
- quality: int from 0 to 4 - quality: int, from 0 to 4
- route: int from 0 to 8 - route: int, from 0 to 8
SR, channel and bit are defined as readonly for instreams. Attempting to write SR, channel and bit are defined as readonly for instreams. Attempting to write
to those parameters will throw an error. They are read and write for outstreams. to those parameters will throw an error. They are read and write for outstreams.
@@ -232,18 +390,18 @@ $vmr.vban.outstream[3].bit = 16
Certain 'special' commands are defined by the API as performing actions rather than setting values. Certain 'special' commands are defined by the API as performing actions rather than setting values.
The following methods are available: The following commands are available:
- show - show
- hide - hide
- restart - restart
- shutdown - shutdown
- Load(filepath) - showvbanchat: bool, (write only)
- lock: bool, (write only)
The following properties are write only and accept boolean values: The following methods are available:
- showvbanchat - Load($filepath): string
- lock
example: example:
@@ -257,7 +415,7 @@ $vmr.command.Load("path/to/filename.xml")
### Recorder ### Recorder
The following methods are available: The following commands are available:
- play - play
- stop - stop
@@ -265,19 +423,53 @@ The following methods are available:
- record - record
- ff - ff
- rew - rew
- A1 - A5: bool
- B1 - B3: bool
- samplerate: int, (22050, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000)
- bitresolution: int, (8, 16, 24, 32)
- channel: int, from 1 to 8
- kbps: int, (32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320)
The following properties accept boolean values. The following methods are available:
- loop - Load($filepath): string
- A1 - A5 - GoTo($timestring): string, must match the format 'hh:mm:ss'
- B1 - B3 - FileType($format): string, ('wav', 'aiff', 'bwf', 'mp3')
example: example:
```powershell ```powershell
$vmr.recorder.play $vmr.recorder.play
$vmr.recorder.A1 = $true
$vmr.recorder.loop = $true $vmr.recorder.GoTo("00:01:15") # go to 1min 15sec into track
```
#### Mode
The following commands are available:
- recbus
- playonload
- loop
- multitrack
example:
```powershell
$vmr.recorder.mode.loop = $true
```
#### ArmStrip[i]|ArmBus[i]
The following method is available:
- Set($val): bool
example:
```powershell
$vmr.recorder.armstrip[0].Set($true)
``` ```
### Multiple parameters ### Multiple parameters

View File

@@ -1,11 +1,11 @@
[cmdletbinding()]
param( param(
[switch]$interactive, [switch]$interactive,
[switch]$output,
[String]$kind = "banana", [String]$kind = "banana",
[String[]]$script = @() [String[]]$script = @()
) )
Import-Module Voicemeeter Import-Module ..\..\lib\Voicemeeter.psm1
function get-value { function get-value {
param([object]$vmr, [string]$line) param([object]$vmr, [string]$line)
@@ -22,16 +22,16 @@ function msgHandler {
param([object]$vmr, [string]$line) param([object]$vmr, [string]$line)
$line + " passed to handler" | Write-Debug $line + " passed to handler" | Write-Debug
if ($line[0] -eq "!") { if ($line[0] -eq "!") {
if ($output) { "Toggling " + $line.substring(1) | Write-Host } "Toggling " + $line.substring(1) | Write-Debug
$retval = get-value -vmr $vmr -line $line.substring(1) $retval = get-value -vmr $vmr -line $line.substring(1)
$vmr.Setter($line.substring(1), 1 - $retval) $vmr.Setter($line.substring(1), 1 - $retval)
} }
elseif ($line.Contains("=")) { elseif ($line.Contains("=")) {
if ($output) { "Setting $line" | Write-Host } "Setting $line" | Write-Debug
$vmr.SendText($line) $vmr.SendText($line)
} }
else { else {
if ($output) { "Getting $line" | Write-Host } "Getting $line" | Write-Debug
$retval = get-value -vmr $vmr -line $line $retval = get-value -vmr $vmr -line $line
$line + " = " + $retval | Write-Host $line + " = " + $retval | Write-Host
} }
@@ -47,11 +47,7 @@ function main {
[object]$vmr [object]$vmr
try { try {
switch ($kind) { $vmr = Connect-Voicemeeter -Kind $kind
"basic" { $vmr = Get-RemoteBasic }
"banana" { $vmr = Get-RemoteBanana }
"potato" { $vmr = Get-RemotePotato }
}
if ($interactive) { if ($interactive) {
"Press <Enter> to exit" | Write-Host "Press <Enter> to exit" | Write-Host
@@ -62,7 +58,7 @@ function main {
msgHandler -vmr $vmr -line $_ msgHandler -vmr $vmr -line $_
} }
} }
finally { $vmr.Logout() } finally { Disconnect-Voicemeeter }
} }
if ($MyInvocation.InvocationName -ne '.') { main } main

View File

@@ -7,26 +7,30 @@
Credits go to @bobsupercow Credits go to @bobsupercow
#> #>
Import-Module Voicemeeter [cmdletbinding()]
param()
Import-Module ..\..\lib\Voicemeeter.psm1
try { try {
$vmr = Get-RemotePotato $vmr = Connect-Voicemeeter -Kind "potato"
$buses = @($vmr.bus[1], $vmr.bus[2], $vmr.bus[4], $vmr.bus[6]) $buses = @($vmr.bus[1], $vmr.bus[2], $vmr.bus[4], $vmr.bus[6])
"Buses in selection: $($buses)"
$unmutedIndex = $null $unmutedIndex = $null
# 1) # 1)
$buses | ForEach-Object { "Cycling through bus selection to check for first unmuted Bus..." | Write-Host
$bus = $_ foreach ($bus in $buses) {
# 2) # 2)
if (-not $bus.mute) { if (-not $bus.mute) {
"bus " + $bus.index + " is unmuted... muting it" | Write-Host "Bus $($bus.index) is unmuted... muting it" | Write-Host
$unmutedIndex = $buses.IndexOf($bus) $unmutedIndex = $buses.IndexOf($bus)
$bus.mute = $true $bus.mute = $true
# 3) # 3)
if ($buses[++$unmutedIndex]) { if ($buses[++$unmutedIndex]) {
"unmuting bus " + $buses[$unmutedIndex].index | Write-Host "Unmuting Bus $($buses[$unmutedIndex].index)" | Write-Host
$buses[$unmutedIndex].mute = $false $buses[$unmutedIndex].mute = $false
break break
} }
@@ -34,7 +38,10 @@ try {
} }
} }
# 4) # 4)
if ($null -eq $unmutedIndex) { $buses[0].mute = $false } if ($null -eq $unmutedIndex) {
"unmuting bus " + $buses[0].index | Write-Host $buses[0].mute = $false
"Unmuting Bus $($buses[0].index)" | Write-Host
} }
finally { $vmr.Logout() }
}
finally { Disconnect-Voicemeeter }

View File

@@ -5,16 +5,17 @@ Demonstrates how to sync Voicemeeter states with OBS scene switches.
## Requirements ## Requirements
- [OBS Studio 28+](https://obsproject.com/) - [OBS Studio 28+](https://obsproject.com/)
- [OBSWebSocket for Powershell](https://github.com/onyx-and-iris/OBSWebSocket-Powershell) - [OBS-Powershell](https://github.com/StartAutomating/obs-powershell)
## Use ## Use
This example assumes the following: This example assumes the following:
- OBS connection info saved in `config.psd1`, placed next to `Vm-Obs-Sync.ps1`: - OBS connection info saved in `config.psd1`, placed next to `Vm-Obs-Sync.ps1`:
```psd1 ```psd1
@{ @{
hostname = "localhost" host = "localhost"
port = 4455 port = 4455
password = "mystrongpassword" password = "mystrongpassword"
} }
@@ -23,3 +24,5 @@ This example assumes the following:
- OBS scenes named `START`, `BRB`, `END` and `LIVE` - OBS scenes named `START`, `BRB`, `END` and `LIVE`
Simply run the script and change current OBS scene. Simply run the script and change current OBS scene.
Closing OBS will end the script.

View File

@@ -1,26 +1,40 @@
Import-Module Voicemeeter [cmdletbinding()]
Import-Module OBSWebSocket param()
$VerbosePreference = "Continue" Import-Module ..\..\lib\Voicemeeter.psm1
Import-Module obs-powershell
$info = @{ function CurrentProgramSceneChanged {
START = "Toggling Strip 0 mute" param([System.Object]$data)
BRB = "Setting Strip 0 gain to -8.3" Write-Host "Switched to scene", $data.sceneName
END = "Setting Strip 0 mono to `$false"
LIVE = "Setting Strip 0 color_x to 0.3" switch ($data.sceneName) {
"START" {
$vmr.strip[0].mute = !$vmr.strip[0].mute
}
"BRB" {
$vmr.strip[0].gain = -8.3
}
"END" {
$vmr.strip[0].mono = $true
}
"LIVE" {
$vmr.strip[0].color_x = 0.3
} }
function CurrentProgramSceneChanged($data) {
"Switched to scene " + $data.sceneName | Write-Host
switch ($data.SceneName) {
"START" { $vmr.strip[0].mute = !$vmr.strip[0].mute }
"BRB" { $vmr.strip[0].gain = -8.3 }
"END" { $vmr.strip[0].mono = $true }
"LIVE" { $vmr.strip[0].color_x = 0.3 }
default { "Expected START, BRB, END or LIVE scene" | Write-Warning; return } default { "Expected START, BRB, END or LIVE scene" | Write-Warning; return }
} }
$info[$data.SceneName] | Write-Host }
function ExitStarted {
param([System.Object]$data)
"OBS shutdown has begun!" | Write-Host
break
}
function eventHandler($data) {
if (Get-Command $data.eventType -ErrorAction SilentlyContinue) {
& $data.eventType -data $data.eventData
}
} }
function ConnFromFile { function ConnFromFile {
@@ -29,22 +43,26 @@ function ConnFromFile {
} }
function main { function main {
try { $vmr = Connect-Voicemeeter -Kind "basic"
$vmr = Get-RemoteBasic
$conn = ConnFromFile $conn = ConnFromFile
$r_client = Get-OBSRequest -hostname $conn.hostname -port $conn.port -pass $conn.password $job = Watch-OBS -WebSocketURI "ws://$($conn.host):$($conn.port)" -WebSocketToken $conn.password
$resp = $r_client.getVersion()
"obs version:" + $resp.obsVersion | Write-Host
"websocket version:" + $resp.obsWebSocketVersion | Write-Host
$e_client = Get-OBSEvent -hostname $conn.hostname -port $conn.port -pass $conn.password try {
$callbacks = @("CurrentProgramSceneChanged", ${function:CurrentProgramSceneChanged}) while ($true) {
$e_client.Register($callbacks) Receive-Job -Job $job | ForEach-Object {
} finally { $data = $_.MessageData
$r_client.TearDown()
$e_client.TearDown() if ($data.op -eq 5) {
$vmr.Logout() eventHandler($data.d)
}
}
}
}
finally {
Disconnect-OBS
Disconnect-Voicemeeter
} }
} }
if ($MyInvocation.InvocationName -ne '.') { main } main

View File

@@ -1,40 +1,35 @@
. $PSScriptRoot\kinds.ps1 . $PSScriptRoot\errors.ps1
. $PSScriptRoot\meta.ps1
. $PSScriptRoot\base.ps1 . $PSScriptRoot\base.ps1
. $PSScriptRoot\kinds.ps1
. $PSScriptRoot\strip.ps1
. $PSScriptRoot\bus.ps1
. $PSScriptRoot\macrobuttons.ps1
. $PSScriptRoot\vban.ps1
. $PSScriptRoot\command.ps1
. $PSScriptRoot\recorder.ps1
. $PSScriptRoot\profiles.ps1
class Remote { class Remote {
[String]$vmpath
[Hashtable]$kind [Hashtable]$kind
[System.Collections.ArrayList]$strip
[System.Collections.ArrayList]$bus
[System.Collections.ArrayList]$button
[PSCustomObject]$vban
[Object]$command
[Object]$recorder
[Object]$profiles [Object]$profiles
# Constructor Remote ([String]$kindId) {
Remote ([String]$kind_id) { $this.vmpath = Setup_DLL
$this.kind = GetKind($kind_id) $this.kind = GetKind($kindId)
$this.Setup()
}
[void] Setup() {
if (!(Setup_DLL)) {
Exit
}
Login -KIND $this.kind.name
$this.profiles = Get_Profiles($this.kind.name) $this.profiles = Get_Profiles($this.kind.name)
$this.strip = Make_Strips($this)
$this.bus = Make_Buses($this)
$this.button = Make_Buttons
$this.vban = Make_Vban($this)
$this.command = Make_Command
$this.recorder = Make_Recorder($this)
} }
[string] ToString() { [string] ToString() {
return "Voicemeeter " + $this.kind.name.substring(0, 1).toupper() + $this.kind.name.substring(1) return "Voicemeeter " + $this.kind.name.substring(0, 1).toupper() + $this.kind.name.substring(1)
} }
[Remote] Login() {
Login -kindId $this.kind.name
return $this
}
[void] Logout() { [void] Logout() {
Logout Logout
} }
@@ -44,7 +39,7 @@ class Remote {
} }
[String] GetVersion() { [String] GetVersion() {
return Version return VmVersion
} }
[void] Set_Profile([String]$config) { [void] Set_Profile([String]$config) {
@@ -76,16 +71,90 @@ class Remote {
[void] MDirty() { M_Dirty } [void] MDirty() { M_Dirty }
} }
class RemoteBasic : Remote {
[System.Collections.ArrayList]$strip
[System.Collections.ArrayList]$bus
[System.Collections.ArrayList]$button
[PSCustomObject]$vban
[Object]$command
RemoteBasic () : base ('basic') {
$this.strip = Make_Strips($this)
$this.bus = Make_Buses($this)
$this.button = Make_Buttons
$this.vban = Make_Vban($this)
$this.command = Make_Command($this)
}
}
class RemoteBanana : Remote {
[System.Collections.ArrayList]$strip
[System.Collections.ArrayList]$bus
[System.Collections.ArrayList]$button
[PSCustomObject]$vban
[Object]$command
[Object]$recorder
RemoteBanana () : base ('banana') {
$this.strip = Make_Strips($this)
$this.bus = Make_Buses($this)
$this.button = Make_Buttons
$this.vban = Make_Vban($this)
$this.command = Make_Command($this)
$this.recorder = Make_Recorder($this)
}
}
class RemotePotato : Remote {
[System.Collections.ArrayList]$strip
[System.Collections.ArrayList]$bus
[System.Collections.ArrayList]$button
[PSCustomObject]$vban
[Object]$command
[Object]$recorder
RemotePotato () : base ('potato') {
$this.strip = Make_Strips($this)
$this.bus = Make_Buses($this)
$this.button = Make_Buttons
$this.vban = Make_Vban($this)
$this.command = Make_Command($this)
$this.recorder = Make_Recorder($this)
}
}
Function Get-RemoteBasic { Function Get-RemoteBasic {
return [Remote]::new('basic') [RemoteBasic]::new().Login()
} }
Function Get-RemoteBanana { Function Get-RemoteBanana {
return [Remote]::new('banana') [RemoteBanana]::new().Login()
} }
Function Get-RemotePotato { Function Get-RemotePotato {
return [Remote]::new('potato') [RemotePotato]::new().Login()
} }
Export-ModuleMember -Function Get-RemoteBasic, Get-RemoteBanana, Get-RemotePotato Function Connect-Voicemeeter {
param([String]$Kind)
switch ($Kind) {
"basic" {
return Get-RemoteBasic
}
"banana" {
return Get-RemoteBanana
}
"potato" {
return Get-RemotePotato
}
default {
throw [LoginError]::new("Unknown Voicemeeter kind `"$Kind`"")
}
}
}
Function Disconnect-Voicemeeter {
Logout
}
Export-ModuleMember -Function Get-RemoteBasic, Get-RemoteBanana, Get-RemotePotato, Connect-Voicemeeter, Disconnect-Voicemeeter

View File

@@ -1,75 +1,77 @@
. $PSScriptRoot\errors.ps1 . $PSScriptRoot\errors.ps1
. $PSScriptRoot\binding.ps1 . $PSScriptRoot\binding.ps1
. $PSScriptRoot\profiles.ps1
. $PSScriptRoot\inst.ps1
. $PSScriptRoot\strip.ps1
. $PSScriptRoot\bus.ps1
. $PSScriptRoot\macrobuttons.ps1
. $PSScriptRoot\vban.ps1
. $PSScriptRoot\command.ps1
. $PSScriptRoot\recorder.ps1
function Login { function Login {
param( param(
[string]$KIND = $null [string]$kindId
) )
try {
$retval = [int][Voicemeeter.Remote]::VBVMR_Login() $retval = [int][Voicemeeter.Remote]::VBVMR_Login()
if (-not $retval) { "LOGGED IN" | Write-Verbose } if ($retval -notin @(0, 1, -2)) {
elseif ($retval -eq 1) { throw [CAPIError]::new($retval, "VBVMR_Login")
"VM NOT RUNNING" | Write-Verbose
New-Variable -Name vm_exe -Value 0
switch ($KIND) {
'basic' { $vm_exe = 1; break }
'banana' { $vm_exe = 2; break }
'potato' {
if ([Environment]::Is64BitOperatingSystem) {
$vm_exe = 6
}
else { $vm_exe = 3 }
break
}
default { throw [LoginError]::new('Unknown Voicemeeter type') }
} }
$retval = [int][Voicemeeter.Remote]::VBVMR_RunVoicemeeter([int64]$vm_exe) switch ($retval) {
if (-not $retval) { "STARTING VOICEMEETER" | Write-Verbose } 1 {
else { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) } "Voicemeeter Engine running but GUI not launched. Launching GUI now." | Write-Verbose
Start-Sleep -s 1 RunVoicemeeter -kindId $kindId
} }
elseif ($retval -eq -2) { -2 {
throw [LoginError]::new('Login may only be called once per session') throw [LoginError]::new("Login may only be called once per session.")
} }
else { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) }
}
catch [LoginError], [CAPIError] {
Write-Warning $_.Exception.ErrorMessage()
exit
} }
while (P_Dirty -or M_Dirty) { Start-Sleep -m 1 } while (P_Dirty -or M_Dirty) { Start-Sleep -m 1 }
"VERSION:[" + $(VmType).ToUpper() + "]" | Write-Verbose "Successfully logged into Voicemeeter [" + $(VmType).ToUpper() + "] Version " + $(VmVersion) | Write-Verbose
} }
function Logout { function Logout {
Start-Sleep -m 20 Start-Sleep -m 100
$retval = [int][Voicemeeter.Remote]::VBVMR_Logout() $retval = [int][Voicemeeter.Remote]::VBVMR_Logout()
if (-not $retval) { "LOGGED OUT" | Write-Verbose } if ($retval -notin @(0)) {
throw [CAPIError]::new($retval, "VBVMR_Logout")
}
if ($retval -eq 0) { "Sucessfully logged out" | Write-Verbose }
}
function RunVoicemeeter {
param(
[string]$kindId
)
$kinds = @{
"basic" = 1
"banana" = 2
"potato" = $(if ([Environment]::Is64BitOperatingSystem) { 6 } else { 3 })
}
$retval = [int][Voicemeeter.Remote]::VBVMR_RunVoicemeeter([int64]$kinds[$kindId])
if ($retval -notin @(0)) {
throw [CAPIError]::new($retval, "VBVMR_RunVoicemeeter")
}
Start-Sleep -s 1
} }
function P_Dirty { function P_Dirty {
[bool][Voicemeeter.Remote]::VBVMR_IsParametersDirty() $retval = [Voicemeeter.Remote]::VBVMR_IsParametersDirty()
if ($retval -notin @(0, 1)) {
throw [CAPIError]::new($retval, "VBVMR_RunVoicemeeter")
}
[bool]$retval
} }
function M_Dirty { function M_Dirty {
[bool][Voicemeeter.Remote]::VBVMR_MacroButton_IsDirty() $retval = [Voicemeeter.Remote]::VBVMR_MacroButton_IsDirty()
if ($retval -notin @(0, 1)) {
throw [CAPIError]::new($retval, "VBVMR_RunVoicemeeter")
}
[bool]$retval
} }
function VmType { function VmType {
New-Variable -Name ptr -Value 0 New-Variable -Name ptr -Value 0
$retval = [int][Voicemeeter.Remote]::VBVMR_GetVoicemeeterType([ref]$ptr) $retval = [int][Voicemeeter.Remote]::VBVMR_GetVoicemeeterType([ref]$ptr)
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) } if ($retval -notin @(0)) {
throw [CAPIError]::new($retval, "VBVMR_GetVoicemeeterType")
}
switch ($ptr) { switch ($ptr) {
1 { return "basic" } 1 { return "basic" }
2 { return "banana" } 2 { return "banana" }
@@ -77,10 +79,12 @@ function VmType {
} }
} }
function Version { function VmVersion {
New-Variable -Name ptr -Value 0 New-Variable -Name ptr -Value 0
$retval = [int][Voicemeeter.Remote]::VBVMR_GetVoicemeeterVersion([ref]$ptr) $retval = [int][Voicemeeter.Remote]::VBVMR_GetVoicemeeterVersion([ref]$ptr)
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) } if ($retval -notin @(0)) {
throw [CAPIError]::new($retval, "VBVMR_GetVoicemeeterVersion")
}
$v1 = ($ptr -band 0xFF000000) -shr 24 $v1 = ($ptr -band 0xFF000000) -shr 24
$v2 = ($ptr -band 0x00FF0000) -shr 16 $v2 = ($ptr -band 0x00FF0000) -shr 16
$v3 = ($ptr -band 0x0000FF00) -shr 8 $v3 = ($ptr -band 0x0000FF00) -shr 8
@@ -93,28 +97,22 @@ function Param_Get {
param( param(
[string]$PARAM, [bool]$IS_STRING = $false [string]$PARAM, [bool]$IS_STRING = $false
) )
Start-Sleep -m 50 Start-Sleep -m 30
while (P_Dirty) { Start-Sleep -m 1 } while (P_Dirty) { Start-Sleep -m 1 }
if ($IS_STRING) { if ($IS_STRING) {
$BYTES = [System.Byte[]]::new(512) $BYTES = [System.Byte[]]::new(512)
try {
$retval = [int][Voicemeeter.Remote]::VBVMR_GetParameterStringA($PARAM, $BYTES) $retval = [int][Voicemeeter.Remote]::VBVMR_GetParameterStringA($PARAM, $BYTES)
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) } if ($retval -notin @(0)) {
} throw [CAPIError]::new($retval, "VBVMR_GetParameterStringA")
catch [CAPIError] {
Write-Warning $_.Exception.ErrorMessage()
} }
[System.Text.Encoding]::ASCII.GetString($BYTES).Trim([char]0) [System.Text.Encoding]::ASCII.GetString($BYTES).Trim([char]0)
} }
else { else {
New-Variable -Name ptr -Value 0.0 New-Variable -Name ptr -Value 0.0
try {
$retval = [int][Voicemeeter.Remote]::VBVMR_GetParameterFloat($PARAM, [ref]$ptr) $retval = [int][Voicemeeter.Remote]::VBVMR_GetParameterFloat($PARAM, [ref]$ptr)
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) } if ($retval -notin @(0)) {
} throw [CAPIError]::new($retval, "VBVMR_GetParameterFloat")
catch [CAPIError] {
Write-Warning $_.Exception.ErrorMessage()
} }
[single]$ptr [single]$ptr
} }
@@ -124,17 +122,17 @@ function Param_Set {
param( param(
[string]$PARAM, [Object]$VALUE [string]$PARAM, [Object]$VALUE
) )
try {
if ($VALUE -is [string]) { if ($VALUE -is [string]) {
$retval = [int][Voicemeeter.Remote]::VBVMR_SetParameterStringA($PARAM, $VALUE) $retval = [int][Voicemeeter.Remote]::VBVMR_SetParameterStringA($PARAM, $VALUE)
if ($retval -notin @(0)) {
throw [CAPIError]::new($retval, "VBVMR_SetParameterStringA")
}
} }
else { else {
$retval = [int][Voicemeeter.Remote]::VBVMR_SetParameterFloat($PARAM, $VALUE) $retval = [int][Voicemeeter.Remote]::VBVMR_SetParameterFloat($PARAM, $VALUE)
if ($retval -notin @(0)) {
throw [CAPIError]::new($retval, "VBVMR_SetParameterFloat")
} }
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) }
}
catch [CAPIError] {
Write-Warning $_.Exception.ErrorMessage()
} }
} }
@@ -142,12 +140,9 @@ function MB_Set {
param( param(
[int64]$ID, [single]$SET, [int64]$MODE [int64]$ID, [single]$SET, [int64]$MODE
) )
try {
$retval = [int][Voicemeeter.Remote]::VBVMR_MacroButton_SetStatus($ID, $SET, $MODE) $retval = [int][Voicemeeter.Remote]::VBVMR_MacroButton_SetStatus($ID, $SET, $MODE)
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) } if ($retval -notin @(0)) {
} throw [CAPIError]::new($retval, "VBVMR_MacroButton_SetStatus")
catch [CAPIError] {
Write-Warning $_.Exception.ErrorMessage()
} }
} }
@@ -159,12 +154,9 @@ function MB_Get {
while (M_Dirty) { Start-Sleep -m 1 } while (M_Dirty) { Start-Sleep -m 1 }
New-Variable -Name ptr -Value 0.0 New-Variable -Name ptr -Value 0.0
try {
$retval = [int][Voicemeeter.Remote]::VBVMR_MacroButton_GetStatus($ID, [ref]$ptr, $MODE) $retval = [int][Voicemeeter.Remote]::VBVMR_MacroButton_GetStatus($ID, [ref]$ptr, $MODE)
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) } if ($retval -notin @(0)) {
} throw [CAPIError]::new($retval, $MyInvocation.MyCommand)
catch [CAPIError] {
Write-Warning $_.Exception.ErrorMessage()
} }
[int]$ptr [int]$ptr
} }
@@ -196,11 +188,20 @@ function Set_By_Script {
param( param(
[string]$script [string]$script
) )
try {
$retval = [int][Voicemeeter.Remote]::VBVMR_SetParameters($script) $retval = [int][Voicemeeter.Remote]::VBVMR_SetParameters($script)
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) } if ($retval -notin @(0)) {
} throw [CAPIError]::new($retval, "VBVMR_SetParameters")
catch [CAPIError] {
Write-Warning $_.Exception.ErrorMessage()
} }
} }
function Get_Level {
param(
[int64]$MODE, [int64]$INDEX
)
New-Variable -Name ptr -Value 0.0
$retval = [int][Voicemeeter.Remote]::VBVMR_GetLevel($MODE, $INDEX, [ref]$ptr)
if ($retval -notin @(0)) {
throw [CAPIError]::new($retval, "VBVMR_GetLevel")
}
[float]$ptr
}

View File

@@ -1,18 +1,11 @@
function Setup_DLL { . $PSScriptRoot\inst.ps1
try {
$vb_path = Get_VBPath
if ([string]::IsNullOrWhiteSpace($vb_path)) { function Setup_DLL {
throw [VMRemoteErrors]::new("ERROR: Couldn't get Voicemeeter path") $VMPATH = Get_VMPath
}
$dll = Join-Path -Path $vb_path -ChildPath ("VoicemeeterRemote" + ` $dll = Join-Path -Path $VMPATH -ChildPath ("VoicemeeterRemote" + `
(& { if ([Environment]::Is64BitOperatingSystem) { "64" } else { "" } }) + ` (& { if ([Environment]::Is64BitOperatingSystem) { "64" } else { "" } }) + `
".dll") ".dll")
}
catch [VMRemoteErrors] {
Write-Warning $_.Exception.ErrorMessage()
return $false
}
$Signature = @" $Signature = @"
[DllImport(@"$dll")] [DllImport(@"$dll")]
@@ -47,8 +40,11 @@ function Setup_DLL {
[DllImport(@"$dll")] [DllImport(@"$dll")]
public static extern int VBVMR_SetParameters(String param); public static extern int VBVMR_SetParameters(String param);
[DllImport(@"$dll")]
public static extern int VBVMR_GetLevel(Int64 mode, Int64 index, ref float ptr);
"@ "@
Add-Type -MemberDefinition $Signature -Name Remote -Namespace Voicemeeter -PassThru | Out-Null Add-Type -MemberDefinition $Signature -Name Remote -Namespace Voicemeeter -PassThru | Out-Null
return $true return $VMPATH
} }

View File

@@ -1,89 +1,205 @@
. $PSScriptRoot\meta.ps1 class IBus {
class Bus {
[int]$index [int]$index
[Object]$remote [Object]$remote
# Constructor IBus ([int]$index, [Object]$remote) {
Bus ([int]$index, [Object]$remote) {
$this.index = $index $this.index = $index
$this.remote = $remote $this.remote = $remote
}
[string] identifier () {
return "Bus[" + $this.index + "]"
}
[single] Getter ($param) {
$this.ToString() + " Getter: $($this.Cmd($param))" | Write-Debug
return $this.remote.Getter($this.Cmd($param))
}
[string] Getter_String ($param) {
$this.ToString() + " Getter_String: $($this.Cmd($param))" | Write-Debug
return $this.remote.Getter_String($this.Cmd($param))
}
[void] Setter ($param, $val) {
$this.ToString() + " Setter: $($this.Cmd($param))=$val" | Write-Debug
$this.remote.Setter($this.Cmd($param), $val)
}
[string] Cmd ($param) {
if ([string]::IsNullOrEmpty($param)) {
return $this.identifier()
}
return "$($this.identifier()).$param"
}
}
class Bus : IBus {
[Object]$mode
[Object]$eq
[Object]$levels
Bus ([int]$index, [Object]$remote) : base ($index, $remote) {
AddBoolMembers -PARAMS @('mono', 'mute') AddBoolMembers -PARAMS @('mono', 'mute')
AddStringMembers -PARAMS @('label') AddStringMembers -PARAMS @('label')
AddFloatMembers -PARAMS @('gain', 'returnreverb', 'returndelay', 'returnfx1', 'returnfx2') AddFloatMembers -PARAMS @('gain', 'returnreverb', 'returndelay', 'returnfx1', 'returnfx2')
AddBusModeMembers -PARAMS @('normal', 'amix', 'bmix', 'repeat', 'composite', 'tvmix', 'upmix21') $this.mode = [BusMode]::new($index, $remote)
AddBusModeMembers -PARAMS @('upmix41', 'upmix61', 'centeronly', 'lfeonly', 'rearonly') $this.eq = [BusEq]::new($index, $remote)
$this.levels = [BusLevels]::new($index, $remote)
} }
[string] ToString() { [string] ToString() {
return $this.GetType().Name + $this.index return $this.GetType().Name + $this.index
} }
[single] Getter ($cmd) {
return Param_Get -PARAM $cmd -IS_STRING $false
}
[string] Getter_String ($cmd) {
return Param_Get -PARAM $cmd -IS_STRING $true
}
[void] Setter ($cmd, $set) {
Param_Set -PARAM $cmd -Value $set
}
[string] cmd ($arg) {
return "Bus[" + $this.index + "].$arg"
}
hidden $_eq = $($this | Add-Member ScriptProperty 'eq' `
{
[bool]$this.Getter($this.cmd('EQ.on'))
} `
{
param($arg)
$this._eq = $this.Setter($this.cmd('EQ.on'), $arg)
}
)
hidden $_eq_ab = $($this | Add-Member ScriptProperty 'eq_ab' `
{
[bool]$this.Getter($this.cmd('eq.ab'))
} `
{
param($arg)
$this._eq = $this.Setter($this.cmd('eq.ab'), $arg)
}
)
[void] FadeTo ([single]$target, [int]$time) { [void] FadeTo ([single]$target, [int]$time) {
$this.Setter($this.cmd('FadeTo'), "($target, $time)") $this.Setter('FadeTo', "($target, $time)")
} }
[void] FadeBy ([single]$target, [int]$time) { [void] FadeBy ([single]$target, [int]$time) {
$this.Setter($this.cmd('FadeBy'), "($target, $time)") $this.Setter('FadeBy', "($target, $time)")
}
}
class BusLevels : IBus {
[int]$init
[int]$offset
BusLevels ([int]$index, [Object]$remote) : base ($index, $remote) {
$this.init = $index * 8
$this.offset = 8
}
[float] Convert([float]$val) {
if ($val -gt 0) {
return [math]::Round(20 * [math]::Log10($val), 1)
}
else {
return - 200.0
}
}
[System.Collections.ArrayList] Getter([int]$mode) {
[System.Collections.ArrayList]$vals = @()
$this.init..$($this.init + $this.offset - 1) | ForEach-Object {
$vals.Add($this.Convert($(Get_Level -MODE $mode -INDEX $_)))
}
return $vals
}
[System.Collections.ArrayList] All() {
return $this.Getter(3)
}
}
class BusMode : IBus {
[System.Collections.ArrayList]$modes
BusMode ([int]$index, [Object]$remote) : base ($index, $remote) {
$this.modes = @(
'normal', 'amix', 'bmix', 'repeat', 'composite', 'tvmix', 'upmix21', 'upmix41', 'upmix61',
'centeronly', 'lfeonly', 'rearonly'
)
AddBoolMembers -PARAMS $this.modes
}
[string] identifier () {
return "Bus[" + $this.index + "].mode"
}
[string] Get () {
foreach ($mode in $this.modes) {
if ($this.$mode) {
break
}
}
return $mode
}
}
class BusEq : IBus {
BusEq ([int]$index, [Object]$remote) : base ($index, $remote) {
AddBoolMembers -PARAMS @('on', 'ab')
}
[string] identifier () {
return "Bus[" + $this.index + "].EQ"
} }
} }
class PhysicalBus : Bus { class PhysicalBus : Bus {
[Object]$device
PhysicalBus ([int]$index, [Object]$remote) : base ($index, $remote) { PhysicalBus ([int]$index, [Object]$remote) : base ($index, $remote) {
$this.device = [BusDevice]::new($index, $remote)
} }
hidden $_device = $($this | Add-Member ScriptProperty 'device' ` }
class BusDevice : IBus {
BusDevice ([int]$index, [Object]$remote) : base ($index, $remote) {
}
[string] identifier () {
return "Bus[" + $this.index + "].Device"
}
hidden $_name = $($this | Add-Member ScriptProperty 'name' `
{ {
$this.Getter_String($this.cmd('device.name')) $this.Getter_String('name')
} ` } `
{ {
return Write-Warning ("ERROR: " + $this.cmd('device.name') + " is read only") return Write-Warning ("ERROR: $($this.identifier()).name is read only")
} }
) )
hidden $_sr = $($this | Add-Member ScriptProperty 'sr' ` hidden $_sr = $($this | Add-Member ScriptProperty 'sr' `
{ {
$this.Getter($this.cmd('device.sr')) $this.Getter('sr')
} ` } `
{ {
return Write-Warning ("ERROR: " + $this.cmd('device.sr') + " is read only") return Write-Warning ("ERROR: $($this.identifier()).sr is read only")
}
)
hidden $_wdm = $($this | Add-Member ScriptProperty 'wdm' `
{
return Write-Warning ("ERROR: $($this.identifier()).wdm is write only")
} `
{
param($arg)
return $this.Setter('wdm', $arg)
}
)
hidden $_ks = $($this | Add-Member ScriptProperty 'ks' `
{
return Write-Warning ("ERROR: $($this.identifier()).ks is write only")
} `
{
param($arg)
return $this.Setter('ks', $arg)
}
)
hidden $_mme = $($this | Add-Member ScriptProperty 'mme' `
{
return Write-Warning ("ERROR: $($this.identifier()).mme is write only")
} `
{
param($arg)
return $this.Setter('mme', $arg)
}
)
hidden $_asio = $($this | Add-Member ScriptProperty 'asio' `
{
return Write-Warning ("ERROR: $($this.identifier()).asio is write only")
} `
{
param($arg)
return $this.Setter('asio', $arg)
} }
) )
} }

View File

@@ -1,64 +1,75 @@
. $PSScriptRoot\meta.ps1
class Special { class Special {
# Constructor [Object]$remote
Special () {
Special ([Object]$remote) {
AddActionMembers -PARAMS @('restart', 'shutdown', 'show') AddActionMembers -PARAMS @('restart', 'shutdown', 'show')
$this.remote = $remote
}
[string] identifier () {
return "Command"
} }
[string] ToString() { [string] ToString() {
return $this.GetType().Name return $this.GetType().Name
} }
[single] Getter ($cmd) { [single] Getter ($param) {
return Param_Get -PARAM $cmd -IS_STRING $false return $this.remote.Getter("$($this.identifier()).$param")
} }
[void] Setter ($param, $val) { [void] Setter ($param, $val) {
if ($val -is [Boolean]) { if ($val -is [Boolean]) {
Param_Set -PARAM $param -Value $(if ($val) { 1 } else { 0 }) $this.remote.Setter("$($this.identifier()).$param", $(if ($val) { 1 } else { 0 }))
} }
else { else {
Param_Set -PARAM $param -Value $val $this.remote.Setter("$($this.identifier()).$param", $val)
} }
} }
[string] cmd ($arg) { [void] RunMacrobuttons() {
return "Command.$arg" "Launching the MacroButtons app" | Write-Verbose
Start-Process -FilePath $(Join-Path -Path $this.remote.vmpath -ChildPath "VoicemeeterMacroButtons.exe")
}
[void] CloseMacrobuttons() {
"Closing the MacroButtons app" | Write-Verbose
Stop-Process -Name "VoicemeeterMacroButtons"
} }
hidden $_hide = $($this | Add-Member ScriptProperty 'hide' ` hidden $_hide = $($this | Add-Member ScriptProperty 'hide' `
{ {
$this._hide = $this.Setter($this.cmd('show'), $false) $this._hide = $this.Setter('show', $false)
} ` } `
{} {}
) )
hidden $_showvbanchat = $($this | Add-Member ScriptProperty 'showvbanchat' ` hidden $_showvbanchat = $($this | Add-Member ScriptProperty 'showvbanchat' `
{ {
$this.Getter($this.cmd('DialogShow.VBANCHAT')) $this.Getter('DialogShow.VBANCHAT')
} ` } `
{ {
param([bool]$arg) param([bool]$arg)
$this._showvbanchat = $this.Setter($this.cmd('DialogShow.VBANCHAT'), $arg) $this._showvbanchat = $this.Setter('DialogShow.VBANCHAT', $arg)
} }
) )
hidden $_lock = $($this | Add-Member ScriptProperty 'lock' ` hidden $_lock = $($this | Add-Member ScriptProperty 'lock' `
{ {
$this._lock = $this.Getter($this.cmd('lock')) $this._lock = $this.Getter('lock')
} ` } `
{ {
param([bool]$arg) param([bool]$arg)
$this._lock = $this.Setter($this.cmd('lock'), $arg) $this._lock = $this.Setter('lock', $arg)
} }
) )
[void] Load ([string]$filename) { [void] Load ([string]$filename) {
$this.Setter($this.cmd('load'), $filename) $this.Setter('load', $filename)
} }
} }
function Make_Command { function Make_Command([Object]$remote) {
return [Special]::new() return [Special]::new($remote)
} }

View File

@@ -1,30 +1,19 @@
class VMRemoteErrors : Exception { class VMRemoteError : Exception {
[string]$msg VMRemoteError ([string]$msg) : base ($msg) {
VMRemoteErrors ([string]$msg) {
$this.msg = $msg
}
[string] ErrorMessage () {
return $this.msg
} }
} }
class LoginError : VMRemoteErrors { class LoginError : VMRemoteError {
LoginError ([string]$msg) : base ([string]$msg) { LoginError ([string]$msg) : base ($msg) {
} }
} }
class CAPIError : VMRemoteErrors { class CAPIError : VMRemoteError {
[int]$retval [int]$retval
[string]$caller [string]$caller
CAPIError ([int]$retval, [string]$caller) { CAPIError ([int]$retval, [string]$caller) : base ("$caller returned $retval") {
$this.retval = $retval $this.retval = $retval
$this.caller = $caller $this.caller = $caller
} }
[string] ErrorMessage () {
return "ERROR: CAPI return value: {0} in {1}" -f $this.retval, $this.caller
}
} }

View File

@@ -1,8 +1,13 @@
function Get_VBPath { function Get_VMPath {
$reg_path = "Registry::HKEY_LOCAL_MACHINE\Software" + ` $REG_KEY = "Registry::HKEY_LOCAL_MACHINE\Software" + `
(& { if ([Environment]::Is64BitOperatingSystem) { "\WOW6432Node" } else { "" } }) + ` (& { if ([Environment]::Is64BitOperatingSystem) { "\WOW6432Node" } else { "" } }) + `
"\Microsoft\Windows\CurrentVersion\Uninstall" "\Microsoft\Windows\CurrentVersion\Uninstall"
$vm_key = "\VB:Voicemeeter {17359A74-1236-5467}\" $VM_KEY = "\VB:Voicemeeter {17359A74-1236-5467}\"
return $(Get-ItemPropertyValue -Path ($reg_path + $vm_key) -Name UninstallString | Split-Path -Parent) try {
return $(Get-ItemPropertyValue -Path ($REG_KEY + $VM_KEY) -Name UninstallString | Split-Path -Parent)
}
catch {
throw [VMRemoteError]::new("Unable to fetch Voicemeeter path from the Registry.")
}
} }

View File

@@ -28,6 +28,6 @@ $KindMap = @{
}; };
} }
function GetKind ([string]$kind_id) { function GetKind ([string]$kindId) {
$KindMap[$kind_id] $KindMap[$kindId]
} }

View File

@@ -1,7 +1,12 @@
enum ButtonTypes {
State = 1
StateOnly = 2
Trigger = 3
}
class MacroButton { class MacroButton {
[int32]$index [int32]$index
# Constructor
MacroButton ([int]$index) { MacroButton ([int]$index) {
$this.index = $index $this.index = $index
} }
@@ -11,40 +16,42 @@ class MacroButton {
} }
[int] Getter ($mode) { [int] Getter ($mode) {
"Button[$($this.index)].$([ButtonTypes].GetEnumName($mode))" | Write-Debug
return MB_Get -Id $this.index -Mode $mode return MB_Get -Id $this.index -Mode $mode
} }
[void] Setter ($set, $mode) { [void] Setter ($val, $mode) {
MB_Set -Id $this.index -SET $set -Mode $mode "Button[$($this.index)].$([ButtonTypes].GetEnumName($mode))=$val" | Write-Debug
MB_Set -Id $this.index -SET $val -Mode $mode
} }
hidden $_state = $($this | Add-Member ScriptProperty 'state' ` hidden $_state = $($this | Add-Member ScriptProperty 'state' `
{ {
$this.Getter(1) [bool]$this.Getter([ButtonTypes]::State)
} ` } `
{ {
param($arg) param($arg)
$this._state = $this.Setter($arg, 1) $this._state = $this.Setter($arg, [ButtonTypes]::State)
} }
) )
hidden $_stateonly = $($this | Add-Member ScriptProperty 'stateonly' ` hidden $_stateonly = $($this | Add-Member ScriptProperty 'stateonly' `
{ {
$this.Getter(2) [bool]$this.Getter([ButtonTypes]::StateOnly)
} ` } `
{ {
param($arg) param($arg)
$this._stateonly = $this.Setter($arg, 2) $this._stateonly = $this.Setter($arg, [ButtonTypes]::StateOnly)
} }
) )
hidden $_trigger = $($this | Add-Member ScriptProperty 'trigger' ` hidden $_trigger = $($this | Add-Member ScriptProperty 'trigger' `
{ {
$this.Getter(3) [bool]$this.Getter([ButtonTypes]::Trigger)
} ` } `
{ {
param($arg) param($arg)
$this._trigger = $this.Setter($arg, 3) $this._trigger = $this.Setter($arg, [ButtonTypes]::Trigger)
} }
) )
} }

View File

@@ -5,9 +5,9 @@ function AddBoolMembers () {
[hashtable]$Signatures = @{} [hashtable]$Signatures = @{}
foreach ($param in $PARAMS) { foreach ($param in $PARAMS) {
# Define getter # Define getter
$Signatures["Getter"] = "[bool]`$this.Getter(`$this.cmd('{0}'))" -f $param $Signatures["Getter"] = "[bool]`$this.Getter('{0}')" -f $param
# Define setter # Define setter
$Signatures["Setter"] = "param ( [Single]`$arg )`n`$this.Setter(`$this.cmd('{0}'), `$arg)" ` $Signatures["Setter"] = "param ( [Single]`$arg )`n`$this.Setter('{0}', `$arg)" `
-f $param -f $param
Addmember Addmember
@@ -21,9 +21,9 @@ function AddFloatMembers () {
[hashtable]$Signatures = @{} [hashtable]$Signatures = @{}
foreach ($param in $PARAMS) { foreach ($param in $PARAMS) {
# Define getter # Define getter
$Signatures["Getter"] = "[math]::Round(`$this.Getter(`$this.cmd('{0}')), 1)" -f $param $Signatures["Getter"] = "[math]::Round(`$this.Getter('{0}'), 1)" -f $param
# Define setter # Define setter
$Signatures["Setter"] = "param ( [Single]`$arg )`n`$this.Setter(`$this.cmd('{0}'), `$arg)" ` $Signatures["Setter"] = "param ( [Single]`$arg )`n`$this.Setter('{0}', `$arg)" `
-f $param -f $param
Addmember Addmember
@@ -37,9 +37,9 @@ function AddIntMembers () {
[hashtable]$Signatures = @{} [hashtable]$Signatures = @{}
foreach ($param in $PARAMS) { foreach ($param in $PARAMS) {
# Define getter # Define getter
$Signatures["Getter"] = "[Int]`$this.Getter(`$this.cmd('{0}'))" -f $param $Signatures["Getter"] = "[Int]`$this.Getter('{0}')" -f $param
# Define setter # Define setter
$Signatures["Setter"] = "param ( [Single]`$arg )`n`$this.Setter(`$this.cmd('{0}'), `$arg)" ` $Signatures["Setter"] = "param ( [Single]`$arg )`n`$this.Setter('{0}', `$arg)" `
-f $param -f $param
Addmember Addmember
@@ -53,9 +53,9 @@ function AddStringMembers () {
[hashtable]$Signatures = @{} [hashtable]$Signatures = @{}
foreach ($param in $PARAMS) { foreach ($param in $PARAMS) {
# Define getter # Define getter
$Signatures["Getter"] = "[String]`$this.Getter_String(`$this.cmd('{0}'))" -f $param $Signatures["Getter"] = "[String]`$this.Getter_String('{0}')" -f $param
# Define setter # Define setter
$Signatures["Setter"] = "param ( [String]`$arg )`n`$this.Setter(`$this.cmd('{0}'), `$arg)" ` $Signatures["Setter"] = "param ( [String]`$arg )`n`$this.Setter('{0}', `$arg)" `
-f $param -f $param
Addmember Addmember
@@ -69,7 +69,7 @@ function AddActionMembers () {
[hashtable]$Signatures = @{} [hashtable]$Signatures = @{}
foreach ($param in $PARAMS) { foreach ($param in $PARAMS) {
# Define getter # Define getter
$Signatures["Getter"] = "`$this.Setter(`$this.cmd('{0}'), `$true)" -f $param $Signatures["Getter"] = "`$this.Setter('{0}', `$true)" -f $param
# Define setter # Define setter
$Signatures["Setter"] = "" $Signatures["Setter"] = ""
@@ -93,9 +93,9 @@ function AddGainlayerMembers () {
[hashtable]$Signatures = @{} [hashtable]$Signatures = @{}
0..7 | ForEach-Object { 0..7 | ForEach-Object {
# Define getter # Define getter
$Signatures["Getter"] = "`$this.Getter(`$this.cmd('gainlayer[{0}]'))" -f $_ $Signatures["Getter"] = "`$this.Getter('gainlayer[{0}]')" -f $_
# Define setter # Define setter
$Signatures["Setter"] = "param ( [Single]`$arg )`n`$this.Setter(`$this.cmd('gainlayer[{0}]'), `$arg)" ` $Signatures["Setter"] = "param ( [Single]`$arg )`n`$this.Setter('gainlayer[{0}]', `$arg)" `
-f $_ -f $_
$param = "gainlayer{0}" -f $_ $param = "gainlayer{0}" -f $_
$null = $param $null = $param
@@ -104,23 +104,6 @@ function AddGainlayerMembers () {
} }
} }
function AddBusModeMembers () {
param(
[String[]]$PARAMS
)
[hashtable]$Signatures = @{}
foreach ($param in $PARAMS) {
# Define getter
$Signatures["Getter"] = "[bool]`$this.Getter(`$this.cmd('mode.{0}'))" -f $param
# Define setter
$Signatures["Setter"] = "param ( [Single]`$arg )`n`$this.Setter(`$this.cmd('mode.{0}'), `$arg)" `
-f $param
$param = "mode_{0}" -f $param
Addmember
}
}
function Addmember { function Addmember {
$AddMemberParams = @{ $AddMemberParams = @{
Name = $param Name = $param

View File

@@ -24,14 +24,9 @@ function Set_Profile {
param( param(
[Object]$DATA, [string]$CONF [Object]$DATA, [string]$CONF
) )
try {
if ($null -eq $DATA -or -not $DATA.$CONF) { if ($null -eq $DATA -or -not $DATA.$CONF) {
throw [VMRemoteErrors]::new("No profile named $CONF was loaded") throw [VMRemoteErrors]::new("No profile named '$CONF' has been loaded into memory.")
} }
Param_Set_Multi -HASH $DATA.$CONF Param_Set_Multi -HASH $DATA.$CONF
Start-Sleep -m 1 Start-Sleep -m 1
} }
catch [VMRemoteErrors] {
Write-Warning $_.Exception.ErrorMessage()
}
}

View File

@@ -1,48 +1,202 @@
. $PSScriptRoot\meta.ps1 class IRecorder {
class Recorder {
[Object]$remote [Object]$remote
# Constructor
Recorder ([Object]$remote) { IRecorder ([Object]$remote) {
$this.remote = $remote $this.remote = $remote
}
[single] Getter ($param) {
$this.Cmd($param) | Write-Debug
return $this.remote.Getter($this.Cmd($param))
}
[void] Setter ($param, $val) {
"$($this.Cmd($param))=$val" | Write-Debug
if ($val -is [Boolean]) {
$this.remote.Setter($this.Cmd($param), $(if ($val) { 1 } else { 0 }))
}
else {
$this.remote.Setter($this.Cmd($param), $val)
}
}
[string] Cmd ($param) {
if ([string]::IsNullOrEmpty($param)) {
return $this.identifier()
}
return "$($this.identifier()).$param"
}
}
class Recorder : IRecorder {
[Object]$remote
[Object]$mode
[System.Collections.ArrayList]$armstrip
[System.Collections.ArrayList]$armbus
Recorder ([Object]$remote) : base ($remote) {
$this.mode = [RecorderMode]::new($remote)
$this.armstrip = @()
0..($remote.kind.p_in + $remote.kind.v_in - 1) | ForEach-Object {
$this.armstrip.Add([RecorderArmStrip]::new($_, $remote))
}
$this.armbus = @()
0..($remote.kind.p_out + $remote.kind.v_out - 1) | ForEach-Object {
$this.armbus.Add([RecorderArmBus]::new($_, $remote))
}
AddActionMembers -PARAMS @('play', 'stop', 'pause', 'replay', 'record', 'ff', 'rew') AddActionMembers -PARAMS @('play', 'stop', 'pause', 'replay', 'record', 'ff', 'rew')
AddFloatMembers -PARAMS @('gain')
AddChannelMembers AddChannelMembers
} }
[string] identifier () {
return "Recorder"
}
[string] ToString() { [string] ToString() {
return $this.GetType().Name return $this.GetType().Name
} }
[single] Getter ($cmd) {
return Param_Get -PARAM $cmd -IS_STRING $false
}
[void] Setter ($param, $val) {
if ($val -is [Boolean]) {
Param_Set -PARAM $param -Value $(if ($val) { 1 } else { 0 })
}
else {
Param_Set -PARAM $param -Value $val
}
}
[string] cmd ($arg) {
return "Recorder.$arg"
}
hidden $_loop = $($this | Add-Member ScriptProperty 'loop' ` hidden $_loop = $($this | Add-Member ScriptProperty 'loop' `
{ {
return Write-Warning ("ERROR: " + $this.cmd('mode.loop') + " is write only") [bool]$this.mode.loop
} ` } `
{ {
param([bool]$arg) param($arg)
$this._loop = $this.Setter($this.cmd('mode.loop'), $arg) $this.mode.loop = $arg
}
)
hidden $_samplerate = $($this | Add-Member ScriptProperty 'samplerate' `
{
$this.Getter('samplerate')
} `
{
param([int]$arg)
$opts = @(22050, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000)
if ($opts.Contains($arg)) {
$this._samplerate = $this.Setter('samplerate', $arg)
}
else {
"samplerate got: $arg, expected one of $opts" | Write-Warning
}
}
)
hidden $_bitresolution = $($this | Add-Member ScriptProperty 'bitresolution' `
{
$this.Getter('bitresolution')
} `
{
param([int]$arg)
$opts = @(8, 16, 24, 32)
if ($opts.Contains($arg)) {
$this._bitresolution = $this.Setter('bitresolution', $arg)
}
else {
"bitresolution got: $arg, expected one of $opts" | Write-Warning
}
}
)
hidden $_channel = $($this | Add-Member ScriptProperty 'channel' `
{
$this.Getter('channel')
} `
{
param([int]$arg)
if ($arg -ge 1 -and $arg -le 8) {
$this._channel = $this.Setter('channel', $arg)
}
else {
"channel got: $arg, expected value from 1 to 8" | Write-Warning
}
}
)
hidden $_kbps = $($this | Add-Member ScriptProperty 'kbps' `
{
$this.Getter('kbps')
} `
{
param([int]$arg)
$opts = @(32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320)
if ($opts.Contains($arg)) {
$this._kbps = $this.Setter('kbps', $arg)
}
else {
"kbps got: $arg, expected one of $opts" | Write-Warning
}
} }
) )
[void] Load ([string]$filename) { [void] Load ([string]$filename) {
$this.Setter($this.cmd('load'), $filename) $this.Setter('load', $filename)
}
[void] GoTo ([string]$timestring) {
try {
if ([datetime]::ParseExact($timestring, "HH:mm:ss", $null)) {
$timespan = [timespan]::Parse($timestring)
$this.Setter("GoTo", $timespan.TotalSeconds)
}
}
catch [FormatException] {
"Time string $timestring does not match the required format 'hh:mm:ss'" | Write-Warning
}
}
[void] FileType($format) {
[int]$val = 0
switch ($format) {
"wav" { $val = 1 }
"aiff" { $val = 2 }
"bwf" { $val = 3 }
"mp3" { $val = 100 }
default { "Filetype() got: $format, expected one of 'wav', 'aiff', 'bwf', 'mp3'" }
}
$this.Setter("filetype", $val)
}
}
class RecorderMode : IRecorder {
RecorderMode ([Object]$remote) : base ($remote) {
AddBoolMembers -PARAMS @('recbus', 'playonload', 'loop', 'multitrack')
}
[string] identifier () {
return "Recorder.Mode"
}
}
class RecorderArm : IRecorder {
[int]$index
RecorderArm ([int]$index, [Object]$remote) : base ($remote) {
$this.index = $index
}
Set ([bool]$val) {
$this.Setter("", $(if ($val) { 1 } else { 0 }))
}
}
class RecorderArmStrip : RecorderArm {
RecorderArmStrip ([int]$index, [Object]$remote) : base ($index, $remote) {
}
[string] identifier () {
return "Recorder.ArmStrip[$($this.index)]"
}
}
class RecorderArmBus : RecorderArm {
RecorderArmBus ([int]$index, [Object]$remote) : base ($index, $remote) {
}
[string] identifier () {
return "Recorder.ArmBus[$($this.index)]"
} }
} }

View File

@@ -1,13 +1,43 @@
. $PSScriptRoot\meta.ps1 class IStrip {
class Strip {
[int]$index [int]$index
[Object]$remote [Object]$remote
Strip ([int]$index, [Object]$remote) { IStrip ([int]$index, [Object]$remote) {
$this.index = $index $this.index = $index
$this.remote = $remote $this.remote = $remote
}
[string] identifier () {
return "Strip[" + $this.index + "]"
}
[single] Getter ($param) {
$this.Cmd($param) | Write-Debug
return $this.remote.Getter($this.Cmd($param))
}
[string] Getter_String ($param) {
$this.Cmd($param) | Write-Debug
return $this.remote.Getter_String($this.Cmd($param))
}
[void] Setter ($param, $val) {
"$($this.Cmd($param))=$val" | Write-Debug
$this.remote.Setter($this.Cmd($param), $val)
}
[string] Cmd ($param) {
if ([string]::IsNullOrEmpty($param)) {
return $this.identifier()
}
return "$($this.identifier()).$param"
}
}
class Strip : IStrip {
[Object]$levels
Strip ([int]$index, [Object]$remote) : base ($index, $remote) {
AddBoolMembers -PARAMS @('mono', 'solo', 'mute') AddBoolMembers -PARAMS @('mono', 'solo', 'mute')
AddIntMembers -PARAMS @('limit') AddIntMembers -PARAMS @('limit')
AddFloatMembers -PARAMS @('gain', 'pan_x', 'pan_y') AddFloatMembers -PARAMS @('gain', 'pan_x', 'pan_y')
@@ -15,59 +45,222 @@ class Strip {
AddChannelMembers AddChannelMembers
AddGainlayerMembers AddGainlayerMembers
$this.levels = [StripLevels]::new($index, $remote)
} }
[string] ToString() { [string] ToString() {
return $this.GetType().Name + $this.index return $this.GetType().Name + $this.index
} }
[single] Getter ($cmd) {
return Param_Get -PARAM $cmd -IS_STRING $false
}
[string] Getter_String ($cmd) {
return Param_Get -PARAM $cmd -IS_STRING $true
}
[void] Setter ($cmd, $val) {
Param_Set -PARAM $cmd -Value $val
}
[string] cmd ($arg) {
return "Strip[" + $this.index + "].$arg"
}
[void] FadeTo ([single]$target, [int]$time) { [void] FadeTo ([single]$target, [int]$time) {
$this.Setter($this.cmd('FadeTo'), "($target, $time)") $this.Setter('FadeTo', "($target, $time)")
} }
[void] FadeBy ([single]$target, [int]$time) { [void] FadeBy ([single]$target, [int]$time) {
$this.Setter($this.cmd('FadeBy'), "($target, $time)") $this.Setter('FadeBy', "($target, $time)")
}
}
class StripLevels : IStrip {
[int]$init
[int]$offset
StripLevels ([int]$index, [Object]$remote) : base ($index, $remote) {
$p_in = $remote.kind.p_in
if ($index -lt $p_in) {
$this.init = $index * 2
$this.offset = 2
}
else {
$this.init = ($p_in * 2) + (($index - $p_in) * 8)
$this.offset = 8
}
}
[float] Convert([float]$val) {
if ($val -gt 0) {
return [math]::Round(20 * [math]::Log10($val), 1)
}
else {
return -200.0
}
}
[System.Collections.ArrayList] Getter([int]$mode) {
[System.Collections.ArrayList]$vals = @()
$this.init..$($this.init + $this.offset - 1) | ForEach-Object {
$vals.Add($this.Convert($(Get_Level -MODE $mode -INDEX $_)))
}
return $vals
}
[System.Collections.ArrayList] PreFader() {
return $this.Getter(0)
}
[System.Collections.ArrayList] PostFader() {
return $this.Getter(1)
}
[System.Collections.ArrayList] PostMute() {
return $this.Getter(2)
} }
} }
class PhysicalStrip : Strip { class PhysicalStrip : Strip {
[Object]$comp
[Object]$gate
[Object]$denoiser
[Object]$eq
[Object]$device
PhysicalStrip ([int]$index, [Object]$remote) : base ($index, $remote) { PhysicalStrip ([int]$index, [Object]$remote) : base ($index, $remote) {
AddFloatMembers -PARAMS @('comp', 'gate', 'color_x', 'color_y', 'fx_x', 'fx_y') AddFloatMembers -PARAMS @('color_x', 'color_y', 'fx_x', 'fx_y')
AddFloatMembers -PARAMS @('reverb', 'delay', 'fx1', 'fx2') AddFloatMembers -PARAMS @('reverb', 'delay', 'fx1', 'fx2')
AddBoolMembers -PARAMS @('postreverb', 'postdelay', 'postfx1', 'postfx2') AddBoolMembers -PARAMS @('postreverb', 'postdelay', 'postfx1', 'postfx2')
$this.comp = [StripComp]::new($index, $remote)
$this.gate = [StripGate]::new($index, $remote)
$this.denoiser = [StripDenoiser]::new($index, $remote)
$this.eq = [StripEq]::new($index, $remote)
$this.device = [StripDevice]::new($index, $remote)
}
} }
hidden $_device = $($this | Add-Member ScriptProperty 'device' ` class StripComp : IStrip {
StripComp ([int]$index, [Object]$remote) : base ($index, $remote) {
AddFloatMembers -PARAMS @('gainin', 'ratio', 'threshold', 'attack', 'release', 'knee', 'gainout')
AddBoolMembers -PARAMS @('makeup')
}
[string] identifier () {
return "Strip[" + $this.index + "].Comp"
}
hidden $_knob = $($this | Add-Member ScriptProperty 'knob' `
{ {
$this.Getter_String($this.cmd('device.name')) $this.Getter_String('')
} ` } `
{ {
return Write-Warning ("ERROR: " + $this.cmd('device.name') + " is read only") param($arg)
return $this.Setter('', $arg)
}
)
}
class StripGate : IStrip {
StripGate ([int]$index, [Object]$remote) : base ($index, $remote) {
AddFloatMembers -PARAMS @('threshold', 'damping', 'bpsidechain', 'attack', 'hold', 'release')
}
[string] identifier () {
return "Strip[" + $this.index + "].Gate"
}
hidden $_knob = $($this | Add-Member ScriptProperty 'knob' `
{
$this.Getter_String('')
} `
{
param($arg)
return $this.Setter('', $arg)
}
)
}
class StripDenoiser : IStrip {
StripDenoiser ([int]$index, [Object]$remote) : base ($index, $remote) {
}
[string] identifier () {
return "Strip[" + $this.index + "].Denoiser"
}
hidden $_knob = $($this | Add-Member ScriptProperty 'knob' `
{
$this.Getter_String('')
} `
{
param($arg)
return $this.Setter('', $arg)
}
)
}
class StripEq : IStrip {
StripEq ([int]$index, [Object]$remote) : base ($index, $remote) {
AddBoolMembers -PARAMS @('on', 'ab')
}
[string] identifier () {
return "Strip[" + $this.index + "].EQ"
}
}
class StripDevice : IStrip {
StripDevice ([int]$index, [Object]$remote) : base ($index, $remote) {
}
[string] identifier () {
return "Strip[" + $this.index + "].Device"
}
hidden $_name = $($this | Add-Member ScriptProperty 'name' `
{
$this.Getter_String('name')
} `
{
return Write-Warning ("ERROR: $($this.identifier()).name is read only")
} }
) )
hidden $_sr = $($this | Add-Member ScriptProperty 'sr' ` hidden $_sr = $($this | Add-Member ScriptProperty 'sr' `
{ {
$this.Getter($this.cmd('device.sr')) $this.Getter('sr')
} ` } `
{ {
return Write-Warning ("ERROR: " + $this.cmd('device.sr') + " is read only") return Write-Warning ("ERROR: $($this.identifier()).sr is read only")
}
)
hidden $_wdm = $($this | Add-Member ScriptProperty 'wdm' `
{
return Write-Warning ("ERROR: $($this.identifier()).wdm is write only")
} `
{
param($arg)
return $this.Setter('wdm', $arg)
}
)
hidden $_ks = $($this | Add-Member ScriptProperty 'ks' `
{
return Write-Warning ("ERROR: $($this.identifier()).ks is write only")
} `
{
param($arg)
return $this.Setter('ks', $arg)
}
)
hidden $_mme = $($this | Add-Member ScriptProperty 'mme' `
{
return Write-Warning ("ERROR: $($this.identifier()).mme is write only")
} `
{
param($arg)
return $this.Setter('mme', $arg)
}
)
hidden $_asio = $($this | Add-Member ScriptProperty 'asio' `
{
return Write-Warning ("ERROR: $($this.identifier()).asio is write only")
} `
{
param($arg)
return $this.Setter('asio', $arg)
} }
) )
} }
@@ -77,6 +270,14 @@ class VirtualStrip : Strip {
AddBoolMembers -PARAMS @('mc') AddBoolMembers -PARAMS @('mc')
AddIntMembers -PARAMS @('k') AddIntMembers -PARAMS @('k')
} }
[void] AppGain ([string]$appname, [single]$gain) {
$this.Setter('AppGain', "(`"$appname`", $gain)")
}
[void] AppMute ([string]$appname, [bool]$mutestate) {
$this.Setter('AppMute', "(`"$appname`", $(if ($mutestate) { 1 } else { 0 })")
}
} }

View File

@@ -1,70 +1,86 @@
class Vban { class IVban {
[int32]$index [int32]$index
[Object]$remote
[string]$direction [string]$direction
# Constructor IVban ([int]$index, [Object]$remote, [string]$direction) {
Vban ([int]$index) {
$this.index = $index $this.index = $index
$this.remote = $remote
$this.direction = $direction
}
[string] identifier () {
return "vban." + $this.direction + "stream[" + $this.index + "]"
}
[single] Getter ($param) {
return $this.remote.Getter($this.Cmd($param))
}
[string] Getter_String ($param) {
$this.Cmd($param) | Write-Debug
return $this.remote.Getter_String($this.Cmd($param))
}
[void] Setter ($param, $val) {
"$($this.Cmd($param))=$val" | Write-Debug
$this.remote.Setter($this.Cmd($param), $val)
}
[string] Cmd ($param) {
if ([string]::IsNullOrEmpty($param)) {
return $this.identifier()
}
return "$($this.identifier()).$param"
}
}
class Vban : IVban {
Vban ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote, $direction) {
} }
[string] ToString() { [string] ToString() {
return $this.GetType().Name + $this.index return $this.GetType().Name + $this.index
} }
[single] Getter ($cmd) {
return Param_Get -PARAM $cmd -IS_STRING $false
}
[string] Getter_String ($cmd) {
return Param_Get -PARAM $cmd -IS_STRING $true
}
[void] Setter ($cmd, $set) {
Param_Set -PARAM $cmd -Value $set
}
[string] cmd ($arg) {
return "vban." + $this.direction + "stream[" + $this.index + "].$arg"
}
hidden $_on = $($this | Add-Member ScriptProperty 'on' ` hidden $_on = $($this | Add-Member ScriptProperty 'on' `
{ {
$this.Getter($this.cmd('on')) $this.Getter('on')
} ` } `
{ {
param([bool]$arg) param([bool]$arg)
$this._on = $this.Setter($this.cmd('on'), $arg) $this._on = $this.Setter('on', $arg)
} }
) )
hidden $_name = $($this | Add-Member ScriptProperty 'name' ` hidden $_name = $($this | Add-Member ScriptProperty 'name' `
{ {
$this.Getter_String($this.cmd('name')) $this.Getter_String('name')
} ` } `
{ {
param([string]$arg) param([string]$arg)
$this._name = $this.Setter($this.cmd('name'), $arg) $this._name = $this.Setter('name', $arg)
} }
) )
hidden $_ip = $($this | Add-Member ScriptProperty 'ip' ` hidden $_ip = $($this | Add-Member ScriptProperty 'ip' `
{ {
$this.Getter_String($this.cmd('ip')) $this.Getter_String('ip')
} ` } `
{ {
param([string]$arg) param([string]$arg)
$this._ip = $this.Setter($this.cmd('ip'), $arg) $this._ip = $this.Setter('ip', $arg)
} }
) )
hidden $_port = $($this | Add-Member ScriptProperty 'port' ` hidden $_port = $($this | Add-Member ScriptProperty 'port' `
{ {
$this.Getter($this.cmd('port')) $this.Getter('port')
} ` } `
{ {
param([string]$arg) param([string]$arg)
if ($arg -in 1024..65535) { if ($arg -ge 1024 -and $arg -le 65535) {
$this._port = $this.Setter($this.cmd('port'), $arg) $this._port = $this.Setter('port', $arg)
} }
else { else {
Write-Warning ('Expected value from 1024 to 65535') Write-Warning ('Expected value from 1024 to 65535')
@@ -74,7 +90,7 @@ class Vban {
hidden $_sr = $($this | Add-Member ScriptProperty 'sr' ` hidden $_sr = $($this | Add-Member ScriptProperty 'sr' `
{ {
$this.Getter($this.cmd('sr')) $this.Getter('sr')
} ` } `
{ {
param([int]$arg) param([int]$arg)
@@ -82,7 +98,7 @@ class Vban {
else { else {
$opts = @(11025, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000) $opts = @(11025, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000)
if ($opts.Contains($arg)) { if ($opts.Contains($arg)) {
$this._port = $this.Setter($this.cmd('sr'), $arg) $this._port = $this.Setter('sr', $arg)
} }
else { else {
Write-Warning ('Expected one of', $opts) Write-Warning ('Expected one of', $opts)
@@ -93,14 +109,14 @@ class Vban {
hidden $_channel = $($this | Add-Member ScriptProperty 'channel' ` hidden $_channel = $($this | Add-Member ScriptProperty 'channel' `
{ {
$this.Getter($this.cmd('channel')) $this.Getter('channel')
} ` } `
{ {
param([int]$arg) param([int]$arg)
if ($this.direction -eq "in") { Write-Warning ('Error, read only value') } if ($this.direction -eq "in") { Write-Warning ('Error, read only value') }
else { else {
if ($arg -in 1..8) { if ($arg -ge 1 -and $arg -le 8) {
$this._channel = $this.Setter($this.cmd('channel'), $arg) $this._channel = $this.Setter('channel', $arg)
} }
else { else {
Write-Warning ('Expected value from 1 to 8') Write-Warning ('Expected value from 1 to 8')
@@ -111,7 +127,7 @@ class Vban {
hidden $_bit = $($this | Add-Member ScriptProperty 'bit' ` hidden $_bit = $($this | Add-Member ScriptProperty 'bit' `
{ {
$val = if ($this.Getter($this.cmd('bit')) -eq 1) { 16 } else { 24 } $val = if ($this.Getter('bit') -eq 1) { 16 } else { 24 }
return $val return $val
} ` } `
{ {
@@ -120,7 +136,7 @@ class Vban {
else { else {
if (@(16, 24).Contains($arg)) { if (@(16, 24).Contains($arg)) {
$val = if ($arg -eq 16) { 1 } else { 2 } $val = if ($arg -eq 16) { 1 } else { 2 }
$this._bit = $this.Setter($this.cmd('bit'), $val) $this._bit = $this.Setter('bit', $val)
} }
else { else {
Write-Warning ('Expected value 16 or 24') Write-Warning ('Expected value 16 or 24')
@@ -131,14 +147,14 @@ class Vban {
hidden $_quality = $($this | Add-Member ScriptProperty 'quality' ` hidden $_quality = $($this | Add-Member ScriptProperty 'quality' `
{ {
$this.Getter($this.cmd('quality')) $this.Getter('quality')
} ` } `
{ {
param([int]$arg) param([int]$arg)
if ($this.direction -eq "in") { Write-Warning ('Error, read only value') } if ($this.direction -eq "in") { Write-Warning ('Error, read only value') }
else { else {
if ($arg -in 0..4) { if ($arg -ge 0 -and $arg -le 4) {
$this._quality = $this.Setter($this.cmd('quality'), $arg) $this._quality = $this.Setter('quality', $arg)
} }
else { else {
Write-Warning ('Expected value from 0 to 4') Write-Warning ('Expected value from 0 to 4')
@@ -149,14 +165,14 @@ class Vban {
hidden $_route = $($this | Add-Member ScriptProperty 'route' ` hidden $_route = $($this | Add-Member ScriptProperty 'route' `
{ {
$this.Getter($this.cmd('route')) $this.Getter('route')
} ` } `
{ {
param([int]$arg) param([int]$arg)
if ($this.direction -eq "in") { Write-Warning ('Error, read only value') } if ($this.direction -eq "in") { Write-Warning ('Error, read only value') }
else { else {
if ($arg -in 0..8) { if ($arg -ge 0 -and $arg -le 8) {
$this._route = $this.Setter($this.cmd('route'), $arg) $this._route = $this.Setter('route', $arg)
} }
else { else {
Write-Warning ('Expected value from 0 to 8') Write-Warning ('Expected value from 0 to 8')
@@ -168,17 +184,13 @@ class Vban {
class VbanInstream : Vban { class VbanInstream : Vban {
# Constructor VbanInstream ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote, $direction) {
VbanInstream ([int]$index) : base ($index) {
$this.direction = "in"
} }
} }
class VbanOutstream : Vban { class VbanOutstream : Vban {
# Constructor VbanOutstream ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote, $direction) {
VbanOutstream ([int]$index) : base ($index) {
$this.direction = "out"
} }
} }
@@ -188,10 +200,10 @@ function Make_Vban ([Object]$remote) {
[System.Collections.ArrayList]$outstream = @() [System.Collections.ArrayList]$outstream = @()
0..$($remote.kind.vban_in - 1) | ForEach-Object { 0..$($remote.kind.vban_in - 1) | ForEach-Object {
[void]$instream.Add([VbanInstream]::new($_)) [void]$instream.Add([VbanInstream]::new($_, $remote, "in"))
} }
0..$($remote.kind.vban_out - 1) | ForEach-Object { 0..$($remote.kind.vban_out - 1) | ForEach-Object {
[void]$outstream.Add([VbanOutstream]::new($_)) [void]$outstream.Add([VbanOutstream]::new($_, $remote, "out"))
} }
$CustomObject = [pscustomobject]@{ $CustomObject = [pscustomobject]@{

View File

@@ -27,12 +27,23 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
} }
} }
Context 'physical only' -ForEach @(
@{ Index = $phys_in }
){
Context 'eq.{param}' -Skip:$ifNotPotato {
It "Should set Strip[$index].EQ.On to $value" {
$vmr.strip[$index].eq.on = $value
$vmr.strip[$index].eq.on | Should -Be $expected
}
}
}
Context 'Bus, one physical one virtual' -ForEach @( Context 'Bus, one physical one virtual' -ForEach @(
@{ Index = $phys_out }, @{ Index = $virt_out } @{ Index = $phys_out }, @{ Index = $virt_out }
){ ){
It "Should set and get Bus[$index].Eq" -Skip:$ifBasic { It "Should set and get Bus[$index].Eq.On" -Skip:$ifBasic {
$vmr.bus[$index].eq = $value $vmr.bus[$index].eq.on = $value
$vmr.bus[$index].eq | Should -Be $expected $vmr.bus[$index].eq.on | Should -Be $expected
} }
It "Should set and get Bus[$index].Mono" { It "Should set and get Bus[$index].Mono" {
@@ -40,14 +51,14 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
$vmr.bus[$index].mono | Should -Be $expected $vmr.bus[$index].mono | Should -Be $expected
} }
It "Should set and get Bus[$index].mode_amix" -Skip:$ifBasic { It "Should set and get Bus[$index].mode.amix" -Skip:$ifBasic {
$vmr.bus[$index].mode_amix = $value $vmr.bus[$index].mode.amix = $value
$vmr.bus[$index].mode_amix | Should -Be $expected $vmr.bus[$index].mode.amix | Should -Be $expected
} }
It "Should set and get Bus[$index].mode_centeronly" -Skip:$ifBasic { It "Should set and get Bus[$index].mode.centeronly" -Skip:$ifBasic {
$vmr.bus[$index].mode_centeronly = $value $vmr.bus[$index].mode.centeronly = $value
$vmr.bus[$index].mode_centeronly | Should -Be $expected $vmr.bus[$index].mode.centeronly | Should -Be $expected
} }
} }
@@ -123,13 +134,58 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
@{ Value = 8.3; Expected = 8.3 }, @{ Value = 5.1; Expected = 5.1 } @{ Value = 8.3; Expected = 8.3 }, @{ Value = 5.1; Expected = 5.1 }
){ ){
It "Should set Strip[$index].Comp to $value" { It "Should set Strip[$index].Comp to $value" {
$vmr.strip[$index].comp = $value $vmr.strip[$index].comp.knob = $value
$vmr.strip[$index].comp | Should -Be $expected $vmr.strip[$index].comp.knob | Should -Be $expected
} }
It "Should set Strip[$index].Gate to $value" { It "Should set Strip[$index].Gate to $value" {
$vmr.strip[$index].gate = $value $vmr.strip[$index].gate.knob = $value
$vmr.strip[$index].gate | Should -Be $expected $vmr.strip[$index].gate.knob | Should -Be $expected
}
}
Context 'denoiser' -Skip:$ifNotPotato -ForEach @(
@{ Value = 8.3; Expected = 8.3 }, @{ Value = 5.1; Expected = 5.1 }
){
It "Should set Strip[$index].Denoiser to $value" {
$vmr.strip[$index].denoiser.knob = $value
$vmr.strip[$index].denoiser.knob | Should -Be $expected
}
}
Context 'comp.{param}' -Skip:$ifNotPotato -ForEach @(
@{ Value = 8.3; Expected = 8.3 }, @{ Value = 5.1; Expected = 5.1 }
){
It "Should set Strip[$index].Comp.Attack to $value" {
$vmr.strip[$index].comp.attack = $value
$vmr.strip[$index].comp.attack | Should -Be $expected
}
}
Context 'comp.{param}' -Skip:$ifNotPotato -ForEach @(
@{ Value = 0.3; Expected = 0.3 }, @{ Value = 0.8; Expected = 0.8 }
){
It "Should set Strip[$index].Comp.Knee to $value" {
$vmr.strip[$index].comp.knee = $value
$vmr.strip[$index].comp.knee | Should -Be $expected
}
}
Context 'gate.{param}' -Skip:$ifNotPotato -ForEach @(
@{ Value = 103; Expected = 103 }, @{ Value = 3800; Expected = 3800 }
){
It "Should set Strip[$index].Gate.BPSidechain to $value" {
$vmr.strip[$index].gate.bpsidechain = $value
$vmr.strip[$index].gate.bpsidechain | Should -Be $expected
}
}
Context 'gate.{param}' -Skip:$ifNotPotato -ForEach @(
@{ Value = 0.3; Expected = 0.3 }, @{ Value = 5000; Expected = 5000 }
){
It "Should set Strip[$index].Gate.Hold to $value" {
$vmr.strip[$index].gate.hold = $value
$vmr.strip[$index].gate.hold | Should -Be $expected
} }
} }
} }

View File

@@ -15,7 +15,7 @@ Function ParseLog {
} }
ForEach ($line in ` ForEach ($line in `
$(Get-content -Path "${logfile}")) { $(Get-Content -Path "${logfile}")) {
if ($line -match $PASSED_PATTERN) { if ($line -match $PASSED_PATTERN) {
$DATA["passed"] += $Matches[1] $DATA["passed"] += $Matches[1]
} }
@@ -32,13 +32,9 @@ Function ParseLog {
function main() { function main() {
try try {
{ $vmr = Connect-Voicemeeter -Kind $kind
switch ($kind) { $vmr.command.RunMacrobuttons() # ensure macrobuttons is running before we begin
"basic" { $vmr = Get-RemoteBasic }
"banana" { $vmr = Get-RemoteBanana }
"potato" { $vmr = Get-RemotePotato }
}
Write-Host "Running tests for $vmr" Write-Host "Running tests for $vmr"
# test boundaries by kind # test boundaries by kind
@@ -73,12 +69,8 @@ function main() {
if ($log) { Parselog -logfile $logfile } if ($log) { Parselog -logfile $logfile }
} }
finally finally { Disconnect-Voicemeeter }
{
$vmr.Logout()
}
} }
main
if ($MyInvocation.InvocationName -ne '.') { main }