From 9209bbbc6544fc9fdb15a24ed90283bd19972b3b Mon Sep 17 00:00:00 2001 From: pblivingston <71585805+pblivingston@users.noreply.github.com> Date: Tue, 2 Dec 2025 12:23:06 -0500 Subject: [PATCH 1/9] armstrip, armbus, armedbus - armstrip, armbus -> boolarraymembers - armedbus prelim tests pass for potato --- lib/recorder.ps1 | 32 ++++++++++++++++++++++++++++---- tests/higher.Tests.ps1 | 23 +++++++++++++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/lib/recorder.ps1 b/lib/recorder.ps1 index c8d95dd..d570190 100644 --- a/lib/recorder.ps1 +++ b/lib/recorder.ps1 @@ -5,13 +5,17 @@ class Recorder : IRemote { Recorder ([Object]$remote) : base ($remote) { $this.mode = [RecorderMode]::new($remote) + $this.armstrip = @() - 0..($remote.kind.p_in + $remote.kind.v_in - 1) | ForEach-Object { - $this.armstrip.Add([RecorderArmStrip]::new($_, $remote)) + $stripCount = $($remote.kind.p_in + $remote.kind.v_in) + for ($i = 0; $i -lt $stripCount; $i++) { + $this.armstrip.Add([BoolArrayMember]::new($i, 'armstrip', $this)) } + $this.armbus = @() - 0..($remote.kind.p_out + $remote.kind.v_out - 1) | ForEach-Object { - $this.armbus.Add([RecorderArmBus]::new($_, $remote)) + $busCount = $($remote.kind.p_out + $remote.kind.v_out) + for ($i = 0; $i -lt $busCount; $i++) { + $this.armbus.Add([BoolArrayMember]::new($i, 'armbus', $this)) } AddActionMembers -PARAMS @('play', 'stop', 'pause', 'replay', 'record', 'ff', 'rew') @@ -96,6 +100,26 @@ class Recorder : IRemote { } ) + hidden $_armedbus = $($this | Add-Member ScriptProperty 'armedbus' ` + { + foreach ($bus in 0..$($this.remote.kind.p_out + $this.remote.kind.v_out - 1)) { + if ($this.remote.Getter("Recorder.ArmBus[$bus]")) { + break + } + } + return $bus + } ` + { + param([int]$arg) + $busMax = $this.remote.kind.p_out + $this.remote.kind.v_out - 1 + if ($arg -ge 0 -and $arg -le $busMax) { + $this._armedbus = $this.remote.Setter("Recorder.ArmBus[$arg]", 1) + } + else { + Write-Warning ("Expected a bus index between 0 and $busMax") + } + }) + [void] Load ([string]$filename) { $this.Setter('load', $filename) } diff --git a/tests/higher.Tests.ps1 b/tests/higher.Tests.ps1 index 7e45b03..22b9c55 100644 --- a/tests/higher.Tests.ps1 +++ b/tests/higher.Tests.ps1 @@ -160,6 +160,20 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' { It 'Should set and get Recorder.loop' { $vmr.recorder.loop = $value } + + It 'Should set and get Recorder.armstrip[i]' -ForEach @( + @{ Index = $phys_in }, @{ Index = $virt_in } + ) { + $vmr.recorder.armstrip[$index].set($value) + $vmr.recorder.armstrip[$index].get() | Should -Be $value + } + + It 'Should set and get Recorder.armbus[i]' -ForEach @( + @{ Index = $phys_out }, @{ Index = $virt_out } + ) { + $vmr.recorder.armbus[$index].set($value) + $vmr.recorder.armbus[$index].get() | Should -Be $value + } } Context 'Command' { @@ -603,6 +617,15 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' { } } } + + Context 'Recorder' -Skip:$ifBasic { + It 'Should set and get Recorder.armedbus' -ForEach @( + @{ Value = $phys_out }, @{ Value = $virt_out } + ) { + $vmr.recorder.armedbus = $value + $vmr.recorder.armedbus | Should -Be $value + } + } } Describe 'String Tests' -Tag 'string' { From 58652b5a3f714a9e964305d9be43a2876816e9f0 Mon Sep 17 00:00:00 2001 From: pblivingston <71585805+pblivingston@users.noreply.github.com> Date: Tue, 2 Dec 2025 12:42:00 -0500 Subject: [PATCH 2/9] update docs arming --- CHANGELOG.md | 2 ++ README.md | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78c3bc5..ac77dbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ AddActionMembers now adds ScriptMethods instead of ScriptProperties: - ip, write-only - Bus.Sel, Bus.Monitor, Bus.Vaio - Bus.Mode.Set($mode) +- Recorder.Armedbus ### Changed @@ -43,6 +44,7 @@ AddActionMembers now adds ScriptMethods instead of ScriptProperties: - Bus.Levels.Convert return type [float] -> [single] for naming consistency, no functional change - Meta: AddBoolMembers, AddIntMembers $arg types for consistency - Device: explicit $arg types for consistency +- Recorder.Armstrip|Armbus -> BoolArrayMember: now have .Get() ### Fixed diff --git a/README.md b/README.md index 76a0ed0..a2271cf 100644 --- a/README.md +++ b/README.md @@ -527,6 +527,7 @@ The following commands are available: - A1 - A5: bool - B1 - B3: bool +- armedbus: int, from 0 to bus index - samplerate: int, (22050, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000) - bitresolution: int, (8, 16, 24, 32) - channel: int, from 1 to 8 @@ -571,9 +572,10 @@ $vmr.recorder.mode.loop = $true #### ArmStrip[i]|ArmBus[i] -The following method is available: +The following methods are available: - Set($val): bool +- Get() example: From d7cb1d610d8725133616e455be32e33b154e50b7 Mon Sep 17 00:00:00 2001 From: pblivingston <71585805+pblivingston@users.noreply.github.com> Date: Tue, 2 Dec 2025 18:06:02 -0500 Subject: [PATCH 3/9] prerectime, prefix prelim testing passes for potato - prefix is currently write-only, so added as a method like FileType --- CHANGELOG.md | 2 ++ README.md | 2 ++ lib/recorder.ps1 | 7 +++++++ tests/higher.Tests.ps1 | 7 +++++++ 4 files changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac77dbb..26a6a68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ AddActionMembers now adds ScriptMethods instead of ScriptProperties: - Bus.Sel, Bus.Monitor, Bus.Vaio - Bus.Mode.Set($mode) - Recorder.Armedbus +- Recorder.PreRecTime +- Recorder.Prefix($prefix) ### Changed diff --git a/README.md b/README.md index a2271cf..270f9df 100644 --- a/README.md +++ b/README.md @@ -528,6 +528,7 @@ The following commands are available: - A1 - A5: bool - B1 - B3: bool - armedbus: int, from 0 to bus index +- prerectime: int, from 0 to 20 seconds - samplerate: int, (22050, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000) - bitresolution: int, (8, 16, 24, 32) - channel: int, from 1 to 8 @@ -545,6 +546,7 @@ The following methods are available: - Load($filepath): string - GoTo($timestring): string, must match the format 'hh:mm:ss' - FileType($format): string, ('wav', 'aiff', 'bwf', 'mp3') +- Prefix($prefix): string example: diff --git a/lib/recorder.ps1 b/lib/recorder.ps1 index d570190..e6cc59b 100644 --- a/lib/recorder.ps1 +++ b/lib/recorder.ps1 @@ -19,7 +19,10 @@ class Recorder : IRemote { } AddActionMembers -PARAMS @('play', 'stop', 'pause', 'replay', 'record', 'ff', 'rew') + AddFloatMembers -PARAMS @('gain') + AddIntMembers -PARAMS @('prerectime') + AddChannelMembers } @@ -147,6 +150,10 @@ class Recorder : IRemote { } $this.Setter('filetype', $val) } + + [void] Prefix ([string]$prefix) { + $this.Setter('prefix', $prefix) + } } class RecorderMode : IRemote { diff --git a/tests/higher.Tests.ps1 b/tests/higher.Tests.ps1 index 22b9c55..fd9f380 100644 --- a/tests/higher.Tests.ps1 +++ b/tests/higher.Tests.ps1 @@ -625,6 +625,13 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' { $vmr.recorder.armedbus = $value $vmr.recorder.armedbus | Should -Be $value } + + It 'Should set and get Recorder.prerectime' -ForEach @( + @{ Value = 5 }, @{ Value = 20 } + ) { + $vmr.recorder.prerectime = $value + $vmr.recorder.prerectime | Should -Be $value + } } } From 8c3217b9a8a4dc4fd8cbf6acf386217e81e4eb9f Mon Sep 17 00:00:00 2001 From: pblivingston <71585805+pblivingston@users.noreply.github.com> Date: Tue, 2 Dec 2025 18:12:15 -0500 Subject: [PATCH 4/9] eject prelim test passes for potato 'Command.Eject' --- CHANGELOG.md | 1 + README.md | 1 + lib/recorder.ps1 | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26a6a68..75ba6ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ AddActionMembers now adds ScriptMethods instead of ScriptProperties: - Recorder.Armedbus - Recorder.PreRecTime - Recorder.Prefix($prefix) +- Recorder.Eject() references 'Command.Eject' ### Changed diff --git a/README.md b/README.md index 270f9df..e89ed11 100644 --- a/README.md +++ b/README.md @@ -543,6 +543,7 @@ The following methods are available: - Rew() - Record() - Pause() +- Eject() - Load($filepath): string - GoTo($timestring): string, must match the format 'hh:mm:ss' - FileType($format): string, ('wav', 'aiff', 'bwf', 'mp3') diff --git a/lib/recorder.ps1 b/lib/recorder.ps1 index e6cc59b..133bcd3 100644 --- a/lib/recorder.ps1 +++ b/lib/recorder.ps1 @@ -154,6 +154,10 @@ class Recorder : IRemote { [void] Prefix ([string]$prefix) { $this.Setter('prefix', $prefix) } + + [void] Eject () { + $this.remote.Setter('Command.Eject', 1) + } } class RecorderMode : IRemote { From 0564dce7b63b70b667104574e62cd9492af4383b Mon Sep 17 00:00:00 2001 From: pblivingston <71585805+pblivingston@users.noreply.github.com> Date: Wed, 3 Dec 2025 02:24:08 -0500 Subject: [PATCH 5/9] recorder.state - prelim tests pass for potato --- CHANGELOG.md | 1 + README.md | 1 + lib/recorder.ps1 | 34 ++++++++++++++++++++++--- tests/higher.Tests.ps1 | 56 ++++++++++++++++++++++++++++++++++++++++++ tests/run.ps1 | 39 ++++++++++++++++++++++++++++- 5 files changed, 127 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75ba6ce..e8e35df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ AddActionMembers now adds ScriptMethods instead of ScriptProperties: - Recorder.PreRecTime - Recorder.Prefix($prefix) - Recorder.Eject() references 'Command.Eject' +- Recorder.State ### Changed diff --git a/README.md b/README.md index e89ed11..0c9bf38 100644 --- a/README.md +++ b/README.md @@ -528,6 +528,7 @@ The following commands are available: - A1 - A5: bool - B1 - B3: bool - armedbus: int, from 0 to bus index +- state: string, ('play', 'stop', 'record', 'pause') - prerectime: int, from 0 to 20 seconds - samplerate: int, (22050, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000) - bitresolution: int, (8, 16, 24, 32) diff --git a/lib/recorder.ps1 b/lib/recorder.ps1 index 133bcd3..a5aa67a 100644 --- a/lib/recorder.ps1 +++ b/lib/recorder.ps1 @@ -2,6 +2,7 @@ class Recorder : IRemote { [Object]$mode [System.Collections.ArrayList]$armstrip [System.Collections.ArrayList]$armbus + [System.Collections.ArrayList]$states Recorder ([Object]$remote) : base ($remote) { $this.mode = [RecorderMode]::new($remote) @@ -18,8 +19,10 @@ class Recorder : IRemote { $this.armbus.Add([BoolArrayMember]::new($i, 'armbus', $this)) } - AddActionMembers -PARAMS @('play', 'stop', 'pause', 'replay', 'record', 'ff', 'rew') - + $this.states = @('play', 'stop', 'record', 'pause') + AddActionMembers -PARAMS $this.states + + AddActionMembers -PARAMS @('replay', 'ff', 'rew') AddFloatMembers -PARAMS @('gain') AddIntMembers -PARAMS @('prerectime') @@ -121,7 +124,32 @@ class Recorder : IRemote { else { Write-Warning ("Expected a bus index between 0 and $busMax") } - }) + } + ) + + hidden $_state = $($this | Add-Member ScriptProperty 'state' ` + { + if ($this.Getter('pause')) { return 'pause' } + foreach ($state in $this.states) { + if ($this.Getter($state)) { + break + } + } + return $state + } ` + { + param([string]$arg) + if (-not $this.states.Contains($arg)) { + Write-Warning ("Recorder.State got: $arg, expected one of $($this.states)") + return + } + if ($arg -eq 'pause' -and -not $this.Getter('record')) { + Write-Warning ("Recorder.State can only be set to 'pause' when recording") + return + } + $this._state = $this.Setter($arg, 1) + } + ) [void] Load ([string]$filename) { $this.Setter('load', $filename) diff --git a/tests/higher.Tests.ps1 b/tests/higher.Tests.ps1 index fd9f380..be54cb6 100644 --- a/tests/higher.Tests.ps1 +++ b/tests/higher.Tests.ps1 @@ -876,4 +876,60 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' { } } } + + Describe 'Action Tests' -Tag 'action' { + Context 'Recorder' -Skip:$ifBasic { + Context 'Recording/Playback' -Skip:$ifCustomDir { + BeforeAll { + $prefix = 'temp' + $filetype = 'wav' + $vmr.recorder.prefix($prefix) + $vmr.recorder.filetype($filetype) + } + + BeforeEach { + $vmr.recorder.state = 'record' + $stamp = '{0:yyyy-MM-dd} at {0:HH}h{0:mm}m{0:ss}s' -f (Get-Date) + Start-Sleep -Milliseconds 2000 + + $tmp = [System.IO.Path]::Combine($recDir, ("{0} {1}.{2}" -f $prefix, $stamp, $filetype)) + + $vmr.recorder.state = 'pause' + Start-Sleep -Milliseconds 500 + } + + AfterEach { + $vmr.recorder.state = 'stop' + $vmr.recorder.eject() + Start-Sleep -Milliseconds 500 + + if (Test-Path $tmp) { + Remove-Item -Path $tmp -Force + } + else { + throw "Recording file $tmp was not found." + } + } + + It 'Should call Recorder.record()' { + $vmr.recorder.record() + $vmr.recorder.state | Should -Be 'record' + } + + It 'Should call Recorder.pause()' { + $vmr.recorder.record() + Start-Sleep -Milliseconds 500 + $vmr.recorder.pause() + $vmr.recorder.state | Should -Be 'pause' + } + + It 'Should call Recorder.play()' { + $vmr.recorder.stop() + Start-Sleep -Milliseconds 500 + $vmr.recorder.play() + $vmr.recorder.state | Should -Be 'play' + } + } + } + } } diff --git a/tests/run.ps1 b/tests/run.ps1 index 02daa8b..5257371 100644 --- a/tests/run.ps1 +++ b/tests/run.ps1 @@ -1,8 +1,41 @@ [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "", Target = "variablename")] -Param([String]$tag, [string]$kind = 'potato') +Param([String]$tag, [string]$kind = 'potato', [string]$recDir = (Join-Path ([Environment]::GetFolderPath('MyDocuments')) 'Voicemeeter')) Import-Module (Join-Path (Split-Path $PSScriptRoot -Parent) 'lib\Voicemeeter.psm1') -Force +function Test-RecDir ([object]$vmr, [string]$recDir) { + $prefix = 'temp' + $filetype = 'wav' + $vmr.recorder.prefix($prefix) + $vmr.recorder.filetype($filetype) + + + try { + $vmr.recorder.record() + $stamp = '{0:yyyy-MM-dd} at {0:HH}h{0:mm}m{0:ss}s' -f (Get-Date) + Start-Sleep -Milliseconds 2000 + + $tmp = Join-Path $recDir ("{0} {1}.{2}" -f $prefix, $stamp, $filetype) + + $vmr.recorder.stop() + $vmr.recorder.eject() + Start-Sleep -Milliseconds 500 + } + catch { + Write-Warning "Failed to record pre-check clip: $_" + } + + if (Test-Path $tmp) { + Remove-Item -Path $tmp -Force + return $false + } + else { + Write-Warning "Recorder output not found at given path: $tmp" + Write-Warning "Skipping Recording/Playback tests. Provide custom path with -recDir" + return $true + } +} + function main() { try { $vmr = Connect-Voicemeeter -Kind $kind @@ -30,6 +63,10 @@ function main() { $ifNotBasic = $vmr.kind.name -ne 'basic' $ifNotPotato = $vmr.kind.name -ne 'potato' + # recording directory: default ~/My Documents/Voicemeeter, override if custom + $recDir = [System.IO.Path]::GetFullPath($recDir) + $ifCustomDir = Test-RecDir -vmr $vmr -recDir $recDir # avoid creating files we can't delete + Invoke-Pester -Tag $tag -PassThru | Out-Null } finally { Disconnect-Voicemeeter } From e42862c32d5f0500144f8947c9be50f322e1be1e Mon Sep 17 00:00:00 2001 From: pblivingston <71585805+pblivingston@users.noreply.github.com> Date: Wed, 3 Dec 2025 02:58:56 -0500 Subject: [PATCH 6/9] add string test - can now test recorder.load($filename) - prelim test passes for potato --- tests/higher.Tests.ps1 | 52 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/tests/higher.Tests.ps1 b/tests/higher.Tests.ps1 index be54cb6..3a8a84c 100644 --- a/tests/higher.Tests.ps1 +++ b/tests/higher.Tests.ps1 @@ -875,31 +875,75 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' { } } } + + Context 'Recorder' -Skip:$ifBasic { + It 'Should record a test file, eject, and load it back' -Skip:$ifCustomDir { + try { + $prefix = 'stringtest' + $filetype = 'wav' + $vmr.recorder.prefix($prefix) + $vmr.recorder.filetype($filetype) + + $vmr.recorder.state = 'record' + $stamp = '{0:yyyy-MM-dd} at {0:HH}h{0:mm}m{0:ss}s' -f (Get-Date) + $vmr.recorder.state | Should -Be 'record' + Start-Sleep -Milliseconds 2000 + + $tmp = [System.IO.Path]::Combine($recDir, ("{0} {1}.{2}" -f $prefix, $stamp, $filetype)) + + $vmr.recorder.state = 'stop' + $vmr.recorder.eject() + Start-Sleep -Milliseconds 500 + + $vmr.recorder.state = 'play' + $vmr.recorder.state | Should -Be 'stop' # because no file is loaded + + $vmr.recorder.load($tmp) + Start-Sleep -Milliseconds 500 + if (-not $vmr.recorder.mode.playonload) { + $vmr.recorder.state = 'play' + } + $vmr.recorder.state | Should -Be 'play' + } + finally { + $vmr.recorder.state = 'stop' + $vmr.recorder.eject() + Start-Sleep -Milliseconds 500 + + if (Test-Path $tmp) { + Remove-Item -Path $tmp -Force + } + else { + throw "Recording file $tmp was not found." + } + } + } + } } Describe 'Action Tests' -Tag 'action' { Context 'Recorder' -Skip:$ifBasic { Context 'Recording/Playback' -Skip:$ifCustomDir { BeforeAll { - $prefix = 'temp' + $prefix = 'actiontest' $filetype = 'wav' $vmr.recorder.prefix($prefix) $vmr.recorder.filetype($filetype) } BeforeEach { - $vmr.recorder.state = 'record' + $vmr.recorder.record() $stamp = '{0:yyyy-MM-dd} at {0:HH}h{0:mm}m{0:ss}s' -f (Get-Date) Start-Sleep -Milliseconds 2000 $tmp = [System.IO.Path]::Combine($recDir, ("{0} {1}.{2}" -f $prefix, $stamp, $filetype)) - $vmr.recorder.state = 'pause' + $vmr.recorder.pause() Start-Sleep -Milliseconds 500 } AfterEach { - $vmr.recorder.state = 'stop' + $vmr.recorder.stop() $vmr.recorder.eject() Start-Sleep -Milliseconds 500 From ab4baa5c440da9a3a823505860d13b56cb291e10 Mon Sep 17 00:00:00 2001 From: pblivingston <71585805+pblivingston@users.noreply.github.com> Date: Wed, 3 Dec 2025 03:31:30 -0500 Subject: [PATCH 7/9] remove loop, cleanup - removed deprecated recorder.loop - placed methods before hidden properties for readability - added a couple mode tests for good measure --- CHANGELOG.md | 2 + lib/recorder.ps1 | 105 +++++++++++++---------------------------- tests/higher.Tests.ps1 | 16 +++++-- 3 files changed, 48 insertions(+), 75 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8e35df..0d06cda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ AddActionMembers now adds ScriptMethods instead of ScriptProperties: - See Command section of README for details on using special commands - See Recorder section of README for details on using playback/record actions +Deprecated Recorder.Loop removed: use Recorder.Mode.Loop + ### Added - IRemote base class diff --git a/lib/recorder.ps1 b/lib/recorder.ps1 index a5aa67a..24bda3e 100644 --- a/lib/recorder.ps1 +++ b/lib/recorder.ps1 @@ -33,15 +33,41 @@ class Recorder : IRemote { return 'Recorder' } - hidden $_loop = $($this | Add-Member ScriptProperty 'loop' ` - { - [bool]$this.mode.loop - } ` - { - param($arg) - $this.mode.loop = $arg + [void] Eject () { + $this.remote.Setter('Command.Eject', 1) + } + + [void] Load ([string]$filename) { + $this.Setter('load', $filename) + } + + [void] Prefix ([string]$prefix) { + $this.Setter('prefix', $prefix) + } + + [void] FileType([string]$format) { + [int]$val = 0 + switch ($format) { + 'wav' { $val = 1 } + 'aiff' { $val = 2 } + 'bwf' { $val = 3 } + 'mp3' { $val = 100 } + default { "Filetype() got: $format, expected one of 'wav', 'aiff', 'bwf', 'mp3'" } } - ) + $this.Setter('filetype', $val) + } + + [void] GoTo ([string]$timestring) { + try { + if ([datetime]::ParseExact($timestring, 'HH:mm:ss', $null)) { + $timespan = [timespan]::Parse($timestring) + $this.Setter('GoTo', $timespan.TotalSeconds) + } + } + catch [FormatException] { + "Time string $timestring does not match the required format 'hh:mm:ss'" | Write-Warning + } + } hidden $_samplerate = $($this | Add-Member ScriptProperty 'samplerate' ` { @@ -150,42 +176,6 @@ class Recorder : IRemote { $this._state = $this.Setter($arg, 1) } ) - - [void] Load ([string]$filename) { - $this.Setter('load', $filename) - } - - [void] GoTo ([string]$timestring) { - try { - if ([datetime]::ParseExact($timestring, 'HH:mm:ss', $null)) { - $timespan = [timespan]::Parse($timestring) - $this.Setter('GoTo', $timespan.TotalSeconds) - } - } - catch [FormatException] { - "Time string $timestring does not match the required format 'hh:mm:ss'" | Write-Warning - } - } - - [void] FileType($format) { - [int]$val = 0 - switch ($format) { - 'wav' { $val = 1 } - 'aiff' { $val = 2 } - 'bwf' { $val = 3 } - 'mp3' { $val = 100 } - default { "Filetype() got: $format, expected one of 'wav', 'aiff', 'bwf', 'mp3'" } - } - $this.Setter('filetype', $val) - } - - [void] Prefix ([string]$prefix) { - $this.Setter('prefix', $prefix) - } - - [void] Eject () { - $this.remote.Setter('Command.Eject', 1) - } } class RecorderMode : IRemote { @@ -198,33 +188,6 @@ class RecorderMode : IRemote { } } -class RecorderArm : IRemote { - RecorderArm ([int]$index, [Object]$remote) : base ($index, $remote) { - } - - Set ([bool]$val) { - $this.Setter('', $(if ($val) { 1 } else { 0 })) - } -} - -class RecorderArmStrip : RecorderArm { - RecorderArmStrip ([int]$index, [Object]$remote) : base ($index, $remote) { - } - - [string] identifier () { - return "Recorder.ArmStrip[$($this.index)]" - } -} - -class RecorderArmBus : RecorderArm { - RecorderArmBus ([int]$index, [Object]$remote) : base ($index, $remote) { - } - - [string] identifier () { - return "Recorder.ArmBus[$($this.index)]" - } -} - function Make_Recorder ([Object]$remote) { return [Recorder]::new($remote) } diff --git a/tests/higher.Tests.ps1 b/tests/higher.Tests.ps1 index 3a8a84c..1804098 100644 --- a/tests/higher.Tests.ps1 +++ b/tests/higher.Tests.ps1 @@ -157,10 +157,6 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' { $vmr.recorder.B1 | Should -Be $expected } - It 'Should set and get Recorder.loop' { - $vmr.recorder.loop = $value - } - It 'Should set and get Recorder.armstrip[i]' -ForEach @( @{ Index = $phys_in }, @{ Index = $virt_in } ) { @@ -174,6 +170,18 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' { $vmr.recorder.armbus[$index].set($value) $vmr.recorder.armbus[$index].get() | Should -Be $value } + + Context 'Mode' { + It 'Should set and get Recorder.mode.multitrack' { + $vmr.recorder.mode.multitrack = $value + $vmr.recorder.mode.multitrack | Should -Be $expected + } + + It 'Should set and get Recorder.mode.loop' { + $vmr.recorder.mode.loop = $value + $vmr.recorder.mode.loop | Should -Be $expected + } + } } Context 'Command' { From 1d41be7396f93f43d1452c7fa2159d267f8b8872 Mon Sep 17 00:00:00 2001 From: pblivingston <71585805+pblivingston@users.noreply.github.com> Date: Wed, 3 Dec 2025 04:18:25 -0500 Subject: [PATCH 8/9] channel, types - correct channel values - add 'gain' to README - cast getters to [int] - add some int tests for safety - skip recording test if basic pester tests pass for all kinds manual tests for safety pass - channel --- CHANGELOG.md | 2 ++ README.md | 3 ++- lib/recorder.ps1 | 13 +++++++------ tests/higher.Tests.ps1 | 21 +++++++++++++++++++++ tests/run.ps1 | 7 ++++++- 5 files changed, 38 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d06cda..462d961 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ Deprecated Recorder.Loop removed: use Recorder.Mode.Loop - Meta: AddBoolMembers, AddIntMembers $arg types for consistency - Device: explicit $arg types for consistency - Recorder.Armstrip|Armbus -> BoolArrayMember: now have .Get() +- Cast Recorder getters to types for consistency ### Fixed @@ -61,6 +62,7 @@ Deprecated Recorder.Loop removed: use Recorder.Mode.Loop - vban.stream.port: [string]$arg -> [int]$arg - vban route range (API documentation is incorrect) - vban.stream.sr: $this._port -> $this._sr +- Recorder.channel values: 1..8 -> (2, 4, 6, 8) ## [3.3.0] - 2024-06-29 diff --git a/README.md b/README.md index 0c9bf38..14b8668 100644 --- a/README.md +++ b/README.md @@ -527,12 +527,13 @@ The following commands are available: - A1 - A5: bool - B1 - B3: bool +- gain: float, from -60.0 to 12.0 - armedbus: int, from 0 to bus index - state: string, ('play', 'stop', 'record', 'pause') - prerectime: int, from 0 to 20 seconds - samplerate: int, (22050, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000) - bitresolution: int, (8, 16, 24, 32) -- channel: int, from 1 to 8 +- channel: int, (2, 4, 6, 8) - kbps: int, (32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320) The following methods are available: diff --git a/lib/recorder.ps1 b/lib/recorder.ps1 index 24bda3e..1d688bd 100644 --- a/lib/recorder.ps1 +++ b/lib/recorder.ps1 @@ -71,7 +71,7 @@ class Recorder : IRemote { hidden $_samplerate = $($this | Add-Member ScriptProperty 'samplerate' ` { - $this.Getter('samplerate') + [int]$this.Getter('samplerate') } ` { param([int]$arg) @@ -87,7 +87,7 @@ class Recorder : IRemote { hidden $_bitresolution = $($this | Add-Member ScriptProperty 'bitresolution' ` { - $this.Getter('bitresolution') + [int]$this.Getter('bitresolution') } ` { param([int]$arg) @@ -103,22 +103,23 @@ class Recorder : IRemote { hidden $_channel = $($this | Add-Member ScriptProperty 'channel' ` { - $this.Getter('channel') + [int]$this.Getter('channel') } ` { param([int]$arg) - if ($arg -ge 1 -and $arg -le 8) { + $opts = @(2, 4, 6, 8) + if ($opts.Contains($arg)) { $this._channel = $this.Setter('channel', $arg) } else { - "channel got: $arg, expected value from 1 to 8" | Write-Warning + "channel got: $arg, expected one of $opts" | Write-Warning } } ) hidden $_kbps = $($this | Add-Member ScriptProperty 'kbps' ` { - $this.Getter('kbps') + [int]$this.Getter('kbps') } ` { param([int]$arg) diff --git a/tests/higher.Tests.ps1 b/tests/higher.Tests.ps1 index 1804098..a787e05 100644 --- a/tests/higher.Tests.ps1 +++ b/tests/higher.Tests.ps1 @@ -640,6 +640,27 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' { $vmr.recorder.prerectime = $value $vmr.recorder.prerectime | Should -Be $value } + + It 'Should set and get Recorder.samplerate' -ForEach @( + @{ Value = 44100 }, @{ Value = 48000 } + ) { + $vmr.recorder.samplerate = $value + $vmr.recorder.samplerate | Should -Be $value + } + + It 'Should set and get Recorder.bitresolution' -ForEach @( + @{ Value = 24 }, @{ Value = 16 } + ) { + $vmr.recorder.bitresolution = $value + $vmr.recorder.bitresolution | Should -Be $value + } + + It 'Should set and get Recorder.kbps' -ForEach @( + @{ Value = 96 }, @{ Value = 192 } + ) { + $vmr.recorder.kbps = $value + $vmr.recorder.kbps | Should -Be $value + } } } diff --git a/tests/run.ps1 b/tests/run.ps1 index 5257371..74b1cc3 100644 --- a/tests/run.ps1 +++ b/tests/run.ps1 @@ -65,7 +65,12 @@ function main() { # recording directory: default ~/My Documents/Voicemeeter, override if custom $recDir = [System.IO.Path]::GetFullPath($recDir) - $ifCustomDir = Test-RecDir -vmr $vmr -recDir $recDir # avoid creating files we can't delete + if ($ifBasic) { + $ifCustomDir = $ifBasic # basic can't record, so skip the test + } + else { + $ifCustomDir = Test-RecDir -vmr $vmr -recDir $recDir # avoid creating files we can't delete + } Invoke-Pester -Tag $tag -PassThru | Out-Null } From df86ad2175c3c3c4cf6be3ae7936cdc9189622e0 Mon Sep 17 00:00:00 2001 From: pblivingston <71585805+pblivingston@users.noreply.github.com> Date: Thu, 4 Dec 2025 00:12:37 -0500 Subject: [PATCH 9/9] prefix, filetype changed to write-only properties pester tests pass for all kinds --- CHANGELOG.md | 3 ++- README.md | 4 ++-- lib/recorder.ps1 | 44 +++++++++++++++++++++++++++--------------- tests/higher.Tests.ps1 | 8 ++++---- tests/run.ps1 | 4 ++-- 5 files changed, 38 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 462d961..a2e8e9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ AddActionMembers now adds ScriptMethods instead of ScriptProperties: - See Recorder section of README for details on using playback/record actions Deprecated Recorder.Loop removed: use Recorder.Mode.Loop +Recorder.FileType changed from method to write-only property ### Added @@ -35,7 +36,7 @@ Deprecated Recorder.Loop removed: use Recorder.Mode.Loop - Bus.Mode.Set($mode) - Recorder.Armedbus - Recorder.PreRecTime -- Recorder.Prefix($prefix) +- Recorder.Prefix - Recorder.Eject() references 'Command.Eject' - Recorder.State diff --git a/README.md b/README.md index 14b8668..8adc862 100644 --- a/README.md +++ b/README.md @@ -531,6 +531,8 @@ The following commands are available: - armedbus: int, from 0 to bus index - state: string, ('play', 'stop', 'record', 'pause') - prerectime: int, from 0 to 20 seconds +- prefix: string, write-only +- filetype: string, write-only, ('wav', 'aiff', 'bwf', 'mp3') - samplerate: int, (22050, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000) - bitresolution: int, (8, 16, 24, 32) - channel: int, (2, 4, 6, 8) @@ -548,8 +550,6 @@ The following methods are available: - Eject() - Load($filepath): string - GoTo($timestring): string, must match the format 'hh:mm:ss' -- FileType($format): string, ('wav', 'aiff', 'bwf', 'mp3') -- Prefix($prefix): string example: diff --git a/lib/recorder.ps1 b/lib/recorder.ps1 index 1d688bd..b07c611 100644 --- a/lib/recorder.ps1 +++ b/lib/recorder.ps1 @@ -41,22 +41,6 @@ class Recorder : IRemote { $this.Setter('load', $filename) } - [void] Prefix ([string]$prefix) { - $this.Setter('prefix', $prefix) - } - - [void] FileType([string]$format) { - [int]$val = 0 - switch ($format) { - 'wav' { $val = 1 } - 'aiff' { $val = 2 } - 'bwf' { $val = 3 } - 'mp3' { $val = 100 } - default { "Filetype() got: $format, expected one of 'wav', 'aiff', 'bwf', 'mp3'" } - } - $this.Setter('filetype', $val) - } - [void] GoTo ([string]$timestring) { try { if ([datetime]::ParseExact($timestring, 'HH:mm:ss', $null)) { @@ -133,6 +117,34 @@ class Recorder : IRemote { } ) + hidden $_prefix = $($this | Add-Member ScriptProperty 'prefix' ` + { + return Write-Warning ("ERROR: $($this.identifier()).prefix is write only") + } ` + { + param([string]$arg) + $this._prefix = $this.Setter('prefix', $arg) + } + ) + + hidden $_filetype = $($this | Add-Member ScriptProperty 'filetype' ` + { + return Write-Warning ("ERROR: $($this.identifier()).filetype is write only") + } ` + { + param([string]$arg) + [int]$val = 0 + switch ($arg) { + 'wav' { $val = 1 } + 'aiff' { $val = 2 } + 'bwf' { $val = 3 } + 'mp3' { $val = 100 } + default { "Filetype() got: $arg, expected one of 'wav', 'aiff', 'bwf', 'mp3'" } + } + $this._filetype = $this.Setter('filetype', $val) + } + ) + hidden $_armedbus = $($this | Add-Member ScriptProperty 'armedbus' ` { foreach ($bus in 0..$($this.remote.kind.p_out + $this.remote.kind.v_out - 1)) { diff --git a/tests/higher.Tests.ps1 b/tests/higher.Tests.ps1 index a787e05..02f8e38 100644 --- a/tests/higher.Tests.ps1 +++ b/tests/higher.Tests.ps1 @@ -910,8 +910,8 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' { try { $prefix = 'stringtest' $filetype = 'wav' - $vmr.recorder.prefix($prefix) - $vmr.recorder.filetype($filetype) + $vmr.recorder.prefix = $prefix + $vmr.recorder.filetype = $filetype $vmr.recorder.state = 'record' $stamp = '{0:yyyy-MM-dd} at {0:HH}h{0:mm}m{0:ss}s' -f (Get-Date) @@ -956,8 +956,8 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' { BeforeAll { $prefix = 'actiontest' $filetype = 'wav' - $vmr.recorder.prefix($prefix) - $vmr.recorder.filetype($filetype) + $vmr.recorder.prefix = $prefix + $vmr.recorder.filetype = $filetype } BeforeEach { diff --git a/tests/run.ps1 b/tests/run.ps1 index 74b1cc3..ebf19fe 100644 --- a/tests/run.ps1 +++ b/tests/run.ps1 @@ -6,8 +6,8 @@ Import-Module (Join-Path (Split-Path $PSScriptRoot -Parent) 'lib\Voicemeeter.psm function Test-RecDir ([object]$vmr, [string]$recDir) { $prefix = 'temp' $filetype = 'wav' - $vmr.recorder.prefix($prefix) - $vmr.recorder.filetype($filetype) + $vmr.recorder.prefix = $prefix + $vmr.recorder.filetype = $filetype try {