mirror of
https://github.com/onyx-and-iris/voicemeeter-api-powershell.git
synced 2026-04-20 22:43:31 +00:00
Compare commits
27 Commits
add-record
...
f199fa587f
| Author | SHA1 | Date | |
|---|---|---|---|
| f199fa587f | |||
| b6c9c65390 | |||
| 436b47a5db | |||
| 0cdd71600f | |||
| 41529c0d58 | |||
| b1a6ac68c1 | |||
| fbfab5b4aa | |||
| 4d371a7582 | |||
| 15b3b375bd | |||
| c8abc6964a | |||
| 907ee3e63b | |||
| f3ed9c28c7 | |||
| d305a4048d | |||
| 108731b4cf | |||
| e7c648f1d0 | |||
| b21a71471b | |||
| 43367525c5 | |||
| d0fbd6deef | |||
| 1df92afcfe | |||
| 2ad8118f2c | |||
| bc6162cf16 | |||
| 9b3d9f2250 | |||
| 844eaeabaa | |||
| a78cdf9a99 | |||
| a40adf27be | |||
| 1397c14522 | |||
| ff1bd5e6cc |
14
.vscode/launch.json
vendored
14
.vscode/launch.json
vendored
@@ -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
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
39
CHANGELOG.md
39
CHANGELOG.md
@@ -9,10 +9,43 @@ 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.
|
- [ ]
|
||||||
- [x] More Recorder commands implemented.
|
|
||||||
|
|
||||||
## [3.0.0]
|
## [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:
|
||||||
|
|
||||||
|
|||||||
105
README.md
105
README.md
@@ -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,8 @@ $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()
|
||||||
```
|
```
|
||||||
|
|
||||||
### Recorder
|
### Recorder
|
||||||
@@ -423,12 +427,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 +468,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,6 +546,15 @@ 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:
|
Run tests using .\tests\pre-commit.ps1 which accepts the following parameters:
|
||||||
@@ -557,4 +570,4 @@ Run tests from repository root in a subshell and write logs, like so:
|
|||||||
|
|
||||||
### 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)
|
||||||
|
|||||||
@@ -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 {
|
||||||
@@ -24,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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,27 +7,30 @@
|
|||||||
Credits go to @bobsupercow
|
Credits go to @bobsupercow
|
||||||
#>
|
#>
|
||||||
|
|
||||||
Import-Module ..\..\lib\Voicemeeter.psm1
|
[cmdletbinding()]
|
||||||
|
param()
|
||||||
|
|
||||||
$VerbosePreference = "Continue"
|
Import-Module ..\..\lib\Voicemeeter.psm1
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
|
[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
|
||||||
@@ -10,19 +11,15 @@ function CurrentProgramSceneChanged {
|
|||||||
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 }
|
||||||
}
|
}
|
||||||
|
|||||||
125
examples/streamdeck/README.md
Normal file
125
examples/streamdeck/README.md
Normal 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)
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -1,14 +1,22 @@
|
|||||||
. $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
|
||||||
[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)
|
||||||
}
|
}
|
||||||
@@ -31,7 +39,7 @@ class Remote {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[String] GetVersion() {
|
[String] GetVersion() {
|
||||||
return Version
|
return VmVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
[void] Set_Profile([String]$config) {
|
[void] Set_Profile([String]$config) {
|
||||||
@@ -129,24 +137,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 {
|
||||||
default { throw [LoginError]::new("Unknown Voicemeeter kind `"$Kind`"") }
|
throw [LoginError]::new("Unknown Voicemeeter kind `"$Kind`"")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch [LoginError], [CAPIError] {
|
|
||||||
Write-Warning $_.Exception.ErrorMessage()
|
|
||||||
throw
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Function Disconnect-Voicemeeter {
|
Function Disconnect-Voicemeeter {
|
||||||
|
|||||||
192
lib/base.ps1
192
lib/base.ps1
@@ -1,74 +1,95 @@
|
|||||||
. $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 ($retval -notin @(0, 1, -2)) {
|
||||||
if (-not $retval) {
|
throw [CAPIError]::new($retval, "VBVMR_Login")
|
||||||
"LOGGED IN" | Write-Verbose
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
if (-not $retval) {
|
|
||||||
"STARTING VOICEMEETER" | Write-Verbose
|
|
||||||
Start-Sleep -s 1
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw [CAPIError]::new($retval, $MyInvocation.MyCommand)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elseif ($retval -eq -2) {
|
|
||||||
throw [LoginError]::new('login may only be called once per session')
|
|
||||||
}
|
|
||||||
else { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) }
|
|
||||||
}
|
}
|
||||||
catch [LoginError] {
|
|
||||||
Write-Warning "$($_.Exception.ErrorMessage()). Fatal error, exiting..."
|
switch ($retval) {
|
||||||
exit -2
|
1 {
|
||||||
|
"Voicemeeter Engine running but GUI not launched. Launching GUI now." | Write-Verbose
|
||||||
|
RunVoicemeeter -kindId $kindId
|
||||||
|
}
|
||||||
|
-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
|
||||||
|
}
|
||||||
|
catch [CAPIError] {
|
||||||
|
$exception = $_
|
||||||
|
$exception | Write-Debug
|
||||||
|
}
|
||||||
|
} while ($sw.elapsed -lt $timeout)
|
||||||
|
|
||||||
|
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" }
|
||||||
@@ -76,10 +97,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
|
||||||
@@ -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 -notin @(0)) {
|
||||||
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) }
|
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 -notin @(0)) {
|
||||||
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) }
|
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 {
|
|
||||||
$retval = [int][Voicemeeter.Remote]::VBVMR_SetParameterFloat($PARAM, $VALUE)
|
|
||||||
}
|
|
||||||
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) }
|
|
||||||
}
|
}
|
||||||
catch [CAPIError] {
|
else {
|
||||||
Write-Warning $_.Exception.ErrorMessage()
|
$retval = [int][Voicemeeter.Remote]::VBVMR_SetParameterFloat($PARAM, $VALUE)
|
||||||
|
if ($retval -notin @(0)) {
|
||||||
|
throw [CAPIError]::new($retval, "VBVMR_SetParameterFloat")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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 -notin @(0)) {
|
||||||
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) }
|
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 -notin @(0)) {
|
||||||
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) }
|
throw [CAPIError]::new($retval, "VBVMR_MacroButton_GetStatus")
|
||||||
}
|
|
||||||
catch [CAPIError] {
|
|
||||||
Write-Warning $_.Exception.ErrorMessage()
|
|
||||||
}
|
}
|
||||||
[int]$ptr
|
[int]$ptr
|
||||||
}
|
}
|
||||||
@@ -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 -notin @(0)) {
|
||||||
if ($retval) { throw [CAPIError]::new($retval, $MyInvocation.MyCommand) }
|
throw [CAPIError]::new($retval, "VBVMR_GetLevel")
|
||||||
}
|
|
||||||
catch [CAPIError] {
|
|
||||||
Write-Warning $_.Exception.ErrorMessage()
|
|
||||||
}
|
}
|
||||||
[float]$ptr
|
[float]$ptr
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
26
lib/bus.ps1
26
lib/bus.ps1
@@ -1,5 +1,3 @@
|
|||||||
. $PSScriptRoot\meta.ps1
|
|
||||||
|
|
||||||
class IBus {
|
class IBus {
|
||||||
[int]$index
|
[int]$index
|
||||||
[Object]$remote
|
[Object]$remote
|
||||||
@@ -13,20 +11,26 @@ class IBus {
|
|||||||
return "Bus[" + $this.index + "]"
|
return "Bus[" + $this.index + "]"
|
||||||
}
|
}
|
||||||
|
|
||||||
[string] ToString() {
|
|
||||||
return $this.GetType().Name + $this.index
|
|
||||||
}
|
|
||||||
|
|
||||||
[single] Getter ($param) {
|
[single] Getter ($param) {
|
||||||
return $this.remote.Getter("$($this.identifier()).$param")
|
$this.ToString() + " Getter: $($this.Cmd($param))" | Write-Debug
|
||||||
|
return $this.remote.Getter($this.Cmd($param))
|
||||||
}
|
}
|
||||||
|
|
||||||
[string] Getter_String ($param) {
|
[string] Getter_String ($param) {
|
||||||
return $this.remote.Getter_String("$($this.identifier()).$param")
|
$this.ToString() + " Getter_String: $($this.Cmd($param))" | Write-Debug
|
||||||
|
return $this.remote.Getter_String($this.Cmd($param))
|
||||||
}
|
}
|
||||||
|
|
||||||
[void] Setter ($param, $val) {
|
[void] Setter ($param, $val) {
|
||||||
$this.remote.Setter("$($this.identifier()).$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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,6 +49,10 @@ class Bus : IBus {
|
|||||||
$this.levels = [BusLevels]::new($index, $remote)
|
$this.levels = [BusLevels]::new($index, $remote)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[string] ToString() {
|
||||||
|
return $this.GetType().Name + $this.index
|
||||||
|
}
|
||||||
|
|
||||||
[void] FadeTo ([single]$target, [int]$time) {
|
[void] FadeTo ([single]$target, [int]$time) {
|
||||||
$this.Setter('FadeTo', "($target, $time)")
|
$this.Setter('FadeTo', "($target, $time)")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
. $PSScriptRoot\meta.ps1
|
|
||||||
. $PSScriptRoot\inst.ps1
|
|
||||||
|
|
||||||
class Special {
|
class Special {
|
||||||
[Object]$remote
|
[Object]$remote
|
||||||
|
|
||||||
@@ -32,10 +29,12 @@ class Special {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[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() {
|
||||||
|
"Closing the MacroButtons app" | Write-Verbose
|
||||||
Stop-Process -Name "VoicemeeterMacroButtons"
|
Stop-Process -Name "VoicemeeterMacroButtons"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
21
lib/inst.ps1
21
lib/inst.ps1
@@ -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.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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' has been loaded into memory.")
|
||||||
throw [VMRemoteErrors]::new("No profile named $CONF was loaded")
|
|
||||||
}
|
|
||||||
Param_Set_Multi -HASH $DATA.$CONF
|
|
||||||
Start-Sleep -m 1
|
|
||||||
}
|
|
||||||
catch [VMRemoteErrors] {
|
|
||||||
Write-Warning $_.Exception.ErrorMessage()
|
|
||||||
}
|
}
|
||||||
|
Param_Set_Multi -HASH $DATA.$CONF
|
||||||
|
Start-Sleep -m 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
. $PSScriptRoot\meta.ps1
|
|
||||||
|
|
||||||
class IRecorder {
|
class IRecorder {
|
||||||
[Object]$remote
|
[Object]$remote
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
. $PSScriptRoot\meta.ps1
|
|
||||||
|
|
||||||
class IStrip {
|
class IStrip {
|
||||||
[int]$index
|
[int]$index
|
||||||
[Object]$remote
|
[Object]$remote
|
||||||
@@ -14,15 +12,25 @@ class IStrip {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[single] Getter ($param) {
|
[single] Getter ($param) {
|
||||||
return $this.remote.Getter("$($this.identifier()).$param")
|
$this.Cmd($param) | Write-Debug
|
||||||
|
return $this.remote.Getter($this.Cmd($param))
|
||||||
}
|
}
|
||||||
|
|
||||||
[string] Getter_String ($param) {
|
[string] Getter_String ($param) {
|
||||||
return $this.remote.Getter_String("$($this.identifier()).$param")
|
$this.Cmd($param) | Write-Debug
|
||||||
|
return $this.remote.Getter_String($this.Cmd($param))
|
||||||
}
|
}
|
||||||
|
|
||||||
[void] Setter ($param, $val) {
|
[void] Setter ($param, $val) {
|
||||||
$this.remote.Setter("$($this.identifier()).$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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
23
lib/vban.ps1
23
lib/vban.ps1
@@ -13,20 +13,25 @@ class IVban {
|
|||||||
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) {
|
[single] Getter ($param) {
|
||||||
return $this.remote.Getter("$($this.identifier()).$param")
|
return $this.remote.Getter($this.Cmd($param))
|
||||||
}
|
}
|
||||||
|
|
||||||
[string] Getter_String ($param) {
|
[string] Getter_String ($param) {
|
||||||
return $this.remote.Getter_String("$($this.identifier()).$param")
|
$this.Cmd($param) | Write-Debug
|
||||||
|
return $this.remote.Getter_String($this.Cmd($param))
|
||||||
}
|
}
|
||||||
|
|
||||||
[void] Setter ($param, $val) {
|
[void] Setter ($param, $val) {
|
||||||
$this.remote.Setter("$($this.identifier()).$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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +39,10 @@ class Vban : IVban {
|
|||||||
Vban ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote, $direction) {
|
Vban ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote, $direction) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[string] ToString() {
|
||||||
|
return $this.GetType().Name + $this.index
|
||||||
|
}
|
||||||
|
|
||||||
hidden $_on = $($this | Add-Member ScriptProperty 'on' `
|
hidden $_on = $($this | Add-Member ScriptProperty 'on' `
|
||||||
{
|
{
|
||||||
$this.Getter('on')
|
$this.Getter('on')
|
||||||
|
|||||||
Reference in New Issue
Block a user