mirror of
https://github.com/onyx-and-iris/voicemeeter-api-powershell.git
synced 2026-03-03 17:39:11 +00:00
Compare commits
No commits in common. "fc75bc20200477c9a368e5532ea7d6a7183034aa" and "3119b1080e7084e64d5c267ba18b9fc6b7f3dd27" have entirely different histories.
fc75bc2020
...
3119b1080e
@ -12,19 +12,12 @@
|
|||||||
Specifies the type of Voicemeeter to connect to (banana or potato). Default is 'banana'.
|
Specifies the type of Voicemeeter to connect to (banana or potato). Default is 'banana'.
|
||||||
.PARAMETER script
|
.PARAMETER script
|
||||||
A list of commands to execute in sequence.
|
A list of commands to execute in sequence.
|
||||||
.EXAMPLE
|
|
||||||
.\CLI.ps1 -interactive -kind banana
|
|
||||||
Starts the CLI in interactive mode for Voicemeeter Banana.
|
|
||||||
.EXAMPLE
|
|
||||||
.\CLI.ps1 -script "Strip[0].Gain=3", "!Bus[1].Mute", "Bus[0].Gain"
|
|
||||||
Executes a series of commands: sets Strip 0 Gain to 3, toggles Bus 1 Mute, and retrieves Bus 0 Gain.
|
|
||||||
#>
|
#>
|
||||||
|
|
||||||
[cmdletbinding()]
|
[cmdletbinding()]
|
||||||
param(
|
param(
|
||||||
[switch]$help,
|
[switch]$help,
|
||||||
[switch]$interactive,
|
[switch]$interactive,
|
||||||
[ValidateSet('basic', 'banana', 'potato')]
|
|
||||||
[String]$kind = 'banana',
|
[String]$kind = 'banana',
|
||||||
[String[]]$script = @()
|
[String[]]$script = @()
|
||||||
)
|
)
|
||||||
|
|||||||
@ -12,11 +12,10 @@ param()
|
|||||||
|
|
||||||
Import-Module ..\..\lib\Voicemeeter.psm1
|
Import-Module ..\..\lib\Voicemeeter.psm1
|
||||||
|
|
||||||
|
<#
|
||||||
|
A class that accepts a list of Voicemeeter buses and unmutes them one at a time in a round-robin fashion
|
||||||
|
#>
|
||||||
class BusRotator {
|
class BusRotator {
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Class to manage rotating through Voicemeeter buses.
|
|
||||||
#>
|
|
||||||
[object]$vmr = $null
|
[object]$vmr = $null
|
||||||
[int]$CurrentIndex = -1
|
[int]$CurrentIndex = -1
|
||||||
[object[]]$Buses
|
[object[]]$Buses
|
||||||
@ -1,293 +0,0 @@
|
|||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Synchronizes OBS Studio scene changes with Voicemeeter audio settings.
|
|
||||||
|
|
||||||
.DESCRIPTION
|
|
||||||
This script monitors OBS Studio for scene changes via WebSocket connection and
|
|
||||||
automatically adjusts Voicemeeter audio settings based on the active scene.
|
|
||||||
|
|
||||||
.PARAMETER ConfigPath
|
|
||||||
Path to the configuration file. Defaults to 'config.psd1' in the script directory.
|
|
||||||
|
|
||||||
.PARAMETER VoicemeeterKind
|
|
||||||
Type of Voicemeeter to connect to. Defaults to 'basic'.
|
|
||||||
|
|
||||||
.EXAMPLE
|
|
||||||
.\Vm-Obs-Sync.ps1
|
|
||||||
|
|
||||||
.EXAMPLE
|
|
||||||
.\Vm-Obs-Sync.ps1 -ConfigPath "C:\myconfig.psd1" -VoicemeeterKind "banana"
|
|
||||||
#>
|
|
||||||
|
|
||||||
[CmdletBinding()]
|
|
||||||
param(
|
|
||||||
[string]$ConfigPath = (Join-Path $PSScriptRoot 'config.psd1'),
|
|
||||||
[ValidateSet('basic', 'banana', 'potato')]
|
|
||||||
[string]$VoicemeeterKind = 'basic'
|
|
||||||
)
|
|
||||||
|
|
||||||
#Requires -Modules obs-powershell
|
|
||||||
|
|
||||||
# Import required modules
|
|
||||||
try {
|
|
||||||
Import-Module ..\..\lib\Voicemeeter.psm1
|
|
||||||
Import-Module obs-powershell
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Write-Error "Failed to import required modules: $($_.Exception.Message)"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Script-level variables
|
|
||||||
$script:vmr = $null
|
|
||||||
$script:obsJob = $null
|
|
||||||
$script:shouldExit = $false
|
|
||||||
|
|
||||||
#region Helper Functions
|
|
||||||
|
|
||||||
function Write-Log {
|
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Writes timestamped log messages to the console.
|
|
||||||
#>
|
|
||||||
param(
|
|
||||||
[Parameter(Mandatory, ValueFromPipeline)]
|
|
||||||
[string]$Message,
|
|
||||||
[ValidateSet('Info', 'Warning', 'Error')]
|
|
||||||
[string]$Level = 'Info'
|
|
||||||
)
|
|
||||||
|
|
||||||
$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
|
|
||||||
$logMessage = "[$timestamp] [$Level] $Message"
|
|
||||||
|
|
||||||
switch ($Level) {
|
|
||||||
'Info' { Write-Information $logMessage -InformationAction Continue }
|
|
||||||
'Warning' { Write-Warning $logMessage }
|
|
||||||
'Error' { Write-Error $logMessage }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Get-ConnectionConfig {
|
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Loads OBS connection configuration from file.
|
|
||||||
#>
|
|
||||||
param([string]$Path = $ConfigPath)
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (-not (Test-Path $Path)) {
|
|
||||||
throw "Configuration file not found: $Path"
|
|
||||||
}
|
|
||||||
|
|
||||||
$config = Import-PowerShellDataFile -Path $Path -ErrorAction Stop
|
|
||||||
|
|
||||||
# Validate required properties
|
|
||||||
$requiredProperties = @('host', 'port', 'password')
|
|
||||||
foreach ($prop in $requiredProperties) {
|
|
||||||
if (-not $config.ContainsKey($prop)) {
|
|
||||||
throw "Missing required configuration property: $prop"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Log "Configuration loaded successfully from: $Path"
|
|
||||||
return $config
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Write-Log "Failed to load configuration: $($_.Exception.Message)" -Level Error
|
|
||||||
throw
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Initialize-Connections {
|
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Initializes connections to Voicemeeter and OBS.
|
|
||||||
#>
|
|
||||||
try {
|
|
||||||
$script:vmr = Connect-Voicemeeter -Kind $VoicemeeterKind -ErrorAction Stop
|
|
||||||
Write-Log 'Voicemeeter connection established'
|
|
||||||
|
|
||||||
$obsConfig = Get-ConnectionConfig
|
|
||||||
|
|
||||||
|
|
||||||
$webSocketUri = "ws://$($obsConfig.host):$($obsConfig.port)"
|
|
||||||
$script:obsJob = Watch-OBS -WebSocketURI $webSocketUri -WebSocketToken $obsConfig.password -ErrorAction Stop
|
|
||||||
Write-Log "OBS connection at $webSocketUri established"
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Write-Log "Failed to initialize connections: $($_.Exception.Message)" -Level Error
|
|
||||||
throw
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Disconnect-All {
|
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Safely disconnects from all services.
|
|
||||||
#>
|
|
||||||
Write-Log 'Cleaning up connections...'
|
|
||||||
|
|
||||||
try {
|
|
||||||
if ($script:obsJob) {
|
|
||||||
Remove-Job -Job $script:obsJob -Force -ErrorAction SilentlyContinue
|
|
||||||
Disconnect-OBS -ErrorAction SilentlyContinue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Write-Log "Error disconnecting from OBS: $($_.Exception.Message)" -Level Warning
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if ($script:vmr) {
|
|
||||||
Disconnect-Voicemeeter -ErrorAction SilentlyContinue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Write-Log "Error disconnecting from Voicemeeter: $($_.Exception.Message)" -Level Warning
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Log 'Cleanup completed'
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Event Handlers
|
|
||||||
|
|
||||||
function Invoke-CurrentProgramSceneChanged {
|
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Handles OBS scene change events.
|
|
||||||
#>
|
|
||||||
param(
|
|
||||||
[Parameter(Mandatory)]
|
|
||||||
[System.Object]$EventData
|
|
||||||
)
|
|
||||||
|
|
||||||
if (-not $EventData.sceneName) {
|
|
||||||
Write-Log 'Scene change event received but no scene name provided' -Level Warning
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Log "Scene changed to: $($EventData.sceneName)"
|
|
||||||
|
|
||||||
try {
|
|
||||||
switch ($EventData.sceneName) {
|
|
||||||
'START' {
|
|
||||||
Write-Log 'Toggling mute for strip 0'
|
|
||||||
$script:vmr.strip[0].mute = !$script:vmr.strip[0].mute
|
|
||||||
}
|
|
||||||
'BRB' {
|
|
||||||
Write-Log 'Setting gain to -8.3dB for strip 0'
|
|
||||||
$script:vmr.strip[0].gain = -8.3
|
|
||||||
}
|
|
||||||
'END' {
|
|
||||||
Write-Log 'Enabling mono for strip 0'
|
|
||||||
$script:vmr.strip[0].mono = $true
|
|
||||||
}
|
|
||||||
'LIVE' {
|
|
||||||
Write-Log 'Setting color_x to 0.3 for strip 0'
|
|
||||||
$script:vmr.strip[0].color_x = 0.3
|
|
||||||
}
|
|
||||||
default {
|
|
||||||
Write-Log "Unknown scene '$($EventData.sceneName)'. Expected: START, BRB, END, or LIVE" -Level Warning
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Write-Log "Error processing scene change: $($_.Exception.Message)" -Level Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Invoke-ExitStarted {
|
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Handles OBS exit events.
|
|
||||||
#>
|
|
||||||
param([System.Object]$EventData)
|
|
||||||
|
|
||||||
Write-Log 'OBS shutdown detected - initiating graceful exit'
|
|
||||||
$script:shouldExit = $true
|
|
||||||
}
|
|
||||||
|
|
||||||
function Invoke-EventDispatcher {
|
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Dispatches OBS events to appropriate handlers.
|
|
||||||
#>
|
|
||||||
param(
|
|
||||||
[Parameter(Mandatory)]
|
|
||||||
[System.Object]$EventData
|
|
||||||
)
|
|
||||||
|
|
||||||
if (-not $EventData.eventType) {
|
|
||||||
Write-Log 'Event received without eventType property' -Level Warning
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
$handlerName = "Invoke-$($EventData.eventType)"
|
|
||||||
|
|
||||||
if (Get-Command $handlerName -ErrorAction SilentlyContinue) {
|
|
||||||
try {
|
|
||||||
& $handlerName -EventData $EventData.eventData
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Write-Log "Error in event handler '$handlerName': $($_.Exception.Message)" -Level Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Write-Log "No handler found for event type: $($EventData.eventType)" -Level Warning
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Main Execution
|
|
||||||
|
|
||||||
function Start-VoicemeeterObsSync {
|
|
||||||
<#
|
|
||||||
.SYNOPSIS
|
|
||||||
Main execution function for the sync process.
|
|
||||||
#>
|
|
||||||
Write-Log 'Starting Voicemeeter-OBS synchronization service'
|
|
||||||
|
|
||||||
try {
|
|
||||||
Initialize-Connections
|
|
||||||
|
|
||||||
Write-Log 'Monitoring OBS events... Press Ctrl+C to stop'
|
|
||||||
|
|
||||||
while (-not $script:shouldExit) {
|
|
||||||
try {
|
|
||||||
$obsEvents = Receive-Job -Job $script:obsJob -ErrorAction SilentlyContinue
|
|
||||||
|
|
||||||
foreach ($obsEvent in $obsEvents) {
|
|
||||||
if ($obsEvent.MessageData.op -eq 5) {
|
|
||||||
Invoke-EventDispatcher -EventData $obsEvent.MessageData.d
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Start-Sleep -Milliseconds 100
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Write-Log "Error processing OBS events: $($_.Exception.Message)" -Level Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Write-Log "Fatal error: $($_.Exception.Message)" -Level Error
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
Disconnect-All
|
|
||||||
}
|
|
||||||
|
|
||||||
Write-Log 'Voicemeeter-OBS synchronization service stopped'
|
|
||||||
}
|
|
||||||
|
|
||||||
# Handle Ctrl+C gracefully
|
|
||||||
$null = Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action {
|
|
||||||
$script:shouldExit = $true
|
|
||||||
}
|
|
||||||
|
|
||||||
Start-VoicemeeterObsSync
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
68
examples/obs/Vm-Obs-Sync.ps1
Normal file
68
examples/obs/Vm-Obs-Sync.ps1
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
[cmdletbinding()]
|
||||||
|
param()
|
||||||
|
|
||||||
|
Import-Module ..\..\lib\Voicemeeter.psm1
|
||||||
|
Import-Module obs-powershell
|
||||||
|
|
||||||
|
function CurrentProgramSceneChanged {
|
||||||
|
param([System.Object]$data)
|
||||||
|
Write-Host 'Switched to scene', $data.sceneName
|
||||||
|
|
||||||
|
switch ($data.sceneName) {
|
||||||
|
'START' {
|
||||||
|
$vmr.strip[0].mute = !$vmr.strip[0].mute
|
||||||
|
}
|
||||||
|
'BRB' {
|
||||||
|
$vmr.strip[0].gain = -8.3
|
||||||
|
}
|
||||||
|
'END' {
|
||||||
|
$vmr.strip[0].mono = $true
|
||||||
|
}
|
||||||
|
'LIVE' {
|
||||||
|
$vmr.strip[0].color_x = 0.3
|
||||||
|
}
|
||||||
|
default { 'Expected START, BRB, END or LIVE scene' | Write-Warning; return }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ExitStarted {
|
||||||
|
param([System.Object]$data)
|
||||||
|
'OBS shutdown has begun!' | Write-Host
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
function eventHandler($data) {
|
||||||
|
if (Get-Command $data.eventType -ErrorAction SilentlyContinue) {
|
||||||
|
& $data.eventType -data $data.eventData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ConnFromFile {
|
||||||
|
$configpath = Join-Path $PSScriptRoot 'config.psd1'
|
||||||
|
return Import-PowerShellDataFile -Path $configpath
|
||||||
|
}
|
||||||
|
|
||||||
|
function main {
|
||||||
|
$vmr = Connect-Voicemeeter -Kind 'basic'
|
||||||
|
|
||||||
|
$conn = ConnFromFile
|
||||||
|
$job = Watch-OBS -WebSocketURI "ws://$($conn.host):$($conn.port)" -WebSocketToken $conn.password
|
||||||
|
|
||||||
|
try {
|
||||||
|
while ($true) {
|
||||||
|
Receive-Job -Job $job | ForEach-Object {
|
||||||
|
$data = $_.MessageData
|
||||||
|
|
||||||
|
if ($data.op -eq 5) {
|
||||||
|
eventHandler($data.d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
Disconnect-OBS
|
||||||
|
Disconnect-Voicemeeter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
||||||
Loading…
x
Reference in New Issue
Block a user