vban-cli 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vban_cli-0.3.0/LICENSE +21 -0
- vban_cli-0.3.0/PKG-INFO +116 -0
- vban_cli-0.3.0/README.md +96 -0
- vban_cli-0.3.0/pyproject.toml +27 -0
- vban_cli-0.3.0/setup.cfg +4 -0
- vban_cli-0.3.0/src/vban_cli/__init__.py +3 -0
- vban_cli-0.3.0/src/vban_cli/app.py +53 -0
- vban_cli-0.3.0/src/vban_cli/bus.py +106 -0
- vban_cli-0.3.0/src/vban_cli/comp.py +67 -0
- vban_cli-0.3.0/src/vban_cli/console.py +4 -0
- vban_cli-0.3.0/src/vban_cli/context.py +8 -0
- vban_cli-0.3.0/src/vban_cli/denoiser.py +46 -0
- vban_cli-0.3.0/src/vban_cli/eq.py +53 -0
- vban_cli-0.3.0/src/vban_cli/gate.py +67 -0
- vban_cli-0.3.0/src/vban_cli/help.py +43 -0
- vban_cli-0.3.0/src/vban_cli/strip.py +270 -0
- vban_cli-0.3.0/src/vban_cli.egg-info/PKG-INFO +116 -0
- vban_cli-0.3.0/src/vban_cli.egg-info/SOURCES.txt +20 -0
- vban_cli-0.3.0/src/vban_cli.egg-info/dependency_links.txt +1 -0
- vban_cli-0.3.0/src/vban_cli.egg-info/entry_points.txt +2 -0
- vban_cli-0.3.0/src/vban_cli.egg-info/requires.txt +2 -0
- vban_cli-0.3.0/src/vban_cli.egg-info/top_level.txt +1 -0
vban_cli-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Onyx and Iris
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
vban_cli-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vban-cli
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: A command-line interface for Voicemeeter leveraging VBAN.
|
|
5
|
+
License: LICENSE
|
|
6
|
+
Classifier: Development Status :: 3 - Alpha
|
|
7
|
+
Classifier: Programming Language :: Python
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
13
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
14
|
+
Requires-Python: >=3.13
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: cyclopts>=4.6.0
|
|
18
|
+
Requires-Dist: vban-cmd>=2.6.0
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# vban-cli
|
|
22
|
+
|
|
23
|
+
[](https://github.com/astral-sh/uv)
|
|
24
|
+
[](https://github.com/astral-sh/ruff)
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
#### With uv
|
|
31
|
+
|
|
32
|
+
```console
|
|
33
|
+
uv tool install vban-cli
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
#### With pipx
|
|
37
|
+
|
|
38
|
+
```console
|
|
39
|
+
pipx install vban-cli
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The CLI should now be discoverable as `vban-cli`
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Configuration
|
|
47
|
+
|
|
48
|
+
### Flags
|
|
49
|
+
|
|
50
|
+
```console
|
|
51
|
+
vban-cli --host=localhost --port=6980 --streamname=Command1
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Environment Variables
|
|
55
|
+
|
|
56
|
+
example .envrc:
|
|
57
|
+
|
|
58
|
+
```env
|
|
59
|
+
#!/usr/bin/env bash
|
|
60
|
+
|
|
61
|
+
export VBAN_CLI_HOST="localhost"
|
|
62
|
+
export VBAN_CLI_PORT=6980
|
|
63
|
+
export VBAN_CLI_STREAMNAME=Command1
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Use
|
|
69
|
+
|
|
70
|
+
```console
|
|
71
|
+
Usage: vban-cli COMMAND
|
|
72
|
+
|
|
73
|
+
╭─ Commands ───────────────────────────────────────────────────────────────────────────────────────╮
|
|
74
|
+
│ bus Control the bus parameters. │
|
|
75
|
+
│ strip Control the strip parameters. │
|
|
76
|
+
│ --help (-h) Display this message and exit. │
|
|
77
|
+
│ --version Display application version. │
|
|
78
|
+
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
79
|
+
╭─ Parameters ─────────────────────────────────────────────────────────────────────────────────────╮
|
|
80
|
+
│ --kind Kind of Voicemeeter [env var: VBAN_CLI_KIND] [default: potato] │
|
|
81
|
+
│ --host VBAN host [env var: VBAN_CLI_HOST] [default: localhost] │
|
|
82
|
+
│ --port VBAN port [env var: VBAN_CLI_PORT] [default: 6980] │
|
|
83
|
+
│ --streamname VBAN stream name [env var: VBAN_CLI_STREAMNAME] [default: Command1] │
|
|
84
|
+
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
For every command and subcommand there exists a `--help` flag for further usage information.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Implementation Notes
|
|
92
|
+
|
|
93
|
+
1. The VBAN TEXT subprotocol defines two packet structures [ident:0][ident-0] and [ident:1][ident-1]. Neither of them contain the data for Bus EQ parameters.
|
|
94
|
+
2. Packet structure with [ident:1][ident-1] is emitted by the VBAN server only on pdirty events. This means we do not receive the initial state of those parameters on initial subscription. Therefore any commands which are intended to fetch the value of parameters defined in packet [ident:1][ident-1] will not work in this CLI.
|
|
95
|
+
3. Packet structure with [ident:1][ident-1] defines parameteric EQ data only for the [first channel][ident-1-peq].
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Further Notes
|
|
101
|
+
|
|
102
|
+
I've made the effort to set up the basic skeletal structure of the CLI as well as demonstrate how to combine subcommand groups with subcommand groups so more can be implemented, it just needs doing. There may be restrictions on some things however, for example, retrieving values is only possible for parameters [defined in the protocol](https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/3be2c1c36563afbd6df3da8436406c77d2cc1f10/VoicemeeterRemote.h#L787). Setting parameters can be done for anything possible by a string request.
|
|
103
|
+
|
|
104
|
+
If there's something missing that you would like to see added the best bet is to submit a PR. You may raise an issue and if it's quick and simple to do I may (or may not) do it.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
`vban-cli` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
[ident-0]: https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/3be2c1c36563afbd6df3da8436406c77d2cc1f10/VoicemeeterRemote.h#L896
|
|
115
|
+
[ident-1]: https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/3be2c1c36563afbd6df3da8436406c77d2cc1f10/VoicemeeterRemote.h#L982
|
|
116
|
+
[ident-1-peq]: https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/3be2c1c36563afbd6df3da8436406c77d2cc1f10/VoicemeeterRemote.h#L995
|
vban_cli-0.3.0/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# vban-cli
|
|
2
|
+
|
|
3
|
+
[](https://github.com/astral-sh/uv)
|
|
4
|
+
[](https://github.com/astral-sh/ruff)
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
#### With uv
|
|
11
|
+
|
|
12
|
+
```console
|
|
13
|
+
uv tool install vban-cli
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
#### With pipx
|
|
17
|
+
|
|
18
|
+
```console
|
|
19
|
+
pipx install vban-cli
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The CLI should now be discoverable as `vban-cli`
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Configuration
|
|
27
|
+
|
|
28
|
+
### Flags
|
|
29
|
+
|
|
30
|
+
```console
|
|
31
|
+
vban-cli --host=localhost --port=6980 --streamname=Command1
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Environment Variables
|
|
35
|
+
|
|
36
|
+
example .envrc:
|
|
37
|
+
|
|
38
|
+
```env
|
|
39
|
+
#!/usr/bin/env bash
|
|
40
|
+
|
|
41
|
+
export VBAN_CLI_HOST="localhost"
|
|
42
|
+
export VBAN_CLI_PORT=6980
|
|
43
|
+
export VBAN_CLI_STREAMNAME=Command1
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Use
|
|
49
|
+
|
|
50
|
+
```console
|
|
51
|
+
Usage: vban-cli COMMAND
|
|
52
|
+
|
|
53
|
+
╭─ Commands ───────────────────────────────────────────────────────────────────────────────────────╮
|
|
54
|
+
│ bus Control the bus parameters. │
|
|
55
|
+
│ strip Control the strip parameters. │
|
|
56
|
+
│ --help (-h) Display this message and exit. │
|
|
57
|
+
│ --version Display application version. │
|
|
58
|
+
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
59
|
+
╭─ Parameters ─────────────────────────────────────────────────────────────────────────────────────╮
|
|
60
|
+
│ --kind Kind of Voicemeeter [env var: VBAN_CLI_KIND] [default: potato] │
|
|
61
|
+
│ --host VBAN host [env var: VBAN_CLI_HOST] [default: localhost] │
|
|
62
|
+
│ --port VBAN port [env var: VBAN_CLI_PORT] [default: 6980] │
|
|
63
|
+
│ --streamname VBAN stream name [env var: VBAN_CLI_STREAMNAME] [default: Command1] │
|
|
64
|
+
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
For every command and subcommand there exists a `--help` flag for further usage information.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Implementation Notes
|
|
72
|
+
|
|
73
|
+
1. The VBAN TEXT subprotocol defines two packet structures [ident:0][ident-0] and [ident:1][ident-1]. Neither of them contain the data for Bus EQ parameters.
|
|
74
|
+
2. Packet structure with [ident:1][ident-1] is emitted by the VBAN server only on pdirty events. This means we do not receive the initial state of those parameters on initial subscription. Therefore any commands which are intended to fetch the value of parameters defined in packet [ident:1][ident-1] will not work in this CLI.
|
|
75
|
+
3. Packet structure with [ident:1][ident-1] defines parameteric EQ data only for the [first channel][ident-1-peq].
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Further Notes
|
|
81
|
+
|
|
82
|
+
I've made the effort to set up the basic skeletal structure of the CLI as well as demonstrate how to combine subcommand groups with subcommand groups so more can be implemented, it just needs doing. There may be restrictions on some things however, for example, retrieving values is only possible for parameters [defined in the protocol](https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/3be2c1c36563afbd6df3da8436406c77d2cc1f10/VoicemeeterRemote.h#L787). Setting parameters can be done for anything possible by a string request.
|
|
83
|
+
|
|
84
|
+
If there's something missing that you would like to see added the best bet is to submit a PR. You may raise an issue and if it's quick and simple to do I may (or may not) do it.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
`vban-cli` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
[ident-0]: https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/3be2c1c36563afbd6df3da8436406c77d2cc1f10/VoicemeeterRemote.h#L896
|
|
95
|
+
[ident-1]: https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/3be2c1c36563afbd6df3da8436406c77d2cc1f10/VoicemeeterRemote.h#L982
|
|
96
|
+
[ident-1-peq]: https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/3be2c1c36563afbd6df3da8436406c77d2cc1f10/VoicemeeterRemote.h#L995
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "vban-cli"
|
|
3
|
+
version = "0.3.0"
|
|
4
|
+
description = "A command-line interface for Voicemeeter leveraging VBAN."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = { text = "LICENSE" }
|
|
7
|
+
requires-python = ">=3.13"
|
|
8
|
+
dependencies = ["cyclopts>=4.6.0", "vban-cmd>=2.6.0"]
|
|
9
|
+
classifiers = [
|
|
10
|
+
"Development Status :: 3 - Alpha",
|
|
11
|
+
"Programming Language :: Python",
|
|
12
|
+
"Programming Language :: Python :: 3.10",
|
|
13
|
+
"Programming Language :: Python :: 3.11",
|
|
14
|
+
"Programming Language :: Python :: 3.12",
|
|
15
|
+
"Programming Language :: Python :: 3.13",
|
|
16
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
|
17
|
+
"Programming Language :: Python :: Implementation :: PyPy",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.scripts]
|
|
21
|
+
vban-cli = "vban_cli.app:run"
|
|
22
|
+
|
|
23
|
+
[tool.uv]
|
|
24
|
+
package = true
|
|
25
|
+
|
|
26
|
+
[tool.uv.sources]
|
|
27
|
+
vban-cmd = { path = "../vban-cmd-python" }
|
vban_cli-0.3.0/setup.cfg
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Annotated
|
|
3
|
+
|
|
4
|
+
import vban_cmd
|
|
5
|
+
from cyclopts import App, Parameter, config
|
|
6
|
+
|
|
7
|
+
from . import __version__ as version
|
|
8
|
+
from . import bus, console, strip
|
|
9
|
+
from .context import Context
|
|
10
|
+
|
|
11
|
+
app = App(
|
|
12
|
+
config=config.Env(
|
|
13
|
+
'VBAN_CLI_',
|
|
14
|
+
), # Environment variable prefix for configuration parameters
|
|
15
|
+
version=version,
|
|
16
|
+
)
|
|
17
|
+
app.command(strip.app.meta, name='strip')
|
|
18
|
+
app.command(bus.app.meta, name='bus')
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@Parameter(name='*')
|
|
22
|
+
@dataclass
|
|
23
|
+
class VBANConfig:
|
|
24
|
+
kind: Annotated[str, Parameter(help='Kind of Voicemeeter')] = 'potato'
|
|
25
|
+
host: Annotated[str, Parameter(help='VBAN host')] = 'localhost'
|
|
26
|
+
port: Annotated[int, Parameter(help='VBAN port')] = 6980
|
|
27
|
+
streamname: Annotated[str, Parameter(help='VBAN stream name')] = 'Command1'
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@app.meta.default
|
|
31
|
+
def launcher(
|
|
32
|
+
*tokens: Annotated[str, Parameter(show=False, allow_leading_hyphen=True)],
|
|
33
|
+
vban_config: Annotated[VBANConfig, Parameter()] = VBANConfig(),
|
|
34
|
+
):
|
|
35
|
+
with vban_cmd.api(
|
|
36
|
+
vban_config.kind,
|
|
37
|
+
ip=vban_config.host,
|
|
38
|
+
port=vban_config.port,
|
|
39
|
+
streamname=vban_config.streamname,
|
|
40
|
+
) as client:
|
|
41
|
+
additional_kwargs = {}
|
|
42
|
+
command, bound, _ = app.parse_args(tokens)
|
|
43
|
+
additional_kwargs['ctx'] = Context(client=client)
|
|
44
|
+
|
|
45
|
+
return command(*bound.args, **bound.kwargs, **additional_kwargs)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def run():
|
|
49
|
+
try:
|
|
50
|
+
app.meta()
|
|
51
|
+
except Exception as e:
|
|
52
|
+
console.err.print(f'Error: {e}')
|
|
53
|
+
return e.code
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
from typing import Annotated, Literal, Optional
|
|
2
|
+
|
|
3
|
+
from cyclopts import App, Argument, Parameter
|
|
4
|
+
|
|
5
|
+
from . import console
|
|
6
|
+
from .context import Context
|
|
7
|
+
from .help import CustomHelpFormatter
|
|
8
|
+
|
|
9
|
+
app = App(name='bus', help_formatter=CustomHelpFormatter())
|
|
10
|
+
# See https://github.com/onyx-and-iris/vban-cli?tab=readme-ov-file#implementation-notes - 1.
|
|
11
|
+
# app.command(eq.app.meta, name='eq')
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@app.meta.default
|
|
15
|
+
def launcher(
|
|
16
|
+
index: Annotated[int, Argument()] = None,
|
|
17
|
+
*tokens: Annotated[str, Parameter(show=False, allow_leading_hyphen=True)],
|
|
18
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
19
|
+
):
|
|
20
|
+
"""Control the bus parameters."""
|
|
21
|
+
additional_kwargs = {}
|
|
22
|
+
command, bound, _ = app.parse_args(tokens)
|
|
23
|
+
if index is not None:
|
|
24
|
+
additional_kwargs['index'] = index
|
|
25
|
+
if ctx is not None:
|
|
26
|
+
additional_kwargs['ctx'] = ctx
|
|
27
|
+
|
|
28
|
+
return command(*bound.args, **bound.kwargs, **additional_kwargs)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@app.command(name='mono')
|
|
32
|
+
def mono(
|
|
33
|
+
new_value: Annotated[Optional[bool], Argument()] = None,
|
|
34
|
+
*,
|
|
35
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
36
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
37
|
+
):
|
|
38
|
+
"""Get or set the mono state of the specified bus.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
new_value : bool, optional
|
|
43
|
+
If provided, sets the mono state to this value. If not provided, the current mono state is printed.
|
|
44
|
+
"""
|
|
45
|
+
if new_value is None:
|
|
46
|
+
console.out.print(ctx.client.bus[index].mono)
|
|
47
|
+
return
|
|
48
|
+
ctx.client.bus[index].mono = new_value
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@app.command(name='mute')
|
|
52
|
+
def mute(
|
|
53
|
+
new_value: Annotated[Optional[bool], Argument()] = None,
|
|
54
|
+
*,
|
|
55
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
56
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
57
|
+
):
|
|
58
|
+
"""Get or set the mute state of the specified bus.
|
|
59
|
+
|
|
60
|
+
Parameters
|
|
61
|
+
----------
|
|
62
|
+
new_value : bool, optional
|
|
63
|
+
If provided, sets the mute state to this value. If not provided, the current mute state is printed.
|
|
64
|
+
"""
|
|
65
|
+
if new_value is None:
|
|
66
|
+
console.out.print(ctx.client.bus[index].mute)
|
|
67
|
+
return
|
|
68
|
+
ctx.client.bus[index].mute = new_value
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@app.command(name='mode')
|
|
72
|
+
def mode(
|
|
73
|
+
type_: Annotated[
|
|
74
|
+
Optional[
|
|
75
|
+
Literal[
|
|
76
|
+
'normal',
|
|
77
|
+
'amix',
|
|
78
|
+
'bmix',
|
|
79
|
+
'repeat',
|
|
80
|
+
'composite',
|
|
81
|
+
'tvmix',
|
|
82
|
+
'upmix21',
|
|
83
|
+
'upmix41',
|
|
84
|
+
'upmix61',
|
|
85
|
+
'centeronly',
|
|
86
|
+
'lfeonly',
|
|
87
|
+
'rearonly',
|
|
88
|
+
]
|
|
89
|
+
],
|
|
90
|
+
Argument(),
|
|
91
|
+
] = None,
|
|
92
|
+
*,
|
|
93
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
94
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
95
|
+
):
|
|
96
|
+
"""Get or set the bus mode of the specified bus.
|
|
97
|
+
|
|
98
|
+
Parameters
|
|
99
|
+
----------
|
|
100
|
+
type_ : str, optional
|
|
101
|
+
If provided, sets the bus mode to this value. If not provided, the current bus mode is printed.
|
|
102
|
+
"""
|
|
103
|
+
if type_ is None:
|
|
104
|
+
console.out.print(ctx.client.bus[index].mode.get())
|
|
105
|
+
return
|
|
106
|
+
setattr(ctx.client.bus[index].mode, type_, True)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
3
|
+
from cyclopts import App, Argument, Parameter
|
|
4
|
+
|
|
5
|
+
from .context import Context
|
|
6
|
+
from .help import CustomHelpFormatter
|
|
7
|
+
|
|
8
|
+
app = App(name='comp', help_formatter=CustomHelpFormatter())
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@app.meta.default
|
|
12
|
+
def launcher(
|
|
13
|
+
*tokens: Annotated[str, Parameter(show=False, allow_leading_hyphen=True)],
|
|
14
|
+
index: Annotated[int, Argument()] = None,
|
|
15
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
16
|
+
):
|
|
17
|
+
"""Control the compressor parameters."""
|
|
18
|
+
additional_kwargs = {}
|
|
19
|
+
command, bound, _ = app.parse_args(tokens)
|
|
20
|
+
if index is not None:
|
|
21
|
+
additional_kwargs['index'] = index
|
|
22
|
+
if ctx is not None:
|
|
23
|
+
additional_kwargs['ctx'] = ctx
|
|
24
|
+
|
|
25
|
+
return command(*bound.args, **bound.kwargs, **additional_kwargs)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@app.command(name='knob')
|
|
29
|
+
def knob(
|
|
30
|
+
new_knob: Annotated[float, Argument()] = None,
|
|
31
|
+
*,
|
|
32
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
33
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
34
|
+
):
|
|
35
|
+
"""Get or set the knob of the specified compressor.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
new_knob : int, optional
|
|
40
|
+
If provided, sets the knob to this value. If not provided, the current knob is printed.
|
|
41
|
+
"""
|
|
42
|
+
if new_knob is None:
|
|
43
|
+
# See https://github.com/onyx-and-iris/vban-cli?tab=readme-ov-file#implementation-notes - 2.
|
|
44
|
+
# console.out.print(ctx.client.strip[index].comp.knob)
|
|
45
|
+
return
|
|
46
|
+
ctx.client.strip[index].comp.knob = new_knob
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@app.command(name='input-gain')
|
|
50
|
+
def input_gain(
|
|
51
|
+
new_gain: Annotated[float, Argument()] = None,
|
|
52
|
+
*,
|
|
53
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
54
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
55
|
+
):
|
|
56
|
+
"""Get or set the input gain of the specified compressor.
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
new_gain : float, optional
|
|
61
|
+
If provided, sets the input gain to this value. If not provided, the current input gain is printed.
|
|
62
|
+
"""
|
|
63
|
+
if new_gain is None:
|
|
64
|
+
# See https://github.com/onyx-and-iris/vban-cli?tab=readme-ov-file#implementation-notes - 2.
|
|
65
|
+
# console.out.print(ctx.client.strip[index].comp.gainin)
|
|
66
|
+
return
|
|
67
|
+
ctx.client.strip[index].comp.gainin = new_gain
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
3
|
+
from cyclopts import App, Argument, Parameter
|
|
4
|
+
|
|
5
|
+
from .context import Context
|
|
6
|
+
from .help import CustomHelpFormatter
|
|
7
|
+
|
|
8
|
+
app = App(name='denoiser', help_formatter=CustomHelpFormatter())
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@app.meta.default
|
|
12
|
+
def launcher(
|
|
13
|
+
*tokens: Annotated[str, Parameter(show=False, allow_leading_hyphen=True)],
|
|
14
|
+
index: Annotated[int, Argument()] = None,
|
|
15
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
16
|
+
):
|
|
17
|
+
"""Control the denoiser parameters."""
|
|
18
|
+
additional_kwargs = {}
|
|
19
|
+
command, bound, _ = app.parse_args(tokens)
|
|
20
|
+
if index is not None:
|
|
21
|
+
additional_kwargs['index'] = index
|
|
22
|
+
if ctx is not None:
|
|
23
|
+
additional_kwargs['ctx'] = ctx
|
|
24
|
+
|
|
25
|
+
return command(*bound.args, **bound.kwargs, **additional_kwargs)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@app.command(name='knob')
|
|
29
|
+
def knob(
|
|
30
|
+
new_knob: Annotated[float, Argument()] = None,
|
|
31
|
+
*,
|
|
32
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
33
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
34
|
+
):
|
|
35
|
+
"""Get or set the knob of the specified denoiser.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
new_knob : int, optional
|
|
40
|
+
If provided, sets the knob to this value. If not provided, the current knob is printed.
|
|
41
|
+
"""
|
|
42
|
+
if new_knob is None:
|
|
43
|
+
# See https://github.com/onyx-and-iris/vban-cli?tab=readme-ov-file#implementation-notes - 2.
|
|
44
|
+
# console.out.print(ctx.client.strip[index].denoiser.knob)
|
|
45
|
+
return
|
|
46
|
+
ctx.client.strip[index].denoiser.knob = new_knob
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
3
|
+
from cyclopts import App, Argument, Parameter
|
|
4
|
+
|
|
5
|
+
from .context import Context
|
|
6
|
+
from .help import CustomHelpFormatter
|
|
7
|
+
|
|
8
|
+
app = App(name='eq', help_formatter=CustomHelpFormatter())
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@app.meta.default
|
|
12
|
+
def launcher(
|
|
13
|
+
band: Annotated[int, Argument()] = None,
|
|
14
|
+
*tokens: Annotated[str, Parameter(show=False, allow_leading_hyphen=True)],
|
|
15
|
+
index: Annotated[int, Argument()] = None,
|
|
16
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
17
|
+
):
|
|
18
|
+
"""Control the EQ parameters.
|
|
19
|
+
|
|
20
|
+
Only channel 0 is supported, see https://github.com/onyx-and-iris/vban-cli?tab=readme-ov-file#implementation-notes - 3.
|
|
21
|
+
"""
|
|
22
|
+
additional_kwargs = {}
|
|
23
|
+
command, bound, _ = app.parse_args(tokens)
|
|
24
|
+
if index is not None:
|
|
25
|
+
additional_kwargs['index'] = index
|
|
26
|
+
if band is not None:
|
|
27
|
+
additional_kwargs['band'] = band
|
|
28
|
+
if ctx is not None:
|
|
29
|
+
additional_kwargs['ctx'] = ctx
|
|
30
|
+
|
|
31
|
+
return command(*bound.args, **bound.kwargs, **additional_kwargs)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@app.command(name='on')
|
|
35
|
+
def on(
|
|
36
|
+
new_state: Annotated[bool, Argument()] = None,
|
|
37
|
+
*,
|
|
38
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
39
|
+
band: Annotated[int, Parameter(show=False)] = None,
|
|
40
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
41
|
+
):
|
|
42
|
+
"""Get or set the on state of the specified EQ band.
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
new_state : bool
|
|
47
|
+
If provided, sets the on state to this value. If not provided, the current on state is printed.
|
|
48
|
+
"""
|
|
49
|
+
if new_state is None:
|
|
50
|
+
# See https://github.com/onyx-and-iris/vban-cli?tab=readme-ov-file#implementation-notes - 2.
|
|
51
|
+
# console.out.print(ctx.client.strip[index].eq.channel[0].cell[band].on)
|
|
52
|
+
return
|
|
53
|
+
ctx.client.strip[index].eq.channel[0].cell[band].on = new_state
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from typing import Annotated
|
|
2
|
+
|
|
3
|
+
from cyclopts import App, Argument, Parameter
|
|
4
|
+
|
|
5
|
+
from .context import Context
|
|
6
|
+
from .help import CustomHelpFormatter
|
|
7
|
+
|
|
8
|
+
app = App(name='gate', help_formatter=CustomHelpFormatter())
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@app.meta.default
|
|
12
|
+
def launcher(
|
|
13
|
+
*tokens: Annotated[str, Parameter(show=False, allow_leading_hyphen=True)],
|
|
14
|
+
index: Annotated[int, Argument()] = None,
|
|
15
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
16
|
+
):
|
|
17
|
+
"""Control the compressor parameters."""
|
|
18
|
+
additional_kwargs = {}
|
|
19
|
+
command, bound, _ = app.parse_args(tokens)
|
|
20
|
+
if index is not None:
|
|
21
|
+
additional_kwargs['index'] = index
|
|
22
|
+
if ctx is not None:
|
|
23
|
+
additional_kwargs['ctx'] = ctx
|
|
24
|
+
|
|
25
|
+
return command(*bound.args, **bound.kwargs, **additional_kwargs)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@app.command(name='knob')
|
|
29
|
+
def knob(
|
|
30
|
+
new_knob: Annotated[float, Argument()] = None,
|
|
31
|
+
*,
|
|
32
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
33
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
34
|
+
):
|
|
35
|
+
"""Get or set the knob of the specified gate.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
new_knob : int, optional
|
|
40
|
+
If provided, sets the knob to this value. If not provided, the current knob is printed.
|
|
41
|
+
"""
|
|
42
|
+
if new_knob is None:
|
|
43
|
+
# See https://github.com/onyx-and-iris/vban-cli?tab=readme-ov-file#implementation-notes - 2.
|
|
44
|
+
# console.out.print(ctx.client.strip[index].gate.knob)
|
|
45
|
+
return
|
|
46
|
+
ctx.client.strip[index].gate.knob = new_knob
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@app.command(name='threshold')
|
|
50
|
+
def threshold(
|
|
51
|
+
new_threshold: Annotated[float, Argument()] = None,
|
|
52
|
+
*,
|
|
53
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
54
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
55
|
+
):
|
|
56
|
+
"""Get or set the threshold of the specified gate.
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
new_threshold : float, optional
|
|
61
|
+
If provided, sets the threshold to this value. If not provided, the current threshold is printed.
|
|
62
|
+
"""
|
|
63
|
+
if new_threshold is None:
|
|
64
|
+
# See https://github.com/onyx-and-iris/vban-cli?tab=readme-ov-file#implementation-notes - 2.
|
|
65
|
+
# console.out.print(ctx.client.strip[index].gate.threshold)
|
|
66
|
+
return
|
|
67
|
+
ctx.client.strip[index].gate.threshold = new_threshold
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from cyclopts.help import DefaultFormatter, HelpPanel
|
|
4
|
+
from rich.console import Console, ConsoleOptions
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CustomHelpFormatter(DefaultFormatter):
|
|
8
|
+
"""Custom help formatter that injects an index argument into the usage line and filters it out from the parameters list.
|
|
9
|
+
|
|
10
|
+
This formatter modifies the usage line to include an <index> argument after the 'strip' command,
|
|
11
|
+
and filters out any parameters related to 'index' from the Parameters section of the help output.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def render_usage(self, console: Console, options: ConsoleOptions, usage) -> None:
|
|
15
|
+
"""Render the usage line with index argument injected."""
|
|
16
|
+
if usage:
|
|
17
|
+
modified_usage = re.sub(
|
|
18
|
+
r'(\S+\s+[a-z]+)\s+(COMMAND)', r'\1 <index> \2', str(usage)
|
|
19
|
+
)
|
|
20
|
+
console.print(f'[bold]Usage:[/bold] {modified_usage}')
|
|
21
|
+
|
|
22
|
+
def __call__(
|
|
23
|
+
self, console: Console, options: ConsoleOptions, panel: HelpPanel
|
|
24
|
+
) -> None:
|
|
25
|
+
"""Render a help panel, filtering out the index parameter from Parameters sections."""
|
|
26
|
+
if panel.title == 'Parameters':
|
|
27
|
+
filtered_entries = [
|
|
28
|
+
entry
|
|
29
|
+
for entry in panel.entries
|
|
30
|
+
if not (
|
|
31
|
+
entry.names and any('index' in name.lower() for name in entry.names)
|
|
32
|
+
)
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
filtered_panel = HelpPanel(
|
|
36
|
+
title=panel.title,
|
|
37
|
+
entries=filtered_entries,
|
|
38
|
+
description=panel.description,
|
|
39
|
+
format=panel.format,
|
|
40
|
+
)
|
|
41
|
+
super().__call__(console, options, filtered_panel)
|
|
42
|
+
else:
|
|
43
|
+
super().__call__(console, options, panel)
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
from typing import Annotated, Optional
|
|
2
|
+
|
|
3
|
+
from cyclopts import App, Argument, Parameter
|
|
4
|
+
|
|
5
|
+
from . import comp, console, denoiser, eq, gate
|
|
6
|
+
from .context import Context
|
|
7
|
+
from .help import CustomHelpFormatter
|
|
8
|
+
|
|
9
|
+
app = App(name='strip', help_formatter=CustomHelpFormatter())
|
|
10
|
+
app.command(eq.app.meta, name='eq')
|
|
11
|
+
app.command(comp.app.meta, name='comp')
|
|
12
|
+
app.command(gate.app.meta, name='gate')
|
|
13
|
+
app.command(denoiser.app.meta, name='denoiser')
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@app.meta.default
|
|
17
|
+
def launcher(
|
|
18
|
+
index: Annotated[int, Argument()] = None,
|
|
19
|
+
*tokens: Annotated[str, Parameter(show=False, allow_leading_hyphen=True)],
|
|
20
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
21
|
+
):
|
|
22
|
+
"""Control the strip parameters."""
|
|
23
|
+
additional_kwargs = {}
|
|
24
|
+
command, bound, _ = app.parse_args(tokens)
|
|
25
|
+
if index is not None:
|
|
26
|
+
additional_kwargs['index'] = index
|
|
27
|
+
if ctx is not None:
|
|
28
|
+
additional_kwargs['ctx'] = ctx
|
|
29
|
+
|
|
30
|
+
return command(*bound.args, **bound.kwargs, **additional_kwargs)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@app.command(name='mono')
|
|
34
|
+
def mono(
|
|
35
|
+
new_state: Annotated[Optional[bool], Argument()] = None,
|
|
36
|
+
*,
|
|
37
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
38
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
39
|
+
):
|
|
40
|
+
"""Get or set the mono state of the specified strip.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
new_state : bool, optional
|
|
45
|
+
If provided, sets the mono state to this value. If not provided, the current mono state is printed.
|
|
46
|
+
"""
|
|
47
|
+
if new_state is None:
|
|
48
|
+
console.out.print(ctx.client.strip[index].mono)
|
|
49
|
+
return
|
|
50
|
+
ctx.client.strip[index].mono = new_state
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@app.command(name='solo')
|
|
54
|
+
def solo(
|
|
55
|
+
new_state: Annotated[Optional[bool], Argument()] = None,
|
|
56
|
+
*,
|
|
57
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
58
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
59
|
+
):
|
|
60
|
+
"""Get or set the solo state of the specified strip.
|
|
61
|
+
|
|
62
|
+
Parameters
|
|
63
|
+
----------
|
|
64
|
+
new_state : bool, optional
|
|
65
|
+
If provided, sets the solo state to this value. If not provided, the current solo state is printed.
|
|
66
|
+
"""
|
|
67
|
+
if new_state is None:
|
|
68
|
+
console.out.print(ctx.client.strip[index].solo)
|
|
69
|
+
return
|
|
70
|
+
ctx.client.strip[index].solo = new_state
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@app.command(name='mute')
|
|
74
|
+
def mute(
|
|
75
|
+
new_state: Annotated[Optional[bool], Argument()] = None,
|
|
76
|
+
*,
|
|
77
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
78
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
79
|
+
):
|
|
80
|
+
"""Get or set the mute state of the specified strip.
|
|
81
|
+
|
|
82
|
+
Parameters
|
|
83
|
+
----------
|
|
84
|
+
new_state : bool, optional
|
|
85
|
+
If provided, sets the mute state to this value. If not provided, the current mute state is printed.
|
|
86
|
+
"""
|
|
87
|
+
if new_state is None:
|
|
88
|
+
console.out.print(ctx.client.strip[index].mute)
|
|
89
|
+
return
|
|
90
|
+
ctx.client.strip[index].mute = new_state
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@app.command(name='gain')
|
|
94
|
+
def gain(
|
|
95
|
+
new_value: Annotated[Optional[float], Argument()] = None,
|
|
96
|
+
*,
|
|
97
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
98
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
99
|
+
):
|
|
100
|
+
"""Get or set the gain of the specified strip.
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
new_value : float, optional
|
|
105
|
+
If provided, sets the gain to this value. If not provided, the current gain is printed.
|
|
106
|
+
"""
|
|
107
|
+
if new_value is None:
|
|
108
|
+
console.out.print(ctx.client.strip[index].gain)
|
|
109
|
+
return
|
|
110
|
+
ctx.client.strip[index].gain = new_value
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@app.command(name='A1')
|
|
114
|
+
def a1(
|
|
115
|
+
new_value: Annotated[Optional[bool], Argument()] = None,
|
|
116
|
+
*,
|
|
117
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
118
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
119
|
+
):
|
|
120
|
+
"""Get or set the A1 state of the specified strip.
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
123
|
+
----------
|
|
124
|
+
new_value : bool, optional
|
|
125
|
+
If provided, sets the A1 state to this value. If not provided, the current A1 state is printed.
|
|
126
|
+
"""
|
|
127
|
+
if new_value is None:
|
|
128
|
+
console.out.print(ctx.client.strip[index].A1)
|
|
129
|
+
return
|
|
130
|
+
ctx.client.strip[index].A1 = new_value
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@app.command(name='A2')
|
|
134
|
+
def a2(
|
|
135
|
+
new_value: Annotated[Optional[bool], Argument()] = None,
|
|
136
|
+
*,
|
|
137
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
138
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
139
|
+
):
|
|
140
|
+
"""Get or set the A2 state of the specified strip.
|
|
141
|
+
|
|
142
|
+
Parameters
|
|
143
|
+
----------
|
|
144
|
+
new_value : bool, optional
|
|
145
|
+
If provided, sets the A2 state to this value. If not provided, the current A2 state is printed.
|
|
146
|
+
"""
|
|
147
|
+
if new_value is None:
|
|
148
|
+
console.out.print(ctx.client.strip[index].A2)
|
|
149
|
+
return
|
|
150
|
+
ctx.client.strip[index].A2 = new_value
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@app.command(name='A3')
|
|
154
|
+
def a3(
|
|
155
|
+
new_value: Annotated[Optional[bool], Argument()] = None,
|
|
156
|
+
*,
|
|
157
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
158
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
159
|
+
):
|
|
160
|
+
"""Get or set the A3 state of the specified strip.
|
|
161
|
+
|
|
162
|
+
Parameters
|
|
163
|
+
----------
|
|
164
|
+
new_value : bool, optional
|
|
165
|
+
If provided, sets the A3 state to this value. If not provided, the current A3 state is printed.
|
|
166
|
+
"""
|
|
167
|
+
if new_value is None:
|
|
168
|
+
console.out.print(ctx.client.strip[index].A3)
|
|
169
|
+
return
|
|
170
|
+
ctx.client.strip[index].A3 = new_value
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@app.command(name='A4')
|
|
174
|
+
def a4(
|
|
175
|
+
new_value: Annotated[Optional[bool], Argument()] = None,
|
|
176
|
+
*,
|
|
177
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
178
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
179
|
+
):
|
|
180
|
+
"""Get or set the A4 state of the specified strip.
|
|
181
|
+
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
new_value : bool, optional
|
|
185
|
+
If provided, sets the A4 state to this value. If not provided, the current A4 state is printed.
|
|
186
|
+
"""
|
|
187
|
+
if new_value is None:
|
|
188
|
+
console.out.print(ctx.client.strip[index].A4)
|
|
189
|
+
return
|
|
190
|
+
ctx.client.strip[index].A4 = new_value
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
@app.command(name='A5')
|
|
194
|
+
def a5(
|
|
195
|
+
new_value: Annotated[Optional[bool], Argument()] = None,
|
|
196
|
+
*,
|
|
197
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
198
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
199
|
+
):
|
|
200
|
+
"""Get or set the A5 state of the specified strip.
|
|
201
|
+
|
|
202
|
+
Parameters
|
|
203
|
+
----------
|
|
204
|
+
new_value : bool, optional
|
|
205
|
+
If provided, sets the A5 state to this value. If not provided, the current A5 state is printed.
|
|
206
|
+
"""
|
|
207
|
+
if new_value is None:
|
|
208
|
+
console.out.print(ctx.client.strip[index].A5)
|
|
209
|
+
return
|
|
210
|
+
ctx.client.strip[index].A5 = new_value
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@app.command(name='B1')
|
|
214
|
+
def b1(
|
|
215
|
+
new_value: Annotated[Optional[bool], Argument()] = None,
|
|
216
|
+
*,
|
|
217
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
218
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
219
|
+
):
|
|
220
|
+
"""Get or set the B1 state of the specified strip.
|
|
221
|
+
|
|
222
|
+
Parameters
|
|
223
|
+
----------
|
|
224
|
+
new_value : bool, optional
|
|
225
|
+
If provided, sets the B1 state to this value. If not provided, the current B1 state is printed.
|
|
226
|
+
"""
|
|
227
|
+
if new_value is None:
|
|
228
|
+
console.out.print(ctx.client.strip[index].B1)
|
|
229
|
+
return
|
|
230
|
+
ctx.client.strip[index].B1 = new_value
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
@app.command(name='B2')
|
|
234
|
+
def b2(
|
|
235
|
+
new_value: Annotated[Optional[bool], Argument()] = None,
|
|
236
|
+
*,
|
|
237
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
238
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
239
|
+
):
|
|
240
|
+
"""Get or set the B2 state of the specified strip.
|
|
241
|
+
|
|
242
|
+
Parameters
|
|
243
|
+
----------
|
|
244
|
+
new_value : bool, optional
|
|
245
|
+
If provided, sets the B2 state to this value. If not provided, the current B2 state is printed.
|
|
246
|
+
"""
|
|
247
|
+
if new_value is None:
|
|
248
|
+
console.out.print(ctx.client.strip[index].B2)
|
|
249
|
+
return
|
|
250
|
+
ctx.client.strip[index].B2 = new_value
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@app.command(name='B3')
|
|
254
|
+
def b3(
|
|
255
|
+
new_value: Annotated[Optional[bool], Argument()] = None,
|
|
256
|
+
*,
|
|
257
|
+
index: Annotated[int, Parameter(show=False)] = None,
|
|
258
|
+
ctx: Annotated[Context, Parameter(show=False)] = None,
|
|
259
|
+
):
|
|
260
|
+
"""Get or set the B3 state of the specified strip.
|
|
261
|
+
|
|
262
|
+
Parameters
|
|
263
|
+
----------
|
|
264
|
+
new_value : bool, optional
|
|
265
|
+
If provided, sets the B3 state to this value. If not provided, the current B3 state is printed.
|
|
266
|
+
"""
|
|
267
|
+
if new_value is None:
|
|
268
|
+
console.out.print(ctx.client.strip[index].B3)
|
|
269
|
+
return
|
|
270
|
+
ctx.client.strip[index].B3 = new_value
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vban-cli
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: A command-line interface for Voicemeeter leveraging VBAN.
|
|
5
|
+
License: LICENSE
|
|
6
|
+
Classifier: Development Status :: 3 - Alpha
|
|
7
|
+
Classifier: Programming Language :: Python
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
13
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
14
|
+
Requires-Python: >=3.13
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: cyclopts>=4.6.0
|
|
18
|
+
Requires-Dist: vban-cmd>=2.6.0
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# vban-cli
|
|
22
|
+
|
|
23
|
+
[](https://github.com/astral-sh/uv)
|
|
24
|
+
[](https://github.com/astral-sh/ruff)
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
#### With uv
|
|
31
|
+
|
|
32
|
+
```console
|
|
33
|
+
uv tool install vban-cli
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
#### With pipx
|
|
37
|
+
|
|
38
|
+
```console
|
|
39
|
+
pipx install vban-cli
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The CLI should now be discoverable as `vban-cli`
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Configuration
|
|
47
|
+
|
|
48
|
+
### Flags
|
|
49
|
+
|
|
50
|
+
```console
|
|
51
|
+
vban-cli --host=localhost --port=6980 --streamname=Command1
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Environment Variables
|
|
55
|
+
|
|
56
|
+
example .envrc:
|
|
57
|
+
|
|
58
|
+
```env
|
|
59
|
+
#!/usr/bin/env bash
|
|
60
|
+
|
|
61
|
+
export VBAN_CLI_HOST="localhost"
|
|
62
|
+
export VBAN_CLI_PORT=6980
|
|
63
|
+
export VBAN_CLI_STREAMNAME=Command1
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Use
|
|
69
|
+
|
|
70
|
+
```console
|
|
71
|
+
Usage: vban-cli COMMAND
|
|
72
|
+
|
|
73
|
+
╭─ Commands ───────────────────────────────────────────────────────────────────────────────────────╮
|
|
74
|
+
│ bus Control the bus parameters. │
|
|
75
|
+
│ strip Control the strip parameters. │
|
|
76
|
+
│ --help (-h) Display this message and exit. │
|
|
77
|
+
│ --version Display application version. │
|
|
78
|
+
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
79
|
+
╭─ Parameters ─────────────────────────────────────────────────────────────────────────────────────╮
|
|
80
|
+
│ --kind Kind of Voicemeeter [env var: VBAN_CLI_KIND] [default: potato] │
|
|
81
|
+
│ --host VBAN host [env var: VBAN_CLI_HOST] [default: localhost] │
|
|
82
|
+
│ --port VBAN port [env var: VBAN_CLI_PORT] [default: 6980] │
|
|
83
|
+
│ --streamname VBAN stream name [env var: VBAN_CLI_STREAMNAME] [default: Command1] │
|
|
84
|
+
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
For every command and subcommand there exists a `--help` flag for further usage information.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Implementation Notes
|
|
92
|
+
|
|
93
|
+
1. The VBAN TEXT subprotocol defines two packet structures [ident:0][ident-0] and [ident:1][ident-1]. Neither of them contain the data for Bus EQ parameters.
|
|
94
|
+
2. Packet structure with [ident:1][ident-1] is emitted by the VBAN server only on pdirty events. This means we do not receive the initial state of those parameters on initial subscription. Therefore any commands which are intended to fetch the value of parameters defined in packet [ident:1][ident-1] will not work in this CLI.
|
|
95
|
+
3. Packet structure with [ident:1][ident-1] defines parameteric EQ data only for the [first channel][ident-1-peq].
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Further Notes
|
|
101
|
+
|
|
102
|
+
I've made the effort to set up the basic skeletal structure of the CLI as well as demonstrate how to combine subcommand groups with subcommand groups so more can be implemented, it just needs doing. There may be restrictions on some things however, for example, retrieving values is only possible for parameters [defined in the protocol](https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/3be2c1c36563afbd6df3da8436406c77d2cc1f10/VoicemeeterRemote.h#L787). Setting parameters can be done for anything possible by a string request.
|
|
103
|
+
|
|
104
|
+
If there's something missing that you would like to see added the best bet is to submit a PR. You may raise an issue and if it's quick and simple to do I may (or may not) do it.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
`vban-cli` is distributed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license.
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
[ident-0]: https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/3be2c1c36563afbd6df3da8436406c77d2cc1f10/VoicemeeterRemote.h#L896
|
|
115
|
+
[ident-1]: https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/3be2c1c36563afbd6df3da8436406c77d2cc1f10/VoicemeeterRemote.h#L982
|
|
116
|
+
[ident-1-peq]: https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/3be2c1c36563afbd6df3da8436406c77d2cc1f10/VoicemeeterRemote.h#L995
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/vban_cli/__init__.py
|
|
5
|
+
src/vban_cli/app.py
|
|
6
|
+
src/vban_cli/bus.py
|
|
7
|
+
src/vban_cli/comp.py
|
|
8
|
+
src/vban_cli/console.py
|
|
9
|
+
src/vban_cli/context.py
|
|
10
|
+
src/vban_cli/denoiser.py
|
|
11
|
+
src/vban_cli/eq.py
|
|
12
|
+
src/vban_cli/gate.py
|
|
13
|
+
src/vban_cli/help.py
|
|
14
|
+
src/vban_cli/strip.py
|
|
15
|
+
src/vban_cli.egg-info/PKG-INFO
|
|
16
|
+
src/vban_cli.egg-info/SOURCES.txt
|
|
17
|
+
src/vban_cli.egg-info/dependency_links.txt
|
|
18
|
+
src/vban_cli.egg-info/entry_points.txt
|
|
19
|
+
src/vban_cli.egg-info/requires.txt
|
|
20
|
+
src/vban_cli.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
vban_cli
|