vban x.1.2.0

changes staged
- on, name, ip partial write-only resolved
- simple ranges of consecutive integers moved to AddIntMembers
- audio instream/outstream divergent behavior separated
- midi outstream route, string
- new video outstream
This commit is contained in:
pblivingston 2025-12-10 19:43:36 -05:00
parent c446ad8c93
commit 0d303e20be
5 changed files with 269 additions and 185 deletions

View File

@ -465,22 +465,64 @@ The following Vban.instream | Vban.outstream properties are available:
- on: bool - on: bool
- name: string - name: string
- ip: string - ip: string
- sr: in, (11025, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000)
- channel: int from 1 to 8
- bit: int, 16 or 24
- quality: int, from 0 to 4
- route: int, from 0 to 8
for example: for example:
```powershell ```powershell
$vmr.vban.instream[0].on = $true $vmr.vban.instream[0].on = $true
$vmr.vban.outstream[3].bit = 16 $vmr.vban.outstream[9].ip = '192.168.1.154'
``` ```
##### audio
The following audio Vban.instream | Vban.outstream properties are available:
- sr: int, (11025, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000)
- channel: int, from 1 to 8
- bit: int, 16 or 24
- quality: int, from 0 to 4
- 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.
for example:
```powershell
$vmr.vban.instream[0].route = 4
$vmr.vban.outstream[3].bit = 16
```
##### midi
The following midi Vban.outstream[8] properties are available:
- route: string, ('none', 'midi_in', 'aux_in', 'vban_in', 'all_in', 'midi_out')
for example:
```powershell
$vmr.vban.outstream[8].route = 'aux_in'
```
##### video
The following video Vban.outstream[9] properties are available:
- vfps: int, from 1 to 30
- vformat: string, ('png', 'jpg')
- vquality: int, from 1 to 100
- vcursor: bool
- route: int, from 0 to 4
for example:
```powershell
$vmr.vban.outstream[9].vformat = 'jpg'
$vmr.vban.outstream[9].vquality = 85
$vmr.vban.outstream[9].vcursor = $true
```
### Command ### Command
Certain 'special' commands are defined by the API as performing actions rather than setting values. Certain 'special' commands are defined by the API as performing actions rather than setting values.

View File

@ -9,7 +9,7 @@ $KindMap = @{
'asio_out' = 8 'asio_out' = 8
'composite' = 0 'composite' = 0
'insert' = 0 'insert' = 0
'vban' = @{ 'in' = 4; 'out' = 4; 'midi' = 1; 'text' = 1 } 'vban' = @{ 'in' = 4; 'out' = 4; 'midi' = 1; 'text' = 1; 'video' = 1 }
'eq_ch' = @{ 'strip' = 0; 'bus' = 0 } 'eq_ch' = @{ 'strip' = 0; 'bus' = 0 }
'cells' = 0 'cells' = 0
'gainlayer' = 0 'gainlayer' = 0
@ -24,7 +24,7 @@ $KindMap = @{
'asio_out' = 8 'asio_out' = 8
'composite' = 8 'composite' = 8
'insert' = 22 'insert' = 22
'vban' = @{ 'in' = 8; 'out' = 8; 'midi' = 1; 'text' = 1 } 'vban' = @{ 'in' = 8; 'out' = 8; 'midi' = 1; 'text' = 1; 'video' = 1 }
'eq_ch' = @{ 'strip' = 0; 'bus' = 8 } 'eq_ch' = @{ 'strip' = 0; 'bus' = 8 }
'cells' = 6 'cells' = 6
'gainlayer' = 0 'gainlayer' = 0
@ -39,7 +39,7 @@ $KindMap = @{
'asio_out' = 8 'asio_out' = 8
'composite' = 8 'composite' = 8
'insert' = 34 'insert' = 34
'vban' = @{ 'in' = 8; 'out' = 8; 'midi' = 1; 'text' = 1 } 'vban' = @{ 'in' = 8; 'out' = 8; 'midi' = 1; 'text' = 1; 'video' = 1 }
'eq_ch' = @{ 'strip' = 2; 'bus' = 8 } 'eq_ch' = @{ 'strip' = 2; 'bus' = 8 }
'cells' = 6 'cells' = 6
'gainlayer' = 8 'gainlayer' = 8

View File

@ -3,18 +3,14 @@ class Vban : IRemote {
Vban ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote) { Vban ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote) {
$this.direction = $direction $this.direction = $direction
AddBoolMembers -PARAMS @('on')
AddStringMembers -PARAMS @('name', 'ip')
} }
[string] identifier () { [string] identifier () {
return 'vban.' + $this.direction + 'stream[' + $this.index + ']' return 'vban.' + $this.direction + 'stream[' + $this.index + ']'
} }
}
class VbanAudio : Vban {
VbanAudio ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote, $direction) {
AddBoolMembers -PARAMS @('on')
AddStringMembers -PARAMS @('name', 'ip')
}
hidden $_port = $($this | Add-Member ScriptProperty 'port' ` hidden $_port = $($this | Add-Member ScriptProperty 'port' `
{ {
@ -30,43 +26,33 @@ class VbanAudio : Vban {
} }
} }
) )
}
hidden $_sr = $($this | Add-Member ScriptProperty 'sr' ` class VbanAudio : Vban {
{ VbanAudio ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote, $direction) {
[int]$this.Getter('sr') AddIntMembers -PARAMS @('quality', 'route')
} `
{
param([int]$arg)
if ($this.direction -eq 'in') { Write-Warning ('Error, read only value') }
else {
$opts = @(11025, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000)
if ($opts.Contains($arg)) {
$this._sr = $this.Setter('sr', $arg)
}
else {
Write-Warning ('Expected one of', $opts)
} }
} }
}
)
hidden $_channel = $($this | Add-Member ScriptProperty 'channel' ` class VbanMidi : Vban {
{ VbanMidi ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote, $direction) {
[int]$this.Getter('channel')
} `
{
param([int]$arg)
if ($this.direction -eq 'in') { Write-Warning ('Error, read only value') }
else {
if ($arg -ge 1 -and $arg -le 8) {
$this._channel = $this.Setter('channel', $arg)
}
else {
Write-Warning ('Expected value from 1 to 8')
} }
} }
class VbanText : Vban {
VbanText ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote, $direction) {
}
}
class VbanVideo : Vban {
VbanVideo ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote, $direction) {
}
}
class VbanInAudio : VbanAudio {
VbanInAudio ([int]$index, [Object]$remote) : base ($index, $remote, 'in') {
AddIntMembers -ReadOnly -PARAMS @('sr', 'channel')
} }
)
hidden $_bit = $($this | Add-Member ScriptProperty 'bit' ` hidden $_bit = $($this | Add-Member ScriptProperty 'bit' `
{ {
@ -74,125 +60,9 @@ class VbanAudio : Vban {
return $val return $val
} ` } `
{ {
param([int]$arg) Write-Warning ("ERROR: $($this.identifier()).bit is read only")
if ($this.direction -eq 'in') { Write-Warning ('Error, read only value') }
else {
if (@(16, 24).Contains($arg)) {
$val = if ($arg -eq 16) { 1 } else { 2 }
$this._bit = $this.Setter('bit', $val)
}
else {
Write-Warning ('Expected value 16 or 24')
}
}
} }
) )
hidden $_quality = $($this | Add-Member ScriptProperty 'quality' `
{
[int]$this.Getter('quality')
} `
{
param([int]$arg)
if ($arg -ge 0 -and $arg -le 4) {
$this._quality = $this.Setter('quality', $arg)
}
else {
Write-Warning ('Expected value from 0 to 4')
}
}
)
hidden $_route = $($this | Add-Member ScriptProperty 'route' `
{
[int]$this.Getter('route')
} `
{
param([int]$arg)
$rt = $this.remote.kind['p_' + $this.direction] + $this.remote.kind['v_' + $this.direction] - 1
if ($arg -ge 0 -and $arg -le $rt) {
$this._route = $this.Setter('route', $arg)
}
else {
Write-Warning ("Expected value from 0 to $rt")
}
}
)
}
class VbanMidi : Vban {
VbanMidi ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote, $direction) {
}
hidden $_on = $($this | Add-Member ScriptProperty 'on' `
{
return Write-Warning ("ERROR: $($this.identifier()).on is write only")
} `
{
param([bool]$arg)
$this._on = $this.Setter('on', $arg)
}
)
hidden $_name = $($this | Add-Member ScriptProperty 'name' `
{
return Write-Warning ("ERROR: $($this.identifier()).name is write only")
} `
{
param([string]$arg)
$this._name = $this.Setter('name', $arg)
}
)
hidden $_ip = $($this | Add-Member ScriptProperty 'ip' `
{
return Write-Warning ("ERROR: $($this.identifier()).ip is write only")
} `
{
param([string]$arg)
$this._ip = $this.Setter('ip', $arg)
}
)
}
class VbanText : Vban {
VbanText ([int]$index, [Object]$remote, [string]$direction) : base ($index, $remote, $direction) {
}
hidden $_on = $($this | Add-Member ScriptProperty 'on' `
{
return Write-Warning ("ERROR: $($this.identifier()).on is write only")
} `
{
param([bool]$arg)
$this._on = $this.Setter('on', $arg)
}
)
hidden $_name = $($this | Add-Member ScriptProperty 'name' `
{
return Write-Warning ("ERROR: $($this.identifier()).name is write only")
} `
{
param([string]$arg)
$this._name = $this.Setter('name', $arg)
}
)
hidden $_ip = $($this | Add-Member ScriptProperty 'ip' `
{
return Write-Warning ("ERROR: $($this.identifier()).ip is write only")
} `
{
param([string]$arg)
$this._ip = $this.Setter('ip', $arg)
}
)
}
class VbanInAudio : VbanAudio {
VbanInAudio ([int]$index, [Object]$remote) : base ($index, $remote, 'in') {
}
} }
class VbanInMidi : VbanMidi { class VbanInMidi : VbanMidi {
@ -207,12 +77,103 @@ class VbanInText : VbanText {
class VbanOutAudio : VbanAudio { class VbanOutAudio : VbanAudio {
VbanOutAudio ([int]$index, [Object]$remote) : base ($index, $remote, 'out') { VbanOutAudio ([int]$index, [Object]$remote) : base ($index, $remote, 'out') {
AddIntMembers -PARAMS @('channel')
} }
hidden $_sr = $($this | Add-Member ScriptProperty 'sr' `
{
[int]$this.Getter('sr')
} `
{
param([int]$arg)
$opts = @(11025, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000)
if ($opts.Contains($arg)) {
$this._sr = $this.Setter('sr', $arg)
}
else {
Write-Warning ('Expected one of', $opts)
}
}
)
hidden $_bit = $($this | Add-Member ScriptProperty 'bit' `
{
$val = if ($this.Getter('bit') -eq 1) { 16 } else { 24 }
return $val
} `
{
param([int]$arg)
if (@(16, 24).Contains($arg)) {
$val = if ($arg -eq 16) { 1 } else { 2 }
$this._bit = $this.Setter('bit', $val)
}
else {
Write-Warning ('Expected value 16 or 24')
}
}
)
} }
class VbanOutMidi : VbanMidi { class VbanOutMidi : VbanMidi {
VbanOutMidi ([int]$index, [Object]$remote) : base ($index, $remote, 'out') { VbanOutMidi ([int]$index, [Object]$remote) : base ($index, $remote, 'out') {
} }
hidden $_route = $($this | Add-Member ScriptProperty 'route' `
{
[string]$val = ''
switch ($this.Getter('route')) {
0 { $val = 'none' }
1 { $val = 'midi_in' }
2 { $val = 'aux_in' }
4 { $val = 'vban_in' }
7 { $val = 'all_in' }
8 { $val = 'midi_out' }
}
return $val
} `
{
param([string]$arg)
[int]$val = 0
switch ($arg) {
'none' { $val = 0 }
'midi_in' { $val = 1 }
'aux_in' { $val = 2 }
'vban_in' { $val = 4 }
'all_in' { $val = 7 }
'midi_out' { $val = 8 }
default { Write-Warning ("route got: $arg, expected one of 'none', 'midi_in', 'aux_in', 'vban_in', 'all_in', 'midi_out'") }
}
$this._route = $this.Setter('route', $val)
}
)
}
class VbanOutVideo : VbanVideo {
VbanOutVideo ([int]$index, [Object]$remote) : base ($index, $remote, 'out') {
AddIntMembers -PARAMS @('vfps', 'vquality', 'route')
AddBoolMembers -PARAMS @('vcursor')
}
hidden $_vformat = $($this | Add-Member ScriptProperty 'vformat' `
{
[string]$val = ''
switch ($this.Getter('vformat')) {
1 { $val = 'png' }
2 { $val = 'jpg' }
}
return $val
} `
{
param([string]$arg)
[int]$val = 0
switch ($arg) {
'png' { $val = 1 }
'jpg' { $val = 2 }
default { Write-Warning ("vformat got: $arg, expected one of 'png', 'jpg'") }
}
$this._vformat = $this.Setter('vformat', $val)
}
)
} }
function Make_Vban ([Object]$remote) { function Make_Vban ([Object]$remote) {
@ -220,7 +181,7 @@ function Make_Vban ([Object]$remote) {
[System.Collections.ArrayList]$outstream = @() [System.Collections.ArrayList]$outstream = @()
$totalInstreams = $remote.kind.vban.in + $remote.kind.vban.midi + $remote.kind.vban.text $totalInstreams = $remote.kind.vban.in + $remote.kind.vban.midi + $remote.kind.vban.text
$totalOutstreams = $remote.kind.vban.out + $remote.kind.vban.midi $totalOutstreams = $remote.kind.vban.out + $remote.kind.vban.midi + $remote.kind.vban.video
for ($i = 0; $i -lt $totalInstreams; $i++) { for ($i = 0; $i -lt $totalInstreams; $i++) {
if ($i -lt $remote.kind.vban.in) { if ($i -lt $remote.kind.vban.in) {
@ -237,9 +198,12 @@ function Make_Vban ([Object]$remote) {
if ($i -lt $remote.kind.vban.out) { if ($i -lt $remote.kind.vban.out) {
[void]$outstream.Add([VbanOutAudio]::new($i, $remote)) [void]$outstream.Add([VbanOutAudio]::new($i, $remote))
} }
else { elseif ($i -lt ($remote.kind.vban.out + $remote.kind.vban.midi)) {
[void]$outstream.Add([VbanOutMidi]::new($i, $remote)) [void]$outstream.Add([VbanOutMidi]::new($i, $remote))
} }
else {
[void]$outstream.Add([VbanOutVideo]::new($i, $remote))
}
} }
$CustomObject = [pscustomobject]@{ $CustomObject = [pscustomobject]@{

View File

@ -150,10 +150,10 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
$vmr.vban.enable | Should -Be $expected $vmr.vban.enable | Should -Be $expected
} }
Context 'Instream' -ForEach @( Context 'Instream, audio, midi, text' -ForEach @(
@{ Index = $vban_inA } @{ Index = $vban_inA }
# @{ Index = $vban_inM } @{ Index = $vban_inM }
# @{ Index = $vban_inT } @{ Index = $vban_inT }
) { ) {
It "Should set vban.instream[$index].on" { It "Should set vban.instream[$index].on" {
$vmr.vban.instream[$index].on = $value $vmr.vban.instream[$index].on = $value
@ -161,15 +161,25 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
} }
} }
Context 'Outstream' -ForEach @( Context 'Outstream, audio, midi, video' -ForEach @(
@{ Index = $vban_outA } @{ Index = $vban_outA }
# @{ Index = $vban_outM } @{ Index = $vban_outM }
@{ Index = $vban_outV }
) { ) {
It "Should set vban.outstream[$index].on" { It "Should set vban.outstream[$index].on" {
$vmr.vban.outstream[$index].on = $value $vmr.vban.outstream[$index].on = $value
$vmr.vban.outstream[$index].on | Should -Be $expected $vmr.vban.outstream[$index].on | Should -Be $expected
} }
} }
Context 'Outstream, video only' -ForEach @(
@{ Index = $vban_outV }
) {
It "Should set vban.outstream[$index].vcursor" {
$vmr.vban.outstream[$index].vcursor = $value
$vmr.vban.outstream[$index].vcursor | Should -Be $expected
}
}
} }
Context 'Recorder' -Skip:$ifBasic { Context 'Recorder' -Skip:$ifBasic {
@ -596,8 +606,10 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
$vmr.vban.port | Should -Be $expected $vmr.vban.port | Should -Be $expected
} }
Context 'Instream' -ForEach @( Context 'Instream, audio, midi, text' -ForEach @(
@{ Index = $vban_inA } @{ Index = $vban_inA }
@{ Index = $vban_inM }
@{ Index = $vban_inT }
) { ) {
It "Should set vban.instream[$index].port" -ForEach @( It "Should set vban.instream[$index].port" -ForEach @(
@{ Value = 1024; Expected = 1024 } @{ Value = 1024; Expected = 1024 }
@ -608,16 +620,21 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Start-Sleep -Milliseconds 2000 Start-Sleep -Milliseconds 2000
$vmr.vban.instream[$index].port | Should -Be $expected $vmr.vban.instream[$index].port | Should -Be $expected
} }
}
It "Should set vban.instream[$index].sr" { Context 'Instream, audio only' -ForEach @(
@{ Index = $vban_inA }
) {
It "Should get vban.instream[$index].sr" {
$vmr.vban.instream[$index].sr | Should -BeOfType [int] $vmr.vban.instream[$index].sr | Should -BeOfType [int]
} }
It "Should set vban.instream[$index].channel" { It "Should get vban.instream[$index].channel" {
$vmr.vban.instream[$index].channel | Should -BeOfType [int] $vmr.vban.instream[$index].channel | Should -BeOfType [int]
} }
It "Should set vban.instream[$index].bit" { It "Should get vban.instream[$index].bit" {
$vmr.vban.instream[$index].bit | Should -BeOfType [int] $vmr.vban.instream[$index].bit | Should -BeOfType [int]
} }
@ -639,8 +656,10 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
} }
} }
Context 'Outstream' -ForEach @( Context 'Outstream, audio, midi, video' -ForEach @(
@{ Index = $vban_outA } @{ Index = $vban_outA }
@{ Index = $vban_outM }
@{ Index = $vban_outV }
) { ) {
It "Should set vban.outstream[$index].port" -ForEach @( It "Should set vban.outstream[$index].port" -ForEach @(
@{ Value = 1024; Expected = 1024 } @{ Value = 1024; Expected = 1024 }
@ -651,6 +670,11 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
Start-Sleep -Milliseconds 2000 Start-Sleep -Milliseconds 2000
$vmr.vban.outstream[$index].port | Should -Be $expected $vmr.vban.outstream[$index].port | Should -Be $expected
} }
}
Context 'Outstream, audio only' -ForEach @(
@{ Index = $vban_outA }
) {
It "Should set vban.outstream[$index].sr" -ForEach @( It "Should set vban.outstream[$index].sr" -ForEach @(
@{ Value = 44100; Expected = 44100 } @{ Value = 44100; Expected = 44100 }
@ -693,6 +717,46 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
$vmr.vban.outstream[$index].route | Should -Be $expected $vmr.vban.outstream[$index].route | Should -Be $expected
} }
} }
Context 'Outstream, midi only' -ForEach @(
@{ Index = $vban_outM }
) {
It "Should set vban.outstream[$index].route" -ForEach @(
@{ Value = 7; Expected = 7 }
@{ Value = 3; Expected = 3 }
) {
$vmr.vban.outstream[$index].route = $value
$vmr.vban.outstream[$index].route | Should -Be $expected
}
}
Context 'Outstream, video only' -ForEach @(
@{ Index = $vban_outV }
) {
It "Should set vban.outstream[$index].vfps" -ForEach @(
@{ Value = 6; Expected = 6 }
@{ Value = 24; Expected = 24 }
) {
$vmr.vban.outstream[$index].vfps = $value
$vmr.vban.outstream[$index].vfps | Should -Be $expected
}
It "Should set vban.outstream[$index].vquality" -ForEach @(
@{ Value = 80; Expected = 80 }
@{ Value = 100; Expected = 100 }
) {
$vmr.vban.outstream[$index].vquality = $value
$vmr.vban.outstream[$index].vquality | Should -Be $expected
}
It "Should set vban.outstream[$index].route" -ForEach @(
@{ Value = 1; Expected = 1 }
@{ Value = 4; Expected = 4 }
) {
$vmr.vban.outstream[$index].route = $value
$vmr.vban.outstream[$index].route | Should -Be $expected
}
}
} }
Context 'Patch' { Context 'Patch' {
@ -980,10 +1044,10 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
} }
Describe 'Vban' { Describe 'Vban' {
Context 'Instream' -ForEach @( Context 'Instream, audio, midi, text' -ForEach @(
@{ Index = $vban_inA } @{ Index = $vban_inA }
# @{ Index = $vban_inM } @{ Index = $vban_inM }
# @{ Index = $vban_inT } @{ Index = $vban_inT }
) { ) {
It "Should set vban.instream[$index].name" -ForEach @( It "Should set vban.instream[$index].name" -ForEach @(
@{ Value = 'TestIn0'; Expected = 'TestIn0' } @{ Value = 'TestIn0'; Expected = 'TestIn0' }
@ -1001,9 +1065,10 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
} }
} }
Context 'Outstream' -ForEach @( Context 'Outstream, audio, midi, video' -ForEach @(
@{ Index = $vban_outA } @{ Index = $vban_outA }
# @{ Index = $vban_outM } @{ Index = $vban_outM }
@{ Index = $vban_outV }
) { ) {
It "Should set vban.outstream[$index].name" -ForEach @( It "Should set vban.outstream[$index].name" -ForEach @(
@{ Value = 'TestOut0'; Expected = 'TestOut0' } @{ Value = 'TestOut0'; Expected = 'TestOut0' }
@ -1020,6 +1085,18 @@ Describe -Tag 'higher', -TestName 'All Higher Tests' {
$vmr.vban.outstream[$index].ip | Should -Be $expected $vmr.vban.outstream[$index].ip | Should -Be $expected
} }
} }
Context 'Outstream, video only' -ForEach @(
@{ Index = $vban_outV }
) {
It "Should set vban.outstream[$index].vformat" -ForEach @(
@{ Value = 'png'; Expected = 'png' }
@{ Value = 'jpg'; Expected = 'jpg' }
) {
$vmr.vban.outstream[$index].vformat = $value
$vmr.vban.outstream[$index].vformat | Should -Be $expected
}
}
} }
Context 'Recorder' -Skip:$ifBasic { Context 'Recorder' -Skip:$ifBasic {

View File

@ -53,6 +53,7 @@ function main() {
$vban_inT = $vmr.kind.vban.in + $vmr.kind.vban.midi + $vmr.kind.vban.text - 1 $vban_inT = $vmr.kind.vban.in + $vmr.kind.vban.midi + $vmr.kind.vban.text - 1
$vban_outA = $vmr.kind.vban.out - 1 $vban_outA = $vmr.kind.vban.out - 1
$vban_outM = $vmr.kind.vban.out + $vmr.kind.vban.midi - 1 $vban_outM = $vmr.kind.vban.out + $vmr.kind.vban.midi - 1
$vban_outV = $vmr.kind.vban.out + $vmr.kind.vban.midi + $vmr.kind.vban.video - 1
$insert = $vmr.kind.insert - 1 $insert = $vmr.kind.insert - 1
$composite = $vmr.kind.composite - 1 $composite = $vmr.kind.composite - 1
$strip_ch = $vmr.kind.eq_ch['strip'] - 1 $strip_ch = $vmr.kind.eq_ch['strip'] - 1