From cf470181a1687fac47655df70a85eece6fe1f520 Mon Sep 17 00:00:00 2001 From: onyx-and-iris Date: Tue, 10 Feb 2026 01:16:44 +0000 Subject: [PATCH] implement dca commands: - DCA added to Client struct - dca command added to both CLIs help mds updated --- cmd/x32-cli/cli.go | 1 + cmd/x32-cli/dca.go | 67 ++++++++++++++++++++++++++++ cmd/xair-cli/cli.go | 1 + cmd/xair-cli/dca.go | 68 ++++++++++++++++++++++++++++ internal/xair/address.go | 4 +- internal/xair/client.go | 4 ++ internal/xair/dca.go | 95 ++++++++++++++++++++++++++++++++++++++++ x32-help.md | 4 ++ xair-help.md | 4 ++ 9 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 cmd/x32-cli/dca.go create mode 100644 cmd/xair-cli/dca.go create mode 100644 internal/xair/dca.go diff --git a/cmd/x32-cli/cli.go b/cmd/x32-cli/cli.go index 9965d56..ef7ab09 100644 --- a/cmd/x32-cli/cli.go +++ b/cmd/x32-cli/cli.go @@ -56,6 +56,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() { diff --git a/cmd/x32-cli/dca.go b/cmd/x32-cli/dca.go new file mode 100644 index 0000000..a478018 --- /dev/null +++ b/cmd/x32-cli/dca.go @@ -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 +} diff --git a/cmd/xair-cli/cli.go b/cmd/xair-cli/cli.go index a48dd8e..aa7aacb 100644 --- a/cmd/xair-cli/cli.go +++ b/cmd/xair-cli/cli.go @@ -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() { diff --git a/cmd/xair-cli/dca.go b/cmd/xair-cli/dca.go new file mode 100644 index 0000000..55a690c --- /dev/null +++ b/cmd/xair-cli/dca.go @@ -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 +} diff --git a/internal/xair/address.go b/internal/xair/address.go index aaed1f6..e7ecc20 100644 --- a/internal/xair/address.go +++ b/internal/xair/address.go @@ -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,6 +17,7 @@ var x32AddressMap = map[string]string{ "bus": "/bus/%02d", "headamp": "/headamp/%03d", "snapshot": "/-snap", + "dca": "/dca/%d", } func addressMapFromMixerKind(kind mixerKind) map[string]string { diff --git a/internal/xair/client.go b/internal/xair/client.go index d1efcef..d8ee841 100644 --- a/internal/xair/client.go +++ b/internal/xair/client.go @@ -21,6 +21,7 @@ type XAirClient struct { Bus *Bus HeadAmp *HeadAmp Snapshot *Snapshot + DCA *DCA } // X32Client is a client for controlling X32 mixers @@ -33,6 +34,7 @@ type X32Client struct { Bus *Bus HeadAmp *HeadAmp Snapshot *Snapshot + DCA *DCA } // NewX32Client creates a new X32Client instance with optional engine configuration @@ -52,6 +54,7 @@ func NewX32Client(mixerIP string, mixerPort int, opts ...EngineOption) (*X32Clie c.Bus = newBus(&c.Client) c.HeadAmp = newHeadAmp(&c.Client) c.Snapshot = newSnapshot(&c.Client) + c.DCA = newDCA(&c.Client) return c, nil } @@ -71,6 +74,7 @@ func NewXAirClient(mixerIP string, mixerPort int, opts ...EngineOption) (*XAirCl c.Bus = newBus(&c.Client) c.HeadAmp = newHeadAmp(&c.Client) c.Snapshot = newSnapshot(&c.Client) + c.DCA = newDCA(&c.Client) return c, nil } diff --git a/internal/xair/dca.go b/internal/xair/dca.go new file mode 100644 index 0000000..dc9b6ff --- /dev/null +++ b/internal/xair/dca.go @@ -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) +} diff --git a/x32-help.md b/x32-help.md index 8081168..de8e735 100644 --- a/x32-help.md +++ b/x32-help.md @@ -190,5 +190,9 @@ Snapshot snapshot load Load a mixer state from a snapshot. snapshot delete Delete a snapshot. +DCA + dca mute Get or set the mute status of the DCA group. + dca name Get or set the name of the DCA group. + Run "x32-cli --help" for more information on a command. ``` diff --git a/xair-help.md b/xair-help.md index 400d4c7..1fbad4f 100644 --- a/xair-help.md +++ b/xair-help.md @@ -122,5 +122,9 @@ Snapshot snapshot load Load a mixer state from a snapshot. snapshot delete Delete a snapshot. +DCA + dca mute Get or set the mute status of the DCA group. + dca name Get or set the name of the DCA group. + Run "xair-cli --help" for more information on a command. ```