17 Commits

Author SHA1 Message Date
106f896c45 upd strip send docstrings/help messages 2026-02-11 09:26:23 +00:00
6615eec466 mark eq/band index args as optional. this lets us differentiate between not set and zero.
add Validate method to SnapshotCmdGroup
2026-02-10 14:16:35 +00:00
942d1b18bd keep validation failure messages consistent.
they now print the incorrect value passed.
2026-02-10 01:24:55 +00:00
2e1c28c909 Validate methods should satisfy the interface Validate() error. This commit fixes that bug. 2026-02-10 01:17:35 +00:00
cf470181a1 implement dca commands:
- DCA added to Client struct
- dca command added to both CLIs

help mds updated
2026-02-10 01:16:44 +00:00
873ff87429 add pre-commit config 2026-02-09 13:59:30 +00:00
376f3109ef add separators 2026-02-09 11:59:35 +00:00
9484f8e4f3 upd Use section in README 2026-02-09 11:56:49 +00:00
a936a7e3db add help mds 2026-02-09 11:56:27 +00:00
github-actions[bot]
a0153f6b84 chore: auto-update Go modules 2026-02-09 00:05:05 +00:00
886c078f67 upd taskfiles 2026-02-08 06:27:28 +00:00
07ac73fbe4 fix dosctring 2026-02-08 05:53:22 +00:00
23422f9641 DRY up the factory methods
use optional functions to set address functions
2026-02-07 14:23:46 +00:00
3c47d12719 we no longer need to pass in the kind
remove option function WithKind
2026-02-07 13:58:37 +00:00
8a452c83b9 pass base addresses to factory methods 2026-02-07 09:24:41 +00:00
abfb1bf08d implement x32 matrix commands 2026-02-07 08:49:23 +00:00
0dc097c49e add example x32 .envrc 2026-02-07 04:48:07 +00:00
37 changed files with 1578 additions and 551 deletions

8
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,8 @@
repos:
- repo: local
hooks:
- id: update-readme
name: update-readme
entry: python update_readme.py
language: python
pass_filenames: false

144
README.md
View File

@@ -32,7 +32,7 @@ xair-cli --host mixer.local --timeout 50ms --help
Or you may load them from your environment:
Example .envrc:
Example xair .envrc:
```bash
#!/usr/bin/env bash
@@ -43,134 +43,25 @@ export XAIR_CLI_TIMEOUT=100ms
export XAIR_CLI_LOGLEVEL=warn
```
Example x32 .envrc:
```bash
#!/usr/bin/env bash
export X32_CLI_HOST=x32.local
export X32_CLI_PORT=10023
export X32_CLI_TIMEOUT=100ms
export X32_CLI_LOGLEVEL=warn
```
---
### Use
```console
Usage: xair-cli <command> [flags]
For each command/subcommand in the tree there exists a `--help` flag, use it to print usage information.
A CLI to control Behringer X-Air mixers.
Flags:
-h, --help Show context-sensitive help.
-H, --host="mixer.local" The host of the X-Air device ($XAIR_CLI_HOST).
-P, --port=10024 The port of the X-Air device ($XAIR_CLI_PORT).
-T, --timeout=100ms Timeout for OSC operations ($XAIR_CLI_TIMEOUT).
-L, --loglevel="warn" Log level for the CLI ($XAIR_CLI_LOGLEVEL).
-v, --version Print xair-cli version information and quit
Commands:
completion (c) Generate shell completion scripts.
Raw
raw Send raw OSC messages to the mixer.
Main
main mute Get or set the mute state of the Main L/R output.
main fader Get or set the fader level of the Main L/R output.
main fadein Fade in the Main L/R output over a specified duration.
main fadeout Fade out the Main L/R output over a specified duration.
main eq on Get or set the EQ on/off state of the Main L/R output.
main eq <band> gain Get or set the gain of the specified EQ band.
main eq <band> freq Get or set the frequency of the specified EQ band.
main eq <band> q Get or set the Q factor of the specified EQ band.
main eq <band> type Get or set the type of the specified EQ band.
main comp on Get or set the compressor on/off state of the Main L/R
output.
main comp mode Get or set the compressor mode of the Main L/R output.
main comp threshold Get or set the compressor threshold of the Main L/R
output.
main comp ratio Get or set the compressor ratio of the Main L/R output.
main comp mix Get or set the compressor mix level of the Main L/R
output.
main comp makeup Get or set the compressor makeup gain of the Main L/R
output.
main comp attack Get or set the compressor attack time of the Main L/R
output.
main comp hold Get or set the compressor hold time of the Main L/R
output.
main comp release Get or set the compressor release time of the Main L/R
output.
Strip
strip <index> mute Get or set the mute state of the strip.
strip <index> fader Get or set the fader level of the strip.
strip <index> fadein Fade in the strip over a specified duration.
strip <index> fadeout Fade out the strip over a specified duration.
strip <index> send Get or set the send level for a specific bus.
strip <index> name Get or set the name of the strip.
strip <index> gate on Get or set the gate on/off state of the strip.
strip <index> gate mode Get or set the gate mode of the strip.
strip <index> gate threshold Get or set the gate threshold of the strip.
strip <index> gate range Get or set the gate range of the strip.
strip <index> gate attack Get or set the gate attack time of the strip.
strip <index> gate hold Get or set the gate hold time of the strip.
strip <index> gate release Get or set the gate release time of the strip.
strip <index> eq on Get or set the EQ on/off state of the strip.
strip <index> eq <band> gain Get or set the gain of the EQ band.
strip <index> eq <band> freq Get or set the frequency of the EQ band.
strip <index> eq <band> q Get or set the Q factor of the EQ band.
strip <index> eq <band> type Get or set the type of the EQ band.
strip <index> comp on Get or set the compressor on/off state of the
strip.
strip <index> comp mode Get or set the compressor mode of the strip.
strip <index> comp threshold Get or set the compressor threshold of the
strip.
strip <index> comp ratio Get or set the compressor ratio of the strip.
strip <index> comp mix Get or set the compressor mix of the strip.
strip <index> comp makeup Get or set the compressor makeup gain of the
strip.
strip <index> comp attack Get or set the compressor attack time of the
strip.
strip <index> comp hold Get or set the compressor hold time of the
strip.
strip <index> comp release Get or set the compressor release time of the
strip.
Bus
bus <index> mute Get or set the mute state of the bus.
bus <index> fader Get or set the fader level of the bus.
bus <index> fadein Fade in the bus over a specified duration.
bus <index> fadeout Fade out the bus over a specified duration.
bus <index> name Get or set the name of the bus.
bus <index> eq on Get or set the EQ on/off state of the bus.
bus <index> eq mode Get or set the EQ mode of the bus (peq, geq or
teq).
bus <index> eq <band> gain Get or set the gain of the EQ band.
bus <index> eq <band> freq Get or set the frequency of the EQ band.
bus <index> eq <band> q Get or set the Q factor of the EQ band.
bus <index> eq <band> type Get or set the type of the EQ band (lcut, lshv,
peq, veq, hshv, hcut).
bus <index> comp on Get or set the compressor on/off state of the
bus.
bus <index> comp mode Get or set the compressor mode of the bus (comp,
exp).
bus <index> comp threshold Get or set the compressor threshold of the bus
(in dB).
bus <index> comp ratio Get or set the compressor ratio of the bus.
bus <index> comp mix Get or set the compressor mix level of the bus
(in %).
bus <index> comp makeup Get or set the compressor makeup gain of the bus
(in dB).
bus <index> comp attack Get or set the compressor attack time of the bus
(in ms).
bus <index> comp hold Get or set the compressor hold time of the bus
(in ms).
bus <index> comp release Get or set the compressor release time of the
bus (in ms).
Headamp
headamp <index> gain Get or set the gain of the headamp.
headamp <index> phantom Get or set the phantom power state of the headamp.
Snapshot
snapshot list List all snapshots.
snapshot <index> name Get or set the name of a snapshot.
snapshot <index> save Save the current mixer state to a snapshot.
snapshot <index> load Load a mixer state from a snapshot.
snapshot <index> delete Delete a snapshot.
Run "xair-cli <command> --help" for more information on a command.
```
- [xair-cli](./xair-help.md)
- [x32-cli](./x32-help.md)
### Examples
@@ -220,6 +111,7 @@ xair-cli raw /ch/01/config/name
xair-cli snapshot 20 save 'twitch live'
```
---
### License

View File

@@ -1,23 +1,22 @@
version: '3'
vars:
BIN_X32: x32-cli
WINDOWS: '{{.BIN_DIR}}/{{.PROGRAM}}_windows_amd64.exe'
LINUX: '{{.BIN_DIR}}/{{.PROGRAM}}_linux_amd64'
MACOS: '{{.BIN_DIR}}/{{.PROGRAM}}_darwin_amd64'
tasks:
windows-amd64:
desc: Build the x32-cli project for Windows
cmds:
- GOOS=windows GOARCH=amd64 go build -o {{.BIN_DIR}}/{{.BIN_X32}}_windows_amd64.exe -ldflags="-X main.version={{.VERSION}}" ./cmd/{{.BIN_X32}}
internal: true
- GOOS=windows GOARCH=amd64 go build -o {{.WINDOWS}} -ldflags="-X main.version={{.VERSION}}" ./cmd/{{.PROGRAM}}
linux-amd64:
desc: Build the x32-cli project for Linux
cmds:
- GOOS=linux GOARCH=amd64 go build -o {{.BIN_DIR}}/{{.BIN_X32}}_linux_amd64 -ldflags="-X main.version={{.VERSION}}" ./cmd/{{.BIN_X32}}
internal: true
- GOOS=linux GOARCH=amd64 go build -o {{.LINUX}} -ldflags="-X main.version={{.VERSION}}" ./cmd/{{.PROGRAM}}
darwin-amd64:
desc: Build the x32-cli project for macOS
cmds:
- GOOS=darwin GOARCH=amd64 go build -o {{.BIN_DIR}}/{{.BIN_X32}}_darwin_amd64 -ldflags="-X main.version={{.VERSION}}" ./cmd/{{.BIN_X32}}
internal: true
- GOOS=darwin GOARCH=amd64 go build -o {{.MACOS}} -ldflags="-X main.version={{.VERSION}}" ./cmd/{{.PROGRAM}}

View File

@@ -1,23 +1,22 @@
version: '3'
vars:
BIN_XAIR: xair-cli
WINDOWS: '{{.BIN_DIR}}/{{.PROGRAM}}_windows_amd64.exe'
LINUX: '{{.BIN_DIR}}/{{.PROGRAM}}_linux_amd64'
MACOS: '{{.BIN_DIR}}/{{.PROGRAM}}_darwin_amd64'
tasks:
windows-amd64:
desc: Build the xair-cli project for Windows
cmds:
- GOOS=windows GOARCH=amd64 go build -o {{.BIN_DIR}}/{{.BIN_XAIR}}_windows_amd64.exe -ldflags="-X main.version={{.VERSION}}" ./cmd/{{.BIN_XAIR}}
internal: true
- GOOS=windows GOARCH=amd64 go build -o {{.WINDOWS}} -ldflags="-X main.version={{.VERSION}}" ./cmd/{{.PROGRAM}}
linux-amd64:
desc: Build the xair-cli project for Linux
cmds:
- GOOS=linux GOARCH=amd64 go build -o {{.BIN_DIR}}/{{.BIN_XAIR}}_linux_amd64 -ldflags="-X main.version={{.VERSION}}" ./cmd/{{.BIN_XAIR}}
internal: true
- GOOS=linux GOARCH=amd64 go build -o {{.LINUX}} -ldflags="-X main.version={{.VERSION}}" ./cmd/{{.PROGRAM}}
darwin-amd64:
desc: Build the xair-cli project for macOS
cmds:
- GOOS=darwin GOARCH=amd64 go build -o {{.BIN_DIR}}/{{.BIN_XAIR}}_darwin_amd64 -ldflags="-X main.version={{.VERSION}}" ./cmd/{{.BIN_XAIR}}
internal: true
- GOOS=darwin GOARCH=amd64 go build -o {{.MACOS}} -ldflags="-X main.version={{.VERSION}}" ./cmd/{{.PROGRAM}}

View File

@@ -1,8 +1,16 @@
version: '3'
includes:
build-xair: ./Taskfile.build-xair.yml
build-x32: ./Taskfile.build-x32.yml
build-xair:
taskfile: ./Taskfile.build-xair.yml
internal: true
vars:
PROGRAM: xair-cli
build-x32:
taskfile: ./Taskfile.build-x32.yml
internal: true
vars:
PROGRAM: x32-cli
vars:
SHELL: '{{if eq .OS "Windows_NT"}}powershell{{end}}'
@@ -20,13 +28,11 @@ tasks:
desc: Build the xair-cli and x32-cli projects for all platforms
deps: [vet]
cmds:
- task: build-xair:windows-amd64
- task: build-xair:linux-amd64
- task: build-xair:darwin-amd64
- task: build-x32:windows-amd64
- task: build-x32:linux-amd64
- task: build-x32:darwin-amd64
- for:
matrix:
PROGRAM: ['build-xair', 'build-x32']
TARGET: ['windows-amd64', 'linux-amd64', 'darwin-amd64']
task: '{{.ITEM.PROGRAM}}:{{.ITEM.TARGET}}'
vet:
desc: Vet the code

View File

@@ -3,8 +3,6 @@ package main
import (
"fmt"
"time"
"github.com/alecthomas/kong"
)
// BusCmdGroup defines the commands related to controlling the buses of the X-Air device.
@@ -174,7 +172,7 @@ type BusEqCmdGroup struct {
On BusEqOnCmd `help:"Get or set the EQ on/off state of the bus." cmd:"on"`
Mode BusEqModeCmd `help:"Get or set the EQ mode of the bus (peq, geq or teq)." cmd:"mode"`
Band struct {
Band int `arg:"" help:"The EQ band number."`
Band *int `arg:"" help:"The EQ band number." optional:""`
Gain BusEqBandGainCmd `help:"Get or set the gain of the EQ band." cmd:"gain"`
Freq BusEqBandFreqCmd `help:"Get or set the frequency of the EQ band." cmd:"freq"`
Q BusEqBandQCmd `help:"Get or set the Q factor of the EQ band." cmd:"q"`
@@ -183,9 +181,13 @@ type BusEqCmdGroup struct {
}
// Validate checks that the provided EQ band number is within the valid range (1-6).
func (cmd *BusEqCmdGroup) Validate(ctx kong.Context) error {
if cmd.Band.Band < 1 || cmd.Band.Band > 6 {
return fmt.Errorf("EQ band number must be between 1 and 6")
func (cmd *BusEqCmdGroup) Validate() error {
if cmd.Band.Band == nil {
return nil
}
if *cmd.Band.Band < 1 || *cmd.Band.Band > 6 {
return fmt.Errorf("EQ band number must be between 1 and 6, got %d", *cmd.Band.Band)
}
return nil
}
@@ -244,18 +246,18 @@ type BusEqBandGainCmd struct {
// Run executes the BusEqBandGainCmd command, either retrieving the current gain of the specified EQ band of the bus or setting it based on the provided argument.
func (cmd *BusEqBandGainCmd) Run(ctx *context, bus *BusCmdGroup, busEq *BusEqCmdGroup) error {
if cmd.Gain == nil {
resp, err := ctx.Client.Bus.Eq.Gain(bus.Index.Index, busEq.Band.Band)
resp, err := ctx.Client.Bus.Eq.Gain(bus.Index.Index, *busEq.Band.Band)
if err != nil {
return err
}
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d gain: %.2f dB\n", bus.Index.Index, busEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d gain: %.2f dB\n", bus.Index.Index, *busEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Bus.Eq.SetGain(bus.Index.Index, busEq.Band.Band, *cmd.Gain); err != nil {
if err := ctx.Client.Bus.Eq.SetGain(bus.Index.Index, *busEq.Band.Band, *cmd.Gain); err != nil {
return err
}
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d gain set to: %.2f dB\n", bus.Index.Index, busEq.Band.Band, *cmd.Gain)
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d gain set to: %.2f dB\n", bus.Index.Index, *busEq.Band.Band, *cmd.Gain)
return nil
}
@@ -267,18 +269,18 @@ type BusEqBandFreqCmd struct {
// Run executes the BusEqBandFreqCmd command, either retrieving the current frequency of the specified EQ band of the bus or setting it based on the provided argument.
func (cmd *BusEqBandFreqCmd) Run(ctx *context, bus *BusCmdGroup, busEq *BusEqCmdGroup) error {
if cmd.Freq == nil {
resp, err := ctx.Client.Bus.Eq.Frequency(bus.Index.Index, busEq.Band.Band)
resp, err := ctx.Client.Bus.Eq.Frequency(bus.Index.Index, *busEq.Band.Band)
if err != nil {
return err
}
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d frequency: %.2f Hz\n", bus.Index.Index, busEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d frequency: %.2f Hz\n", bus.Index.Index, *busEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Bus.Eq.SetFrequency(bus.Index.Index, busEq.Band.Band, *cmd.Freq); err != nil {
if err := ctx.Client.Bus.Eq.SetFrequency(bus.Index.Index, *busEq.Band.Band, *cmd.Freq); err != nil {
return err
}
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d frequency set to: %.2f Hz\n", bus.Index.Index, busEq.Band.Band, *cmd.Freq)
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d frequency set to: %.2f Hz\n", bus.Index.Index, *busEq.Band.Band, *cmd.Freq)
return nil
}
@@ -290,18 +292,18 @@ type BusEqBandQCmd struct {
// Run executes the BusEqBandQCmd command, either retrieving the current Q factor of the specified EQ band of the bus or setting it based on the provided argument.
func (cmd *BusEqBandQCmd) Run(ctx *context, bus *BusCmdGroup, busEq *BusEqCmdGroup) error {
if cmd.Q == nil {
resp, err := ctx.Client.Bus.Eq.Q(bus.Index.Index, busEq.Band.Band)
resp, err := ctx.Client.Bus.Eq.Q(bus.Index.Index, *busEq.Band.Band)
if err != nil {
return err
}
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d Q factor: %.2f\n", bus.Index.Index, busEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d Q factor: %.2f\n", bus.Index.Index, *busEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Bus.Eq.SetQ(bus.Index.Index, busEq.Band.Band, *cmd.Q); err != nil {
if err := ctx.Client.Bus.Eq.SetQ(bus.Index.Index, *busEq.Band.Band, *cmd.Q); err != nil {
return err
}
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d Q factor set to: %.2f\n", bus.Index.Index, busEq.Band.Band, *cmd.Q)
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d Q factor set to: %.2f\n", bus.Index.Index, *busEq.Band.Band, *cmd.Q)
return nil
}
@@ -313,18 +315,18 @@ type BusEqBandTypeCmd struct {
// Run executes the BusEqBandTypeCmd command, either retrieving the current type of the specified EQ band of the bus or setting it based on the provided argument.
func (cmd *BusEqBandTypeCmd) Run(ctx *context, bus *BusCmdGroup, busEq *BusEqCmdGroup) error {
if cmd.Type == nil {
resp, err := ctx.Client.Bus.Eq.Type(bus.Index.Index, busEq.Band.Band)
resp, err := ctx.Client.Bus.Eq.Type(bus.Index.Index, *busEq.Band.Band)
if err != nil {
return err
}
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d type: %s\n", bus.Index.Index, busEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d type: %s\n", bus.Index.Index, *busEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Bus.Eq.SetType(bus.Index.Index, busEq.Band.Band, *cmd.Type); err != nil {
if err := ctx.Client.Bus.Eq.SetType(bus.Index.Index, *busEq.Band.Band, *cmd.Type); err != nil {
return err
}
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d type set to: %s\n", bus.Index.Index, busEq.Band.Band, *cmd.Type)
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d type set to: %s\n", bus.Index.Index, *busEq.Band.Band, *cmd.Type)
return nil
}

View File

@@ -51,10 +51,12 @@ type CLI struct {
Raw RawCmd `help:"Send raw OSC messages to the mixer." cmd:"" group:"Raw"`
Main MainCmdGroup `help:"Control the Main L/R output" cmd:"" group:"Main"`
Mainmono MainMonoCmdGroup `help:"Control the Main Mono output" cmd:"" group:"MainMono"`
Matrix MatrixCmdGroup `help:"Control the matrix outputs." cmd:"" group:"Matrix"`
Strip StripCmdGroup `help:"Control the strips." cmd:"" group:"Strip"`
Bus BusCmdGroup `help:"Control the buses." cmd:"" group:"Bus"`
Headamp HeadampCmdGroup `help:"Control input gain and phantom power." cmd:"" group:"Headamp"`
Snapshot SnapshotCmdGroup `help:"Save and load mixer states." cmd:"" group:"Snapshot"`
Dca DCACmdGroup `help:"Control DCA groups." cmd:"" group:"DCA"`
}
func main() {
@@ -120,7 +122,6 @@ func connect(config Config) (*xair.X32Client, error) {
client, err := xair.NewX32Client(
config.Host,
config.Port,
xair.WithKind("x32"),
xair.WithTimeout(config.Timeout),
)
if err != nil {

67
cmd/x32-cli/dca.go Normal file
View File

@@ -0,0 +1,67 @@
package main
import (
"fmt"
)
type DCACmdGroup struct {
Index struct {
Index int `arg:"" help:"The index of the DCA group (1-8)."`
Mute DCAMuteCmd `help:"Get or set the mute status of the DCA group." cmd:""`
Name DCANameCmd `help:"Get or set the name of the DCA group." cmd:""`
} `arg:"" help:"Control a specific DCA group by its index."`
}
// Validate checks if the provided index is within the valid range.
func (cmd *DCACmdGroup) Validate() error {
if cmd.Index.Index < 1 || cmd.Index.Index > 8 {
return fmt.Errorf("DCA group index must be between 1 and 8, got %d", cmd.Index.Index)
}
return nil
}
// DCAMuteCmd is the command to get or set the mute status of a DCA group.
type DCAMuteCmd struct {
State *string `arg:"" help:"Set the mute status of the DCA group." optional:"" enum:"true,false"`
}
// Run executes the DCAMuteCmd command.
func (cmd *DCAMuteCmd) Run(ctx *context, dca *DCACmdGroup) error {
if cmd.State == nil {
resp, err := ctx.Client.DCA.Mute(dca.Index.Index)
if err != nil {
return fmt.Errorf("failed to get DCA mute status: %w", err)
}
fmt.Fprintf(ctx.Out, "DCA Group %d mute state: %t\n", dca.Index.Index, resp)
return nil
}
if err := ctx.Client.DCA.SetMute(dca.Index.Index, *cmd.State == "true"); err != nil {
return fmt.Errorf("failed to set DCA mute status: %w", err)
}
return nil
}
// DCANameCmd is the command to get or set the name of a DCA group.
type DCANameCmd struct {
Name *string `arg:"" help:"Set the name of the DCA group." optional:""`
}
// Run executes the DCANameCmd command.
func (cmd *DCANameCmd) Run(ctx *context, dca *DCACmdGroup) error {
if cmd.Name == nil {
resp, err := ctx.Client.DCA.Name(dca.Index.Index)
if err != nil {
return fmt.Errorf("failed to get DCA name: %w", err)
}
if resp == "" {
resp = fmt.Sprintf("DCA %d", dca.Index.Index)
}
fmt.Fprintf(ctx.Out, "DCA Group %d is named '%s'\n", dca.Index.Index, resp)
return nil
}
if err := ctx.Client.DCA.SetName(dca.Index.Index, *cmd.Name); err != nil {
return fmt.Errorf("failed to set DCA name: %w", err)
}
return nil
}

View File

@@ -3,8 +3,6 @@ package main
import (
"fmt"
"time"
"github.com/alecthomas/kong"
)
// MainCmdGroup defines the command group for controlling the Main L/R output, including commands for mute state, fader level, and fade-in/fade-out times.
@@ -137,7 +135,7 @@ func (cmd *MainFadeoutCmd) Run(ctx *context) error {
type MainEqCmdGroup struct {
On MainEqOnCmd `help:"Get or set the EQ on/off state of the Main L/R output." cmd:"on"`
Band struct {
Band int `arg:"" help:"The EQ band number."`
Band *int `arg:"" help:"The EQ band number." optional:""`
Gain MainEqBandGainCmd `help:"Get or set the gain of the specified EQ band." cmd:"gain"`
Freq MainEqBandFreqCmd `help:"Get or set the frequency of the specified EQ band." cmd:"freq"`
Q MainEqBandQCmd `help:"Get or set the Q factor of the specified EQ band." cmd:"q"`
@@ -146,9 +144,13 @@ type MainEqCmdGroup struct {
}
// Validate checks if the provided EQ band number is within the valid range (1-6) for the Main L/R output.
func (cmd *MainEqCmdGroup) Validate(ctx kong.Context) error {
if cmd.Band.Band < 1 || cmd.Band.Band > 6 {
return fmt.Errorf("invalid EQ band number: %d. Valid range is 1-6", cmd.Band.Band)
func (cmd *MainEqCmdGroup) Validate() error {
if cmd.Band.Band == nil {
return nil
}
if *cmd.Band.Band < 1 || *cmd.Band.Band > 6 {
return fmt.Errorf("EQ band number must be between 1 and 6, got %d", *cmd.Band.Band)
}
return nil
}
@@ -184,18 +186,18 @@ type MainEqBandGainCmd struct {
// Run executes the MainEqBandGainCmd command, either retrieving the current gain of a specific EQ band on the Main L/R output or setting it based on the provided argument.
func (cmd *MainEqBandGainCmd) Run(ctx *context, main *MainCmdGroup, mainEq *MainEqCmdGroup) error {
if cmd.Level == nil {
resp, err := ctx.Client.Main.Eq.Gain(0, mainEq.Band.Band)
resp, err := ctx.Client.Main.Eq.Gain(0, *mainEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Main L/R EQ band %d gain: %w", mainEq.Band.Band, err)
return fmt.Errorf("failed to get Main L/R EQ band %d gain: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d gain: %.2f dB\n", mainEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d gain: %.2f dB\n", *mainEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Main.Eq.SetGain(0, mainEq.Band.Band, *cmd.Level); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d gain: %w", mainEq.Band.Band, err)
if err := ctx.Client.Main.Eq.SetGain(0, *mainEq.Band.Band, *cmd.Level); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d gain: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d gain set to: %.2f dB\n", mainEq.Band.Band, *cmd.Level)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d gain set to: %.2f dB\n", *mainEq.Band.Band, *cmd.Level)
return nil
}
@@ -207,18 +209,18 @@ type MainEqBandFreqCmd struct {
// Run executes the MainEqBandFreqCmd command, either retrieving the current frequency of a specific EQ band on the Main L/R output or setting it based on the provided argument.
func (cmd *MainEqBandFreqCmd) Run(ctx *context, main *MainCmdGroup, mainEq *MainEqCmdGroup) error {
if cmd.Frequency == nil {
resp, err := ctx.Client.Main.Eq.Frequency(0, mainEq.Band.Band)
resp, err := ctx.Client.Main.Eq.Frequency(0, *mainEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Main L/R EQ band %d frequency: %w", mainEq.Band.Band, err)
return fmt.Errorf("failed to get Main L/R EQ band %d frequency: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d frequency: %.2f Hz\n", mainEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d frequency: %.2f Hz\n", *mainEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Main.Eq.SetFrequency(0, mainEq.Band.Band, *cmd.Frequency); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d frequency: %w", mainEq.Band.Band, err)
if err := ctx.Client.Main.Eq.SetFrequency(0, *mainEq.Band.Band, *cmd.Frequency); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d frequency: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d frequency set to: %.2f Hz\n", mainEq.Band.Band, *cmd.Frequency)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d frequency set to: %.2f Hz\n", *mainEq.Band.Band, *cmd.Frequency)
return nil
}
@@ -230,18 +232,18 @@ type MainEqBandQCmd struct {
// Run executes the MainEqBandQCmd command, either retrieving the current Q factor of a specific EQ band on the Main L/R output or setting it based on the provided argument.
func (cmd *MainEqBandQCmd) Run(ctx *context, main *MainCmdGroup, mainEq *MainEqCmdGroup) error {
if cmd.Q == nil {
resp, err := ctx.Client.Main.Eq.Q(0, mainEq.Band.Band)
resp, err := ctx.Client.Main.Eq.Q(0, *mainEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Main L/R EQ band %d Q factor: %w", mainEq.Band.Band, err)
return fmt.Errorf("failed to get Main L/R EQ band %d Q factor: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d Q factor: %.2f\n", mainEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d Q factor: %.2f\n", *mainEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Main.Eq.SetQ(0, mainEq.Band.Band, *cmd.Q); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d Q factor: %w", mainEq.Band.Band, err)
if err := ctx.Client.Main.Eq.SetQ(0, *mainEq.Band.Band, *cmd.Q); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d Q factor: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d Q factor set to: %.2f\n", mainEq.Band.Band, *cmd.Q)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d Q factor set to: %.2f\n", *mainEq.Band.Band, *cmd.Q)
return nil
}
@@ -253,18 +255,18 @@ type MainEqBandTypeCmd struct {
// Run executes the MainEqBandTypeCmd command, either retrieving the current type of a specific EQ band on the Main L/R output or setting it based on the provided argument.
func (cmd *MainEqBandTypeCmd) Run(ctx *context, main *MainCmdGroup, mainEq *MainEqCmdGroup) error {
if cmd.Type == nil {
resp, err := ctx.Client.Main.Eq.Type(0, mainEq.Band.Band)
resp, err := ctx.Client.Main.Eq.Type(0, *mainEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Main L/R EQ band %d type: %w", mainEq.Band.Band, err)
return fmt.Errorf("failed to get Main L/R EQ band %d type: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d type: %s\n", mainEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d type: %s\n", *mainEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Main.Eq.SetType(0, mainEq.Band.Band, *cmd.Type); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d type: %w", mainEq.Band.Band, err)
if err := ctx.Client.Main.Eq.SetType(0, *mainEq.Band.Band, *cmd.Type); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d type: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d type set to: %s\n", mainEq.Band.Band, *cmd.Type)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d type set to: %s\n", *mainEq.Band.Band, *cmd.Type)
return nil
}

View File

@@ -3,8 +3,6 @@ package main
import (
"fmt"
"time"
"github.com/alecthomas/kong"
)
// MainMonoCmdGroup defines the command group for controlling the Main Mono output, including commands for mute state, fader level, and fade-in/fade-out times.
@@ -137,7 +135,7 @@ func (cmd *MainMonoFadeoutCmd) Run(ctx *context) error {
type MainMonoEqCmdGroup struct {
On MainMonoEqOnCmd `help:"Get or set the EQ on/off state of the Main Mono output." cmd:"on"`
Band struct {
Band int `arg:"" help:"The EQ band number."`
Band *int `arg:"" help:"The EQ band number." optional:""`
Gain MainMonoEqBandGainCmd `help:"Get or set the gain of the specified EQ band." cmd:"gain"`
Freq MainMonoEqBandFreqCmd `help:"Get or set the frequency of the specified EQ band." cmd:"freq"`
Q MainMonoEqBandQCmd `help:"Get or set the Q factor of the specified EQ band." cmd:"q"`
@@ -146,9 +144,13 @@ type MainMonoEqCmdGroup struct {
}
// Validate checks if the provided EQ band number is within the valid range (1-6) for the Main Mono output.
func (cmd *MainMonoEqCmdGroup) Validate(ctx kong.Context) error {
if cmd.Band.Band < 1 || cmd.Band.Band > 6 {
return fmt.Errorf("invalid EQ band number: %d. Valid range is 1-6", cmd.Band.Band)
func (cmd *MainMonoEqCmdGroup) Validate() error {
if cmd.Band.Band == nil {
return nil
}
if *cmd.Band.Band < 1 || *cmd.Band.Band > 6 {
return fmt.Errorf("EQ band number must be between 1 and 6, got %d", *cmd.Band.Band)
}
return nil
}
@@ -184,18 +186,18 @@ type MainMonoEqBandGainCmd struct {
// Run executes the MainMonoEqBandGainCmd command, either retrieving the current gain of a specific EQ band on the Main Mono output or setting it based on the provided argument.
func (cmd *MainMonoEqBandGainCmd) Run(ctx *context, main *MainCmdGroup, mainEq *MainMonoEqCmdGroup) error {
if cmd.Level == nil {
resp, err := ctx.Client.MainMono.Eq.Gain(0, mainEq.Band.Band)
resp, err := ctx.Client.MainMono.Eq.Gain(0, *mainEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Main Mono EQ band %d gain: %w", mainEq.Band.Band, err)
return fmt.Errorf("failed to get Main Mono EQ band %d gain: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d gain: %.2f dB\n", mainEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d gain: %.2f dB\n", *mainEq.Band.Band, resp)
return nil
}
if err := ctx.Client.MainMono.Eq.SetGain(0, mainEq.Band.Band, *cmd.Level); err != nil {
return fmt.Errorf("failed to set Main Mono EQ band %d gain: %w", mainEq.Band.Band, err)
if err := ctx.Client.MainMono.Eq.SetGain(0, *mainEq.Band.Band, *cmd.Level); err != nil {
return fmt.Errorf("failed to set Main Mono EQ band %d gain: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d gain set to: %.2f dB\n", mainEq.Band.Band, *cmd.Level)
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d gain set to: %.2f dB\n", *mainEq.Band.Band, *cmd.Level)
return nil
}
@@ -207,18 +209,18 @@ type MainMonoEqBandFreqCmd struct {
// Run executes the MainMonoEqBandFreqCmd command, either retrieving the current frequency of a specific EQ band on the Main Mono output or setting it based on the provided argument.
func (cmd *MainMonoEqBandFreqCmd) Run(ctx *context, main *MainCmdGroup, mainEq *MainMonoEqCmdGroup) error {
if cmd.Frequency == nil {
resp, err := ctx.Client.MainMono.Eq.Frequency(0, mainEq.Band.Band)
resp, err := ctx.Client.MainMono.Eq.Frequency(0, *mainEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Main Mono EQ band %d frequency: %w", mainEq.Band.Band, err)
return fmt.Errorf("failed to get Main Mono EQ band %d frequency: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d frequency: %.2f Hz\n", mainEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d frequency: %.2f Hz\n", *mainEq.Band.Band, resp)
return nil
}
if err := ctx.Client.MainMono.Eq.SetFrequency(0, mainEq.Band.Band, *cmd.Frequency); err != nil {
return fmt.Errorf("failed to set Main Mono EQ band %d frequency: %w", mainEq.Band.Band, err)
if err := ctx.Client.MainMono.Eq.SetFrequency(0, *mainEq.Band.Band, *cmd.Frequency); err != nil {
return fmt.Errorf("failed to set Main Mono EQ band %d frequency: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d frequency set to: %.2f Hz\n", mainEq.Band.Band, *cmd.Frequency)
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d frequency set to: %.2f Hz\n", *mainEq.Band.Band, *cmd.Frequency)
return nil
}
@@ -230,18 +232,18 @@ type MainMonoEqBandQCmd struct {
// Run executes the MainMonoEqBandQCmd command, either retrieving the current Q factor of a specific EQ band on the Main Mono output or setting it based on the provided argument.
func (cmd *MainMonoEqBandQCmd) Run(ctx *context, main *MainCmdGroup, mainEq *MainMonoEqCmdGroup) error {
if cmd.Q == nil {
resp, err := ctx.Client.MainMono.Eq.Q(0, mainEq.Band.Band)
resp, err := ctx.Client.MainMono.Eq.Q(0, *mainEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Main Mono EQ band %d Q factor: %w", mainEq.Band.Band, err)
return fmt.Errorf("failed to get Main Mono EQ band %d Q factor: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d Q factor: %.2f\n", mainEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d Q factor: %.2f\n", *mainEq.Band.Band, resp)
return nil
}
if err := ctx.Client.MainMono.Eq.SetQ(0, mainEq.Band.Band, *cmd.Q); err != nil {
return fmt.Errorf("failed to set Main Mono EQ band %d Q factor: %w", mainEq.Band.Band, err)
if err := ctx.Client.MainMono.Eq.SetQ(0, *mainEq.Band.Band, *cmd.Q); err != nil {
return fmt.Errorf("failed to set Main Mono EQ band %d Q factor: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d Q factor set to: %.2f\n", mainEq.Band.Band, *cmd.Q)
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d Q factor set to: %.2f\n", *mainEq.Band.Band, *cmd.Q)
return nil
}
@@ -253,18 +255,18 @@ type MainMonoEqBandTypeCmd struct {
// Run executes the MainMonoEqBandTypeCmd command, either retrieving the current type of a specific EQ band on the Main Mono output or setting it based on the provided argument.
func (cmd *MainMonoEqBandTypeCmd) Run(ctx *context, main *MainCmdGroup, mainEq *MainMonoEqCmdGroup) error {
if cmd.Type == nil {
resp, err := ctx.Client.MainMono.Eq.Type(0, mainEq.Band.Band)
resp, err := ctx.Client.MainMono.Eq.Type(0, *mainEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Main Mono EQ band %d type: %w", mainEq.Band.Band, err)
return fmt.Errorf("failed to get Main Mono EQ band %d type: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d type: %s\n", mainEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d type: %s\n", *mainEq.Band.Band, resp)
return nil
}
if err := ctx.Client.MainMono.Eq.SetType(0, mainEq.Band.Band, *cmd.Type); err != nil {
return fmt.Errorf("failed to set Main Mono EQ band %d type: %w", mainEq.Band.Band, err)
if err := ctx.Client.MainMono.Eq.SetType(0, *mainEq.Band.Band, *cmd.Type); err != nil {
return fmt.Errorf("failed to set Main Mono EQ band %d type: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d type set to: %s\n", mainEq.Band.Band, *cmd.Type)
fmt.Fprintf(ctx.Out, "Main Mono EQ band %d type set to: %s\n", *mainEq.Band.Band, *cmd.Type)
return nil
}

501
cmd/x32-cli/matrix.go Normal file
View File

@@ -0,0 +1,501 @@
package main
import (
"fmt"
"time"
)
// MatrixCmdGroup defines the command group for controlling the Matrix outputs, including commands for mute state, fader level, and fade-in/fade-out times.
type MatrixCmdGroup struct {
Index struct {
Index int `arg:"" help:"The index of the Matrix output (1-6)."`
Mute MatrixMuteCmd `help:"Get or set the mute state of the Matrix output." cmd:""`
Fader MatrixFaderCmd `help:"Get or set the fader level of the Matrix output." cmd:""`
Fadein MatrixFadeinCmd `help:"Fade in the Matrix output over a specified duration." cmd:""`
Fadeout MatrixFadeoutCmd `help:"Fade out the Matrix output over a specified duration." cmd:""`
Eq MatrixEqCmdGroup `help:"Commands for controlling the equalizer settings of the Matrix output." cmd:"eq"`
Comp MatrixCompCmdGroup `help:"Commands for controlling the compressor settings of the Matrix output." cmd:"comp"`
} `help:"Commands for controlling individual Matrix outputs." arg:""`
}
func (cmd *MatrixCmdGroup) Validate() error {
if cmd.Index.Index < 1 || cmd.Index.Index > 6 {
return fmt.Errorf("Matrix output index must be between 1 and 6, got %d", cmd.Index.Index)
}
return nil
}
// MatrixMuteCmd defines the command for getting or setting the mute state of the Matrix output, allowing users to specify the desired state as "true"/"on" or "false"/"off".
type MatrixMuteCmd struct {
Mute *string `arg:"" help:"The mute state to set. If not provided, the current state will be printed." optional:"" enum:"true,false"`
}
// Run executes the MatrixMuteCmd command, either retrieving the current mute state of the Matrix output or setting it based on the provided argument.
func (cmd *MatrixMuteCmd) Run(ctx *context, matrix *MatrixCmdGroup) error {
if cmd.Mute == nil {
resp, err := ctx.Client.Matrix.Mute(matrix.Index.Index)
if err != nil {
return fmt.Errorf("failed to get Matrix mute state: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix mute state: %t\n", resp)
return nil
}
if err := ctx.Client.Matrix.SetMute(matrix.Index.Index, *cmd.Mute == "true"); err != nil {
return fmt.Errorf("failed to set Matrix mute state: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix mute state set to: %s\n", *cmd.Mute)
return nil
}
// MatrixFaderCmd defines the command for getting or setting the fader level of the Matrix output, allowing users to specify the desired level in dB.
type MatrixFaderCmd struct {
Level *float64 `arg:"" help:"The fader level to set. If not provided, the current level will be printed." optional:""`
}
// Run executes the MatrixFaderCmd command, either retrieving the current fader level of the Matrix output or setting it based on the provided argument.
func (cmd *MatrixFaderCmd) Run(ctx *context, matrix *MatrixCmdGroup) error {
if cmd.Level == nil {
resp, err := ctx.Client.Matrix.Fader(matrix.Index.Index)
if err != nil {
return fmt.Errorf("failed to get Matrix fader level: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix fader level: %.2f\n", resp)
return nil
}
if err := ctx.Client.Matrix.SetFader(matrix.Index.Index, *cmd.Level); err != nil {
return fmt.Errorf("failed to set Matrix fader level: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix fader level set to: %.2f\n", *cmd.Level)
return nil
}
// MatrixFadeinCmd defines the command for getting or setting the fade-in time of the Matrix output, allowing users to specify the desired duration for the fade-in effect.
type MatrixFadeinCmd struct {
Duration time.Duration `flag:"" help:"The duration of the fade-in. (in seconds.)" default:"5s"`
Target float64 ` help:"The target level for the fade-in. If not provided, the current target level will be printed." default:"0.0" arg:""`
}
// Run executes the MatrixFadeinCmd command, either retrieving the current fade-in time of the Matrix output or setting it based on the provided argument, with an optional target level for the fade-in effect.
func (cmd *MatrixFadeinCmd) Run(ctx *context, matrix *MatrixCmdGroup) error {
currentLevel, err := ctx.Client.Matrix.Fader(matrix.Index.Index)
if err != nil {
return fmt.Errorf("failed to get Matrix fader level: %w", err)
}
if currentLevel >= cmd.Target {
return fmt.Errorf(
"current fader level (%.2f) is already at or above the target level (%.2f)",
currentLevel,
cmd.Target,
)
}
totalSteps := float64(cmd.Target - currentLevel)
stepDuration := time.Duration(cmd.Duration.Seconds()*1000/totalSteps) * time.Millisecond
for currentLevel < cmd.Target {
currentLevel++
if err := ctx.Client.Matrix.SetFader(matrix.Index.Index, currentLevel); err != nil {
return fmt.Errorf("failed to set Matrix fader level: %w", err)
}
time.Sleep(stepDuration)
}
fmt.Fprintf(ctx.Out, "Matrix fade-in completed. Final level: %.2f\n", currentLevel)
return nil
}
// MatrixFadeoutCmd defines the command for getting or setting the fade-out time of the Matrix output, allowing users to specify the desired duration for the fade-out effect and an optional target level to fade out to.
type MatrixFadeoutCmd struct {
Duration time.Duration `flag:"" help:"The duration of the fade-out. (in seconds.)" default:"5s"`
Target float64 ` help:"The target level for the fade-out. If not provided, the current target level will be printed." default:"-90.0" arg:""`
}
// Run executes the MatrixFadeoutCmd command, either retrieving the current fade-out time of the Matrix output or setting it based on the provided argument, with an optional target level for the fade-out effect.
func (cmd *MatrixFadeoutCmd) Run(ctx *context, matrix *MatrixCmdGroup) error {
currentLevel, err := ctx.Client.Matrix.Fader(matrix.Index.Index)
if err != nil {
return fmt.Errorf("failed to get Matrix fader level: %w", err)
}
if currentLevel <= cmd.Target {
return fmt.Errorf(
"current fader level (%.2f) is already at or below the target level (%.2f)",
currentLevel,
cmd.Target,
)
}
totalSteps := float64(currentLevel - cmd.Target)
stepDuration := time.Duration(cmd.Duration.Seconds()*1000/totalSteps) * time.Millisecond
for currentLevel > cmd.Target {
currentLevel--
if err := ctx.Client.Matrix.SetFader(matrix.Index.Index, currentLevel); err != nil {
return fmt.Errorf("failed to set Matrix fader level: %w", err)
}
time.Sleep(stepDuration)
}
fmt.Fprintf(ctx.Out, "Matrix fade-out completed. Final level: %.2f\n", currentLevel)
return nil
}
// MatrixEqCmdGroup defines the command group for controlling the equalizer settings of the Matrix output, including commands for getting or setting the EQ parameters.
type MatrixEqCmdGroup struct {
On MatrixEqOnCmd `help:"Get or set the EQ on/off state of the Matrix output." cmd:"on"`
Band struct {
Band *int `arg:"" help:"The EQ band number." optional:""`
Gain MatrixEqBandGainCmd `help:"Get or set the gain of the specified EQ band." cmd:"gain"`
Freq MatrixEqBandFreqCmd `help:"Get or set the frequency of the specified EQ band." cmd:"freq"`
Q MatrixEqBandQCmd `help:"Get or set the Q factor of the specified EQ band." cmd:"q"`
Type MatrixEqBandTypeCmd `help:"Get or set the type of the specified EQ band." cmd:"type"`
} `help:"Commands for controlling individual EQ bands of the Matrix output." arg:""`
}
// Validate checks if the provided EQ band number is within the valid range (1-6) for the Matrix output.
func (cmd *MatrixEqCmdGroup) Validate() error {
if cmd.Band.Band == nil {
return nil
}
if *cmd.Band.Band < 1 || *cmd.Band.Band > 6 {
return fmt.Errorf("EQ band number must be between 1 and 6, got %d", *cmd.Band.Band)
}
return nil
}
// MatrixEqOnCmd defines the command for getting or setting the EQ on/off state of the Matrix output, allowing users to specify the desired state as "true"/"on" or "false"/"off".
type MatrixEqOnCmd struct {
Enable *string `arg:"" help:"The EQ on/off state to set. If not provided, the current state will be printed." optional:"" enum:"true,false"`
}
// Run executes the MatrixEqOnCmd command, either retrieving the current EQ on/off state of the Matrix output or setting it based on the provided argument.
func (cmd *MatrixEqOnCmd) Run(ctx *context, matrix *MatrixCmdGroup) error {
if cmd.Enable == nil {
resp, err := ctx.Client.Matrix.Eq.On(matrix.Index.Index)
if err != nil {
return fmt.Errorf("failed to get Matrix EQ on/off state: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix EQ on/off state: %t\n", resp)
return nil
}
if err := ctx.Client.Matrix.Eq.SetOn(matrix.Index.Index, *cmd.Enable == "true"); err != nil {
return fmt.Errorf("failed to set Matrix EQ on/off state: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix EQ on/off state set to: %t\n", *cmd.Enable == "true")
return nil
}
// MatrixEqBandGainCmd defines the command for getting or setting the gain of a specific EQ band on the Matrix output, allowing users to specify the desired gain in dB.
type MatrixEqBandGainCmd struct {
Level *float64 `arg:"" help:"The gain level to set for the specified EQ band. If not provided, the current gain will be printed." optional:""`
}
// Run executes the MatrixEqBandGainCmd command, either retrieving the current gain of a specific EQ band on the Matrix output or setting it based on the provided argument.
func (cmd *MatrixEqBandGainCmd) Run(ctx *context, matrix *MatrixCmdGroup, matrixEq *MatrixEqCmdGroup) error {
if cmd.Level == nil {
resp, err := ctx.Client.Matrix.Eq.Gain(matrix.Index.Index, *matrixEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Matrix EQ band %d gain: %w", *matrixEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Matrix EQ band %d gain: %.2f dB\n", *matrixEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Matrix.Eq.SetGain(matrix.Index.Index, *matrixEq.Band.Band, *cmd.Level); err != nil {
return fmt.Errorf("failed to set Matrix EQ band %d gain: %w", *matrixEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Matrix EQ band %d gain set to: %.2f dB\n", *matrixEq.Band.Band, *cmd.Level)
return nil
}
// MatrixEqBandFreqCmd defines the command for getting or setting the frequency of a specific EQ band on the Matrix output, allowing users to specify the desired frequency in Hz.
type MatrixEqBandFreqCmd struct {
Frequency *float64 `arg:"" help:"The frequency to set for the specified EQ band. If not provided, the current frequency will be printed." optional:""`
}
// Run executes the MatrixEqBandFreqCmd command, either retrieving the current frequency of a specific EQ band on the Matrix output or setting it based on the provided argument.
func (cmd *MatrixEqBandFreqCmd) Run(ctx *context, matrix *MatrixCmdGroup, matrixEq *MatrixEqCmdGroup) error {
if cmd.Frequency == nil {
resp, err := ctx.Client.Matrix.Eq.Frequency(matrix.Index.Index, *matrixEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Matrix EQ band %d frequency: %w", *matrixEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Matrix EQ band %d frequency: %.2f Hz\n", *matrixEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Matrix.Eq.SetFrequency(matrix.Index.Index, *matrixEq.Band.Band, *cmd.Frequency); err != nil {
return fmt.Errorf("failed to set Matrix EQ band %d frequency: %w", *matrixEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Matrix EQ band %d frequency set to: %.2f Hz\n", *matrixEq.Band.Band, *cmd.Frequency)
return nil
}
// MatrixEqBandQCmd defines the command for getting or setting the Q factor of a specific EQ band on the Matrix output, allowing users to specify the desired Q factor.
type MatrixEqBandQCmd struct {
Q *float64 `arg:"" help:"The Q factor to set for the specified EQ band. If not provided, the current Q factor will be printed." optional:""`
}
// Run executes the MatrixEqBandQCmd command, either retrieving the current Q factor of a specific EQ band on the Matrix output or setting it based on the provided argument.
func (cmd *MatrixEqBandQCmd) Run(ctx *context, matrix *MatrixCmdGroup, matrixEq *MatrixEqCmdGroup) error {
if cmd.Q == nil {
resp, err := ctx.Client.Matrix.Eq.Q(matrix.Index.Index, *matrixEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Matrix EQ band %d Q factor: %w", *matrixEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Matrix EQ band %d Q factor: %.2f\n", *matrixEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Matrix.Eq.SetQ(matrix.Index.Index, *matrixEq.Band.Band, *cmd.Q); err != nil {
return fmt.Errorf("failed to set Matrix EQ band %d Q factor: %w", *matrixEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Matrix EQ band %d Q factor set to: %.2f\n", *matrixEq.Band.Band, *cmd.Q)
return nil
}
// MatrixEqBandTypeCmd defines the command for getting or setting the type of a specific EQ band on the Matrix output, allowing users to specify the desired type as "peaking", "low_shelf", "high_shelf", "low_pass", or "high_pass".
type MatrixEqBandTypeCmd struct {
Type *string `arg:"" help:"The type to set for the specified EQ band. If not provided, the current type will be printed." optional:"" enum:"peaking,low_shelf,high_shelf,low_pass,high_pass"`
}
// Run executes the MatrixEqBandTypeCmd command, either retrieving the current type of a specific EQ band on the Matrix output or setting it based on the provided argument.
func (cmd *MatrixEqBandTypeCmd) Run(ctx *context, matrix *MatrixCmdGroup, matrixEq *MatrixEqCmdGroup) error {
if cmd.Type == nil {
resp, err := ctx.Client.Matrix.Eq.Type(matrix.Index.Index, *matrixEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Matrix EQ band %d type: %w", *matrixEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Matrix EQ band %d type: %s\n", *matrixEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Matrix.Eq.SetType(matrix.Index.Index, *matrixEq.Band.Band, *cmd.Type); err != nil {
return fmt.Errorf("failed to set Matrix EQ band %d type: %w", *matrixEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Matrix EQ band %d type set to: %s\n", *matrixEq.Band.Band, *cmd.Type)
return nil
}
// MatrixCompCmdGroup defines the command group for controlling the compressor settings of the Matrix output, including commands for getting or setting the compressor parameters.
type MatrixCompCmdGroup struct {
On MatrixCompOnCmd `help:"Get or set the compressor on/off state of the Matrix output." cmd:"on"`
Mode MatrixCompModeCmd `help:"Get or set the compressor mode of the Matrix output." cmd:"mode"`
Threshold MatrixCompThresholdCmd `help:"Get or set the compressor threshold of the Matrix output." cmd:"threshold"`
Ratio MatrixCompRatioCmd `help:"Get or set the compressor ratio of the Matrix output." cmd:"ratio"`
Mix MatrixCompMixCmd `help:"Get or set the compressor mix level of the Matrix output." cmd:"mix"`
Makeup MatrixCompMakeupCmd `help:"Get or set the compressor makeup gain of the Matrix output." cmd:"makeup"`
Attack MatrixCompAttackCmd `help:"Get or set the compressor attack time of the Matrix output." cmd:"attack"`
Hold MatrixCompHoldCmd `help:"Get or set the compressor hold time of the Matrix output." cmd:"hold"`
Release MatrixCompReleaseCmd `help:"Get or set the compressor release time of the Matrix output." cmd:"release"`
}
// MatrixCompOnCmd defines the command for getting or setting the compressor on/off state of the Matrix output, allowing users to specify the desired state as "true"/"on" or "false"/"off".
type MatrixCompOnCmd struct {
Enable *string `arg:"" help:"The compressor on/off state to set. If not provided, the current state will be printed." optional:"" enum:"true,false"`
}
// Run executes the MatrixCompOnCmd command, either retrieving the current compressor on/off state of the Matrix output or setting it based on the provided argument.
func (cmd *MatrixCompOnCmd) Run(ctx *context, matrix *MatrixCmdGroup) error {
if cmd.Enable == nil {
resp, err := ctx.Client.Matrix.Comp.On(matrix.Index.Index)
if err != nil {
return fmt.Errorf("failed to get Matrix compressor on/off state: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor on/off state: %t\n", resp)
return nil
}
if err := ctx.Client.Matrix.Comp.SetOn(matrix.Index.Index, *cmd.Enable == "true"); err != nil {
return fmt.Errorf("failed to set Matrix compressor on/off state: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor on/off state set to: %t\n", *cmd.Enable == "true")
return nil
}
// MatrixCompModeCmd defines the command for getting or setting the compressor mode of the Matrix output, allowing users to specify the desired mode as "comp" or "exp".
type MatrixCompModeCmd struct {
Mode *string `arg:"" help:"The compressor mode to set. If not provided, the current mode will be printed." optional:"" enum:"comp,exp"`
}
// Run executes the MatrixCompModeCmd command, either retrieving the current compressor mode of the Matrix output or setting it based on the provided argument.
func (cmd *MatrixCompModeCmd) Run(ctx *context, matrix *MatrixCmdGroup) error {
if cmd.Mode == nil {
resp, err := ctx.Client.Matrix.Comp.Mode(matrix.Index.Index)
if err != nil {
return fmt.Errorf("failed to get Matrix compressor mode: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor mode: %s\n", resp)
return nil
}
if err := ctx.Client.Matrix.Comp.SetMode(matrix.Index.Index, *cmd.Mode); err != nil {
return fmt.Errorf("failed to set Matrix compressor mode: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor mode set to: %s\n", *cmd.Mode)
return nil
}
// MatrixCompThresholdCmd defines the command for getting or setting the compressor threshold of the Matrix output, allowing users to specify the desired threshold in dB.
type MatrixCompThresholdCmd struct {
Threshold *float64 `arg:"" help:"The compressor threshold to set. If not provided, the current threshold will be printed." optional:""`
}
// Run executes the MatrixCompThresholdCmd command, either retrieving the current compressor threshold of the Matrix output or setting it based on the provided argument.
func (cmd *MatrixCompThresholdCmd) Run(ctx *context, matrix *MatrixCmdGroup) error {
if cmd.Threshold == nil {
resp, err := ctx.Client.Matrix.Comp.Threshold(matrix.Index.Index)
if err != nil {
return fmt.Errorf("failed to get Matrix compressor threshold: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor threshold: %.2f dB\n", resp)
return nil
}
if err := ctx.Client.Matrix.Comp.SetThreshold(matrix.Index.Index, *cmd.Threshold); err != nil {
return fmt.Errorf("failed to set Matrix compressor threshold: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor threshold set to: %.2f dB\n", *cmd.Threshold)
return nil
}
// MatrixCompRatioCmd defines the command for getting or setting the compressor ratio of the Matrix output, allowing users to specify the desired ratio.
type MatrixCompRatioCmd struct {
Ratio *float64 `arg:"" help:"The compressor ratio to set. If not provided, the current ratio will be printed." optional:""`
}
// Run executes the MatrixCompRatioCmd command, either retrieving the current compressor ratio of the Matrix output or setting it based on the provided argument.
func (cmd *MatrixCompRatioCmd) Run(ctx *context, matrix *MatrixCmdGroup) error {
if cmd.Ratio == nil {
resp, err := ctx.Client.Matrix.Comp.Ratio(matrix.Index.Index)
if err != nil {
return fmt.Errorf("failed to get Matrix compressor ratio: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor ratio: %.2f\n", resp)
return nil
}
if err := ctx.Client.Matrix.Comp.SetRatio(matrix.Index.Index, *cmd.Ratio); err != nil {
return fmt.Errorf("failed to set Matrix compressor ratio: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor ratio set to: %.2f\n", *cmd.Ratio)
return nil
}
// MatrixCompMixCmd defines the command for getting or setting the compressor mix level of the Matrix output, allowing users to specify the desired mix level in percentage.
type MatrixCompMixCmd struct {
Mix *float64 `arg:"" help:"The compressor mix level to set. If not provided, the current mix level will be printed." optional:""`
}
// Run executes the MatrixCompMixCmd command, either retrieving the current compressor mix level of the Matrix output or setting it based on the provided argument.
func (cmd *MatrixCompMixCmd) Run(ctx *context, matrix *MatrixCmdGroup) error {
if cmd.Mix == nil {
resp, err := ctx.Client.Matrix.Comp.Mix(matrix.Index.Index)
if err != nil {
return fmt.Errorf("failed to get Matrix compressor mix level: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor mix level: %.2f%%\n", resp)
return nil
}
if err := ctx.Client.Matrix.Comp.SetMix(matrix.Index.Index, *cmd.Mix); err != nil {
return fmt.Errorf("failed to set Matrix compressor mix level: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor mix level set to: %.2f%%\n", *cmd.Mix)
return nil
}
// MatrixCompMakeupCmd defines the command for getting or setting the compressor makeup gain of the Matrix output, allowing users to specify the desired makeup gain in dB.
type MatrixCompMakeupCmd struct {
Makeup *float64 `arg:"" help:"The compressor makeup gain to set. If not provided, the current makeup gain will be printed." optional:""`
}
// Run executes the MatrixCompMakeupCmd command, either retrieving the current compressor makeup gain of the Matrix output or setting it based on the provided argument.
func (cmd *MatrixCompMakeupCmd) Run(ctx *context, matrix *MatrixCmdGroup) error {
if cmd.Makeup == nil {
resp, err := ctx.Client.Matrix.Comp.Makeup(matrix.Index.Index)
if err != nil {
return fmt.Errorf("failed to get Matrix compressor makeup gain: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor makeup gain: %.2f dB\n", resp)
return nil
}
if err := ctx.Client.Matrix.Comp.SetMakeup(matrix.Index.Index, *cmd.Makeup); err != nil {
return fmt.Errorf("failed to set Matrix compressor makeup gain: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor makeup gain set to: %.2f dB\n", *cmd.Makeup)
return nil
}
// MatrixCompAttackCmd defines the command for getting or setting the compressor attack time of the Matrix output, allowing users to specify the desired attack time in milliseconds.
type MatrixCompAttackCmd struct {
Attack *float64 `arg:"" help:"The compressor attack time to set. If not provided, the current attack time will be printed." optional:""`
}
// Run executes the MatrixCompAttackCmd command, either retrieving the current compressor attack time of the Matrix output or setting it based on the provided argument.
func (cmd *MatrixCompAttackCmd) Run(ctx *context, matrix *MatrixCmdGroup) error {
if cmd.Attack == nil {
resp, err := ctx.Client.Matrix.Comp.Attack(matrix.Index.Index)
if err != nil {
return fmt.Errorf("failed to get Matrix compressor attack time: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor attack time: %.2f ms\n", resp)
return nil
}
if err := ctx.Client.Matrix.Comp.SetAttack(matrix.Index.Index, *cmd.Attack); err != nil {
return fmt.Errorf("failed to set Matrix compressor attack time: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor attack time set to: %.2f ms\n", *cmd.Attack)
return nil
}
// MatrixCompHoldCmd defines the command for getting or setting the compressor hold time of the Matrix output, allowing users to specify the desired hold time in milliseconds.
type MatrixCompHoldCmd struct {
Hold *float64 `arg:"" help:"The compressor hold time to set. If not provided, the current hold time will be printed." optional:""`
}
// Run executes the MatrixCompHoldCmd command, either retrieving the current compressor hold time of the Matrix output or setting it based on the provided argument.
func (cmd *MatrixCompHoldCmd) Run(ctx *context, matrix *MatrixCmdGroup) error {
if cmd.Hold == nil {
resp, err := ctx.Client.Matrix.Comp.Hold(matrix.Index.Index)
if err != nil {
return fmt.Errorf("failed to get Matrix compressor hold time: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor hold time: %.2f ms\n", resp)
return nil
}
if err := ctx.Client.Matrix.Comp.SetHold(matrix.Index.Index, *cmd.Hold); err != nil {
return fmt.Errorf("failed to set Matrix compressor hold time: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor hold time set to: %.2f ms\n", *cmd.Hold)
return nil
}
// MatrixCompReleaseCmd defines the command for getting or setting the compressor release time of the Matrix output, allowing users to specify the desired release time in milliseconds.
type MatrixCompReleaseCmd struct {
Release *float64 `arg:"" help:"The compressor release time to set. If not provided, the current release time will be printed." optional:""`
}
// Run executes the MatrixCompReleaseCmd command, either retrieving the current compressor release time of the Matrix output or setting it based on the provided argument.
func (cmd *MatrixCompReleaseCmd) Run(ctx *context, matrix *MatrixCmdGroup) error {
if cmd.Release == nil {
resp, err := ctx.Client.Matrix.Comp.Release(matrix.Index.Index)
if err != nil {
return fmt.Errorf("failed to get Matrix compressor release time: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor release time: %.2f ms\n", resp)
return nil
}
if err := ctx.Client.Matrix.Comp.SetRelease(matrix.Index.Index, *cmd.Release); err != nil {
return fmt.Errorf("failed to set Matrix compressor release time: %w", err)
}
fmt.Fprintf(ctx.Out, "Matrix compressor release time set to: %.2f ms\n", *cmd.Release)
return nil
}

View File

@@ -5,7 +5,7 @@ import "fmt"
type SnapshotCmdGroup struct {
List ListCmd `help:"List all snapshots." cmd:"list"`
Index struct {
Index int `arg:"" help:"The index of the snapshot."`
Index *int `arg:"" help:"The index of the snapshot." optional:""`
Name NameCmd `help:"Get or set the name of a snapshot." cmd:"name"`
Save SaveCmd `help:"Save the current mixer state to a snapshot." cmd:"save"`
Load LoadCmd `help:"Load a mixer state from a snapshot." cmd:"load"`
@@ -13,6 +13,19 @@ type SnapshotCmdGroup struct {
} `help:"The index of the snapshot." arg:""`
}
// Validate checks if the provided snapshot index is within the valid range (1-64) when any of the subcommands that require an index are used.
func (c *SnapshotCmdGroup) Validate() error {
if c.Index.Index == nil {
return nil
}
if *c.Index.Index < 1 || *c.Index.Index > 64 {
return fmt.Errorf("snapshot index must be between 1 and 64")
}
return nil
}
type ListCmd struct {
}
@@ -36,7 +49,7 @@ type NameCmd struct {
func (c *NameCmd) Run(ctx *context, snapshot *SnapshotCmdGroup) error {
if c.Name == nil {
name, err := ctx.Client.Snapshot.Name(snapshot.Index.Index)
name, err := ctx.Client.Snapshot.Name(*snapshot.Index.Index)
if err != nil {
return err
}
@@ -44,7 +57,7 @@ func (c *NameCmd) Run(ctx *context, snapshot *SnapshotCmdGroup) error {
return nil
}
return ctx.Client.Snapshot.SetName(snapshot.Index.Index, *c.Name)
return ctx.Client.Snapshot.SetName(*snapshot.Index.Index, *c.Name)
}
type SaveCmd struct {
@@ -57,19 +70,19 @@ func (c *SaveCmd) Run(ctx *context, snapshot *SnapshotCmdGroup) error {
return err
}
return ctx.Client.Snapshot.CurrentSave(snapshot.Index.Index)
return ctx.Client.Snapshot.CurrentSave(*snapshot.Index.Index)
}
type LoadCmd struct {
}
func (c *LoadCmd) Run(ctx *context, snapshot *SnapshotCmdGroup) error {
return ctx.Client.Snapshot.CurrentLoad(snapshot.Index.Index)
return ctx.Client.Snapshot.CurrentLoad(*snapshot.Index.Index)
}
type DeleteCmd struct {
}
func (c *DeleteCmd) Run(ctx *context, snapshot *SnapshotCmdGroup) error {
return ctx.Client.Snapshot.CurrentDelete(snapshot.Index.Index)
return ctx.Client.Snapshot.CurrentDelete(*snapshot.Index.Index)
}

View File

@@ -3,8 +3,6 @@ package main
import (
"fmt"
"time"
"github.com/alecthomas/kong"
)
// StripCmdGroup defines the command group for controlling the strips of the mixer, including commands for getting and setting various parameters such as mute state, fader level, send levels, and EQ settings.
@@ -142,27 +140,41 @@ func (cmd *StripFadeoutCmd) Run(ctx *context, strip *StripCmdGroup) error {
}
}
// StripSendCmd defines the command for getting or setting the send level for a specific bus on a strip, allowing users to control the level of the signal being sent from the strip to a particular bus.
// StripSendCmd defines the command for getting or setting the auxiliary send level
// for a specific send destination (mix bus) on a strip.
type StripSendCmd struct {
BusNum int `arg:"" help:"The bus number to get or set the send level for."`
Level *float64 `arg:"" help:"The send level to set (in dB)." optional:""`
SendIndex int `arg:"" help:"The index of the send destination (mix bus). (1-based indexing)"`
Level *float64 `arg:"" help:"The send level to set (in dB)." optional:""`
}
// Run executes the StripSendCmd command, either retrieving the current send level for the specified bus on the strip or setting it based on the provided argument.
// Run executes the StripSendCmd command, either retrieving the current send level for the specified send destination
// or setting it based on the provided argument.
func (cmd *StripSendCmd) Run(ctx *context, strip *StripCmdGroup) error {
if cmd.Level == nil {
resp, err := ctx.Client.Strip.SendLevel(strip.Index.Index, cmd.BusNum)
resp, err := ctx.Client.Strip.SendLevel(strip.Index.Index, cmd.SendIndex)
if err != nil {
return fmt.Errorf("failed to get send level: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d send level for bus %d: %.2f dB\n", strip.Index.Index, cmd.BusNum, resp)
fmt.Fprintf(
ctx.Out,
"Strip %d send %d level: %.2f dB\n",
strip.Index.Index,
cmd.SendIndex,
resp,
)
return nil
}
if err := ctx.Client.Strip.SetSendLevel(strip.Index.Index, cmd.BusNum, *cmd.Level); err != nil {
if err := ctx.Client.Strip.SetSendLevel(strip.Index.Index, cmd.SendIndex, *cmd.Level); err != nil {
return fmt.Errorf("failed to set send level: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d send level for bus %d set to: %.2f dB\n", strip.Index.Index, cmd.BusNum, *cmd.Level)
fmt.Fprintf(
ctx.Out,
"Strip %d send %d level set to: %.2f dB\n",
strip.Index.Index,
cmd.SendIndex,
*cmd.Level,
)
return nil
}
@@ -365,7 +377,7 @@ func (cmd *StripGateReleaseCmd) Run(ctx *context, strip *StripCmdGroup) error {
type StripEqCmdGroup struct {
On StripEqOnCmd `help:"Get or set the EQ on/off state of the strip." cmd:""`
Band struct {
Band int `arg:"" help:"The EQ band number."`
Band *int `arg:"" help:"The EQ band number." optional:""`
Gain StripEqBandGainCmd `help:"Get or set the gain of the EQ band." cmd:""`
Freq StripEqBandFreqCmd `help:"Get or set the frequency of the EQ band." cmd:""`
Q StripEqBandQCmd `help:"Get or set the Q factor of the EQ band." cmd:""`
@@ -374,9 +386,13 @@ type StripEqCmdGroup struct {
}
// Validate checks if the provided EQ band number is valid (between 1 and 4) and returns an error if it is not.
func (cmd *StripEqCmdGroup) Validate(ctx kong.Context) error {
if cmd.Band.Band < 1 || cmd.Band.Band > 4 {
return fmt.Errorf("EQ band number must be between 1 and 4")
func (cmd *StripEqCmdGroup) Validate() error {
if cmd.Band.Band == nil {
return nil
}
if *cmd.Band.Band < 1 || *cmd.Band.Band > 4 {
return fmt.Errorf("EQ band number must be between 1 and 4, got %d", *cmd.Band.Band)
}
return nil
}
@@ -412,18 +428,18 @@ type StripEqBandGainCmd struct {
// Run executes the StripEqBandGainCmd command, either retrieving the current gain of the specified EQ band on the strip or setting it based on the provided argument.
func (cmd *StripEqBandGainCmd) Run(ctx *context, strip *StripCmdGroup, stripEq *StripEqCmdGroup) error {
if cmd.Gain == nil {
resp, err := ctx.Client.Strip.Eq.Gain(strip.Index.Index, stripEq.Band.Band)
resp, err := ctx.Client.Strip.Eq.Gain(strip.Index.Index, *stripEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get EQ band gain: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d gain: %.2f\n", strip.Index.Index, stripEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d gain: %.2f\n", strip.Index.Index, *stripEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Strip.Eq.SetGain(strip.Index.Index, stripEq.Band.Band, *cmd.Gain); err != nil {
if err := ctx.Client.Strip.Eq.SetGain(strip.Index.Index, *stripEq.Band.Band, *cmd.Gain); err != nil {
return fmt.Errorf("failed to set EQ band gain: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d gain set to: %.2f\n", strip.Index.Index, stripEq.Band.Band, *cmd.Gain)
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d gain set to: %.2f\n", strip.Index.Index, *stripEq.Band.Band, *cmd.Gain)
return nil
}
@@ -435,22 +451,22 @@ type StripEqBandFreqCmd struct {
// Run executes the StripEqBandFreqCmd command, either retrieving the current frequency of the specified EQ band on the strip or setting it based on the provided argument.
func (cmd *StripEqBandFreqCmd) Run(ctx *context, strip *StripCmdGroup, stripEq *StripEqCmdGroup) error {
if cmd.Freq == nil {
resp, err := ctx.Client.Strip.Eq.Frequency(strip.Index.Index, stripEq.Band.Band)
resp, err := ctx.Client.Strip.Eq.Frequency(strip.Index.Index, *stripEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get EQ band frequency: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d frequency: %.2f Hz\n", strip.Index.Index, stripEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d frequency: %.2f Hz\n", strip.Index.Index, *stripEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Strip.Eq.SetFrequency(strip.Index.Index, stripEq.Band.Band, *cmd.Freq); err != nil {
if err := ctx.Client.Strip.Eq.SetFrequency(strip.Index.Index, *stripEq.Band.Band, *cmd.Freq); err != nil {
return fmt.Errorf("failed to set EQ band frequency: %w", err)
}
fmt.Fprintf(
ctx.Out,
"Strip %d EQ band %d frequency set to: %.2f Hz\n",
strip.Index.Index,
stripEq.Band.Band,
*stripEq.Band.Band,
*cmd.Freq,
)
return nil
@@ -464,18 +480,18 @@ type StripEqBandQCmd struct {
// Run executes the StripEqBandQCmd command, either retrieving the current Q factor of the specified EQ band on the strip or setting it based on the provided argument.
func (cmd *StripEqBandQCmd) Run(ctx *context, strip *StripCmdGroup, stripEq *StripEqCmdGroup) error {
if cmd.Q == nil {
resp, err := ctx.Client.Strip.Eq.Q(strip.Index.Index, stripEq.Band.Band)
resp, err := ctx.Client.Strip.Eq.Q(strip.Index.Index, *stripEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get EQ band Q factor: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d Q factor: %.2f\n", strip.Index.Index, stripEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d Q factor: %.2f\n", strip.Index.Index, *stripEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Strip.Eq.SetQ(strip.Index.Index, stripEq.Band.Band, *cmd.Q); err != nil {
if err := ctx.Client.Strip.Eq.SetQ(strip.Index.Index, *stripEq.Band.Band, *cmd.Q); err != nil {
return fmt.Errorf("failed to set EQ band Q factor: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d Q factor set to: %.2f\n", strip.Index.Index, stripEq.Band.Band, *cmd.Q)
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d Q factor set to: %.2f\n", strip.Index.Index, *stripEq.Band.Band, *cmd.Q)
return nil
}
@@ -487,18 +503,18 @@ type StripEqBandTypeCmd struct {
// Run executes the StripEqBandTypeCmd command, either retrieving the current type of the specified EQ band on the strip or setting it based on the provided argument.
func (cmd *StripEqBandTypeCmd) Run(ctx *context, strip *StripCmdGroup, stripEq *StripEqCmdGroup) error {
if cmd.Type == nil {
resp, err := ctx.Client.Strip.Eq.Type(strip.Index.Index, stripEq.Band.Band)
resp, err := ctx.Client.Strip.Eq.Type(strip.Index.Index, *stripEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get EQ band type: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d type: %s\n", strip.Index.Index, stripEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d type: %s\n", strip.Index.Index, *stripEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Strip.Eq.SetType(strip.Index.Index, stripEq.Band.Band, *cmd.Type); err != nil {
if err := ctx.Client.Strip.Eq.SetType(strip.Index.Index, *stripEq.Band.Band, *cmd.Type); err != nil {
return fmt.Errorf("failed to set EQ band type: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d type set to: %s\n", strip.Index.Index, stripEq.Band.Band, *cmd.Type)
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d type set to: %s\n", strip.Index.Index, *stripEq.Band.Band, *cmd.Type)
return nil
}

View File

@@ -3,8 +3,6 @@ package main
import (
"fmt"
"time"
"github.com/alecthomas/kong"
)
// BusCmdGroup defines the commands related to controlling the buses of the X-Air device.
@@ -174,7 +172,7 @@ type BusEqCmdGroup struct {
On BusEqOnCmd `help:"Get or set the EQ on/off state of the bus." cmd:"on"`
Mode BusEqModeCmd `help:"Get or set the EQ mode of the bus (peq, geq or teq)." cmd:"mode"`
Band struct {
Band int `arg:"" help:"The EQ band number."`
Band *int `arg:"" help:"The EQ band number." optional:""`
Gain BusEqBandGainCmd `help:"Get or set the gain of the EQ band." cmd:"gain"`
Freq BusEqBandFreqCmd `help:"Get or set the frequency of the EQ band." cmd:"freq"`
Q BusEqBandQCmd `help:"Get or set the Q factor of the EQ band." cmd:"q"`
@@ -183,9 +181,13 @@ type BusEqCmdGroup struct {
}
// Validate checks that the provided EQ band number is within the valid range (1-6).
func (cmd *BusEqCmdGroup) Validate(ctx kong.Context) error {
if cmd.Band.Band < 1 || cmd.Band.Band > 6 {
return fmt.Errorf("EQ band number must be between 1 and 6")
func (cmd *BusEqCmdGroup) Validate() error {
if cmd.Band.Band == nil {
return nil
}
if *cmd.Band.Band < 1 || *cmd.Band.Band > 6 {
return fmt.Errorf("EQ band number must be between 1 and 6, got %d", *cmd.Band.Band)
}
return nil
}
@@ -244,7 +246,7 @@ type BusEqBandGainCmd struct {
// Run executes the BusEqBandGainCmd command, either retrieving the current gain of the specified EQ band of the bus or setting it based on the provided argument.
func (cmd *BusEqBandGainCmd) Run(ctx *context, bus *BusCmdGroup, busEq *BusEqCmdGroup) error {
if cmd.Gain == nil {
resp, err := ctx.Client.Bus.Eq.Gain(bus.Index.Index, busEq.Band.Band)
resp, err := ctx.Client.Bus.Eq.Gain(bus.Index.Index, *busEq.Band.Band)
if err != nil {
return err
}
@@ -252,10 +254,10 @@ func (cmd *BusEqBandGainCmd) Run(ctx *context, bus *BusCmdGroup, busEq *BusEqCmd
return nil
}
if err := ctx.Client.Bus.Eq.SetGain(bus.Index.Index, busEq.Band.Band, *cmd.Gain); err != nil {
if err := ctx.Client.Bus.Eq.SetGain(bus.Index.Index, *busEq.Band.Band, *cmd.Gain); err != nil {
return err
}
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d gain set to: %.2f dB\n", bus.Index.Index, busEq.Band.Band, *cmd.Gain)
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d gain set to: %.2f dB\n", bus.Index.Index, *busEq.Band.Band, *cmd.Gain)
return nil
}
@@ -267,18 +269,18 @@ type BusEqBandFreqCmd struct {
// Run executes the BusEqBandFreqCmd command, either retrieving the current frequency of the specified EQ band of the bus or setting it based on the provided argument.
func (cmd *BusEqBandFreqCmd) Run(ctx *context, bus *BusCmdGroup, busEq *BusEqCmdGroup) error {
if cmd.Freq == nil {
resp, err := ctx.Client.Bus.Eq.Frequency(bus.Index.Index, busEq.Band.Band)
resp, err := ctx.Client.Bus.Eq.Frequency(bus.Index.Index, *busEq.Band.Band)
if err != nil {
return err
}
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d frequency: %.2f Hz\n", bus.Index.Index, busEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d frequency: %.2f Hz\n", bus.Index.Index, *busEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Bus.Eq.SetFrequency(bus.Index.Index, busEq.Band.Band, *cmd.Freq); err != nil {
if err := ctx.Client.Bus.Eq.SetFrequency(bus.Index.Index, *busEq.Band.Band, *cmd.Freq); err != nil {
return err
}
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d frequency set to: %.2f Hz\n", bus.Index.Index, busEq.Band.Band, *cmd.Freq)
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d frequency set to: %.2f Hz\n", bus.Index.Index, *busEq.Band.Band, *cmd.Freq)
return nil
}
@@ -290,18 +292,18 @@ type BusEqBandQCmd struct {
// Run executes the BusEqBandQCmd command, either retrieving the current Q factor of the specified EQ band of the bus or setting it based on the provided argument.
func (cmd *BusEqBandQCmd) Run(ctx *context, bus *BusCmdGroup, busEq *BusEqCmdGroup) error {
if cmd.Q == nil {
resp, err := ctx.Client.Bus.Eq.Q(bus.Index.Index, busEq.Band.Band)
resp, err := ctx.Client.Bus.Eq.Q(bus.Index.Index, *busEq.Band.Band)
if err != nil {
return err
}
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d Q factor: %.2f\n", bus.Index.Index, busEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d Q factor: %.2f\n", bus.Index.Index, *busEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Bus.Eq.SetQ(bus.Index.Index, busEq.Band.Band, *cmd.Q); err != nil {
if err := ctx.Client.Bus.Eq.SetQ(bus.Index.Index, *busEq.Band.Band, *cmd.Q); err != nil {
return err
}
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d Q factor set to: %.2f\n", bus.Index.Index, busEq.Band.Band, *cmd.Q)
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d Q factor set to: %.2f\n", bus.Index.Index, *busEq.Band.Band, *cmd.Q)
return nil
}
@@ -313,18 +315,18 @@ type BusEqBandTypeCmd struct {
// Run executes the BusEqBandTypeCmd command, either retrieving the current type of the specified EQ band of the bus or setting it based on the provided argument.
func (cmd *BusEqBandTypeCmd) Run(ctx *context, bus *BusCmdGroup, busEq *BusEqCmdGroup) error {
if cmd.Type == nil {
resp, err := ctx.Client.Bus.Eq.Type(bus.Index.Index, busEq.Band.Band)
resp, err := ctx.Client.Bus.Eq.Type(bus.Index.Index, *busEq.Band.Band)
if err != nil {
return err
}
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d type: %s\n", bus.Index.Index, busEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d type: %s\n", bus.Index.Index, *busEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Bus.Eq.SetType(bus.Index.Index, busEq.Band.Band, *cmd.Type); err != nil {
if err := ctx.Client.Bus.Eq.SetType(bus.Index.Index, *busEq.Band.Band, *cmd.Type); err != nil {
return err
}
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d type set to: %s\n", bus.Index.Index, busEq.Band.Band, *cmd.Type)
fmt.Fprintf(ctx.Out, "Bus %d EQ band %d type set to: %s\n", bus.Index.Index, *busEq.Band.Band, *cmd.Type)
return nil
}

View File

@@ -54,6 +54,7 @@ type CLI struct {
Bus BusCmdGroup `help:"Control the buses." cmd:"" group:"Bus"`
Headamp HeadampCmdGroup `help:"Control input gain and phantom power." cmd:"" group:"Headamp"`
Snapshot SnapshotCmdGroup `help:"Save and load mixer states." cmd:"" group:"Snapshot"`
Dca DCACmdGroup `help:"Control DCA groups." cmd:"" group:"DCA"`
}
func main() {
@@ -119,7 +120,6 @@ func connect(config Config) (*xair.XAirClient, error) {
client, err := xair.NewXAirClient(
config.Host,
config.Port,
xair.WithKind("xair"),
xair.WithTimeout(config.Timeout),
)
if err != nil {

68
cmd/xair-cli/dca.go Normal file
View File

@@ -0,0 +1,68 @@
package main
import (
"fmt"
)
// DCACmdGroup is the command group for controlling DCA groups.
type DCACmdGroup struct {
Index struct {
Index int `arg:"" help:"The index of the DCA group (1-4)."`
Mute DCAMuteCmd `help:"Get or set the mute status of the DCA group." cmd:""`
Name DCANameCmd `help:"Get or set the name of the DCA group." cmd:""`
} `arg:"" help:"Control a specific DCA group by its index."`
}
// Validate checks if the provided index is within the valid range.
func (cmd *DCACmdGroup) Validate() error {
if cmd.Index.Index < 1 || cmd.Index.Index > 4 {
return fmt.Errorf("DCA group index must be between 1 and 4, got %d", cmd.Index.Index)
}
return nil
}
// DCAMuteCmd is the command to get or set the mute status of a DCA group.
type DCAMuteCmd struct {
State *string `arg:"" help:"Set the mute status of the DCA group." optional:"" enum:"true,false"`
}
// Run executes the DCAMuteCmd command.
func (cmd *DCAMuteCmd) Run(ctx *context, dca *DCACmdGroup) error {
if cmd.State == nil {
resp, err := ctx.Client.DCA.Mute(dca.Index.Index)
if err != nil {
return fmt.Errorf("failed to get DCA mute status: %w", err)
}
fmt.Fprintf(ctx.Out, "DCA Group %d mute state: %t\n", dca.Index.Index, resp)
return nil
}
if err := ctx.Client.DCA.SetMute(dca.Index.Index, *cmd.State == "true"); err != nil {
return fmt.Errorf("failed to set DCA mute status: %w", err)
}
return nil
}
// DCANameCmd is the command to get or set the name of a DCA group.
type DCANameCmd struct {
Name *string `arg:"" help:"Set the name of the DCA group." optional:""`
}
// Run executes the DCANameCmd command.
func (cmd *DCANameCmd) Run(ctx *context, dca *DCACmdGroup) error {
if cmd.Name == nil {
resp, err := ctx.Client.DCA.Name(dca.Index.Index)
if err != nil {
return fmt.Errorf("failed to get DCA name: %w", err)
}
if resp == "" {
resp = fmt.Sprintf("DCA %d", dca.Index.Index)
}
fmt.Fprintf(ctx.Out, "DCA Group %d is named '%s'\n", dca.Index.Index, resp)
return nil
}
if err := ctx.Client.DCA.SetName(dca.Index.Index, *cmd.Name); err != nil {
return fmt.Errorf("failed to set DCA name: %w", err)
}
return nil
}

View File

@@ -3,8 +3,6 @@ package main
import (
"fmt"
"time"
"github.com/alecthomas/kong"
)
// MainCmdGroup defines the command group for controlling the Main L/R output, including commands for mute state, fader level, and fade-in/fade-out times.
@@ -137,7 +135,7 @@ func (cmd *MainFadeoutCmd) Run(ctx *context) error {
type MainEqCmdGroup struct {
On MainEqOnCmd `help:"Get or set the EQ on/off state of the Main L/R output." cmd:"on"`
Band struct {
Band int `arg:"" help:"The EQ band number."`
Band *int `arg:"" help:"The EQ band number." optional:""`
Gain MainEqBandGainCmd `help:"Get or set the gain of the specified EQ band." cmd:"gain"`
Freq MainEqBandFreqCmd `help:"Get or set the frequency of the specified EQ band." cmd:"freq"`
Q MainEqBandQCmd `help:"Get or set the Q factor of the specified EQ band." cmd:"q"`
@@ -146,9 +144,13 @@ type MainEqCmdGroup struct {
}
// Validate checks if the provided EQ band number is within the valid range (1-6) for the Main L/R output.
func (cmd *MainEqCmdGroup) Validate(ctx kong.Context) error {
if cmd.Band.Band < 1 || cmd.Band.Band > 6 {
return fmt.Errorf("invalid EQ band number: %d. Valid range is 1-6", cmd.Band.Band)
func (cmd *MainEqCmdGroup) Validate() error {
if cmd.Band.Band == nil {
return nil
}
if *cmd.Band.Band < 1 || *cmd.Band.Band > 6 {
return fmt.Errorf("EQ band number must be between 1 and 6, got %d", *cmd.Band.Band)
}
return nil
}
@@ -184,18 +186,18 @@ type MainEqBandGainCmd struct {
// Run executes the MainEqBandGainCmd command, either retrieving the current gain of a specific EQ band on the Main L/R output or setting it based on the provided argument.
func (cmd *MainEqBandGainCmd) Run(ctx *context, main *MainCmdGroup, mainEq *MainEqCmdGroup) error {
if cmd.Level == nil {
resp, err := ctx.Client.Main.Eq.Gain(0, mainEq.Band.Band)
resp, err := ctx.Client.Main.Eq.Gain(0, *mainEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Main L/R EQ band %d gain: %w", mainEq.Band.Band, err)
return fmt.Errorf("failed to get Main L/R EQ band %d gain: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d gain: %.2f dB\n", mainEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d gain: %.2f dB\n", *mainEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Main.Eq.SetGain(0, mainEq.Band.Band, *cmd.Level); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d gain: %w", mainEq.Band.Band, err)
if err := ctx.Client.Main.Eq.SetGain(0, *mainEq.Band.Band, *cmd.Level); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d gain: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d gain set to: %.2f dB\n", mainEq.Band.Band, *cmd.Level)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d gain set to: %.2f dB\n", *mainEq.Band.Band, *cmd.Level)
return nil
}
@@ -207,18 +209,18 @@ type MainEqBandFreqCmd struct {
// Run executes the MainEqBandFreqCmd command, either retrieving the current frequency of a specific EQ band on the Main L/R output or setting it based on the provided argument.
func (cmd *MainEqBandFreqCmd) Run(ctx *context, main *MainCmdGroup, mainEq *MainEqCmdGroup) error {
if cmd.Frequency == nil {
resp, err := ctx.Client.Main.Eq.Frequency(0, mainEq.Band.Band)
resp, err := ctx.Client.Main.Eq.Frequency(0, *mainEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Main L/R EQ band %d frequency: %w", mainEq.Band.Band, err)
return fmt.Errorf("failed to get Main L/R EQ band %d frequency: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d frequency: %.2f Hz\n", mainEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d frequency: %.2f Hz\n", *mainEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Main.Eq.SetFrequency(0, mainEq.Band.Band, *cmd.Frequency); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d frequency: %w", mainEq.Band.Band, err)
if err := ctx.Client.Main.Eq.SetFrequency(0, *mainEq.Band.Band, *cmd.Frequency); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d frequency: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d frequency set to: %.2f Hz\n", mainEq.Band.Band, *cmd.Frequency)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d frequency set to: %.2f Hz\n", *mainEq.Band.Band, *cmd.Frequency)
return nil
}
@@ -230,18 +232,18 @@ type MainEqBandQCmd struct {
// Run executes the MainEqBandQCmd command, either retrieving the current Q factor of a specific EQ band on the Main L/R output or setting it based on the provided argument.
func (cmd *MainEqBandQCmd) Run(ctx *context, main *MainCmdGroup, mainEq *MainEqCmdGroup) error {
if cmd.Q == nil {
resp, err := ctx.Client.Main.Eq.Q(0, mainEq.Band.Band)
resp, err := ctx.Client.Main.Eq.Q(0, *mainEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Main L/R EQ band %d Q factor: %w", mainEq.Band.Band, err)
return fmt.Errorf("failed to get Main L/R EQ band %d Q factor: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d Q factor: %.2f\n", mainEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d Q factor: %.2f\n", *mainEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Main.Eq.SetQ(0, mainEq.Band.Band, *cmd.Q); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d Q factor: %w", mainEq.Band.Band, err)
if err := ctx.Client.Main.Eq.SetQ(0, *mainEq.Band.Band, *cmd.Q); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d Q factor: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d Q factor set to: %.2f\n", mainEq.Band.Band, *cmd.Q)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d Q factor set to: %.2f\n", *mainEq.Band.Band, *cmd.Q)
return nil
}
@@ -253,18 +255,18 @@ type MainEqBandTypeCmd struct {
// Run executes the MainEqBandTypeCmd command, either retrieving the current type of a specific EQ band on the Main L/R output or setting it based on the provided argument.
func (cmd *MainEqBandTypeCmd) Run(ctx *context, main *MainCmdGroup, mainEq *MainEqCmdGroup) error {
if cmd.Type == nil {
resp, err := ctx.Client.Main.Eq.Type(0, mainEq.Band.Band)
resp, err := ctx.Client.Main.Eq.Type(0, *mainEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get Main L/R EQ band %d type: %w", mainEq.Band.Band, err)
return fmt.Errorf("failed to get Main L/R EQ band %d type: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d type: %s\n", mainEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d type: %s\n", *mainEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Main.Eq.SetType(0, mainEq.Band.Band, *cmd.Type); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d type: %w", mainEq.Band.Band, err)
if err := ctx.Client.Main.Eq.SetType(0, *mainEq.Band.Band, *cmd.Type); err != nil {
return fmt.Errorf("failed to set Main L/R EQ band %d type: %w", *mainEq.Band.Band, err)
}
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d type set to: %s\n", mainEq.Band.Band, *cmd.Type)
fmt.Fprintf(ctx.Out, "Main L/R EQ band %d type set to: %s\n", *mainEq.Band.Band, *cmd.Type)
return nil
}

View File

@@ -5,7 +5,7 @@ import "fmt"
type SnapshotCmdGroup struct {
List ListCmd `help:"List all snapshots." cmd:"list"`
Index struct {
Index int `arg:"" help:"The index of the snapshot."`
Index *int `arg:"" help:"The index of the snapshot." optional:""`
Name NameCmd `help:"Get or set the name of a snapshot." cmd:"name"`
Save SaveCmd `help:"Save the current mixer state to a snapshot." cmd:"save"`
Load LoadCmd `help:"Load a mixer state from a snapshot." cmd:"load"`
@@ -13,6 +13,19 @@ type SnapshotCmdGroup struct {
} `help:"The index of the snapshot." arg:""`
}
// Validate checks if the provided snapshot index is within the valid range (1-64) when any of the subcommands that require an index are used.
func (c *SnapshotCmdGroup) Validate() error {
if c.Index.Index == nil {
return nil
}
if *c.Index.Index < 1 || *c.Index.Index > 64 {
return fmt.Errorf("snapshot index must be between 1 and 64")
}
return nil
}
type ListCmd struct {
}
@@ -36,7 +49,7 @@ type NameCmd struct {
func (c *NameCmd) Run(ctx *context, snapshot *SnapshotCmdGroup) error {
if c.Name == nil {
name, err := ctx.Client.Snapshot.Name(snapshot.Index.Index)
name, err := ctx.Client.Snapshot.Name(*snapshot.Index.Index)
if err != nil {
return err
}
@@ -44,7 +57,7 @@ func (c *NameCmd) Run(ctx *context, snapshot *SnapshotCmdGroup) error {
return nil
}
return ctx.Client.Snapshot.SetName(snapshot.Index.Index, *c.Name)
return ctx.Client.Snapshot.SetName(*snapshot.Index.Index, *c.Name)
}
type SaveCmd struct {
@@ -57,19 +70,19 @@ func (c *SaveCmd) Run(ctx *context, snapshot *SnapshotCmdGroup) error {
return err
}
return ctx.Client.Snapshot.CurrentSave(snapshot.Index.Index)
return ctx.Client.Snapshot.CurrentSave(*snapshot.Index.Index)
}
type LoadCmd struct {
}
func (c *LoadCmd) Run(ctx *context, snapshot *SnapshotCmdGroup) error {
return ctx.Client.Snapshot.CurrentLoad(snapshot.Index.Index)
return ctx.Client.Snapshot.CurrentLoad(*snapshot.Index.Index)
}
type DeleteCmd struct {
}
func (c *DeleteCmd) Run(ctx *context, snapshot *SnapshotCmdGroup) error {
return ctx.Client.Snapshot.CurrentDelete(snapshot.Index.Index)
return ctx.Client.Snapshot.CurrentDelete(*snapshot.Index.Index)
}

View File

@@ -3,8 +3,6 @@ package main
import (
"fmt"
"time"
"github.com/alecthomas/kong"
)
// StripCmdGroup defines the command group for controlling the strips of the mixer, including commands for getting and setting various parameters such as mute state, fader level, send levels, and EQ settings.
@@ -142,27 +140,29 @@ func (cmd *StripFadeoutCmd) Run(ctx *context, strip *StripCmdGroup) error {
}
}
// StripSendCmd defines the command for getting or setting the send level for a specific bus on a strip, allowing users to control the level of the signal being sent from the strip to a particular bus.
// StripSendCmd defines the command for getting or setting the auxiliary send level
// for a specific send destination (mix bus or effects channel) on a strip.
type StripSendCmd struct {
BusNum int `arg:"" help:"The bus number to get or set the send level for."`
Level *float64 `arg:"" help:"The send level to set (in dB)." optional:""`
SendIndex int `arg:"" help:"The index of the send destination (mix bus or effects channel). (1-based indexing)"`
Level *float64 `arg:"" help:"The send level to set (in dB)." optional:""`
}
// Run executes the StripSendCmd command, either retrieving the current send level for the specified bus on the strip or setting it based on the provided argument.
// Run executes the StripSendCmd command, either retrieving the current send level for the specified destination
// or setting it based on the provided argument.
func (cmd *StripSendCmd) Run(ctx *context, strip *StripCmdGroup) error {
if cmd.Level == nil {
resp, err := ctx.Client.Strip.SendLevel(strip.Index.Index, cmd.BusNum)
resp, err := ctx.Client.Strip.SendLevel(strip.Index.Index, cmd.SendIndex)
if err != nil {
return fmt.Errorf("failed to get send level: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d send level for bus %d: %.2f dB\n", strip.Index.Index, cmd.BusNum, resp)
fmt.Fprintf(ctx.Out, "Strip %d send %d level: %.2f dB\n", strip.Index.Index, cmd.SendIndex, resp)
return nil
}
if err := ctx.Client.Strip.SetSendLevel(strip.Index.Index, cmd.BusNum, *cmd.Level); err != nil {
if err := ctx.Client.Strip.SetSendLevel(strip.Index.Index, cmd.SendIndex, *cmd.Level); err != nil {
return fmt.Errorf("failed to set send level: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d send level for bus %d set to: %.2f dB\n", strip.Index.Index, cmd.BusNum, *cmd.Level)
fmt.Fprintf(ctx.Out, "Strip %d send %d level set to: %.2f dB\n", strip.Index.Index, cmd.SendIndex, *cmd.Level)
return nil
}
@@ -365,7 +365,7 @@ func (cmd *StripGateReleaseCmd) Run(ctx *context, strip *StripCmdGroup) error {
type StripEqCmdGroup struct {
On StripEqOnCmd `help:"Get or set the EQ on/off state of the strip." cmd:""`
Band struct {
Band int `arg:"" help:"The EQ band number."`
Band *int `arg:"" help:"The EQ band number." optional:""`
Gain StripEqBandGainCmd `help:"Get or set the gain of the EQ band." cmd:""`
Freq StripEqBandFreqCmd `help:"Get or set the frequency of the EQ band." cmd:""`
Q StripEqBandQCmd `help:"Get or set the Q factor of the EQ band." cmd:""`
@@ -374,9 +374,13 @@ type StripEqCmdGroup struct {
}
// Validate checks if the provided EQ band number is valid (between 1 and 4) and returns an error if it is not.
func (cmd *StripEqCmdGroup) Validate(ctx kong.Context) error {
if cmd.Band.Band < 1 || cmd.Band.Band > 4 {
return fmt.Errorf("EQ band number must be between 1 and 4")
func (cmd *StripEqCmdGroup) Validate() error {
if cmd.Band.Band == nil {
return nil
}
if *cmd.Band.Band < 1 || *cmd.Band.Band > 4 {
return fmt.Errorf("EQ band number must be between 1 and 4, got %d", *cmd.Band.Band)
}
return nil
}
@@ -412,18 +416,18 @@ type StripEqBandGainCmd struct {
// Run executes the StripEqBandGainCmd command, either retrieving the current gain of the specified EQ band on the strip or setting it based on the provided argument.
func (cmd *StripEqBandGainCmd) Run(ctx *context, strip *StripCmdGroup, stripEq *StripEqCmdGroup) error {
if cmd.Gain == nil {
resp, err := ctx.Client.Strip.Eq.Gain(strip.Index.Index, stripEq.Band.Band)
resp, err := ctx.Client.Strip.Eq.Gain(strip.Index.Index, *stripEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get EQ band gain: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d gain: %.2f\n", strip.Index.Index, stripEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d gain: %.2f\n", strip.Index.Index, *stripEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Strip.Eq.SetGain(strip.Index.Index, stripEq.Band.Band, *cmd.Gain); err != nil {
if err := ctx.Client.Strip.Eq.SetGain(strip.Index.Index, *stripEq.Band.Band, *cmd.Gain); err != nil {
return fmt.Errorf("failed to set EQ band gain: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d gain set to: %.2f\n", strip.Index.Index, stripEq.Band.Band, *cmd.Gain)
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d gain set to: %.2f\n", strip.Index.Index, *stripEq.Band.Band, *cmd.Gain)
return nil
}
@@ -435,22 +439,22 @@ type StripEqBandFreqCmd struct {
// Run executes the StripEqBandFreqCmd command, either retrieving the current frequency of the specified EQ band on the strip or setting it based on the provided argument.
func (cmd *StripEqBandFreqCmd) Run(ctx *context, strip *StripCmdGroup, stripEq *StripEqCmdGroup) error {
if cmd.Freq == nil {
resp, err := ctx.Client.Strip.Eq.Frequency(strip.Index.Index, stripEq.Band.Band)
resp, err := ctx.Client.Strip.Eq.Frequency(strip.Index.Index, *stripEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get EQ band frequency: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d frequency: %.2f Hz\n", strip.Index.Index, stripEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d frequency: %.2f Hz\n", strip.Index.Index, *stripEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Strip.Eq.SetFrequency(strip.Index.Index, stripEq.Band.Band, *cmd.Freq); err != nil {
if err := ctx.Client.Strip.Eq.SetFrequency(strip.Index.Index, *stripEq.Band.Band, *cmd.Freq); err != nil {
return fmt.Errorf("failed to set EQ band frequency: %w", err)
}
fmt.Fprintf(
ctx.Out,
"Strip %d EQ band %d frequency set to: %.2f Hz\n",
strip.Index.Index,
stripEq.Band.Band,
*stripEq.Band.Band,
*cmd.Freq,
)
return nil
@@ -464,18 +468,18 @@ type StripEqBandQCmd struct {
// Run executes the StripEqBandQCmd command, either retrieving the current Q factor of the specified EQ band on the strip or setting it based on the provided argument.
func (cmd *StripEqBandQCmd) Run(ctx *context, strip *StripCmdGroup, stripEq *StripEqCmdGroup) error {
if cmd.Q == nil {
resp, err := ctx.Client.Strip.Eq.Q(strip.Index.Index, stripEq.Band.Band)
resp, err := ctx.Client.Strip.Eq.Q(strip.Index.Index, *stripEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get EQ band Q factor: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d Q factor: %.2f\n", strip.Index.Index, stripEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d Q factor: %.2f\n", strip.Index.Index, *stripEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Strip.Eq.SetQ(strip.Index.Index, stripEq.Band.Band, *cmd.Q); err != nil {
if err := ctx.Client.Strip.Eq.SetQ(strip.Index.Index, *stripEq.Band.Band, *cmd.Q); err != nil {
return fmt.Errorf("failed to set EQ band Q factor: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d Q factor set to: %.2f\n", strip.Index.Index, stripEq.Band.Band, *cmd.Q)
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d Q factor set to: %.2f\n", strip.Index.Index, *stripEq.Band.Band, *cmd.Q)
return nil
}
@@ -487,18 +491,18 @@ type StripEqBandTypeCmd struct {
// Run executes the StripEqBandTypeCmd command, either retrieving the current type of the specified EQ band on the strip or setting it based on the provided argument.
func (cmd *StripEqBandTypeCmd) Run(ctx *context, strip *StripCmdGroup, stripEq *StripEqCmdGroup) error {
if cmd.Type == nil {
resp, err := ctx.Client.Strip.Eq.Type(strip.Index.Index, stripEq.Band.Band)
resp, err := ctx.Client.Strip.Eq.Type(strip.Index.Index, *stripEq.Band.Band)
if err != nil {
return fmt.Errorf("failed to get EQ band type: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d type: %s\n", strip.Index.Index, stripEq.Band.Band, resp)
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d type: %s\n", strip.Index.Index, *stripEq.Band.Band, resp)
return nil
}
if err := ctx.Client.Strip.Eq.SetType(strip.Index.Index, stripEq.Band.Band, *cmd.Type); err != nil {
if err := ctx.Client.Strip.Eq.SetType(strip.Index.Index, *stripEq.Band.Band, *cmd.Type); err != nil {
return fmt.Errorf("failed to set EQ band type: %w", err)
}
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d type set to: %s\n", strip.Index.Index, stripEq.Band.Band, *cmd.Type)
fmt.Fprintf(ctx.Out, "Strip %d EQ band %d type set to: %s\n", strip.Index.Index, *stripEq.Band.Band, *cmd.Type)
return nil
}

10
go.mod
View File

@@ -3,7 +3,7 @@ module github.com/onyx-and-iris/xair-cli
go 1.25
require (
github.com/alecthomas/kong v1.13.0
github.com/alecthomas/kong v1.14.0
github.com/charmbracelet/log v0.4.2
github.com/hypebeast/go-osc v0.0.0-20220308234300-cec5a8a1e5f5
github.com/jotaen/kong-completion v0.0.11
@@ -13,12 +13,12 @@ require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/colorprofile v0.4.1 // indirect
github.com/charmbracelet/lipgloss v1.1.0 // indirect
github.com/charmbracelet/x/ansi v0.11.4 // indirect
github.com/charmbracelet/x/cellbuf v0.0.14 // indirect
github.com/charmbracelet/x/ansi v0.11.6 // indirect
github.com/charmbracelet/x/cellbuf v0.0.15 // indirect
github.com/charmbracelet/x/term v0.2.2 // indirect
github.com/clipperhouse/displaywidth v0.9.0 // indirect
github.com/clipperhouse/stringish v0.1.1 // indirect
github.com/clipperhouse/uax29/v2 v2.5.0 // indirect
github.com/clipperhouse/uax29/v2 v2.6.0 // indirect
github.com/go-logfmt/logfmt v0.6.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
@@ -31,5 +31,5 @@ require (
github.com/riywo/loginshell v0.0.0-20200815045211-7d26008be1ab // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/sys v0.41.0 // indirect
)

20
go.sum
View File

@@ -1,7 +1,7 @@
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/kong v1.13.0 h1:5e/7XC3ugvhP1DQBmTS+WuHtCbcv44hsohMgcvVxSrA=
github.com/alecthomas/kong v1.13.0/go.mod h1:wrlbXem1CWqUV5Vbmss5ISYhsVPkBb1Yo7YKJghju2I=
github.com/alecthomas/kong v1.14.0 h1:gFgEUZWu2ZmZ+UhyZ1bDhuutbKN1nTtJTwh19Wsn21s=
github.com/alecthomas/kong v1.14.0/go.mod h1:wrlbXem1CWqUV5Vbmss5ISYhsVPkBb1Yo7YKJghju2I=
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
@@ -12,18 +12,18 @@ github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoF
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
github.com/charmbracelet/log v0.4.2 h1:hYt8Qj6a8yLnvR+h7MwsJv/XvmBJXiueUcI3cIxsyig=
github.com/charmbracelet/log v0.4.2/go.mod h1:qifHGX/tc7eluv2R6pWIpyHDDrrb/AG71Pf2ysQu5nw=
github.com/charmbracelet/x/ansi v0.11.4 h1:6G65PLu6HjmE858CnTUQY1LXT3ZUWwfvqEROLF8vqHI=
github.com/charmbracelet/x/ansi v0.11.4/go.mod h1:/5AZ+UfWExW3int5H5ugnsG/PWjNcSQcwYsHBlPFQN4=
github.com/charmbracelet/x/cellbuf v0.0.14 h1:iUEMryGyFTelKW3THW4+FfPgi4fkmKnnaLOXuc+/Kj4=
github.com/charmbracelet/x/cellbuf v0.0.14/go.mod h1:P447lJl49ywBbil/KjCk2HexGh4tEY9LH0/1QrZZ9rA=
github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8=
github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ=
github.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI=
github.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q=
github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
github.com/clipperhouse/displaywidth v0.9.0 h1:Qb4KOhYwRiN3viMv1v/3cTBlz3AcAZX3+y9OLhMtAtA=
github.com/clipperhouse/displaywidth v0.9.0/go.mod h1:aCAAqTlh4GIVkhQnJpbL0T/WfcrJXHcj8C0yjYcjOZA=
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
github.com/clipperhouse/uax29/v2 v2.5.0 h1:x7T0T4eTHDONxFJsL94uKNKPHrclyFI0lm7+w94cO8U=
github.com/clipperhouse/uax29/v2 v2.5.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
github.com/clipperhouse/uax29/v2 v2.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoKXuhpos=
github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -68,8 +68,8 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJu
golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU=
golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@@ -3,9 +3,10 @@ package xair
var xairAddressMap = map[string]string{
"main": "/lr",
"strip": "/ch/%02d",
"bus": "/bus/%01d",
"bus": "/bus/%d",
"headamp": "/headamp/%02d",
"snapshot": "/-snap",
"dca": "/dca/%d",
}
var x32AddressMap = map[string]string{
@@ -16,11 +17,12 @@ var x32AddressMap = map[string]string{
"bus": "/bus/%02d",
"headamp": "/headamp/%03d",
"snapshot": "/-snap",
"dca": "/dca/%d",
}
func addressMapForMixerKind(kind MixerKind) map[string]string {
func addressMapFromMixerKind(kind mixerKind) map[string]string {
switch kind {
case KindX32:
case kindX32:
return x32AddressMap
default:
return xairAddressMap

View File

@@ -9,12 +9,13 @@ type Bus struct {
Comp *Comp
}
// newBus creates a new Bus instance
func newBus(c *Client) *Bus {
return &Bus{
client: c,
baseAddress: c.addressMap["bus"],
Eq: newEqForBus(c),
Comp: newCompForBus(c),
Eq: newEq(c, c.addressMap["bus"]),
Comp: newComp(c, c.addressMap["bus"]),
}
}

View File

@@ -2,7 +2,6 @@ package xair
import (
"fmt"
"net"
"time"
"github.com/charmbracelet/log"
@@ -11,9 +10,10 @@ import (
)
type Client struct {
engine
*engine
}
// XAirClient is a client for controlling XAir mixers
type XAirClient struct {
Client
Main *Main
@@ -21,8 +21,10 @@ type XAirClient struct {
Bus *Bus
HeadAmp *HeadAmp
Snapshot *Snapshot
DCA *DCA
}
// X32Client is a client for controlling X32 mixers
type X32Client struct {
Client
Main *Main
@@ -32,52 +34,18 @@ type X32Client struct {
Bus *Bus
HeadAmp *HeadAmp
Snapshot *Snapshot
DCA *DCA
}
func createEngine(mixerIP string, mixerPort int, opts ...Option) (*engine, error) {
localAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", 0))
if err != nil {
return nil, fmt.Errorf("failed to resolve local address: %v", err)
}
conn, err := net.ListenUDP("udp", localAddr)
if err != nil {
return nil, fmt.Errorf("failed to create UDP connection: %v", err)
}
mixerAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", mixerIP, mixerPort))
if err != nil {
conn.Close()
return nil, fmt.Errorf("failed to resolve mixer address: %v", err)
}
log.Debugf("Local UDP connection: %s ", conn.LocalAddr().String())
e := &engine{
timeout: 100 * time.Millisecond,
conn: conn,
mixerAddr: mixerAddr,
parser: newParser(),
done: make(chan bool),
respChan: make(chan *osc.Message, 100),
}
for _, opt := range opts {
opt(e)
}
return e, nil
}
// NewX32Client creates a new X32Client instance
func NewX32Client(mixerIP string, mixerPort int, opts ...Option) (*X32Client, error) {
e, err := createEngine(mixerIP, mixerPort, opts...)
// NewX32Client creates a new X32Client instance with optional engine configuration
func NewX32Client(mixerIP string, mixerPort int, opts ...EngineOption) (*X32Client, error) {
e, err := newEngine(mixerIP, mixerPort, kindX32, opts...)
if err != nil {
return nil, err
}
c := &X32Client{
Client: Client{*e},
Client: Client{e},
}
c.Main = newMainStereo(&c.Client)
c.MainMono = newMainMono(&c.Client)
@@ -86,25 +54,27 @@ func NewX32Client(mixerIP string, mixerPort int, opts ...Option) (*X32Client, er
c.Bus = newBus(&c.Client)
c.HeadAmp = newHeadAmp(&c.Client)
c.Snapshot = newSnapshot(&c.Client)
c.DCA = newDCA(&c.Client)
return c, nil
}
// NewXAirClient creates a new XAirClient instance
func NewXAirClient(mixerIP string, mixerPort int, opts ...Option) (*XAirClient, error) {
e, err := createEngine(mixerIP, mixerPort, opts...)
// NewXAirClient creates a new XAirClient instance with optional engine configuration
func NewXAirClient(mixerIP string, mixerPort int, opts ...EngineOption) (*XAirClient, error) {
e, err := newEngine(mixerIP, mixerPort, kindXAir, opts...)
if err != nil {
return nil, err
}
c := &XAirClient{
Client: Client{*e},
Client: Client{e},
}
c.Main = newMainStereo(&c.Client)
c.Strip = newStrip(&c.Client)
c.Bus = newBus(&c.Client)
c.HeadAmp = newHeadAmp(&c.Client)
c.Snapshot = newSnapshot(&c.Client)
c.DCA = newDCA(&c.Client)
return c, nil
}

View File

@@ -2,53 +2,31 @@ package xair
import "fmt"
// Comp represents the compressor parameters.
type Comp struct {
client *Client
baseAddress string
AddressFunc func(fmtString string, args ...any) string
}
// Factory function to create Comp instance for Main
func newCompForMain(c *Client) *Comp {
return &Comp{
// Factory function to create Comp instance with optional configuration
func newComp(c *Client, baseAddress string, opts ...CompOption) *Comp {
comp := &Comp{
client: c,
baseAddress: c.addressMap["main"],
AddressFunc: func(fmtString string, args ...any) string {
return fmtString
},
}
}
// Factory function to create Comp instance for Strip
func newCompForStrip(c *Client) *Comp {
return &Comp{
client: c,
baseAddress: c.addressMap["strip"],
baseAddress: fmt.Sprintf("%s/dyn", baseAddress),
AddressFunc: fmt.Sprintf,
}
}
// Factory function to create Comp instance for Bus
func newCompForBus(c *Client) *Comp {
return &Comp{
client: c,
baseAddress: c.addressMap["bus"],
AddressFunc: fmt.Sprintf,
for _, opt := range opts {
opt(comp)
}
}
// Factory function to create Comp instance for Matrix
func newCompForMatrix(c *Client) *Comp {
return &Comp{
client: c,
baseAddress: c.addressMap["matrix"],
AddressFunc: fmt.Sprintf,
}
return comp
}
// On retrieves the on/off status of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) On(index int) (bool, error) {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/on"
address := c.AddressFunc(c.baseAddress, index) + "/on"
err := c.client.SendMessage(address)
if err != nil {
return false, err
@@ -67,7 +45,7 @@ func (c *Comp) On(index int) (bool, error) {
// SetOn sets the on/off status of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) SetOn(index int, on bool) error {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/on"
address := c.AddressFunc(c.baseAddress, index) + "/on"
var value int32
if on {
value = 1
@@ -77,7 +55,7 @@ func (c *Comp) SetOn(index int, on bool) error {
// Mode retrieves the current mode of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) Mode(index int) (string, error) {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/mode"
address := c.AddressFunc(c.baseAddress, index) + "/mode"
err := c.client.SendMessage(address)
if err != nil {
return "", err
@@ -98,14 +76,14 @@ func (c *Comp) Mode(index int) (string, error) {
// SetMode sets the mode of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) SetMode(index int, mode string) error {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/mode"
address := c.AddressFunc(c.baseAddress, index) + "/mode"
possibleModes := []string{"comp", "exp"}
return c.client.SendMessage(address, int32(indexOf(possibleModes, mode)))
}
// Threshold retrieves the threshold value of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) Threshold(index int) (float64, error) {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/thr"
address := c.AddressFunc(c.baseAddress, index) + "/thr"
err := c.client.SendMessage(address)
if err != nil {
return 0, err
@@ -124,13 +102,13 @@ func (c *Comp) Threshold(index int) (float64, error) {
// SetThreshold sets the threshold value of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) SetThreshold(index int, threshold float64) error {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/thr"
address := c.AddressFunc(c.baseAddress, index) + "/thr"
return c.client.SendMessage(address, float32(linSet(-60, 0, threshold)))
}
// Ratio retrieves the ratio value of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) Ratio(index int) (float32, error) {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/ratio"
address := c.AddressFunc(c.baseAddress, index) + "/ratio"
err := c.client.SendMessage(address)
if err != nil {
return 0, err
@@ -152,7 +130,7 @@ func (c *Comp) Ratio(index int) (float32, error) {
// SetRatio sets the ratio value of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) SetRatio(index int, ratio float64) error {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/ratio"
address := c.AddressFunc(c.baseAddress, index) + "/ratio"
possibleValues := []float32{1.1, 1.3, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 7.0, 10, 20, 100}
return c.client.SendMessage(address, int32(indexOf(possibleValues, float32(ratio))))
@@ -160,7 +138,7 @@ func (c *Comp) SetRatio(index int, ratio float64) error {
// Attack retrieves the attack time of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) Attack(index int) (float64, error) {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/attack"
address := c.AddressFunc(c.baseAddress, index) + "/attack"
err := c.client.SendMessage(address)
if err != nil {
return 0, err
@@ -179,13 +157,13 @@ func (c *Comp) Attack(index int) (float64, error) {
// SetAttack sets the attack time of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) SetAttack(index int, attack float64) error {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/attack"
address := c.AddressFunc(c.baseAddress, index) + "/attack"
return c.client.SendMessage(address, float32(linSet(0, 120, attack)))
}
// Hold retrieves the hold time of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) Hold(index int) (float64, error) {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/hold"
address := c.AddressFunc(c.baseAddress, index) + "/hold"
err := c.client.SendMessage(address)
if err != nil {
return 0, err
@@ -204,13 +182,13 @@ func (c *Comp) Hold(index int) (float64, error) {
// SetHold sets the hold time of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) SetHold(index int, hold float64) error {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/hold"
address := c.AddressFunc(c.baseAddress, index) + "/hold"
return c.client.SendMessage(address, float32(logSet(0.02, 2000, hold)))
}
// Release retrieves the release time of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) Release(index int) (float64, error) {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/release"
address := c.AddressFunc(c.baseAddress, index) + "/release"
err := c.client.SendMessage(address)
if err != nil {
return 0, err
@@ -229,13 +207,13 @@ func (c *Comp) Release(index int) (float64, error) {
// SetRelease sets the release time of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) SetRelease(index int, release float64) error {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/release"
address := c.AddressFunc(c.baseAddress, index) + "/release"
return c.client.SendMessage(address, float32(logSet(4, 4000, release)))
}
// Makeup retrieves the makeup gain of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) Makeup(index int) (float64, error) {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/mgain"
address := c.AddressFunc(c.baseAddress, index) + "/mgain"
err := c.client.SendMessage(address)
if err != nil {
return 0, err
@@ -254,13 +232,13 @@ func (c *Comp) Makeup(index int) (float64, error) {
// SetMakeup sets the makeup gain of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) SetMakeup(index int, makeup float64) error {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/mgain"
address := c.AddressFunc(c.baseAddress, index) + "/mgain"
return c.client.SendMessage(address, float32(linSet(0, 24, makeup)))
}
// Mix retrieves the mix value of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) Mix(index int) (float64, error) {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/mix"
address := c.AddressFunc(c.baseAddress, index) + "/mix"
err := c.client.SendMessage(address)
if err != nil {
return 0, err
@@ -279,6 +257,6 @@ func (c *Comp) Mix(index int) (float64, error) {
// SetMix sets the mix value of the Compressor for a specific strip or bus (1-based indexing).
func (c *Comp) SetMix(index int, mix float64) error {
address := c.AddressFunc(c.baseAddress, index) + "/dyn/mix"
address := c.AddressFunc(c.baseAddress, index) + "/mix"
return c.client.SendMessage(address, float32(linSet(0, 100, mix)))
}

95
internal/xair/dca.go Normal file
View File

@@ -0,0 +1,95 @@
package xair
import "fmt"
type DCA struct {
client *Client
baseAddress string
}
// newDCA creates a new DCA instance
func newDCA(c *Client) *DCA {
return &DCA{
client: c,
baseAddress: c.addressMap["dca"],
}
}
// Mute requests the current mute status for a DCA group
func (d *DCA) Mute(group int) (bool, error) {
address := fmt.Sprintf(d.baseAddress, group) + "/on"
err := d.client.SendMessage(address)
if err != nil {
return false, err
}
msg, err := d.client.ReceiveMessage()
if err != nil {
return false, err
}
val, ok := msg.Arguments[0].(int32)
if !ok {
return false, fmt.Errorf("unexpected argument type for DCA mute value")
}
return val == 0, nil
}
// SetMute sets the mute status for a specific DCA group (1-based indexing)
func (d *DCA) SetMute(group int, muted bool) error {
address := fmt.Sprintf(d.baseAddress, group) + "/on"
var value int32
if !muted {
value = 1
}
return d.client.SendMessage(address, value)
}
// Name requests the current name for a DCA group
func (d *DCA) Name(group int) (string, error) {
address := fmt.Sprintf(d.baseAddress, group) + "/config/name"
err := d.client.SendMessage(address)
if err != nil {
return "", err
}
msg, err := d.client.ReceiveMessage()
if err != nil {
return "", err
}
name, ok := msg.Arguments[0].(string)
if !ok {
return "", fmt.Errorf("unexpected argument type for DCA name value")
}
return name, nil
}
// SetName sets the name for a specific DCA group (1-based indexing)
func (d *DCA) SetName(group int, name string) error {
address := fmt.Sprintf(d.baseAddress, group) + "/config/name"
return d.client.SendMessage(address, name)
}
// Color requests the current color for a DCA group
func (d *DCA) Color(group int) (int32, error) {
address := fmt.Sprintf(d.baseAddress, group) + "/config/color"
err := d.client.SendMessage(address)
if err != nil {
return 0, err
}
msg, err := d.client.ReceiveMessage()
if err != nil {
return 0, err
}
color, ok := msg.Arguments[0].(int32)
if !ok {
return 0, fmt.Errorf("unexpected argument type for DCA color value")
}
return color, nil
}
// SetColor sets the color for a specific DCA group (1-based indexing)
func (d *DCA) SetColor(group int, color int32) error {
address := fmt.Sprintf(d.baseAddress, group) + "/config/color"
return d.client.SendMessage(address, color)
}

View File

@@ -14,7 +14,7 @@ type parser interface {
}
type engine struct {
Kind MixerKind
Kind mixerKind
timeout time.Duration
conn *net.UDPConn
mixerAddr *net.UDPAddr
@@ -26,6 +26,42 @@ type engine struct {
respChan chan *osc.Message
}
func newEngine(mixerIP string, mixerPort int, kind mixerKind, opts ...EngineOption) (*engine, error) {
localAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", 0))
if err != nil {
return nil, fmt.Errorf("failed to resolve local address: %v", err)
}
conn, err := net.ListenUDP("udp", localAddr)
if err != nil {
return nil, fmt.Errorf("failed to create UDP connection: %v", err)
}
mixerAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", mixerIP, mixerPort))
if err != nil {
conn.Close()
return nil, fmt.Errorf("failed to resolve mixer address: %v", err)
}
log.Debugf("Local UDP connection: %s ", conn.LocalAddr().String())
e := &engine{
timeout: 100 * time.Millisecond,
conn: conn,
mixerAddr: mixerAddr,
parser: newParser(),
addressMap: addressMapFromMixerKind(kind),
done: make(chan bool),
respChan: make(chan *osc.Message, 100),
}
for _, opt := range opts {
opt(e)
}
return e, nil
}
// receiveLoop handles incoming OSC messages
func (e *engine) receiveLoop() {
buffer := make([]byte, 4096)

View File

@@ -4,53 +4,31 @@ import (
"fmt"
)
// Eq represents the EQ parameters.
type Eq struct {
client *Client
baseAddress string
AddressFunc func(fmtString string, args ...any) string
}
// Factory function to create Eq instance for Main
func newEqForMain(c *Client) *Eq {
return &Eq{
// Factory function to create Eq instance with optional configuration
func newEq(c *Client, baseAddress string, opts ...EqOption) *Eq {
eq := &Eq{
client: c,
baseAddress: c.addressMap["main"],
AddressFunc: func(fmtString string, args ...any) string {
return fmtString
},
}
}
// Factory function to create Eq instance for Strip
func newEqForStrip(c *Client) *Eq {
return &Eq{
client: c,
baseAddress: c.addressMap["strip"],
baseAddress: fmt.Sprintf("%s/eq", baseAddress),
AddressFunc: fmt.Sprintf,
}
}
// Factory function to create Eq instance for Bus
func newEqForBus(c *Client) *Eq {
return &Eq{
client: c,
baseAddress: c.addressMap["bus"],
AddressFunc: fmt.Sprintf,
for _, opt := range opts {
opt(eq)
}
}
// Factory function to create Eq instance for Matrix
func newEqForMatrix(c *Client) *Eq {
return &Eq{
client: c,
baseAddress: c.addressMap["matrix"],
AddressFunc: fmt.Sprintf,
}
return eq
}
// On retrieves the on/off status of the EQ for a specific strip or bus (1-based indexing).
func (e *Eq) On(index int) (bool, error) {
address := e.AddressFunc(e.baseAddress, index) + "/eq/on"
address := e.AddressFunc(e.baseAddress, index) + "/on"
err := e.client.SendMessage(address)
if err != nil {
return false, err
@@ -69,7 +47,7 @@ func (e *Eq) On(index int) (bool, error) {
// SetOn sets the on/off status of the EQ for a specific strip or bus (1-based indexing).
func (e *Eq) SetOn(index int, on bool) error {
address := e.AddressFunc(e.baseAddress, index) + "/eq/on"
address := e.AddressFunc(e.baseAddress, index) + "/on"
var value int32
if on {
value = 1
@@ -78,7 +56,7 @@ func (e *Eq) SetOn(index int, on bool) error {
}
func (e *Eq) Mode(index int) (string, error) {
address := e.AddressFunc(e.baseAddress, index) + "/eq/mode"
address := e.AddressFunc(e.baseAddress, index) + "/mode"
err := e.client.SendMessage(address)
if err != nil {
return "", err
@@ -98,14 +76,14 @@ func (e *Eq) Mode(index int) (string, error) {
}
func (e *Eq) SetMode(index int, mode string) error {
address := e.AddressFunc(e.baseAddress, index) + "/eq/mode"
address := e.AddressFunc(e.baseAddress, index) + "/mode"
possibleModes := []string{"peq", "geq", "teq"}
return e.client.SendMessage(address, int32(indexOf(possibleModes, mode)))
}
// Gain retrieves the gain for a specific EQ band on a strip or bus (1-based indexing).
func (e *Eq) Gain(index int, band int) (float64, error) {
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/eq/%d/g", band)
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/g", band)
err := e.client.SendMessage(address)
if err != nil {
return 0, err
@@ -124,13 +102,13 @@ func (e *Eq) Gain(index int, band int) (float64, error) {
// SetGain sets the gain for a specific EQ band on a strip or bus (1-based indexing).
func (e *Eq) SetGain(index int, band int, gain float64) error {
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/eq/%d/g", band)
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/g", band)
return e.client.SendMessage(address, float32(linSet(-15, 15, gain)))
}
// Frequency retrieves the frequency for a specific EQ band on a strip or bus (1-based indexing).
func (e *Eq) Frequency(index int, band int) (float64, error) {
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/eq/%d/f", band)
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/f", band)
err := e.client.SendMessage(address)
if err != nil {
return 0, err
@@ -149,13 +127,13 @@ func (e *Eq) Frequency(index int, band int) (float64, error) {
// SetFrequency sets the frequency for a specific EQ band on a strip or bus (1-based indexing).
func (e *Eq) SetFrequency(index int, band int, frequency float64) error {
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/eq/%d/f", band)
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/f", band)
return e.client.SendMessage(address, float32(logSet(20, 20000, frequency)))
}
// Q retrieves the Q factor for a specific EQ band on a strip or bus (1-based indexing).
func (e *Eq) Q(index int, band int) (float64, error) {
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/eq/%d/q", band)
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/q", band)
err := e.client.SendMessage(address)
if err != nil {
return 0, err
@@ -174,13 +152,13 @@ func (e *Eq) Q(index int, band int) (float64, error) {
// SetQ sets the Q factor for a specific EQ band on a strip or bus (1-based indexing).
func (e *Eq) SetQ(index int, band int, q float64) error {
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/eq/%d/q", band)
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/q", band)
return e.client.SendMessage(address, float32(1.0-logSet(0.3, 10, q)))
}
// Type retrieves the type for a specific EQ band on a strip or bus (1-based indexing).
func (e *Eq) Type(index int, band int) (string, error) {
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/eq/%d/type", band)
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/type", band)
err := e.client.SendMessage(address)
if err != nil {
return "", err
@@ -201,7 +179,7 @@ func (e *Eq) Type(index int, band int) (string, error) {
// SetType sets the type for a specific EQ band on a strip or bus (1-based indexing).
func (e *Eq) SetType(index int, band int, eqType string) error {
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/eq/%d/type", band)
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/type", band)
possibleTypes := []string{"lcut", "lshv", "peq", "veq", "hshv", "hcut"}
return e.client.SendMessage(address, int32(indexOf(possibleTypes, eqType)))
}

View File

@@ -2,22 +2,31 @@ package xair
import "fmt"
// Gate represents the gate parameters.
type Gate struct {
client *Client
baseAddress string
AddressFunc func(fmtString string, args ...any) string
}
// Factory function to create Gate instance for Strip
func newGateForStrip(c *Client) *Gate {
return &Gate{
// Factory function to create Gate instance with optional configuration
func newGate(c *Client, baseAddress string, opts ...GateOption) *Gate {
gate := &Gate{
client: c,
baseAddress: c.addressMap["strip"],
baseAddress: fmt.Sprintf("%s/gate", baseAddress),
AddressFunc: fmt.Sprintf,
}
for _, opt := range opts {
opt(gate)
}
return gate
}
// On retrieves the on/off status of the Gate for a specific strip (1-based indexing).
func (g *Gate) On(index int) (bool, error) {
address := fmt.Sprintf(g.baseAddress, index) + "/gate/on"
address := g.AddressFunc(g.baseAddress, index) + "/on"
err := g.client.SendMessage(address)
if err != nil {
return false, err
@@ -36,7 +45,7 @@ func (g *Gate) On(index int) (bool, error) {
// SetOn sets the on/off status of the Gate for a specific strip (1-based indexing).
func (g *Gate) SetOn(index int, on bool) error {
address := fmt.Sprintf(g.baseAddress, index) + "/gate/on"
address := g.AddressFunc(g.baseAddress, index) + "/on"
var value int32
if on {
value = 1
@@ -46,7 +55,7 @@ func (g *Gate) SetOn(index int, on bool) error {
// Mode retrieves the current mode of the Gate for a specific strip (1-based indexing).
func (g *Gate) Mode(index int) (string, error) {
address := fmt.Sprintf(g.baseAddress, index) + "/gate/mode"
address := g.AddressFunc(g.baseAddress, index) + "/mode"
err := g.client.SendMessage(address)
if err != nil {
return "", err
@@ -67,7 +76,7 @@ func (g *Gate) Mode(index int) (string, error) {
// SetMode sets the mode of the Gate for a specific strip (1-based indexing).
func (g *Gate) SetMode(index int, mode string) error {
address := fmt.Sprintf(g.baseAddress, index) + "/gate/mode"
address := g.AddressFunc(g.baseAddress, index) + "/mode"
possibleModes := []string{"exp2", "exp3", "exp4", "gate", "duck"}
return g.client.SendMessage(address, int32(indexOf(possibleModes, mode)))
@@ -75,7 +84,7 @@ func (g *Gate) SetMode(index int, mode string) error {
// Threshold retrieves the threshold value of the Gate for a specific strip (1-based indexing).
func (g *Gate) Threshold(index int) (float64, error) {
address := fmt.Sprintf(g.baseAddress, index) + "/gate/thr"
address := g.AddressFunc(g.baseAddress, index) + "/thr"
err := g.client.SendMessage(address)
if err != nil {
return 0, err
@@ -94,13 +103,13 @@ func (g *Gate) Threshold(index int) (float64, error) {
// SetThreshold sets the threshold value of the Gate for a specific strip (1-based indexing).
func (g *Gate) SetThreshold(index int, threshold float64) error {
address := fmt.Sprintf(g.baseAddress, index) + "/gate/thr"
address := g.AddressFunc(g.baseAddress, index) + "/thr"
return g.client.SendMessage(address, float32(linSet(-80, 0, threshold)))
}
// Range retrieves the range value of the Gate for a specific strip (1-based indexing).
func (g *Gate) Range(index int) (float64, error) {
address := fmt.Sprintf(g.baseAddress, index) + "/gate/range"
address := g.AddressFunc(g.baseAddress, index) + "/range"
err := g.client.SendMessage(address)
if err != nil {
return 0, err
@@ -119,13 +128,13 @@ func (g *Gate) Range(index int) (float64, error) {
// SetRange sets the range value of the Gate for a specific strip (1-based indexing).
func (g *Gate) SetRange(index int, rangeVal float64) error {
address := fmt.Sprintf(g.baseAddress, index) + "/gate/range"
address := g.AddressFunc(g.baseAddress, index) + "/range"
return g.client.SendMessage(address, float32(linSet(3, 60, rangeVal)))
}
// Attack retrieves the attack time of the Gate for a specific strip (1-based indexing).
func (g *Gate) Attack(index int) (float64, error) {
address := fmt.Sprintf(g.baseAddress, index) + "/gate/attack"
address := g.AddressFunc(g.baseAddress, index) + "/attack"
err := g.client.SendMessage(address)
if err != nil {
return 0, err
@@ -144,13 +153,13 @@ func (g *Gate) Attack(index int) (float64, error) {
// SetAttack sets the attack time of the Gate for a specific strip (1-based indexing).
func (g *Gate) SetAttack(index int, attack float64) error {
address := fmt.Sprintf(g.baseAddress, index) + "/gate/attack"
address := g.AddressFunc(g.baseAddress, index) + "/attack"
return g.client.SendMessage(address, float32(linSet(0, 120, attack)))
}
// Hold retrieves the hold time of the Gate for a specific strip (1-based indexing).
func (g *Gate) Hold(index int) (float64, error) {
address := fmt.Sprintf(g.baseAddress, index) + "/gate/hold"
address := g.AddressFunc(g.baseAddress, index) + "/hold"
err := g.client.SendMessage(address)
if err != nil {
return 0, err
@@ -169,13 +178,13 @@ func (g *Gate) Hold(index int) (float64, error) {
// SetHold sets the hold time of the Gate for a specific strip (1-based indexing).
func (g *Gate) SetHold(index int, hold float64) error {
address := fmt.Sprintf(g.baseAddress, index) + "/gate/hold"
address := g.AddressFunc(g.baseAddress, index) + "/hold"
return g.client.SendMessage(address, float32(logSet(0.02, 2000, hold)))
}
// Release retrieves the release time of the Gate for a specific strip (1-based indexing).
func (g *Gate) Release(index int) (float64, error) {
address := fmt.Sprintf(g.baseAddress, index) + "/gate/release"
address := g.AddressFunc(g.baseAddress, index) + "/release"
err := g.client.SendMessage(address)
if err != nil {
return 0, err
@@ -194,6 +203,6 @@ func (g *Gate) Release(index int) (float64, error) {
// SetRelease sets the release time of the Gate for a specific strip (1-based indexing).
func (g *Gate) SetRelease(index int, release float64) error {
address := fmt.Sprintf(g.baseAddress, index) + "/gate/release"
address := g.AddressFunc(g.baseAddress, index) + "/release"
return g.client.SendMessage(address, float32(logSet(5, 4000, release)))
}

View File

@@ -1,8 +1,8 @@
package xair
type MixerKind string
type mixerKind string
const (
KindXAir MixerKind = "xair"
KindX32 MixerKind = "x32"
kindXAir mixerKind = "xair"
kindX32 mixerKind = "x32"
)

View File

@@ -11,19 +11,29 @@ type Main struct {
// newMainStereo creates a new Main instance for stereo main output
func newMainStereo(c *Client) *Main {
addressFunc := func(fmtString string, args ...any) string {
return fmtString
}
return &Main{
client: c,
baseAddress: c.addressMap["main"],
Eq: newEqForMain(c),
Comp: newCompForMain(c),
Eq: newEq(c, c.addressMap["main"], WithEqAddressFunc(addressFunc)),
Comp: newComp(c, c.addressMap["main"], WithCompAddressFunc(addressFunc)),
}
}
// newMainMono creates a new MainMono instance for mono main output (X32 only)
func newMainMono(c *Client) *Main {
addressFunc := func(fmtString string, args ...any) string {
return fmtString
}
return &Main{
baseAddress: c.addressMap["mainmono"],
client: c,
Eq: newEq(c, c.addressMap["mainmono"], WithEqAddressFunc(addressFunc)),
Comp: newComp(c, c.addressMap["mainmono"], WithCompAddressFunc(addressFunc)),
}
}

View File

@@ -14,8 +14,8 @@ func newMatrix(c *Client) *Matrix {
return &Matrix{
client: c,
baseAddress: c.addressMap["matrix"],
Eq: newEqForMatrix(c),
Comp: newCompForMatrix(c),
Eq: newEq(c, c.addressMap["matrix"]),
Comp: newComp(c, c.addressMap["matrix"]),
}
}

View File

@@ -2,17 +2,38 @@ package xair
import "time"
type Option func(*engine)
type EngineOption func(*engine)
func WithKind(kind string) Option {
return func(e *engine) {
e.Kind = MixerKind(kind)
e.addressMap = addressMapForMixerKind(e.Kind)
}
}
func WithTimeout(timeout time.Duration) Option {
// WithTimeout sets the timeout duration for OSC message responses
func WithTimeout(timeout time.Duration) EngineOption {
return func(e *engine) {
e.timeout = timeout
}
}
type CompOption func(*Comp)
// WithCompAddressFunc allows customization of the OSC address formatting for Comp parameters
func WithCompAddressFunc(f func(fmtString string, args ...any) string) CompOption {
return func(c *Comp) {
c.AddressFunc = f
}
}
type EqOption func(*Eq)
// WithEqAddressFunc allows customization of the OSC address formatting for Eq parameters
func WithEqAddressFunc(f func(fmtString string, args ...any) string) EqOption {
return func(e *Eq) {
e.AddressFunc = f
}
}
type GateOption func(*Gate)
// WithGateAddressFunc allows customization of the OSC address formatting for Gate parameters
func WithGateAddressFunc(f func(fmtString string, args ...any) string) GateOption {
return func(g *Gate) {
g.AddressFunc = f
}
}

View File

@@ -7,6 +7,7 @@ type Snapshot struct {
baseAddress string
}
// newSnapshot creates a new Snapshot instance
func newSnapshot(c *Client) *Snapshot {
return &Snapshot{
client: c,

View File

@@ -10,13 +10,14 @@ type Strip struct {
Comp *Comp
}
// newStrip creates a new Strip instance
func newStrip(c *Client) *Strip {
return &Strip{
client: c,
baseAddress: c.addressMap["strip"],
Gate: newGateForStrip(c),
Eq: newEqForStrip(c),
Comp: newCompForStrip(c),
Gate: newGate(c, c.addressMap["strip"]),
Eq: newEq(c, c.addressMap["strip"]),
Comp: newComp(c, c.addressMap["strip"]),
}
}
@@ -125,7 +126,7 @@ func (s *Strip) SetColor(strip int, color int32) error {
return s.client.SendMessage(address, color)
}
// Sends requests the sends level for a mixbus.
// SendLevel requests auxiliary send level for a send destination.
func (s *Strip) SendLevel(strip int, bus int) (float64, error) {
address := fmt.Sprintf(s.baseAddress, strip) + fmt.Sprintf("/mix/%02d/level", bus)
err := s.client.SendMessage(address)
@@ -144,7 +145,7 @@ func (s *Strip) SendLevel(strip int, bus int) (float64, error) {
return mustDbFrom(float64(val)), nil
}
// SetSendLevel sets the sends level for a mixbus.
// SetSendLevel sets the auxiliary send level for a send destination.
func (s *Strip) SetSendLevel(strip int, bus int, level float64) error {
address := fmt.Sprintf(s.baseAddress, strip) + fmt.Sprintf("/mix/%02d/level", bus)
return s.client.SendMessage(address, float32(mustDbInto(level)))

198
x32-help.md Normal file
View File

@@ -0,0 +1,198 @@
```console
Usage: x32-cli <command> [flags]
A CLI to control Behringer X32 mixers.
Flags:
-h, --help Show context-sensitive help.
-H, --host="mixer.local" The host of the X32 device ($X32_CLI_HOST).
-P, --port=10023 The port of the X32 device ($X32_CLI_PORT).
-T, --timeout=100ms Timeout for OSC operations ($X32_CLI_TIMEOUT).
-L, --loglevel="warn" Log level for the CLI ($X32_CLI_LOGLEVEL).
-v, --version Print x32-cli version information and quit
Commands:
completion (c) Generate shell completion scripts.
Raw
raw Send raw OSC messages to the mixer.
Main
main mute Get or set the mute state of the Main L/R output.
main fader Get or set the fader level of the Main L/R output.
main fadein Fade in the Main L/R output over a specified duration.
main fadeout Fade out the Main L/R output over a specified duration.
main eq on Get or set the EQ on/off state of the Main L/R output.
main eq <band> gain Get or set the gain of the specified EQ band.
main eq <band> freq Get or set the frequency of the specified EQ band.
main eq <band> q Get or set the Q factor of the specified EQ band.
main eq <band> type Get or set the type of the specified EQ band.
main comp on Get or set the compressor on/off state of the Main L/R
output.
main comp mode Get or set the compressor mode of the Main L/R output.
main comp threshold Get or set the compressor threshold of the Main L/R
output.
main comp ratio Get or set the compressor ratio of the Main L/R output.
main comp mix Get or set the compressor mix level of the Main L/R
output.
main comp makeup Get or set the compressor makeup gain of the Main L/R
output.
main comp attack Get or set the compressor attack time of the Main L/R
output.
main comp hold Get or set the compressor hold time of the Main L/R
output.
main comp release Get or set the compressor release time of the Main L/R
output.
MainMono
mainmono mute Get or set the mute state of the Main Mono output.
mainmono fader Get or set the fader level of the Main Mono output.
mainmono fadein Fade in the Main Mono output over a specified
duration.
mainmono fadeout Fade out the Main Mono output over a specified
duration.
mainmono eq on Get or set the EQ on/off state of the Main Mono
output.
mainmono eq <band> gain Get or set the gain of the specified EQ band.
mainmono eq <band> freq Get or set the frequency of the specified EQ band.
mainmono eq <band> q Get or set the Q factor of the specified EQ band.
mainmono eq <band> type Get or set the type of the specified EQ band.
mainmono comp on Get or set the compressor on/off state of the Main
Mono output.
mainmono comp mode Get or set the compressor mode of the Main Mono
output.
mainmono comp threshold Get or set the compressor threshold of the Main
Mono output.
mainmono comp ratio Get or set the compressor ratio of the Main Mono
output.
mainmono comp mix Get or set the compressor mix level of the Main
Mono output.
mainmono comp makeup Get or set the compressor makeup gain of the Main
Mono output.
mainmono comp attack Get or set the compressor attack time of the Main
Mono output.
mainmono comp hold Get or set the compressor hold time of the Main
Mono output.
mainmono comp release Get or set the compressor release time of the Main
Mono output.
Matrix
matrix <index> mute Get or set the mute state of the Matrix
output.
matrix <index> fader Get or set the fader level of the Matrix
output.
matrix <index> fadein Fade in the Matrix output over a specified
duration.
matrix <index> fadeout Fade out the Matrix output over a specified
duration.
matrix <index> eq on Get or set the EQ on/off state of the Matrix
output.
matrix <index> eq <band> gain Get or set the gain of the specified EQ band.
matrix <index> eq <band> freq Get or set the frequency of the specified EQ
band.
matrix <index> eq <band> q Get or set the Q factor of the specified EQ
band.
matrix <index> eq <band> type Get or set the type of the specified EQ band.
matrix <index> comp on Get or set the compressor on/off state of the
Matrix output.
matrix <index> comp mode Get or set the compressor mode of the Matrix
output.
matrix <index> comp threshold Get or set the compressor threshold of the
Matrix output.
matrix <index> comp ratio Get or set the compressor ratio of the Matrix
output.
matrix <index> comp mix Get or set the compressor mix level of the
Matrix output.
matrix <index> comp makeup Get or set the compressor makeup gain of the
Matrix output.
matrix <index> comp attack Get or set the compressor attack time of the
Matrix output.
matrix <index> comp hold Get or set the compressor hold time of the
Matrix output.
matrix <index> comp release Get or set the compressor release time of the
Matrix output.
Strip
strip <index> mute Get or set the mute state of the strip.
strip <index> fader Get or set the fader level of the strip.
strip <index> fadein Fade in the strip over a specified duration.
strip <index> fadeout Fade out the strip over a specified duration.
strip <index> send Get or set the send level for a specific bus.
strip <index> name Get or set the name of the strip.
strip <index> gate on Get or set the gate on/off state of the strip.
strip <index> gate mode Get or set the gate mode of the strip.
strip <index> gate threshold Get or set the gate threshold of the strip.
strip <index> gate range Get or set the gate range of the strip.
strip <index> gate attack Get or set the gate attack time of the strip.
strip <index> gate hold Get or set the gate hold time of the strip.
strip <index> gate release Get or set the gate release time of the strip.
strip <index> eq on Get or set the EQ on/off state of the strip.
strip <index> eq <band> gain Get or set the gain of the EQ band.
strip <index> eq <band> freq Get or set the frequency of the EQ band.
strip <index> eq <band> q Get or set the Q factor of the EQ band.
strip <index> eq <band> type Get or set the type of the EQ band.
strip <index> comp on Get or set the compressor on/off state of the
strip.
strip <index> comp mode Get or set the compressor mode of the strip.
strip <index> comp threshold Get or set the compressor threshold of the
strip.
strip <index> comp ratio Get or set the compressor ratio of the strip.
strip <index> comp mix Get or set the compressor mix of the strip.
strip <index> comp makeup Get or set the compressor makeup gain of the
strip.
strip <index> comp attack Get or set the compressor attack time of the
strip.
strip <index> comp hold Get or set the compressor hold time of the
strip.
strip <index> comp release Get or set the compressor release time of the
strip.
Bus
bus <index> mute Get or set the mute state of the bus.
bus <index> fader Get or set the fader level of the bus.
bus <index> fadein Fade in the bus over a specified duration.
bus <index> fadeout Fade out the bus over a specified duration.
bus <index> name Get or set the name of the bus.
bus <index> eq on Get or set the EQ on/off state of the bus.
bus <index> eq mode Get or set the EQ mode of the bus (peq, geq or
teq).
bus <index> eq <band> gain Get or set the gain of the EQ band.
bus <index> eq <band> freq Get or set the frequency of the EQ band.
bus <index> eq <band> q Get or set the Q factor of the EQ band.
bus <index> eq <band> type Get or set the type of the EQ band (lcut, lshv,
peq, veq, hshv, hcut).
bus <index> comp on Get or set the compressor on/off state of the
bus.
bus <index> comp mode Get or set the compressor mode of the bus (comp,
exp).
bus <index> comp threshold Get or set the compressor threshold of the bus
(in dB).
bus <index> comp ratio Get or set the compressor ratio of the bus.
bus <index> comp mix Get or set the compressor mix level of the bus
(in %).
bus <index> comp makeup Get or set the compressor makeup gain of the bus
(in dB).
bus <index> comp attack Get or set the compressor attack time of the bus
(in ms).
bus <index> comp hold Get or set the compressor hold time of the bus
(in ms).
bus <index> comp release Get or set the compressor release time of the
bus (in ms).
Headamp
headamp <index> gain Get or set the gain of the headamp.
headamp <index> phantom Get or set the phantom power state of the headamp.
Snapshot
snapshot list List all snapshots.
snapshot <index> name Get or set the name of a snapshot.
snapshot <index> save Save the current mixer state to a snapshot.
snapshot <index> load Load a mixer state from a snapshot.
snapshot <index> delete Delete a snapshot.
DCA
dca <index> mute Get or set the mute status of the DCA group.
dca <index> name Get or set the name of the DCA group.
Run "x32-cli <command> --help" for more information on a command.
```

130
xair-help.md Normal file
View File

@@ -0,0 +1,130 @@
```console
Usage: xair-cli <command> [flags]
A CLI to control Behringer X-Air mixers.
Flags:
-h, --help Show context-sensitive help.
-H, --host="mixer.local" The host of the X-Air device ($XAIR_CLI_HOST).
-P, --port=10024 The port of the X-Air device ($XAIR_CLI_PORT).
-T, --timeout=100ms Timeout for OSC operations ($XAIR_CLI_TIMEOUT).
-L, --loglevel="warn" Log level for the CLI ($XAIR_CLI_LOGLEVEL).
-v, --version Print xair-cli version information and quit
Commands:
completion (c) Generate shell completion scripts.
Raw
raw Send raw OSC messages to the mixer.
Main
main mute Get or set the mute state of the Main L/R output.
main fader Get or set the fader level of the Main L/R output.
main fadein Fade in the Main L/R output over a specified duration.
main fadeout Fade out the Main L/R output over a specified duration.
main eq on Get or set the EQ on/off state of the Main L/R output.
main eq <band> gain Get or set the gain of the specified EQ band.
main eq <band> freq Get or set the frequency of the specified EQ band.
main eq <band> q Get or set the Q factor of the specified EQ band.
main eq <band> type Get or set the type of the specified EQ band.
main comp on Get or set the compressor on/off state of the Main L/R
output.
main comp mode Get or set the compressor mode of the Main L/R output.
main comp threshold Get or set the compressor threshold of the Main L/R
output.
main comp ratio Get or set the compressor ratio of the Main L/R output.
main comp mix Get or set the compressor mix level of the Main L/R
output.
main comp makeup Get or set the compressor makeup gain of the Main L/R
output.
main comp attack Get or set the compressor attack time of the Main L/R
output.
main comp hold Get or set the compressor hold time of the Main L/R
output.
main comp release Get or set the compressor release time of the Main L/R
output.
Strip
strip <index> mute Get or set the mute state of the strip.
strip <index> fader Get or set the fader level of the strip.
strip <index> fadein Fade in the strip over a specified duration.
strip <index> fadeout Fade out the strip over a specified duration.
strip <index> send Get or set the send level for a specific bus.
strip <index> name Get or set the name of the strip.
strip <index> gate on Get or set the gate on/off state of the strip.
strip <index> gate mode Get or set the gate mode of the strip.
strip <index> gate threshold Get or set the gate threshold of the strip.
strip <index> gate range Get or set the gate range of the strip.
strip <index> gate attack Get or set the gate attack time of the strip.
strip <index> gate hold Get or set the gate hold time of the strip.
strip <index> gate release Get or set the gate release time of the strip.
strip <index> eq on Get or set the EQ on/off state of the strip.
strip <index> eq <band> gain Get or set the gain of the EQ band.
strip <index> eq <band> freq Get or set the frequency of the EQ band.
strip <index> eq <band> q Get or set the Q factor of the EQ band.
strip <index> eq <band> type Get or set the type of the EQ band.
strip <index> comp on Get or set the compressor on/off state of the
strip.
strip <index> comp mode Get or set the compressor mode of the strip.
strip <index> comp threshold Get or set the compressor threshold of the
strip.
strip <index> comp ratio Get or set the compressor ratio of the strip.
strip <index> comp mix Get or set the compressor mix of the strip.
strip <index> comp makeup Get or set the compressor makeup gain of the
strip.
strip <index> comp attack Get or set the compressor attack time of the
strip.
strip <index> comp hold Get or set the compressor hold time of the
strip.
strip <index> comp release Get or set the compressor release time of the
strip.
Bus
bus <index> mute Get or set the mute state of the bus.
bus <index> fader Get or set the fader level of the bus.
bus <index> fadein Fade in the bus over a specified duration.
bus <index> fadeout Fade out the bus over a specified duration.
bus <index> name Get or set the name of the bus.
bus <index> eq on Get or set the EQ on/off state of the bus.
bus <index> eq mode Get or set the EQ mode of the bus (peq, geq or
teq).
bus <index> eq <band> gain Get or set the gain of the EQ band.
bus <index> eq <band> freq Get or set the frequency of the EQ band.
bus <index> eq <band> q Get or set the Q factor of the EQ band.
bus <index> eq <band> type Get or set the type of the EQ band (lcut, lshv,
peq, veq, hshv, hcut).
bus <index> comp on Get or set the compressor on/off state of the
bus.
bus <index> comp mode Get or set the compressor mode of the bus (comp,
exp).
bus <index> comp threshold Get or set the compressor threshold of the bus
(in dB).
bus <index> comp ratio Get or set the compressor ratio of the bus.
bus <index> comp mix Get or set the compressor mix level of the bus
(in %).
bus <index> comp makeup Get or set the compressor makeup gain of the bus
(in dB).
bus <index> comp attack Get or set the compressor attack time of the bus
(in ms).
bus <index> comp hold Get or set the compressor hold time of the bus
(in ms).
bus <index> comp release Get or set the compressor release time of the
bus (in ms).
Headamp
headamp <index> gain Get or set the gain of the headamp.
headamp <index> phantom Get or set the phantom power state of the headamp.
Snapshot
snapshot list List all snapshots.
snapshot <index> name Get or set the name of a snapshot.
snapshot <index> save Save the current mixer state to a snapshot.
snapshot <index> load Load a mixer state from a snapshot.
snapshot <index> delete Delete a snapshot.
DCA
dca <index> mute Get or set the mute status of the DCA group.
dca <index> name Get or set the name of the DCA group.
Run "xair-cli <command> --help" for more information on a command.
```