52 Commits

Author SHA1 Message Date
16dd73231e Merge pull request #9 from pblivingston/patch-arraymembers
Patch and ArrayMember classes
2025-11-26 15:34:42 +00:00
pblivingston
15a977834d add a2 for basic
patch.outa2[i]
2025-11-26 10:01:32 -05:00
pblivingston
f3ed1de557 Update README.md
- correct postfxinsert
- correct examples
- better readability for patch arraymembers
2025-11-26 09:30:44 -05:00
pblivingston
54319924d0 update docs
manual tests all pass:
- asio[i].set($val)
- asio[i].get()
- outa2[i]-outa5[i].set($val)
- outa2[i]-outa5[i].get()

these require an asio device
2025-11-25 21:57:15 -05:00
4d54e0a15f Merge pull request #7 from pblivingston/iremote
Add IRemote abstract base class.
2025-11-26 02:33:58 +00:00
pblivingston
dce6f37bf1 Merge branch 'iremote' into patch-arraymembers 2025-11-25 21:32:31 -05:00
pblivingston
5fc5680c75 fix ToString 2025-11-25 21:29:45 -05:00
pblivingston
80869d4306 tests
pester tests pass
2025-11-25 21:25:13 -05:00
pblivingston
e0b01288ff Update kinds.ps1 2025-11-25 20:43:31 -05:00
pblivingston
3a5c7286f6 Patch
Patch class with:
- Patch.asio[i]
- Patch.OutA2[i]-OutA5[i]
- Patch.composite[i]
- Patch.insert[i]
- Patch.postFaderComposite
- Patch.postFxInsert
2025-11-25 20:38:57 -05:00
pblivingston
c086f58ade ArrayMember classes 2025-11-25 18:54:36 -05:00
pblivingston
e5137b842b Update CHANGELOG.md 2025-11-25 16:44:16 -05:00
pblivingston
78f7fc80d4 vban
implement iremote
2025-11-25 16:39:44 -05:00
pblivingston
62d9e89b5f strip
implement iremote
2025-11-25 16:33:04 -05:00
pblivingston
a6f7d8efe0 recorder
implement iremote
2025-11-25 16:05:13 -05:00
pblivingston
b372cf8087 Update command.ps1
forgot to pass to base
2025-11-25 15:59:39 -05:00
pblivingston
eeb30925fa command
implement iremote
2025-11-25 15:40:15 -05:00
pblivingston
09d8bd48eb bus
implement iremote
2025-11-25 15:35:00 -05:00
pblivingston
b0a6bf7b63 nullable index
make index nullable so ToString can append the index for indexed objects
2025-11-25 15:32:27 -05:00
pblivingston
9a2529c617 module path in tests
change module path so we can run from /tests/
2025-11-25 15:25:40 -05:00
pblivingston
2404bfb50f create iremote.ps1 2025-11-25 14:39:10 -05:00
bd0779add2 add Taskfile
upd tasks in launch.json

add with Task to Run tests in README
2025-06-06 13:50:16 +01:00
a0a2c72634 run through formatter
rename pre-commit to run

remove num and log parameters
2025-06-06 13:49:35 +01:00
0f68a2373d run through formatter 2025-06-06 13:48:24 +01:00
2d6437d37b run through formatter 2025-06-06 13:48:11 +01:00
f199fa587f add Voicemeeter + OBS button example 2025-06-05 20:19:16 +01:00
b6c9c65390 update requirements with note about different scriptdeck versions 2025-06-05 20:10:19 +01:00
436b47a5db upd example 2025-06-05 16:43:30 +01:00
0cdd71600f reword 2025-06-05 01:58:02 +01:00
41529c0d58 add module installation note 2025-06-05 01:55:53 +01:00
b1a6ac68c1 add stream deck example README 2025-06-05 01:51:15 +01:00
fbfab5b4aa 3.3.0 section added to CHANGELOG
added dates for past versions
2024-06-29 10:03:32 +01:00
4d371a7582 Remove the 1 second wait from RunVoicemeeter
Write exception message to Debug
2024-06-29 07:13:11 +01:00
15b3b375bd md fix 2024-06-29 06:55:48 +01:00
c8abc6964a update RunVoicemeeter to launch x64 bit GUIs for all kinds
Keep testing login for up to 2 seconds.
If timeout exceeded throw VMRemoteError
2024-06-29 06:53:20 +01:00
907ee3e63b upd tested against 2024-06-28 11:12:01 +01:00
f3ed9c28c7 upd doc link 2024-01-03 09:38:22 +00:00
d305a4048d "\" -Join path parts 2023-08-17 15:02:03 +01:00
108731b4cf add RunMacrobuttons(), CloseMacrobuttons() 2023-08-17 03:19:05 +01:00
e7c648f1d0 fix function names 2023-08-17 03:05:32 +01:00
b21a71471b 3.2.0 section added to CHANGELOG 2023-08-17 02:57:24 +01:00
43367525c5 Errors section added to README 2023-08-17 02:56:38 +01:00
d0fbd6deef CAPIError properties renamed.
code and function better describe their meaning.
2023-08-17 02:54:30 +01:00
1df92afcfe check size of script 2023-08-17 02:53:01 +01:00
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
30 changed files with 889 additions and 651 deletions

5
.gitignore vendored
View File

@@ -1,7 +1,6 @@
# quick test
quick.ps1
lib/*.psd1 lib/*.psd1
**/*.log **/*.log
config.psd1 config.psd1
test-*.ps1

28
.vscode/launch.json vendored
View File

@@ -16,7 +16,9 @@
"\"!strip[0].mute\",", "\"!strip[0].mute\",",
"\"strip[0].mute\",", "\"strip[0].mute\",",
"\"bus[2].eq.on=1\",", "\"bus[2].eq.on=1\",",
"\"command.lock=1\"" "\"command.lock=1\"",
"-Verbose",
"-Debug"
], ],
"createTemporaryIntegratedConsole": true "createTemporaryIntegratedConsole": true
}, },
@@ -26,7 +28,10 @@
"request": "launch", "request": "launch",
"cwd": "${workspaceRoot}/examples/nextbus", "cwd": "${workspaceRoot}/examples/nextbus",
"script": "${workspaceFolder}/examples/nextbus/GoTo-NextBus.ps1", "script": "${workspaceFolder}/examples/nextbus/GoTo-NextBus.ps1",
"args": [], "args": [
"-Verbose",
"-Debug"
],
"createTemporaryIntegratedConsole": true "createTemporaryIntegratedConsole": true
}, },
{ {
@@ -35,7 +40,10 @@
"request": "launch", "request": "launch",
"cwd": "${workspaceRoot}/examples/obs", "cwd": "${workspaceRoot}/examples/obs",
"script": "${workspaceFolder}/examples/obs/Vm-Obs-Sync.ps1", "script": "${workspaceFolder}/examples/obs/Vm-Obs-Sync.ps1",
"args": [], "args": [
"-Verbose",
"-Debug"
],
"createTemporaryIntegratedConsole": true "createTemporaryIntegratedConsole": true
}, },
{ {
@@ -43,21 +51,9 @@
"type": "PowerShell", "type": "PowerShell",
"request": "launch", "request": "launch",
"cwd": "${workspaceRoot}", "cwd": "${workspaceRoot}",
"script": "${workspaceFolder}/tests/pre-commit.ps1", "script": "${workspaceFolder}/tests/run.ps1",
"args": [], "args": [],
"createTemporaryIntegratedConsole": true "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,10 +9,47 @@ 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] Level methods for Strip,Bus classes implemented. ### Added
- [x] More Recorder commands implemented.
## [3.0.0] - IRemote base class
- ArrayMember classes for array-like properties
- Patch class
## [3.3.0] - 2024-06-29
### Added
- Add a timeout (2s) to the login function. If timeout exceeded a VMRemoteError is thrown.
### Changed
- Launch x64 bit GUIs for all kinds if on 64 bit system.
## [3.2.0] - 2023-08-17
### Added
- Debug statements added to Getters, Setters in higher classes.
- RunVoicemeeter function added to base.ps1. Accepts kind name as parameter.
- Errors section to README.
### Fixed
- All CAPIErrors are now exposed to the consumer.
- The function name and error code can be retrieved using [CAPIError].function and [CAPIError].code
- Set_By_Script now throws [VMRemoteError] if script length exceeds 48kB.
- parameter range checks in Vban class.
## [3.1.0] - 2023-08-15
### 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] - 2023-08-09
v3 introduces some breaking changes. They are as follows: v3 introduces some breaking changes. They are as follows:

138
README.md
View File

@@ -8,9 +8,9 @@ For past/future changes to this project refer to: [CHANGELOG](CHANGELOG.md)
## Tested against ## Tested against
- Basic 1.0.8.8 - Basic 1.1.1.1
- Banana 2.0.6.8 - Banana 2.1.1.1
- Potato 3.0.2.8 - Potato 3.1.1.1
## Requirements ## Requirements
@@ -115,13 +115,13 @@ $vmr.Logout()
The following strip commands are available: The following strip commands are available:
- mute: boolean - mute: bool
- mono: boolean - mono: bool
- mc: boolean - mc: bool
- k: int, from 0 to 4 - k: int, from 0 to 4
- solo: boolean - solo: bool
- A1-A5: boolean - A1-A5: bool
- B1-B3: boolean - 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
- label: string - label: string
@@ -135,10 +135,10 @@ 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:
@@ -165,7 +165,7 @@ The following strip.comp commands are available:
- release: float, from 0.0 to 5000.0 - release: float, from 0.0 to 5000.0
- knee: float, 0.0 to 1.0 - knee: float, 0.0 to 1.0
- gainout: float, from -24.0 to 24.0 - gainout: float, from -24.0 to 24.0
- makeup: boolean - makeup: bool
for example: for example:
@@ -206,7 +206,7 @@ $vmr.strip[3].denoiser.knob = 5
#### AppGain | AppMute #### AppGain | AppMute
- `AppGain(amount, gain)` : string, float - `AppGain(amount, gain)` : string, float
- `AppMute(amount, mutestate)` : string, boolean - `AppMute(amount, mutestate)` : string, bool
for example: for example:
@@ -253,18 +253,18 @@ $vmr.bus[3].returnreverb = 5.7
The following bus.mode members are available: The following bus.mode members are available:
- normal: boolean - normal: bool
- amix: boolean - amix: bool
- bmix: boolean - bmix: bool
- repeat: boolean - repeat: bool
- composite: boolean - composite: bool
- tvmix: boolean - tvmix: bool
- upmix21: boolean - upmix21: bool
- upmix41: boolean - upmix41: bool
- upmix61: boolean - upmix61: bool
- centeronly: boolean - centeronly: bool
- lfeonly: boolean - lfeonly: bool
- rearonly: boolean - rearonly: bool
The following bus.mode commands are available: The following bus.mode commands are available:
@@ -317,8 +317,8 @@ wdm, ks, mme, asio are defined as write only.
The following strip.eq | bus.eq commands are available: The following strip.eq | bus.eq commands are available:
- on: boolean - on: bool
- ab: boolean - ab: bool
for example: for example:
@@ -359,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.
@@ -396,12 +396,14 @@ The following commands are available:
- hide - hide
- restart - restart
- shutdown - shutdown
- showvbanchat: boolean (write only) - showvbanchat: bool, (write only)
- lock: boolean (write only) - lock: bool, (write only)
The following methods are available: The following methods are available:
- Load($filepath): string - Load($filepath): string
- RunMacrobuttons(): Launches the macrobuttons app
- CloseMacrobuttons(): Closes the macrobuttons app
example: example:
@@ -411,6 +413,31 @@ $vmr.command.show
$vmr.command.lock = $true $vmr.command.lock = $true
$vmr.command.Load("path/to/filename.xml") $vmr.command.Load("path/to/filename.xml")
$vmr.command.RunMacrobuttons()
```
### Patch
The following Patch commands are available:
- postFaderComposite: bool
- postFxInsert: bool
The following Patch members have .Set($val) and .Get() available:
- asio[i]: int, from 0 to ASIO input channels
- OutA2[i]-OutA5[i]: int, from 0 to ASIO output channels
- composite[i]: int, from 0 to strip channels
- insert[i]: bool
for example:
```powershell
$vmr.patch.asio[3].set(2) # patches ASIO input channel 2 (2) to strip 2, channel 2 (3)
$vmr.patch.OutA3[0].set(24) # patches bus A3, channel 1 (0) to ASIO output channel 24
$vmr.patch.composite[5].set(0) # sets composite channel 6 (5) to default bus channel
$vmr.patch.insert[4].get()
``` ```
### Recorder ### Recorder
@@ -423,12 +450,12 @@ The following commands are available:
- record - record
- ff - ff
- rew - rew
- A1 - A5: boolean - A1 - A5: bool
- B1 - B3: boolean - B1 - B3: bool
- samplerate: int (22050, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000) - samplerate: int, (22050, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000)
- bitresolution: int (8, 16, 24, 32) - bitresolution: int, (8, 16, 24, 32)
- channel: int from 1 to 8 - channel: int, from 1 to 8
- kbps: int (32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320) - kbps: int, (32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320)
The following methods are available: The following methods are available:
@@ -464,7 +491,7 @@ $vmr.recorder.mode.loop = $true
The following method is available: The following method is available:
- Set($val): boolean - Set($val): bool
example: example:
@@ -542,19 +569,28 @@ Access to lower level polling functions are provided with these functions:
- `$vmr.PDirty`: Returns true if a parameter has been updated. - `$vmr.PDirty`: Returns true if a parameter has been updated.
- `$vmr.MDirty`: Returns true if a macrobutton has been updated. - `$vmr.MDirty`: Returns true if a macrobutton has been updated.
### Errors
- `VMRemoteError`: Base custom error class.
- `LoginError`: Raised when a login error occurs.
- `CAPIError`: Raised when a C-API function returns an error code.
- The following class properties are available:
- `function`: The name of the C-API function that returned the error code.
- `code`: The error code.
### Run tests ### Run tests
Run tests using .\tests\pre-commit.ps1 which accepts the following parameters: Parameters:
- `kind`: Run tests of this kind - `kind`: Run tests of this kind
- `tag`: Run tests tagged with this marker (currently `higher` or `lower`) - `tag`: Run tests tagged with this marker (currently `higher` or `lower`)
- `num`: Run this number of tests
- `log`: Write summary log file
Run tests from repository root in a subshell and write logs, like so: *with Task*
`powershell .\tests\pre-commit.ps1 -k "potato" -t "higher" -log` ```console
task test -- -t "higher" -k "banana"
```
### Official Documentation ### Official Documentation
- [Voicemeeter Remote C API](https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/update-docs/VoicemeeterRemoteAPI.pdf) - [Voicemeeter Remote C API](https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/main/VoicemeeterRemoteAPI.pdf)

11
Taskfile.yaml Normal file
View File

@@ -0,0 +1,11 @@
version: '3'
tasks:
test:
desc: 'Run tests'
preconditions:
- sh: 'pwsh -c "if ([System.Version](Get-InstalledModule Pester).Version.ToString() -gt [System.Version]"5.7.0") { exit 0 } else { exit 1 }"'
msg: 'Pester version must be greater than 5.7.0'
cmds:
- echo "Running tests..."
- pwsh -c "tests\run.ps1 {{.CLI_ARGS}}"

View File

@@ -1,14 +1,12 @@
[cmdletbinding()]
param( param(
[switch]$interactive, [switch]$interactive,
[switch]$output, [String]$kind = 'banana',
[String]$kind = "banana",
[String[]]$script = @() [String[]]$script = @()
) )
Import-Module ..\..\lib\Voicemeeter.psm1 Import-Module ..\..\lib\Voicemeeter.psm1
$VerbosePreference = "Continue"
function get-value { function get-value {
param([object]$vmr, [string]$line) param([object]$vmr, [string]$line)
try { try {
@@ -22,20 +20,20 @@ function get-value {
function msgHandler { 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
} }
} }
@@ -52,7 +50,7 @@ function main {
$vmr = Connect-Voicemeeter -Kind $kind $vmr = Connect-Voicemeeter -Kind $kind
if ($interactive) { if ($interactive) {
"Press <Enter> to exit" | Write-Host 'Press <Enter> to exit' | Write-Host
read-hostuntilempty -vmr $vmr read-hostuntilempty -vmr $vmr
return return
} }

View File

@@ -7,27 +7,30 @@
Credits go to @bobsupercow Credits go to @bobsupercow
#> #>
[cmdletbinding()]
param()
Import-Module ..\..\lib\Voicemeeter.psm1 Import-Module ..\..\lib\Voicemeeter.psm1
$VerbosePreference = "Continue"
try { try {
$vmr = Connect-Voicemeeter -Kind "potato" $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)
'Cycling through bus selection to check for first unmuted Bus...' | Write-Host
foreach ($bus in $buses) { 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
} }
@@ -37,7 +40,7 @@ try {
# 4) # 4)
if ($null -eq $unmutedIndex) { if ($null -eq $unmutedIndex) {
$buses[0].mute = $false $buses[0].mute = $false
"unmuting bus $($buses[0].index)" | Write-Host "Unmuting Bus $($buses[0].index)" | Write-Host
} }
} }

View File

@@ -1,36 +1,33 @@
[cmdletbinding()]
param()
Import-Module ..\..\lib\Voicemeeter.psm1 Import-Module ..\..\lib\Voicemeeter.psm1
Import-Module obs-powershell Import-Module obs-powershell
$VerbosePreference = "Continue"
function CurrentProgramSceneChanged { function CurrentProgramSceneChanged {
param([System.Object]$data) param([System.Object]$data)
Write-Host "Switched to scene", $data.sceneName Write-Host 'Switched to scene', $data.sceneName
switch ($data.sceneName) { switch ($data.sceneName) {
"START" { 'START' {
$vmr.strip[0].mute = !$vmr.strip[0].mute $vmr.strip[0].mute = !$vmr.strip[0].mute
"Toggling Strip 0 mute"
} }
"BRB" { 'BRB' {
$vmr.strip[0].gain = -8.3 $vmr.strip[0].gain = -8.3
"Setting Strip 0 gain to -8.3"
} }
"END" { 'END' {
$vmr.strip[0].mono = $true $vmr.strip[0].mono = $true
"Setting Strip 0 mono to `$true"
} }
"LIVE" { 'LIVE' {
$vmr.strip[0].color_x = 0.3 $vmr.strip[0].color_x = 0.3
"Setting Strip 0 color_x to 0.3"
} }
default { "Expected START, BRB, END or LIVE scene" | Write-Warning; return } default { 'Expected START, BRB, END or LIVE scene' | Write-Warning; return }
} }
} }
function ExitStarted { function ExitStarted {
param([System.Object]$data) param([System.Object]$data)
"OBS shutdown has begun!" | Write-Host 'OBS shutdown has begun!' | Write-Host
break break
} }
@@ -41,12 +38,12 @@ function eventHandler($data) {
} }
function ConnFromFile { function ConnFromFile {
$configpath = Join-Path $PSScriptRoot "config.psd1" $configpath = Join-Path $PSScriptRoot 'config.psd1'
return Import-PowerShellDataFile -Path $configpath return Import-PowerShellDataFile -Path $configpath
} }
function main { function main {
$vmr = Connect-Voicemeeter -Kind "basic" $vmr = Connect-Voicemeeter -Kind 'basic'
$conn = ConnFromFile $conn = ConnFromFile
$job = Watch-OBS -WebSocketURI "ws://$($conn.host):$($conn.port)" -WebSocketToken $conn.password $job = Watch-OBS -WebSocketURI "ws://$($conn.host):$($conn.port)" -WebSocketToken $conn.password

View File

@@ -0,0 +1,125 @@
# About
Thanks to the guys at [Start Automating](https://startautomating.com/) it's possible to use this module straight from your Stream Deck.
## Requirements
### ScriptDeck
*Windows Powershell*
- [Windows ScriptDeck](https://marketplace.elgato.com/product/windows-scriptdeck-857f01dd-8fd4-44d5-8ec7-67ac850b21d3)
*Powershell core*
- [ScriptDeck](https://marketplace.elgato.com/product/scriptdeck-927e59aa-b42d-4da7-84cc-8c78f4dd7e18)
Note, even though one of them is named Windows they both work on Windows for different powershell versions, see [this issue](https://github.com/StartAutomating/ScriptDeck/issues/120)
### Voicemeeter API Powershell
- Install it as a module, see [Installation](https://github.com/onyx-and-iris/voicemeeter-api-powershell?tab=readme-ov-file#installation)
## How
Once ScriptDeck is installed create a button using *Powershell Script*, then:
### On one button
Due to the design of Voicemeeter's API you may only login/logout once per session so in order to program multiple buttons you must do the following for just ONE button (it can be any button).
#### Button 1
*When Loaded*
```powershell
$global:vmr = Connect-Voicemeeter -Kind "banana"
```
*When Unloaded*
```powershell
Disconnect-Voicemeeter
```
*When Pressed*
```powershell
if ($vmr.strip[0].mute) {
$vmr.bus[0].mute=1
$vmr.bus[1].mute=1
} else {
$vmr.bus[0].mute=0
$vmr.bus[1].mute=0
}
```
### Other buttons
Then your other buttons can have any scripts using the `$vmr` object:
#### Button 2
*When Pressed*
```powershell
$vmr.strip[1].mute=1
$vmr.strip[2].mute=1
if (-not $vmr.strip[0].mute) {
$vmr.strip[0].mute=1
}
```
#### Button 3
*When Pressed*
```powershell
$vmr.strip[0].mute=$(-not $vmr.strip[0].mute)
$vmr.strip[1].mute=$(-not $vmr.strip[1].mute)
$vmr.strip[2].mute=$(-not $vmr.strip[2].mute)
```
---
Then let's say you have zillions of buttons you want to program, for each Stream Deck window configure ONE button as described above and the other buttons of the same window as described above.
If this explanation is unclear or you'd like me to add some screenshots just ask.
## Leveraging Powershell
Since we're now working with Powershell we can do some useful things, for example, lets create a button that interacts with Voicemeeter and OBS:
First make sure you've installed [obs-powershell](https://github.com/StartAutomating/obs-powershell).
Now let's create a button that only toggles some strip mutes if the current OBS scene is "LIVE".
#### Button
*When Loaded*
```powershell
$global:vmr = Connect-Voicemeeter -Kind "banana"
Connect-OBS -WebSocketToken <websocket token>
```
*When Unloaded*
```powershell
Disconnect-Voicemeeter
Disconnect-OBS
```
*When Pressed*
```powershell
$currentScene = $(Get-OBSCurrentProgramScene | Select-Object -ExpandProperty currentProgramSceneName)
if ($currentScene -eq "LIVE") {
$vmr.strip[0].mute=$(-not $vmr.strip[0].mute)
$vmr.strip[1].mute=$(-not $vmr.strip[1].mute)
$vmr.strip[2].mute=$(-not $vmr.strip[2].mute)
}
```

View File

@@ -1,20 +1,31 @@
. $PSScriptRoot\kinds.ps1 . $PSScriptRoot\errors.ps1
. $PSScriptRoot\meta.ps1
. $PSScriptRoot\base.ps1 . $PSScriptRoot\base.ps1
. $PSScriptRoot\kinds.ps1
. $PSScriptRoot\iremote.ps1
. $PSScriptRoot\arraymember.ps1
. $PSScriptRoot\strip.ps1
. $PSScriptRoot\bus.ps1
. $PSScriptRoot\macrobuttons.ps1
. $PSScriptRoot\vban.ps1
. $PSScriptRoot\command.ps1
. $PSScriptRoot\recorder.ps1
. $PSScriptRoot\patch.ps1
. $PSScriptRoot\profiles.ps1
class Remote { class Remote {
[String]$vmpath
[Hashtable]$kind [Hashtable]$kind
[Object]$profiles [Object]$profiles
Remote ([String]$kindId) { Remote ([String]$kindId) {
if (!(Setup_DLL)) { $this.vmpath = Setup_DLL
Exit -1
}
$this.kind = GetKind($kindId) $this.kind = GetKind($kindId)
$this.profiles = Get_Profiles($this.kind.name) $this.profiles = Get_Profiles($this.kind.name)
} }
[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() { [Remote] Login() {
@@ -31,7 +42,7 @@ class Remote {
} }
[String] GetVersion() { [String] GetVersion() {
return Version return VmVersion
} }
[void] Set_Profile([String]$config) { [void] Set_Profile([String]$config) {
@@ -69,6 +80,7 @@ class RemoteBasic : Remote {
[System.Collections.ArrayList]$button [System.Collections.ArrayList]$button
[PSCustomObject]$vban [PSCustomObject]$vban
[Object]$command [Object]$command
[Object]$patch
RemoteBasic () : base ('basic') { RemoteBasic () : base ('basic') {
$this.strip = Make_Strips($this) $this.strip = Make_Strips($this)
@@ -76,6 +88,7 @@ class RemoteBasic : Remote {
$this.button = Make_Buttons $this.button = Make_Buttons
$this.vban = Make_Vban($this) $this.vban = Make_Vban($this)
$this.command = Make_Command($this) $this.command = Make_Command($this)
$this.patch = Make_Patch($this)
} }
} }
@@ -85,6 +98,7 @@ class RemoteBanana : Remote {
[System.Collections.ArrayList]$button [System.Collections.ArrayList]$button
[PSCustomObject]$vban [PSCustomObject]$vban
[Object]$command [Object]$command
[Object]$patch
[Object]$recorder [Object]$recorder
RemoteBanana () : base ('banana') { RemoteBanana () : base ('banana') {
@@ -93,6 +107,7 @@ class RemoteBanana : Remote {
$this.button = Make_Buttons $this.button = Make_Buttons
$this.vban = Make_Vban($this) $this.vban = Make_Vban($this)
$this.command = Make_Command($this) $this.command = Make_Command($this)
$this.patch = Make_Patch($this)
$this.recorder = Make_Recorder($this) $this.recorder = Make_Recorder($this)
} }
} }
@@ -103,6 +118,7 @@ class RemotePotato : Remote {
[System.Collections.ArrayList]$button [System.Collections.ArrayList]$button
[PSCustomObject]$vban [PSCustomObject]$vban
[Object]$command [Object]$command
[Object]$patch
[Object]$recorder [Object]$recorder
RemotePotato () : base ('potato') { RemotePotato () : base ('potato') {
@@ -111,6 +127,7 @@ class RemotePotato : Remote {
$this.button = Make_Buttons $this.button = Make_Buttons
$this.vban = Make_Vban($this) $this.vban = Make_Vban($this)
$this.command = Make_Command($this) $this.command = Make_Command($this)
$this.patch = Make_Patch($this)
$this.recorder = Make_Recorder($this) $this.recorder = Make_Recorder($this)
} }
} }
@@ -129,24 +146,20 @@ Function Get-RemotePotato {
Function Connect-Voicemeeter { Function Connect-Voicemeeter {
param([String]$Kind) param([String]$Kind)
try {
switch ($Kind) { switch ($Kind) {
"basic" { 'basic' {
return Get-RemoteBasic return Get-RemoteBasic
} }
"banana" { 'banana' {
return Get-RemoteBanana return Get-RemoteBanana
} }
"potato" { 'potato' {
return Get-RemotePotato return Get-RemotePotato
} }
default { throw [LoginError]::new("Unknown Voicemeeter kind `"$Kind`"") } default {
throw [LoginError]::new("Unknown Voicemeeter kind `"$Kind`"")
} }
} }
catch [LoginError], [CAPIError] {
Write-Warning $_.Exception.ErrorMessage()
throw
}
} }
Function Disconnect-Voicemeeter { Function Disconnect-Voicemeeter {

64
lib/arraymember.ps1 Normal file
View File

@@ -0,0 +1,64 @@
class ArrayMember : IRemote {
[string]$prefix
[Object]$parent
ArrayMember (
[int]$index, [string]$prefix, [Object]$parent
) : base ($index, $parent.remote) {
$this.prefix = $prefix
$this.parent = $parent
}
[string] identifier () {
$parentId = $this.parent.identifier()
return "{0}.{1}[{2}]" -f $parentId, $this.prefix, $this.index
}
[void] Set ($val) {
$this.Setter('', $val)
}
}
class BoolArrayMember : ArrayMember {
BoolArrayMember (
[int]$index, [string]$prefix, [Object]$parent
) : base ($index, $prefix, $parent) {}
[bool] Get () {
return [bool]$this.Getter('')
}
}
class IntArrayMember : ArrayMember {
IntArrayMember (
[int]$index, [string]$prefix, [Object]$parent
) : base ($index, $prefix, $parent) {}
[int] Get () {
return [int]$this.Getter('')
}
}
class FloatArrayMember : ArrayMember {
[int]$decimals
FloatArrayMember (
[int]$index, [string]$prefix, [Object]$parent, [int]$decimals = 1
) : base ($index, $prefix, $parent) {
$this.decimals = $decimals
}
[double] Get () {
return [math]::Round($this.Getter(''), $this.decimals)
}
}
class StringArrayMember : ArrayMember {
StringArrayMember (
[int]$index, [string]$prefix, [Object]$parent
) : base ($index, $prefix, $parent) {}
[string] Get () {
return [string]$this.Getter_String('')
}
}

View File

@@ -1,85 +1,108 @@
. $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]$kindId [string]$kindId
) )
try {
$retval = [int][Voicemeeter.Remote]::VBVMR_Login() $retval = [int][Voicemeeter.Remote]::VBVMR_Login()
if (-not $retval) { if ($retval -notin @(0, 1, -2)) {
"LOGGED IN" | Write-Verbose throw [CAPIError]::new($retval, 'VBVMR_Login')
}
elseif ($retval -eq 1) {
"VM NOT RUNNING" | Write-Verbose
New-Variable -Name vmExe -Value 0
if ( $kindId -eq "basic" ) { $vmExe = 1 }
elseif ( $kindId -eq "banana" ) { $vmExe = 2 }
elseif ( $kindId -eq "potato" ) {
$vmExe = $(if ([Environment]::Is64BitOperatingSystem) { 6 } else { 3 })
} }
$retval = [int][Voicemeeter.Remote]::VBVMR_RunVoicemeeter([int64]$vmExe) switch ($retval) {
if (-not $retval) { 1 {
"STARTING VOICEMEETER" | Write-Verbose 'Voicemeeter Engine running but GUI not launched. Launching GUI now.' | Write-Verbose
Start-Sleep -s 1 RunVoicemeeter -kindId $kindId
} }
else { -2 {
throw [CAPIError]::new($retval, $MyInvocation.MyCommand) throw [LoginError]::new('Login may only be called once per session.')
} }
} }
elseif ($retval -eq -2) {
throw [LoginError]::new('login may only be called once per session') $timeout = New-TimeSpan -Seconds 2
$sw = [diagnostics.stopwatch]::StartNew()
$exception = $null
do {
Start-Sleep -m 100
try {
'Successfully logged into Voicemeeter [' + $(VmType).ToUpper() + '] Version ' + $(VmVersion) | Write-Verbose
$exception = $null
break
} }
else { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) } catch [CAPIError] {
$exception = $_
$exception | Write-Debug
} }
catch [LoginError] { } while ($sw.elapsed -lt $timeout)
Write-Warning "$($_.Exception.ErrorMessage()). Fatal error, exiting..."
exit -2 if ($null -ne $exception) {
throw [VMRemoteError]::new('Timeout logging into the API.')
} }
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
} }
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' = $(if ([Environment]::Is64BitOperatingSystem) { 4 } else { 1 })
'banana' = $(if ([Environment]::Is64BitOperatingSystem) { 5 } else { 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')
}
} }
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_IsParametersDirty')
}
[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_MacroButton_IsDirty')
}
[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' }
3 { return "potato" } 3 { return 'potato' }
} }
} }
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
@@ -92,28 +115,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
} }
@@ -123,17 +140,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()
} }
} }
@@ -141,12 +158,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()
} }
} }
@@ -158,12 +172,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, 'VBVMR_MacroButton_GetStatus')
catch [CAPIError] {
Write-Warning $_.Exception.ErrorMessage()
} }
[int]$ptr [int]$ptr
} }
@@ -173,8 +184,8 @@ function Param_Set_Multi {
[hashtable]$HASH [hashtable]$HASH
) )
foreach ($key in $HASH.keys) { foreach ($key in $HASH.keys) {
$classobj, $m2, $m3 = $key.Split("_") $classobj, $m2, $m3 = $key.Split('_')
if ($m2 -match "^\d+$") { $index = [int]$m2 } else { $index = [int]$m3 } if ($m2 -match '^\d+$') { $index = [int]$m2 } else { $index = [int]$m3 }
foreach ($h in $HASH[$key].GetEnumerator()) { foreach ($h in $HASH[$key].GetEnumerator()) {
$property = $h.Name $property = $h.Name
@@ -195,12 +206,12 @@ function Set_By_Script {
param( param(
[string]$script [string]$script
) )
try { if ($script.Length -gt 48000) {
$retval = [int][Voicemeeter.Remote]::VBVMR_SetParameters($script) throw [VMRemoteError]::new('Script size cannot be larger than 48kB')
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) }
} }
catch [CAPIError] { $retval = [int][Voicemeeter.Remote]::VBVMR_SetParameters($script)
Write-Warning $_.Exception.ErrorMessage() if ($retval -notin @(0)) {
throw [CAPIError]::new($retval, 'VBVMR_SetParameters')
} }
} }
@@ -209,12 +220,9 @@ function Get_Level {
[int64]$MODE, [int64]$INDEX [int64]$MODE, [int64]$INDEX
) )
New-Variable -Name ptr -Value 0.0 New-Variable -Name ptr -Value 0.0
try {
$retval = [int][Voicemeeter.Remote]::VBVMR_GetLevel($MODE, $INDEX, [ref]$ptr) $retval = [int][Voicemeeter.Remote]::VBVMR_GetLevel($MODE, $INDEX, [ref]$ptr)
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) } if ($retval -notin @(0)) {
} throw [CAPIError]::new($retval, 'VBVMR_GetLevel')
catch [CAPIError] {
Write-Warning $_.Exception.ErrorMessage()
} }
[float]$ptr [float]$ptr
} }

View File

@@ -1,18 +1,11 @@
function Setup_DLL { . $PSScriptRoot\inst.ps1
try {
$vb_path = Get_VMPath
if ([string]::IsNullOrWhiteSpace($vb_path)) { function Setup_DLL {
throw [VMRemoteError]::new("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 [VMRemoteError] {
Write-Warning $_.Exception.ErrorMessage()
return $false
}
$Signature = @" $Signature = @"
[DllImport(@"$dll")] [DllImport(@"$dll")]
@@ -53,5 +46,5 @@ function Setup_DLL {
"@ "@
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,36 +1,4 @@
. $PSScriptRoot\meta.ps1 class Bus : IRemote {
class IBus {
[int]$index
[Object]$remote
IBus ([int]$index, [Object]$remote) {
$this.index = $index
$this.remote = $remote
}
[string] identifier () {
return "Bus[" + $this.index + "]"
}
[string] ToString() {
return $this.GetType().Name + $this.index
}
[single] Getter ($param) {
return $this.remote.Getter("$($this.identifier()).$param")
}
[string] Getter_String ($param) {
return $this.remote.Getter_String("$($this.identifier()).$param")
}
[void] Setter ($param, $val) {
$this.remote.Setter("$($this.identifier()).$param", $val)
}
}
class Bus : IBus {
[Object]$mode [Object]$mode
[Object]$eq [Object]$eq
[Object]$levels [Object]$levels
@@ -45,6 +13,10 @@ class Bus : IBus {
$this.levels = [BusLevels]::new($index, $remote) $this.levels = [BusLevels]::new($index, $remote)
} }
[string] identifier () {
return 'Bus[' + $this.index + ']'
}
[void] FadeTo ([single]$target, [int]$time) { [void] FadeTo ([single]$target, [int]$time) {
$this.Setter('FadeTo', "($target, $time)") $this.Setter('FadeTo', "($target, $time)")
} }
@@ -54,7 +26,7 @@ class Bus : IBus {
} }
} }
class BusLevels : IBus { class BusLevels : IRemote {
[int]$init [int]$init
[int]$offset [int]$offset
@@ -85,7 +57,7 @@ class BusLevels : IBus {
} }
} }
class BusMode : IBus { class BusMode : IRemote {
[System.Collections.ArrayList]$modes [System.Collections.ArrayList]$modes
BusMode ([int]$index, [Object]$remote) : base ($index, $remote) { BusMode ([int]$index, [Object]$remote) : base ($index, $remote) {
@@ -98,7 +70,7 @@ class BusMode : IBus {
} }
[string] identifier () { [string] identifier () {
return "Bus[" + $this.index + "].mode" return 'Bus[' + $this.index + '].mode'
} }
[string] Get () { [string] Get () {
@@ -111,13 +83,13 @@ class BusMode : IBus {
} }
} }
class BusEq : IBus { class BusEq : IRemote {
BusEq ([int]$index, [Object]$remote) : base ($index, $remote) { BusEq ([int]$index, [Object]$remote) : base ($index, $remote) {
AddBoolMembers -PARAMS @('on', 'ab') AddBoolMembers -PARAMS @('on', 'ab')
} }
[string] identifier () { [string] identifier () {
return "Bus[" + $this.index + "].EQ" return 'Bus[' + $this.index + '].EQ'
} }
} }
@@ -129,12 +101,12 @@ class PhysicalBus : Bus {
} }
} }
class BusDevice : IBus { class BusDevice : IRemote {
BusDevice ([int]$index, [Object]$remote) : base ($index, $remote) { BusDevice ([int]$index, [Object]$remote) : base ($index, $remote) {
} }
[string] identifier () { [string] identifier () {
return "Bus[" + $this.index + "].Device" return 'Bus[' + $this.index + '].Device'
} }
hidden $_name = $($this | Add-Member ScriptProperty 'name' ` hidden $_name = $($this | Add-Member ScriptProperty 'name' `

View File

@@ -1,42 +1,20 @@
. $PSScriptRoot\meta.ps1 class Special : IRemote {
. $PSScriptRoot\inst.ps1 Special ([Object]$remote) : base ($remote) {
class Special {
[Object]$remote
Special ([Object]$remote) {
AddActionMembers -PARAMS @('restart', 'shutdown', 'show') AddActionMembers -PARAMS @('restart', 'shutdown', 'show')
$this.remote = $remote
} }
[string] identifier () { [string] identifier () {
return "Command" return 'Command'
}
[string] ToString() {
return $this.GetType().Name
}
[single] Getter ($param) {
return $this.remote.Getter("$($this.identifier()).$param")
}
[void] Setter ($param, $val) {
if ($val -is [Boolean]) {
$this.remote.Setter("$($this.identifier()).$param", $(if ($val) { 1 } else { 0 }))
}
else {
$this.remote.Setter("$($this.identifier()).$param", $val)
}
} }
[void] RunMacrobuttons() { [void] RunMacrobuttons() {
Start-Process -FilePath $(Join-Path -Path $(Get_VMPath) -ChildPath "VoicemeeterMacroButtons.exe") 'Launching the MacroButtons app' | Write-Verbose
Start-Process -FilePath $(Join-Path -Path $this.remote.vmpath -ChildPath 'VoicemeeterMacroButtons.exe')
} }
[void] CloseMacrobuttons() { [void] CloseMacrobuttons() {
Stop-Process -Name "VoicemeeterMacroButtons" 'Closing the MacroButtons app' | Write-Verbose
Stop-Process -Name 'VoicemeeterMacroButtons'
} }
hidden $_hide = $($this | Add-Member ScriptProperty 'hide' ` hidden $_hide = $($this | Add-Member ScriptProperty 'hide' `

View File

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

View File

@@ -1,8 +1,19 @@
function Get_VMPath { function Get_VMPath {
$reg_path = "Registry::HKEY_LOCAL_MACHINE\Software" + ` $REG_KEY = @(
(& { if ([Environment]::Is64BitOperatingSystem) { "\WOW6432Node" } else { "" } }) + ` 'Registry::HKEY_LOCAL_MACHINE',
"\Microsoft\Windows\CurrentVersion\Uninstall" 'Software',
$vm_key = "\VB:Voicemeeter {17359A74-1236-5467}\" (& { if ([Environment]::Is64BitOperatingSystem) { 'WOW6432Node' } else { '' } }),
'Microsoft',
'Windows',
'CurrentVersion',
'Uninstall'
).Where({ $_ -ne '' }) -Join '\'
$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) -Join '\') -Name UninstallString | Split-Path -Parent)
}
catch {
throw [VMRemoteError]::new('Unable to fetch Voicemeeter path from the Registry.')
}
} }

52
lib/iremote.ps1 Normal file
View File

@@ -0,0 +1,52 @@
class IRemote {
[Nullable[int]]$index
[Object]$remote
IRemote ([Object]$remote) {
$this.remote = $remote
}
IRemote ([int]$index, [Object]$remote) {
$this.index = $index
$this.remote = $remote
}
[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
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"
}
# Must be overridden by derived classes
[string] identifier () {
throw [System.NotImplementedException]::new("$($this.GetType().Name) must override identifier()")
}
[string] ToString() {
if ($null -ne $this.index) {
return $this.GetType().Name + $this.index
}
return $this.GetType().Name
}
}

View File

@@ -1,30 +1,42 @@
$KindMap = @{ $KindMap = @{
"basic" = @{ 'basic' = @{
"name" = "basic" 'name' = 'basic'
"p_in" = 2 'p_in' = 2
"v_in" = 1 'v_in' = 1
"p_out" = 1 'p_out' = 1
"v_out" = 1 'v_out' = 1
"vban_in" = 4 'asio_in' = 4
"vban_out" = 4 'asio_out' = 8
'composite' = 0
'insert' = 0
'vban_in' = 4
'vban_out' = 4
}; };
"banana" = @{ 'banana' = @{
"name" = "banana" 'name' = 'banana'
"p_in" = 3 'p_in' = 3
"v_in" = 2 'v_in' = 2
"p_out" = 3 'p_out' = 3
"v_out" = 2 'v_out' = 2
"vban_in" = 8 'asio_in' = 6
"vban_out" = 8 'asio_out' = 8
'composite' = 8
'insert' = 22
'vban_in' = 8
'vban_out' = 8
}; };
"potato" = @{ 'potato' = @{
"name" = "potato" 'name' = 'potato'
"p_in" = 5 'p_in' = 5
"v_in" = 3 'v_in' = 3
"p_out" = 5 'p_out' = 5
"v_out" = 3 'v_out' = 3
"vban_in" = 8 'asio_in' = 10
"vban_out" = 8 'asio_out' = 8
'composite' = 8
'insert' = 34
'vban_in' = 8
'vban_out' = 8
}; };
} }

View File

@@ -1,3 +1,9 @@
enum ButtonTypes {
State = 1
StateOnly = 2
Trigger = 3
}
class MacroButton { class MacroButton {
[int32]$index [int32]$index
@@ -10,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' `
{ {
[bool]$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' `
{ {
[bool]$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' `
{ {
[bool]$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('{0}')" -f $param $Signatures['Getter'] = "[bool]`$this.Getter('{0}')" -f $param
# Define setter # Define setter
$Signatures["Setter"] = "param ( [Single]`$arg )`n`$this.Setter('{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('{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('{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('{0}')" -f $param $Signatures['Getter'] = "[Int]`$this.Getter('{0}')" -f $param
# Define setter # Define setter
$Signatures["Setter"] = "param ( [Single]`$arg )`n`$this.Setter('{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('{0}')" -f $param $Signatures['Getter'] = "[String]`$this.Getter_String('{0}')" -f $param
# Define setter # Define setter
$Signatures["Setter"] = "param ( [String]`$arg )`n`$this.Setter('{0}', `$arg)" ` $Signatures['Setter'] = "param ( [String]`$arg )`n`$this.Setter('{0}', `$arg)" `
-f $param -f $param
Addmember Addmember
@@ -69,9 +69,9 @@ function AddActionMembers () {
[hashtable]$Signatures = @{} [hashtable]$Signatures = @{}
foreach ($param in $PARAMS) { foreach ($param in $PARAMS) {
# Define getter # Define getter
$Signatures["Getter"] = "`$this.Setter('{0}', `$true)" -f $param $Signatures['Getter'] = "`$this.Setter('{0}', `$true)" -f $param
# Define setter # Define setter
$Signatures["Setter"] = "" $Signatures['Setter'] = ''
Addmember Addmember
} }
@@ -83,7 +83,7 @@ function AddChannelMembers () {
[System.Collections.ArrayList]$channels = @() [System.Collections.ArrayList]$channels = @()
1..$($num_A + $num_B) | ForEach-Object { 1..$($num_A + $num_B) | ForEach-Object {
if ($_ -le $num_A) { $channels.Add("A{0}" -f $_) } else { $channels.Add("B{0}" -f $($_ - $num_A)) } if ($_ -le $num_A) { $channels.Add('A{0}' -f $_) } else { $channels.Add('B{0}' -f $($_ - $num_A)) }
} }
AddBoolMembers -PARAMS $channels AddBoolMembers -PARAMS $channels
@@ -93,11 +93,11 @@ function AddGainlayerMembers () {
[hashtable]$Signatures = @{} [hashtable]$Signatures = @{}
0..7 | ForEach-Object { 0..7 | ForEach-Object {
# Define getter # Define getter
$Signatures["Getter"] = "`$this.Getter('gainlayer[{0}]')" -f $_ $Signatures['Getter'] = "`$this.Getter('gainlayer[{0}]')" -f $_
# Define setter # Define setter
$Signatures["Setter"] = "param ( [Single]`$arg )`n`$this.Setter('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
Addmember Addmember
@@ -108,8 +108,8 @@ function Addmember {
$AddMemberParams = @{ $AddMemberParams = @{
Name = $param Name = $param
MemberType = 'ScriptProperty' MemberType = 'ScriptProperty'
Value = [scriptblock]::Create($Signatures["Getter"]) Value = [scriptblock]::Create($Signatures['Getter'])
SecondValue = [scriptblock]::Create($Signatures["Setter"]) SecondValue = [scriptblock]::Create($Signatures['Setter'])
} }
$this | Add-Member @AddMemberParams $this | Add-Member @AddMemberParams
} }

52
lib/patch.ps1 Normal file
View File

@@ -0,0 +1,52 @@
class Patch : IRemote {
[System.Collections.ArrayList]$asio
[System.Collections.ArrayList]$composite
[System.Collections.ArrayList]$insert
Patch ([Object]$remote) : base ($remote) {
AddBoolMembers -PARAMS @('postFaderComposite', 'postFxInsert')
$this.AddASIOOutMembers()
$this.asio = @()
for ($i = 0; $i -lt $remote.kind.asio_in; $i++) {
$this.asio.Add([IntArrayMember]::new($i, 'asio', $this))
}
$this.composite = @()
for ($i = 0; $i -lt $remote.kind.composite; $i++) {
$this.composite.Add([IntArrayMember]::new($i, 'composite', $this))
}
$this.insert = @()
for ($i = 0; $i -lt $remote.kind.insert; $i++) {
$this.insert.Add([BoolArrayMember]::new($i, 'insert', $this))
}
}
[string] identifier () {
return 'Patch'
}
hidden [void] AddASIOOutMembers () {
$num_A = $this.remote.kind.p_out
if ($this.remote.kind.name -eq 'basic') {
$num_A += $this.remote.kind.v_out
}
$asio_out = $this.remote.kind.asio_out
if ($asio_out -le 0) { return }
for ($a = 2; $a -le $num_A; $a++) {
[System.Collections.ArrayList]$members = @()
for ($i = 0; $i -lt $asio_out; $i++) {
$members.Add([IntArrayMember]::new($i, "OutA$a", $this))
}
Add-Member -InputObject $this -MemberType NoteProperty -Name "OutA$a" -Value $members -Force
}
}
}
function Make_Patch ([Object]$remote) {
return [Patch]::new($remote)
}

View File

@@ -1,5 +1,5 @@
function Get_Profiles ([string]$kind_id) { function Get_Profiles ([string]$kind_id) {
$basepath = Join-Path -Path $(Split-Path -Path $PSScriptRoot) -ChildPath "profiles" $basepath = Join-Path -Path $(Split-Path -Path $PSScriptRoot) -ChildPath 'profiles'
if (Test-Path $basepath) { if (Test-Path $basepath) {
$fullpath = Join-Path -Path $basepath -ChildPath $kind_id $fullpath = Join-Path -Path $basepath -ChildPath $kind_id
} }
@@ -11,7 +11,7 @@ function Get_Profiles ([string]$kind_id) {
$filenames | ForEach-Object { $filenames | ForEach-Object {
(Join-Path -Path $fullpath -ChildPath $_) | ForEach-Object { (Join-Path -Path $fullpath -ChildPath $_) | ForEach-Object {
$filename = [System.IO.Path]::GetFileNameWithoutExtension($_) $filename = [System.IO.Path]::GetFileNameWithoutExtension($_)
Write-Host ("Importing profile " + $kind_id + "/" + $filename) Write-Host ('Importing profile ' + $kind_id + '/' + $filename)
$data[$filename] = Import-PowerShellDataFile -Path $_ $data[$filename] = Import-PowerShellDataFile -Path $_
} }
} }
@@ -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,37 +1,4 @@
. $PSScriptRoot\meta.ps1 class Recorder : IRemote {
class IRecorder {
[Object]$remote
IRecorder ([Object]$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 [Object]$mode
[System.Collections.ArrayList]$armstrip [System.Collections.ArrayList]$armstrip
[System.Collections.ArrayList]$armbus [System.Collections.ArrayList]$armbus
@@ -53,11 +20,7 @@ class Recorder : IRecorder {
} }
[string] identifier () { [string] identifier () {
return "Recorder" return 'Recorder'
}
[string] ToString() {
return $this.GetType().Name
} }
hidden $_loop = $($this | Add-Member ScriptProperty 'loop' ` hidden $_loop = $($this | Add-Member ScriptProperty 'loop' `
@@ -139,9 +102,9 @@ class Recorder : IRecorder {
[void] GoTo ([string]$timestring) { [void] GoTo ([string]$timestring) {
try { try {
if ([datetime]::ParseExact($timestring, "HH:mm:ss", $null)) { if ([datetime]::ParseExact($timestring, 'HH:mm:ss', $null)) {
$timespan = [timespan]::Parse($timestring) $timespan = [timespan]::Parse($timestring)
$this.Setter("GoTo", $timespan.TotalSeconds) $this.Setter('GoTo', $timespan.TotalSeconds)
} }
} }
catch [FormatException] { catch [FormatException] {
@@ -152,35 +115,32 @@ class Recorder : IRecorder {
[void] FileType($format) { [void] FileType($format) {
[int]$val = 0 [int]$val = 0
switch ($format) { switch ($format) {
"wav" { $val = 1 } 'wav' { $val = 1 }
"aiff" { $val = 2 } 'aiff' { $val = 2 }
"bwf" { $val = 3 } 'bwf' { $val = 3 }
"mp3" { $val = 100 } 'mp3' { $val = 100 }
default { "Filetype() got: $format, expected one of 'wav', 'aiff', 'bwf', 'mp3'" } default { "Filetype() got: $format, expected one of 'wav', 'aiff', 'bwf', 'mp3'" }
} }
$this.Setter("filetype", $val) $this.Setter('filetype', $val)
} }
} }
class RecorderMode : IRecorder { class RecorderMode : IRemote {
RecorderMode ([Object]$remote) : base ($remote) { RecorderMode ([Object]$remote) : base ($remote) {
AddBoolMembers -PARAMS @('recbus', 'playonload', 'loop', 'multitrack') AddBoolMembers -PARAMS @('recbus', 'playonload', 'loop', 'multitrack')
} }
[string] identifier () { [string] identifier () {
return "Recorder.Mode" return 'Recorder.Mode'
} }
} }
class RecorderArm : IRecorder { class RecorderArm : IRemote {
[int]$index RecorderArm ([int]$index, [Object]$remote) : base ($index, $remote) {
RecorderArm ([int]$index, [Object]$remote) : base ($remote) {
$this.index = $index
} }
Set ([bool]$val) { Set ([bool]$val) {
$this.Setter("", $(if ($val) { 1 } else { 0 })) $this.Setter('', $(if ($val) { 1 } else { 0 }))
} }
} }

View File

@@ -1,32 +1,4 @@
. $PSScriptRoot\meta.ps1 class Strip : IRemote {
class IStrip {
[int]$index
[Object]$remote
IStrip ([int]$index, [Object]$remote) {
$this.index = $index
$this.remote = $remote
}
[string] identifier () {
return "Strip[" + $this.index + "]"
}
[single] Getter ($param) {
return $this.remote.Getter("$($this.identifier()).$param")
}
[string] Getter_String ($param) {
return $this.remote.Getter_String("$($this.identifier()).$param")
}
[void] Setter ($param, $val) {
$this.remote.Setter("$($this.identifier()).$param", $val)
}
}
class Strip : IStrip {
[Object]$levels [Object]$levels
Strip ([int]$index, [Object]$remote) : base ($index, $remote) { Strip ([int]$index, [Object]$remote) : base ($index, $remote) {
@@ -41,8 +13,8 @@ class Strip : IStrip {
$this.levels = [StripLevels]::new($index, $remote) $this.levels = [StripLevels]::new($index, $remote)
} }
[string] ToString() { [string] identifier () {
return $this.GetType().Name + $this.index return 'Strip[' + $this.index + ']'
} }
[void] FadeTo ([single]$target, [int]$time) { [void] FadeTo ([single]$target, [int]$time) {
@@ -54,7 +26,7 @@ class Strip : IStrip {
} }
} }
class StripLevels : IStrip { class StripLevels : IRemote {
[int]$init [int]$init
[int]$offset [int]$offset
@@ -120,14 +92,14 @@ class PhysicalStrip : Strip {
} }
} }
class StripComp : IStrip { class StripComp : IRemote {
StripComp ([int]$index, [Object]$remote) : base ($index, $remote) { StripComp ([int]$index, [Object]$remote) : base ($index, $remote) {
AddFloatMembers -PARAMS @('gainin', 'ratio', 'threshold', 'attack', 'release', 'knee', 'gainout') AddFloatMembers -PARAMS @('gainin', 'ratio', 'threshold', 'attack', 'release', 'knee', 'gainout')
AddBoolMembers -PARAMS @('makeup') AddBoolMembers -PARAMS @('makeup')
} }
[string] identifier () { [string] identifier () {
return "Strip[" + $this.index + "].Comp" return 'Strip[' + $this.index + '].Comp'
} }
hidden $_knob = $($this | Add-Member ScriptProperty 'knob' ` hidden $_knob = $($this | Add-Member ScriptProperty 'knob' `
@@ -141,13 +113,13 @@ class StripComp : IStrip {
) )
} }
class StripGate : IStrip { class StripGate : IRemote {
StripGate ([int]$index, [Object]$remote) : base ($index, $remote) { StripGate ([int]$index, [Object]$remote) : base ($index, $remote) {
AddFloatMembers -PARAMS @('threshold', 'damping', 'bpsidechain', 'attack', 'hold', 'release') AddFloatMembers -PARAMS @('threshold', 'damping', 'bpsidechain', 'attack', 'hold', 'release')
} }
[string] identifier () { [string] identifier () {
return "Strip[" + $this.index + "].Gate" return 'Strip[' + $this.index + '].Gate'
} }
hidden $_knob = $($this | Add-Member ScriptProperty 'knob' ` hidden $_knob = $($this | Add-Member ScriptProperty 'knob' `
@@ -161,12 +133,12 @@ class StripGate : IStrip {
) )
} }
class StripDenoiser : IStrip { class StripDenoiser : IRemote {
StripDenoiser ([int]$index, [Object]$remote) : base ($index, $remote) { StripDenoiser ([int]$index, [Object]$remote) : base ($index, $remote) {
} }
[string] identifier () { [string] identifier () {
return "Strip[" + $this.index + "].Denoiser" return 'Strip[' + $this.index + '].Denoiser'
} }
hidden $_knob = $($this | Add-Member ScriptProperty 'knob' ` hidden $_knob = $($this | Add-Member ScriptProperty 'knob' `
@@ -180,22 +152,22 @@ class StripDenoiser : IStrip {
) )
} }
class StripEq : IStrip { class StripEq : IRemote {
StripEq ([int]$index, [Object]$remote) : base ($index, $remote) { StripEq ([int]$index, [Object]$remote) : base ($index, $remote) {
AddBoolMembers -PARAMS @('on', 'ab') AddBoolMembers -PARAMS @('on', 'ab')
} }
[string] identifier () { [string] identifier () {
return "Strip[" + $this.index + "].EQ" return 'Strip[' + $this.index + '].EQ'
} }
} }
class StripDevice : IStrip { class StripDevice : IRemote {
StripDevice ([int]$index, [Object]$remote) : base ($index, $remote) { StripDevice ([int]$index, [Object]$remote) : base ($index, $remote) {
} }
[string] identifier () { [string] identifier () {
return "Strip[" + $this.index + "].Device" return 'Strip[' + $this.index + '].Device'
} }
hidden $_name = $($this | Add-Member ScriptProperty 'name' ` hidden $_name = $($this | Add-Member ScriptProperty 'name' `

View File

@@ -1,37 +1,12 @@
class IVban { class Vban : IRemote {
[int32]$index
[Object]$remote
[string]$direction [string]$direction
IVban ([int]$index, [Object]$remote, [string]$direction) { Vban ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote) {
$this.index = $index
$this.remote = $remote
$this.direction = $direction $this.direction = $direction
} }
[string] identifier () { [string] identifier () {
return "vban." + $this.direction + "stream[" + $this.index + "]" return 'vban.' + $this.direction + 'stream[' + $this.index + ']'
}
[string] ToString() {
return $this.GetType().Name + $this.index
}
[single] Getter ($param) {
return $this.remote.Getter("$($this.identifier()).$param")
}
[string] Getter_String ($param) {
return $this.remote.Getter_String("$($this.identifier()).$param")
}
[void] Setter ($param, $val) {
$this.remote.Setter("$($this.identifier()).$param", $val)
}
}
class Vban : IVban {
Vban ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote, $direction) {
} }
hidden $_on = $($this | Add-Member ScriptProperty 'on' ` hidden $_on = $($this | Add-Member ScriptProperty 'on' `
@@ -85,7 +60,7 @@ class Vban : IVban {
} ` } `
{ {
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 {
$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)) {
@@ -104,7 +79,7 @@ class Vban : IVban {
} ` } `
{ {
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 -ge 1 -and $arg -le 8) { if ($arg -ge 1 -and $arg -le 8) {
$this._channel = $this.Setter('channel', $arg) $this._channel = $this.Setter('channel', $arg)
@@ -123,7 +98,7 @@ class Vban : IVban {
} ` } `
{ {
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 (@(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 }
@@ -142,7 +117,7 @@ class Vban : IVban {
} ` } `
{ {
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 -ge 0 -and $arg -le 4) { if ($arg -ge 0 -and $arg -le 4) {
$this._quality = $this.Setter('quality', $arg) $this._quality = $this.Setter('quality', $arg)
@@ -160,7 +135,7 @@ class Vban : IVban {
} ` } `
{ {
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 -ge 0 -and $arg -le 8) { if ($arg -ge 0 -and $arg -le 8) {
$this._route = $this.Setter('route', $arg) $this._route = $this.Setter('route', $arg)
@@ -191,10 +166,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($_, $remote, "in")) [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($_, $remote, "out")) [void]$outstream.Add([VbanOutstream]::new($_, $remote, 'out'))
} }
$CustomObject = [pscustomobject]@{ $CustomObject = [pscustomobject]@{
@@ -204,7 +179,7 @@ function Make_Vban ([Object]$remote) {
$CustomObject | Add-Member ScriptProperty 'enable' ` $CustomObject | Add-Member ScriptProperty 'enable' `
{ {
return Write-Warning ("ERROR: vban.enable is write only") return Write-Warning ('ERROR: vban.enable is write only')
} ` } `
{ {
param([bool]$arg) param([bool]$arg)

View File

@@ -2,10 +2,10 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Describe 'Bool tests' -ForEach @( Describe 'Bool tests' -ForEach @(
@{ Value = $true; Expected = $true } @{ Value = $true; Expected = $true }
@{ Value = $false; Expected = $false } @{ Value = $false; Expected = $false }
){ ) {
Context 'Strip, one physical one virtual' -ForEach @( Context 'Strip, one physical one virtual' -ForEach @(
@{ Index = $phys_in }, @{ Index = $virt_in } @{ Index = $phys_in }, @{ Index = $virt_in }
){ ) {
It "Should set and get Strip[$index].Mute" { It "Should set and get Strip[$index].Mute" {
$vmr.strip[$index].mute = $value $vmr.strip[$index].mute = $value
$vmr.strip[$index].mute | Should -Be $expected $vmr.strip[$index].mute | Should -Be $expected
@@ -29,7 +29,7 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Context 'physical only' -ForEach @( Context 'physical only' -ForEach @(
@{ Index = $phys_in } @{ Index = $phys_in }
){ ) {
Context 'eq.{param}' -Skip:$ifNotPotato { Context 'eq.{param}' -Skip:$ifNotPotato {
It "Should set Strip[$index].EQ.On to $value" { It "Should set Strip[$index].EQ.On to $value" {
$vmr.strip[$index].eq.on = $value $vmr.strip[$index].eq.on = $value
@@ -40,7 +40,7 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
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.On" -Skip:$ifBasic { It "Should set and get Bus[$index].Eq.On" -Skip:$ifBasic {
$vmr.bus[$index].eq.on = $value $vmr.bus[$index].eq.on = $value
$vmr.bus[$index].eq.on | Should -Be $expected $vmr.bus[$index].eq.on | Should -Be $expected
@@ -64,7 +64,7 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Context 'Macrobutton' -ForEach @( Context 'Macrobutton' -ForEach @(
@{ Index = 0 }, @{ Index = 69 } @{ Index = 0 }, @{ Index = 69 }
){ ) {
It "Should set and get macrobutton[$index] State" { It "Should set and get macrobutton[$index] State" {
$vmr.button[$index].state = $value $vmr.button[$index].state = $value
$vmr.button[$index].state | Should -Be $expected $vmr.button[$index].state | Should -Be $expected
@@ -73,7 +73,7 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Context 'Vban instream' -ForEach @( Context 'Vban instream' -ForEach @(
@{ Index = $vban_in } @{ Index = $vban_in }
){ ) {
It "Should set vban.instream[$index].on" { It "Should set vban.instream[$index].on" {
$vmr.vban.instream[$index].on = $value $vmr.vban.instream[$index].on = $value
$vmr.vban.instream[$index].on | Should -Be $expected $vmr.vban.instream[$index].on | Should -Be $expected
@@ -82,7 +82,7 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Context 'Vban outstream' -ForEach @( Context 'Vban outstream' -ForEach @(
@{ Index = $vban_out } @{ Index = $vban_out }
){ ) {
It "Should set vban.outstream[$index].on" { It "Should set vban.outstream[$index].on" {
$vmr.vban.outstream[$index].on = $value $vmr.vban.outstream[$index].on = $value
$vmr.vban.outstream[$index].on | Should -Be $expected $vmr.vban.outstream[$index].on | Should -Be $expected
@@ -90,17 +90,17 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
} }
Context 'Recorder' -Skip:$ifBasic { Context 'Recorder' -Skip:$ifBasic {
It "Should set and get Recorder.A3" { It 'Should set and get Recorder.A3' {
$vmr.recorder.A3 = $value $vmr.recorder.A3 = $value
$vmr.recorder.A3 | Should -Be $expected $vmr.recorder.A3 | Should -Be $expected
} }
It "Should set and get Recorder.B1" { It 'Should set and get Recorder.B1' {
$vmr.recorder.B1 = $value $vmr.recorder.B1 = $value
$vmr.recorder.B1 | Should -Be $expected $vmr.recorder.B1 | Should -Be $expected
} }
It "Should set and get Recorder.loop" { It 'Should set and get Recorder.loop' {
$vmr.recorder.loop = $value $vmr.recorder.loop = $value
} }
} }
@@ -110,16 +110,33 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
$vmr.command.lock = $value $vmr.command.lock = $value
} }
} }
Context 'Patch' {
It 'Should set and get Patch.insert[$insert]' -Skip:$ifBasic {
$vmr.patch.insert[$insert].set($value)
$vmr.patch.insert[$insert].get() | Should -Be $value
}
It 'Should set and get Patch.postfadercomposite' -Skip:$ifBasic {
$vmr.patch.postfadercomposite = $value
$vmr.patch.postfadercomposite | Should -Be $value
}
It 'Should set and get Patch.postfxinsert' -Skip:$ifBasic {
$vmr.patch.postfxinsert = $value
$vmr.patch.postfxinsert | Should -Be $value
}
}
} }
Describe 'Float Tests' { Describe 'Float Tests' {
Describe 'Strip tests' { Describe 'Strip tests' {
Context 'one physical, one virtual' -ForEach @( Context 'one physical, one virtual' -ForEach @(
@{ Index = $phys_in }, @{ Index = $virt_in } @{ Index = $phys_in }, @{ Index = $virt_in }
){ ) {
Context 'gain' -ForEach @( Context 'gain' -ForEach @(
@{ Value = 3.6; Expected = 3.6 }, @{ Value = -8.2; Expected = -8.2 } @{ Value = 3.6; Expected = 3.6 }, @{ Value = -8.2; Expected = -8.2 }
){ ) {
It "Should set Strip[$index].Gain to $value" { It "Should set Strip[$index].Gain to $value" {
$vmr.strip[$index].gain = $value $vmr.strip[$index].gain = $value
$vmr.strip[$index].gain | Should -Be $expected $vmr.strip[$index].gain | Should -Be $expected
@@ -129,10 +146,10 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Context 'physical only' -Skip:$ifBasic -ForEach @( Context 'physical only' -Skip:$ifBasic -ForEach @(
@{ Index = $phys_in } @{ Index = $phys_in }
){ ) {
Context 'comp, gate' -ForEach @( Context 'comp, gate' -ForEach @(
@{ 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.knob = $value $vmr.strip[$index].comp.knob = $value
$vmr.strip[$index].comp.knob | Should -Be $expected $vmr.strip[$index].comp.knob | Should -Be $expected
@@ -146,7 +163,7 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Context 'denoiser' -Skip:$ifNotPotato -ForEach @( Context 'denoiser' -Skip:$ifNotPotato -ForEach @(
@{ 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].Denoiser to $value" { It "Should set Strip[$index].Denoiser to $value" {
$vmr.strip[$index].denoiser.knob = $value $vmr.strip[$index].denoiser.knob = $value
$vmr.strip[$index].denoiser.knob | Should -Be $expected $vmr.strip[$index].denoiser.knob | Should -Be $expected
@@ -155,7 +172,7 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Context 'comp.{param}' -Skip:$ifNotPotato -ForEach @( Context 'comp.{param}' -Skip:$ifNotPotato -ForEach @(
@{ 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.Attack to $value" { It "Should set Strip[$index].Comp.Attack to $value" {
$vmr.strip[$index].comp.attack = $value $vmr.strip[$index].comp.attack = $value
$vmr.strip[$index].comp.attack | Should -Be $expected $vmr.strip[$index].comp.attack | Should -Be $expected
@@ -164,7 +181,7 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Context 'comp.{param}' -Skip:$ifNotPotato -ForEach @( Context 'comp.{param}' -Skip:$ifNotPotato -ForEach @(
@{ Value = 0.3; Expected = 0.3 }, @{ Value = 0.8; Expected = 0.8 } @{ Value = 0.3; Expected = 0.3 }, @{ Value = 0.8; Expected = 0.8 }
){ ) {
It "Should set Strip[$index].Comp.Knee to $value" { It "Should set Strip[$index].Comp.Knee to $value" {
$vmr.strip[$index].comp.knee = $value $vmr.strip[$index].comp.knee = $value
$vmr.strip[$index].comp.knee | Should -Be $expected $vmr.strip[$index].comp.knee | Should -Be $expected
@@ -173,7 +190,7 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Context 'gate.{param}' -Skip:$ifNotPotato -ForEach @( Context 'gate.{param}' -Skip:$ifNotPotato -ForEach @(
@{ Value = 103; Expected = 103 }, @{ Value = 3800; Expected = 3800 } @{ Value = 103; Expected = 103 }, @{ Value = 3800; Expected = 3800 }
){ ) {
It "Should set Strip[$index].Gate.BPSidechain to $value" { It "Should set Strip[$index].Gate.BPSidechain to $value" {
$vmr.strip[$index].gate.bpsidechain = $value $vmr.strip[$index].gate.bpsidechain = $value
$vmr.strip[$index].gate.bpsidechain | Should -Be $expected $vmr.strip[$index].gate.bpsidechain | Should -Be $expected
@@ -182,7 +199,7 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Context 'gate.{param}' -Skip:$ifNotPotato -ForEach @( Context 'gate.{param}' -Skip:$ifNotPotato -ForEach @(
@{ Value = 0.3; Expected = 0.3 }, @{ Value = 5000; Expected = 5000 } @{ Value = 0.3; Expected = 0.3 }, @{ Value = 5000; Expected = 5000 }
){ ) {
It "Should set Strip[$index].Gate.Hold to $value" { It "Should set Strip[$index].Gate.Hold to $value" {
$vmr.strip[$index].gate.hold = $value $vmr.strip[$index].gate.hold = $value
$vmr.strip[$index].gate.hold | Should -Be $expected $vmr.strip[$index].gate.hold | Should -Be $expected
@@ -194,10 +211,10 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Describe 'Bus tests' { Describe 'Bus tests' {
Context 'one physical, one virtual' -ForEach @( Context 'one physical, one virtual' -ForEach @(
@{ Index = $phys_out }, @{ Index = $virt_out } @{ Index = $phys_out }, @{ Index = $virt_out }
){ ) {
Context 'gain' -ForEach @( Context 'gain' -ForEach @(
@{ Value = 5.2; Expected = 5.2 }, @{ Value = -38.2; Expected = -38.2 } @{ Value = 5.2; Expected = 5.2 }, @{ Value = -38.2; Expected = -38.2 }
){ ) {
It "Should set Bus[$index].Gain to $value" { It "Should set Bus[$index].Gain to $value" {
$vmr.bus[$index].gain = $value $vmr.bus[$index].gain = $value
$vmr.bus[$index].gain | Should -Be $expected $vmr.bus[$index].gain | Should -Be $expected
@@ -209,11 +226,11 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Describe 'Int Tests' -ForEach @( Describe 'Int Tests' -ForEach @(
@{ Index = $phys_in }, @{ Index = $virt_in } @{ Index = $phys_in }, @{ Index = $virt_in }
){ ) {
Context 'Strip, one physical, one virtual' -Skip:$ifBasic -ForEach @( Context 'Strip, one physical, one virtual' -Skip:$ifBasic -ForEach @(
@{ Value = 3; Expected = 3 } @{ Value = 3; Expected = 3 }
@{ Value = -6; Expected = -6 } @{ Value = -6; Expected = -6 }
){ ) {
It "Should set Strip[$index].Limit to 3" { It "Should set Strip[$index].Limit to 3" {
$vmr.strip[$index].limit = $value $vmr.strip[$index].limit = $value
$vmr.strip[$index].limit | Should -Be $expected $vmr.strip[$index].limit | Should -Be $expected
@@ -224,7 +241,7 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Context 'sr' -ForEach @( Context 'sr' -ForEach @(
@{ Value = 44100; Expected = 44100 } @{ Value = 44100; Expected = 44100 }
@{ Value = 48000; Expected = 48000 } @{ Value = 48000; Expected = 48000 }
){ ) {
It "Should set vban.outstream[$index].sr to $value" { It "Should set vban.outstream[$index].sr to $value" {
$vmr.vban.outstream[$index].sr = $value $vmr.vban.outstream[$index].sr = $value
$vmr.vban.outstream[$index].sr | Should -Be $expected $vmr.vban.outstream[$index].sr | Should -Be $expected
@@ -234,23 +251,32 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Context 'channel' -ForEach @( Context 'channel' -ForEach @(
@{ Value = 1; Expected = 1 } @{ Value = 1; Expected = 1 }
@{ Value = 2; Expected = 2 } @{ Value = 2; Expected = 2 }
){ ) {
It 'Should set vban.outstream[0].channel to 1' { It 'Should set vban.outstream[0].channel to 1' {
$vmr.vban.outstream[$index].channel = $value $vmr.vban.outstream[$index].channel = $value
$vmr.vban.outstream[$index].channel | Should -Be $expected $vmr.vban.outstream[$index].channel | Should -Be $expected
} }
} }
} }
Context 'Patch' {
It 'Should set and get Patch.composite[$composite]' -Skip:$ifBasic -ForEach @(
@{ Value = 22 }, @{ Value = 6 }
) {
$vmr.patch.composite[$composite].set($value)
$vmr.patch.composite[$composite].get() | Should -Be $value
}
}
} }
Describe 'String Tests' { Describe 'String Tests' {
Context 'Strip, one physical, one virtual' -ForEach @( Context 'Strip, one physical, one virtual' -ForEach @(
@{ Index = $phys_in }, @{ Index = $virt_in } @{ Index = $phys_in }, @{ Index = $virt_in }
){ ) {
It "Should set Strip[$index].Label" -ForEach @( It "Should set Strip[$index].Label" -ForEach @(
@{ Value = "test0"; Expected = "test0" } @{ Value = 'test0'; Expected = 'test0' }
@{ Value = "test1"; Expected = "test1" } @{ Value = 'test1'; Expected = 'test1' }
){ ) {
$vmr.strip[$index].label = $value $vmr.strip[$index].label = $value
$vmr.strip[$index].label | Should -Be $expected $vmr.strip[$index].label | Should -Be $expected
} }
@@ -258,11 +284,11 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
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 Bus[$index].Label" -ForEach @( It "Should set Bus[$index].Label" -ForEach @(
@{ Value = "test0"; Expected = "test0" } @{ Value = 'test0'; Expected = 'test0' }
@{ Value = "test1"; Expected = "test1" } @{ Value = 'test1'; Expected = 'test1' }
){ ) {
$vmr.bus[$index].label = $value $vmr.bus[$index].label = $value
$vmr.bus[$index].label | Should -Be $expected $vmr.bus[$index].label | Should -Be $expected
} }
@@ -270,11 +296,11 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Describe 'Vban' -ForEach @( Describe 'Vban' -ForEach @(
@{ Index = $vban_in } @{ Index = $vban_in }
){ ) {
Context 'instream' { Context 'instream' {
Context 'ip' -ForEach @( Context 'ip' -ForEach @(
@{ Value = "0.0.0.0"; Expected = "0.0.0.0" } @{ Value = '0.0.0.0'; Expected = '0.0.0.0' }
){ ) {
It "Should set vban.instream[$index].name to $value" { It "Should set vban.instream[$index].name to $value" {
$vmr.vban.instream[$index].ip = $value $vmr.vban.instream[$index].ip = $value
$vmr.vban.instream[$index].ip | Should -Be $expected $vmr.vban.instream[$index].ip | Should -Be $expected
@@ -284,8 +310,8 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Context 'outstream' { Context 'outstream' {
Context 'ip' -ForEach @( Context 'ip' -ForEach @(
@{ Value = "0.0.0.0"; Expected = "0.0.0.0" } @{ Value = '0.0.0.0'; Expected = '0.0.0.0' }
){ ) {
It "Should set vban.outstream[$index].name to $value" { It "Should set vban.outstream[$index].name to $value" {
$vmr.vban.outstream[$index].ip = $value $vmr.vban.outstream[$index].ip = $value
$vmr.vban.outstream[$index].ip | Should -Be $expected $vmr.vban.outstream[$index].ip | Should -Be $expected

View File

@@ -6,13 +6,13 @@ Describe -Tag 'lower', -TestName 'All Lower Tests' {
Describe 'Macrobutton Tests' -ForEach @( Describe 'Macrobutton Tests' -ForEach @(
@{ Value = 1; Expected = 1 } @{ Value = 1; Expected = 1 }
@{ Value = 0; Expected = 0 } @{ Value = 0; Expected = 0 }
){ ) {
Context 'buttons 0, 69' -ForEach @( Context 'buttons 0, 69' -ForEach @(
@{ Index = 0 }, @{ Index = 69 } @{ Index = 0 }, @{ Index = 69 }
){ ) {
Context 'state, stateonly and trigger' -ForEach @( Context 'state, stateonly and trigger' -ForEach @(
@{ Mode = 1 }, @{ Mode = 2 }, @{ Mode = 3 } @{ Mode = 1 }, @{ Mode = 2 }, @{ Mode = 3 }
){ ) {
It "Should set and get macrobutton[$index] State" { It "Should set and get macrobutton[$index] State" {
MB_Set -ID $index -SET $value -MODE $mode MB_Set -ID $index -SET $value -MODE $mode
MB_Get -ID $index -MODE $mode | Should -Be $expected MB_Get -ID $index -MODE $mode | Should -Be $expected
@@ -24,13 +24,13 @@ Describe -Tag 'lower', -TestName 'All Lower Tests' {
Describe 'Set and Get Param Float Tests' -ForEach @( Describe 'Set and Get Param Float Tests' -ForEach @(
@{ Value = 1; Expected = 1 } @{ Value = 1; Expected = 1 }
@{ Value = 0; Expected = 0 } @{ Value = 0; Expected = 0 }
){ ) {
Context 'Strip, one physical one virtual' -ForEach @( Context 'Strip, one physical one virtual' -ForEach @(
@{ Index = $phys_in }, @{ Index = $virt_in } @{ Index = $phys_in }, @{ Index = $virt_in }
){ ) {
Context 'mute, mono, A1, B2' -ForEach @( Context 'mute, mono, A1, B2' -ForEach @(
@{ param = "mute" }, @{ param = "A1" } @{ param = 'mute' }, @{ param = 'A1' }
){ ) {
It "Should set Strip[0].$param to 1" { It "Should set Strip[0].$param to 1" {
Param_Set -PARAM "Strip[$index].$param" -VALUE $value Param_Set -PARAM "Strip[$index].$param" -VALUE $value
Param_Get -PARAM "Strip[$index].$param" | Should -Be $expected Param_Get -PARAM "Strip[$index].$param" | Should -Be $expected
@@ -42,10 +42,10 @@ Describe -Tag 'lower', -TestName 'All Lower Tests' {
Describe 'Set and Get Param String Tests' -ForEach @( Describe 'Set and Get Param String Tests' -ForEach @(
@{ Value = 'test0'; Expected = 'test0' } @{ Value = 'test0'; Expected = 'test0' }
@{ Value = 'test1'; Expected = 'test1' } @{ Value = 'test1'; Expected = 'test1' }
){ ) {
Context 'Strip, one physical one virtual' -ForEach @( Context 'Strip, one physical one virtual' -ForEach @(
@{ Index = $phys_in }, @{ Index = $virt_in } @{ Index = $phys_in }, @{ Index = $virt_in }
){ ) {
It "Should set Strip[$index].Label to $value" { It "Should set Strip[$index].Label to $value" {
Param_Set -PARAM "Strip[$index].Label" -VALUE $value Param_Set -PARAM "Strip[$index].Label" -VALUE $value
Param_Get -PARAM "Strip[$index].Label" -IS_STRING $true | Should -Be $expected Param_Get -PARAM "Strip[$index].Label" -IS_STRING $true | Should -Be $expected

View File

@@ -1,76 +0,0 @@
Param([String]$tag, [Int]$num = 1, [switch]$log, [string]$kind = "potato")
Import-Module .\lib\Voicemeeter.psm1
Function ParseLog {
Param([String]$logfile)
$summary_file = Join-Path $PSScriptRoot "_summary.log"
if (Test-Path $summary_file) { Clear-Content $summary_file }
$PASSED_PATTERN = "^PassedCount\s+:\s(\d+)"
$FAILED_PATTERN = "^FailedCount\s+:\s(\d+)"
$DATA = @{
"passed" = 0
"failed" = 0
}
ForEach ($line in `
$(Get-Content -Path "${logfile}")) {
if ($line -match $PASSED_PATTERN) {
$DATA["passed"] += $Matches[1]
}
elseif ($line -match $FAILED_PATTERN) {
$DATA["failed"] += $Matches[1]
}
}
"=========================`n" + `
"$num tests run:`n" + `
"=========================" | Tee-Object -FilePath $summary_file -Append
$DATA | ForEach-Object { $_ } | Tee-Object -FilePath $summary_file -Append
}
function main() {
try {
$vmr = Connect-Voicemeeter -Kind $kind
$vmr.command.RunMacrobuttons() # ensure macrobuttons is running before we begin
Write-Host "Running tests for $vmr"
# test boundaries by kind
$phys_in = $vmr.kind.p_in - 1
$virt_in = $vmr.kind.p_in + $vmr.kind.v_in - 1
$phys_out = $vmr.kind.p_out - 1
$virt_out = $vmr.kind.p_out + $vmr.kind.v_out - 1
$vban_in = $vmr.kind.vban_in - 1
$vban_out = $vmr.kind.vban_out - 1
# skip conditions by kind
$ifBasic = $vmr.kind.name -eq "basic"
$ifBanana = $vmr.kind.name -eq "banana"
$ifPotato = $vmr.kind.name -eq "potato"
$ifNotBasic = $vmr.kind.name -ne "basic"
$ifNotBanana = $vmr.kind.name -ne "banana"
$ifNotPotato = $vmr.kind.name -ne "potato"
$logfile = Join-Path $PSScriptRoot "_results.log"
if (Test-Path $logfile) { Clear-Content $logfile }
1..$num | ForEach-Object {
if ($log) {
"Running test $_ of $num" | Tee-Object -FilePath $logfile -Append
Invoke-Pester -Tag $tag -PassThru | Tee-Object -FilePath $logfile -Append
}
else {
"Running test $_ of $num"
Invoke-Pester -Tag $tag -PassThru
}
}
if ($log) { Parselog -logfile $logfile }
}
finally { Disconnect-Voicemeeter }
}
main

32
tests/run.ps1 Normal file
View File

@@ -0,0 +1,32 @@
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "", Target = "variablename")]
Param([String]$tag, [string]$kind = 'potato')
Import-Module (Join-Path (Split-Path $PSScriptRoot -Parent) 'lib\Voicemeeter.psm1') -Force
function main() {
try {
$vmr = Connect-Voicemeeter -Kind $kind
$vmr.command.RunMacrobuttons() # ensure macrobuttons is running before we begin
Write-Host "Running tests for $vmr"
# test boundaries by kind
$phys_in = $vmr.kind.p_in - 1
$virt_in = $vmr.kind.p_in + $vmr.kind.v_in - 1
$phys_out = $vmr.kind.p_out - 1
$virt_out = $vmr.kind.p_out + $vmr.kind.v_out - 1
$vban_in = $vmr.kind.vban_in - 1
$vban_out = $vmr.kind.vban_out - 1
$insert = $vmr.kind.insert - 1
$composite = $vmr.kind.composite - 1
# skip conditions by kind
$ifBasic = $vmr.kind.name -eq 'basic'
$ifNotPotato = $vmr.kind.name -ne 'potato'
Invoke-Pester -Tag $tag -PassThru | Out-Null
}
finally { Disconnect-Voicemeeter }
}
main