Compare commits

..

2 Commits

Author SHA1 Message Date
58866b794b implement info command
upd help mds
2026-02-11 21:47:56 +00:00
32a09db1a4 unexport client 2026-02-11 21:25:40 +00:00
18 changed files with 129 additions and 80 deletions

View File

@ -46,9 +46,10 @@ type CLI struct {
Version VersionFlag `help:"Print x32-cli version information and quit" name:"version" short:"v"` Version VersionFlag `help:"Print x32-cli version information and quit" name:"version" short:"v"`
Completion kongcompletion.Completion `help:"Generate shell completion scripts." cmd:"" aliases:"c"` Completion kongcompletion.Completion `help:"Generate shell completion scripts." cmd:""`
Info InfoCmd `help:"Print mixer information." cmd:""`
Raw RawCmd `help:"Send raw OSC messages to the mixer." cmd:""`
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"` Main MainCmdGroup `help:"Control the Main L/R output" cmd:"" group:"Main"`
Mainmono MainMonoCmdGroup `help:"Control the Main Mono output" cmd:"" group:"MainMono"` Mainmono MainMonoCmdGroup `help:"Control the Main Mono output" cmd:"" group:"MainMono"`
Matrix MatrixCmdGroup `help:"Control the matrix outputs." cmd:"" group:"Matrix"` Matrix MatrixCmdGroup `help:"Control the matrix outputs." cmd:"" group:"Matrix"`

18
cmd/x32-cli/info.go Normal file
View File

@ -0,0 +1,18 @@
package main
import "fmt"
type InfoCmd struct {
}
func (c *InfoCmd) Run(ctx *context) error {
fmt.Fprintf(
ctx.Out,
"Host: %s | Name: %s | Model: %s | Firmware: %s\n",
ctx.Client.Info.Host,
ctx.Client.Info.Name,
ctx.Client.Info.Model,
ctx.Client.Info.Firmware,
)
return nil
}

View File

@ -46,9 +46,10 @@ type CLI struct {
Version VersionFlag `help:"Print xair-cli version information and quit" name:"version" short:"v"` Version VersionFlag `help:"Print xair-cli version information and quit" name:"version" short:"v"`
Completion kongcompletion.Completion `help:"Generate shell completion scripts." cmd:"" aliases:"c"` Completion kongcompletion.Completion `help:"Generate shell completion scripts." cmd:""`
Info InfoCmd `help:"Print mixer information." cmd:""`
Raw RawCmd `help:"Send raw OSC messages to the mixer." cmd:""`
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"` Main MainCmdGroup `help:"Control the Main L/R output" cmd:"" group:"Main"`
Strip StripCmdGroup `help:"Control the strips." cmd:"" group:"Strip"` Strip StripCmdGroup `help:"Control the strips." cmd:"" group:"Strip"`
Bus BusCmdGroup `help:"Control the buses." cmd:"" group:"Bus"` Bus BusCmdGroup `help:"Control the buses." cmd:"" group:"Bus"`

18
cmd/xair-cli/info.go Normal file
View File

@ -0,0 +1,18 @@
package main
import "fmt"
type InfoCmd struct {
}
func (c *InfoCmd) Run(ctx *context) error {
fmt.Fprintf(
ctx.Out,
"Host: %s | Name: %s | Model: %s | Firmware: %s\n",
ctx.Client.Info.Host,
ctx.Client.Info.Name,
ctx.Client.Info.Model,
ctx.Client.Info.Firmware,
)
return nil
}

View File

@ -3,14 +3,14 @@ package xair
import "fmt" import "fmt"
type Bus struct { type Bus struct {
client *Client client *client
baseAddress string baseAddress string
Eq *Eq Eq *Eq
Comp *Comp Comp *Comp
} }
// newBus creates a new Bus instance // newBus creates a new Bus instance
func newBus(c *Client) *Bus { func newBus(c *client) *Bus {
return &Bus{ return &Bus{
client: c, client: c,
baseAddress: c.addressMap["bus"], baseAddress: c.addressMap["bus"],

View File

@ -9,13 +9,9 @@ import (
"github.com/hypebeast/go-osc/osc" "github.com/hypebeast/go-osc/osc"
) )
type Client struct {
*engine
}
// XAirClient is a client for controlling XAir mixers // XAirClient is a client for controlling XAir mixers
type XAirClient struct { type XAirClient struct {
Client client
Main *Main Main *Main
Strip *Strip Strip *Strip
Bus *Bus Bus *Bus
@ -24,9 +20,29 @@ type XAirClient struct {
DCA *DCA DCA *DCA
} }
// 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, InfoResponse{}},
}
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
}
// X32Client is a client for controlling X32 mixers // X32Client is a client for controlling X32 mixers
type X32Client struct { type X32Client struct {
Client client
Main *Main Main *Main
MainMono *Main MainMono *Main
Matrix *Matrix Matrix *Matrix
@ -45,48 +61,33 @@ func NewX32Client(mixerIP string, mixerPort int, opts ...EngineOption) (*X32Clie
} }
c := &X32Client{ c := &X32Client{
Client: Client{e}, client: client{e, InfoResponse{}},
} }
c.Main = newMainStereo(&c.Client) c.Main = newMainStereo(&c.client)
c.MainMono = newMainMono(&c.Client) c.MainMono = newMainMono(&c.client)
c.Matrix = newMatrix(&c.Client) c.Matrix = newMatrix(&c.client)
c.Strip = newStrip(&c.Client) c.Strip = newStrip(&c.client)
c.Bus = newBus(&c.Client) c.Bus = newBus(&c.client)
c.HeadAmp = newHeadAmp(&c.Client) c.HeadAmp = newHeadAmp(&c.client)
c.Snapshot = newSnapshot(&c.Client) c.Snapshot = newSnapshot(&c.client)
c.DCA = newDCA(&c.Client) c.DCA = newDCA(&c.client)
return c, nil return c, nil
} }
// NewXAirClient creates a new XAirClient instance with optional engine configuration type client struct {
func NewXAirClient(mixerIP string, mixerPort int, opts ...EngineOption) (*XAirClient, error) { *engine
e, err := newEngine(mixerIP, mixerPort, kindXAir, opts...) Info InfoResponse
if err != nil {
return nil, err
}
c := &XAirClient{
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
} }
// Start begins listening for messages in a goroutine // Start begins listening for messages in a goroutine
func (c *Client) StartListening() { func (c *client) StartListening() {
go c.engine.receiveLoop() go c.engine.receiveLoop()
log.Debugf("Started listening on %s...", c.engine.conn.LocalAddr().String()) log.Debugf("Started listening on %s...", c.engine.conn.LocalAddr().String())
} }
// Close stops the client and closes the connection // Close stops the client and closes the connection
func (c *Client) Close() { func (c *client) Close() {
close(c.engine.done) close(c.engine.done)
if c.engine.conn != nil { if c.engine.conn != nil {
c.engine.conn.Close() c.engine.conn.Close()
@ -94,12 +95,12 @@ func (c *Client) Close() {
} }
// SendMessage sends an OSC message to the mixer using the unified connection // SendMessage sends an OSC message to the mixer using the unified connection
func (c *Client) SendMessage(address string, args ...any) error { func (c *client) SendMessage(address string, args ...any) error {
return c.engine.sendToAddress(c.mixerAddr, address, args...) return c.engine.sendToAddress(c.mixerAddr, address, args...)
} }
// ReceiveMessage receives an OSC message from the mixer // ReceiveMessage receives an OSC message from the mixer
func (c *Client) ReceiveMessage() (*osc.Message, error) { func (c *client) ReceiveMessage() (*osc.Message, error) {
t := time.Tick(c.engine.timeout) t := time.Tick(c.engine.timeout)
select { select {
case <-t: case <-t:
@ -113,7 +114,7 @@ func (c *Client) ReceiveMessage() (*osc.Message, error) {
} }
// RequestInfo requests mixer information // RequestInfo requests mixer information
func (c *Client) RequestInfo() (InfoResponse, error) { func (c *client) RequestInfo() (InfoResponse, error) {
var info InfoResponse var info InfoResponse
err := c.SendMessage("/xinfo") err := c.SendMessage("/xinfo")
if err != nil { if err != nil {
@ -124,20 +125,31 @@ func (c *Client) RequestInfo() (InfoResponse, error) {
if err != nil { if err != nil {
return info, err return info, err
} }
if len(msg.Arguments) >= 3 { if len(msg.Arguments) == 4 {
info.Host = msg.Arguments[0].(string) if host, ok := msg.Arguments[0].(string); ok {
info.Name = msg.Arguments[1].(string) info.Host = host
info.Model = msg.Arguments[2].(string)
} }
if name, ok := msg.Arguments[1].(string); ok {
info.Name = name
}
if model, ok := msg.Arguments[2].(string); ok {
info.Model = model
}
if firmware, ok := msg.Arguments[3].(string); ok {
info.Firmware = firmware
}
}
c.Info = info
return info, nil return info, nil
} }
// KeepAlive sends keep-alive message (required for multi-client usage) // KeepAlive sends keep-alive message (required for multi-client usage)
func (c *Client) KeepAlive() error { func (c *client) KeepAlive() error {
return c.SendMessage("/xremote") return c.SendMessage("/xremote")
} }
// RequestStatus requests mixer status // RequestStatus requests mixer status
func (c *Client) RequestStatus() error { func (c *client) RequestStatus() error {
return c.SendMessage("/status") return c.SendMessage("/status")
} }

View File

@ -4,13 +4,13 @@ import "fmt"
// Comp represents the compressor parameters. // Comp represents the compressor parameters.
type Comp struct { type Comp struct {
client *Client client *client
baseAddress string baseAddress string
AddressFunc func(fmtString string, args ...any) string AddressFunc func(fmtString string, args ...any) string
} }
// Factory function to create Comp instance with optional configuration // Factory function to create Comp instance with optional configuration
func newComp(c *Client, baseAddress string, opts ...CompOption) *Comp { func newComp(c *client, baseAddress string, opts ...CompOption) *Comp {
comp := &Comp{ comp := &Comp{
client: c, client: c,
baseAddress: fmt.Sprintf("%s/dyn", baseAddress), baseAddress: fmt.Sprintf("%s/dyn", baseAddress),

View File

@ -3,12 +3,12 @@ package xair
import "fmt" import "fmt"
type DCA struct { type DCA struct {
client *Client client *client
baseAddress string baseAddress string
} }
// newDCA creates a new DCA instance // newDCA creates a new DCA instance
func newDCA(c *Client) *DCA { func newDCA(c *client) *DCA {
return &DCA{ return &DCA{
client: c, client: c,
baseAddress: c.addressMap["dca"], baseAddress: c.addressMap["dca"],

View File

@ -6,13 +6,13 @@ import (
// Eq represents the EQ parameters. // Eq represents the EQ parameters.
type Eq struct { type Eq struct {
client *Client client *client
baseAddress string baseAddress string
AddressFunc func(fmtString string, args ...any) string AddressFunc func(fmtString string, args ...any) string
} }
// Factory function to create Eq instance with optional configuration // Factory function to create Eq instance with optional configuration
func newEq(c *Client, baseAddress string, opts ...EqOption) *Eq { func newEq(c *client, baseAddress string, opts ...EqOption) *Eq {
eq := &Eq{ eq := &Eq{
client: c, client: c,
baseAddress: fmt.Sprintf("%s/eq", baseAddress), baseAddress: fmt.Sprintf("%s/eq", baseAddress),

View File

@ -4,13 +4,13 @@ import "fmt"
// Gate represents the gate parameters. // Gate represents the gate parameters.
type Gate struct { type Gate struct {
client *Client client *client
baseAddress string baseAddress string
AddressFunc func(fmtString string, args ...any) string AddressFunc func(fmtString string, args ...any) string
} }
// Factory function to create Gate instance with optional configuration // Factory function to create Gate instance with optional configuration
func newGate(c *Client, baseAddress string, opts ...GateOption) *Gate { func newGate(c *client, baseAddress string, opts ...GateOption) *Gate {
gate := &Gate{ gate := &Gate{
client: c, client: c,
baseAddress: fmt.Sprintf("%s/gate", baseAddress), baseAddress: fmt.Sprintf("%s/gate", baseAddress),

View File

@ -3,12 +3,12 @@ package xair
import "fmt" import "fmt"
type HeadAmp struct { type HeadAmp struct {
client *Client client *client
baseAddress string baseAddress string
} }
// newHeadAmp creates a new HeadAmp instance with the provided client. // newHeadAmp creates a new HeadAmp instance with the provided client.
func newHeadAmp(c *Client) *HeadAmp { func newHeadAmp(c *client) *HeadAmp {
return &HeadAmp{ return &HeadAmp{
client: c, client: c,
baseAddress: c.addressMap["headamp"], baseAddress: c.addressMap["headamp"],

View File

@ -3,14 +3,14 @@ package xair
import "fmt" import "fmt"
type Main struct { type Main struct {
client *Client client *client
baseAddress string baseAddress string
Eq *Eq Eq *Eq
Comp *Comp Comp *Comp
} }
// newMainStereo creates a new Main instance for stereo main output // newMainStereo creates a new Main instance for stereo main output
func newMainStereo(c *Client) *Main { func newMainStereo(c *client) *Main {
addressFunc := func(fmtString string, args ...any) string { addressFunc := func(fmtString string, args ...any) string {
return fmtString return fmtString
} }
@ -24,7 +24,7 @@ func newMainStereo(c *Client) *Main {
} }
// newMainMono creates a new MainMono instance for mono main output (X32 only) // newMainMono creates a new MainMono instance for mono main output (X32 only)
func newMainMono(c *Client) *Main { func newMainMono(c *client) *Main {
addressFunc := func(fmtString string, args ...any) string { addressFunc := func(fmtString string, args ...any) string {
return fmtString return fmtString
} }

View File

@ -3,14 +3,14 @@ package xair
import "fmt" import "fmt"
type Matrix struct { type Matrix struct {
client *Client client *client
baseAddress string baseAddress string
Eq *Eq Eq *Eq
Comp *Comp Comp *Comp
} }
// newMatrix creates a new Matrix instance // newMatrix creates a new Matrix instance
func newMatrix(c *Client) *Matrix { func newMatrix(c *client) *Matrix {
return &Matrix{ return &Matrix{
client: c, client: c,
baseAddress: c.addressMap["matrix"], baseAddress: c.addressMap["matrix"],

View File

@ -4,4 +4,5 @@ type InfoResponse struct {
Host string Host string
Name string Name string
Model string Model string
Firmware string
} }

View File

@ -3,12 +3,12 @@ package xair
import "fmt" import "fmt"
type Snapshot struct { type Snapshot struct {
client *Client client *client
baseAddress string baseAddress string
} }
// newSnapshot creates a new Snapshot instance // newSnapshot creates a new Snapshot instance
func newSnapshot(c *Client) *Snapshot { func newSnapshot(c *client) *Snapshot {
return &Snapshot{ return &Snapshot{
client: c, client: c,
baseAddress: c.addressMap["snapshot"], baseAddress: c.addressMap["snapshot"],

View File

@ -3,7 +3,7 @@ package xair
import "fmt" import "fmt"
type Strip struct { type Strip struct {
client *Client client *client
baseAddress string baseAddress string
Gate *Gate Gate *Gate
Eq *Eq Eq *Eq
@ -11,7 +11,7 @@ type Strip struct {
} }
// newStrip creates a new Strip instance // newStrip creates a new Strip instance
func newStrip(c *Client) *Strip { func newStrip(c *client) *Strip {
return &Strip{ return &Strip{
client: c, client: c,
baseAddress: c.addressMap["strip"], baseAddress: c.addressMap["strip"],

View File

@ -12,9 +12,8 @@ Flags:
-v, --version Print x32-cli version information and quit -v, --version Print x32-cli version information and quit
Commands: Commands:
completion (c) Generate shell completion scripts. completion Generate shell completion scripts.
info Print mixer information.
Raw
raw Send raw OSC messages to the mixer. raw Send raw OSC messages to the mixer.
Main Main

View File

@ -12,9 +12,8 @@ Flags:
-v, --version Print xair-cli version information and quit -v, --version Print xair-cli version information and quit
Commands: Commands:
completion (c) Generate shell completion scripts. completion Generate shell completion scripts.
info Print mixer information.
Raw
raw Send raw OSC messages to the mixer. raw Send raw OSC messages to the mixer.
Main Main