11 Commits

Author SHA1 Message Date
079a0b240d ensure all optional args are marked as optional 2026-02-06 00:41:26 +00:00
fe711f79f1 Main struct now uses address map 2026-02-06 00:41:06 +00:00
c94ac62cb8 upd address maps 2026-02-06 00:40:52 +00:00
5933b25114 move parser interface into engine.go
add snapshot field to Client
2026-02-06 00:40:42 +00:00
fa704832d5 reword 2026-02-05 21:44:39 +00:00
69925021af spell fix 2026-02-05 15:43:19 +00:00
e092ed3c4e add Configuration section to README 2026-02-05 15:42:39 +00:00
d87bc2678c add short Config flags 2026-02-05 15:42:07 +00:00
c3221f3df5 reduce default timeout to 100ms
add env var for raw timeout
2026-02-05 15:13:33 +00:00
dc733ba500 add macos target to Taskfile 2026-02-05 14:20:03 +00:00
2a5e0e022f upd README 2026-02-05 13:42:57 +00:00
11 changed files with 87 additions and 37 deletions

View File

@@ -6,6 +6,28 @@
go install github.com/onyx-and-iris/xair-cli@latest
```
### Configuration
#### Flags
- --host/-H: Host of the mixer.
- --port/-P: Port of the mixer.
- --kind/-k: The kind of mixer. May one of (*xair*, *x32*).
- Use this flag to connect to an x32 mixer.
#### Environment Variables
Example .envrc:
```bash
#!/usr/bin/env bash
XAIR_CLI_HOST=mixer.local
XAIR_CLI_PORT=10024
XAIR_CLI_KIND=xair
XAIR_CLI_RAW_TIMEOUT=50ms
```
### Use
```console
@@ -29,8 +51,8 @@ Raw
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 Get or set the fade-in time of the Main L/R output.
main fadeout Get or set the fade-out time 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.
Strip
strip <index> mute Get or set the mute state of the strip.

View File

@@ -9,6 +9,7 @@ vars:
WINDOWS: '{{.BIN_DIR}}/{{.PROGRAM}}_windows_amd64.exe'
LINUX: '{{.BIN_DIR}}/{{.PROGRAM}}_linux_amd64'
MACOS: '{{.BIN_DIR}}/{{.PROGRAM}}_darwin_amd64'
tasks:
default:
@@ -22,6 +23,7 @@ tasks:
cmds:
- task: build-windows
- task: build-linux
- task: build-macos
vet:
desc: Vet the code
@@ -46,6 +48,12 @@ tasks:
- GOOS=linux GOARCH=amd64 go build -o {{.LINUX}} -ldflags="-X main.version={{.VERSION}}"
internal: true
build-macos:
desc: Build the xair-cli project for macOS
cmds:
- GOOS=darwin GOARCH=amd64 go build -o {{.MACOS}} -ldflags="-X main.version={{.VERSION}}"
internal: true
test:
desc: Run tests
cmds:

22
bus.go
View File

@@ -148,7 +148,7 @@ func (cmd *BusFadeoutCmd) Run(ctx *context, bus *BusCmdGroup) error {
// BusNameCmd defines the command for getting or setting the name of a bus.
type BusNameCmd struct {
Name *string `arg:"" help:"The name to set for the bus. If not provided, the current name will be returned."`
Name *string `arg:"" help:"The name to set for the bus. If not provided, the current name will be returned." optional:""`
}
// Run executes the BusNameCmd command, either retrieving the current name of the bus or setting it based on the provided argument.
@@ -238,7 +238,7 @@ func (cmd *BusEqModeCmd) Run(ctx *context, bus *BusCmdGroup) error {
// BusEqBandGainCmd defines the command for getting or setting the gain of a specific EQ band of a bus.
type BusEqBandGainCmd struct {
Gain *float64 `arg:"" help:"The gain to set for the EQ band (in dB). If not provided, the current gain will be returned."`
Gain *float64 `arg:"" help:"The gain to set for the EQ band (in dB). If not provided, the current gain will be returned." optional:""`
}
// 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.
@@ -261,7 +261,7 @@ func (cmd *BusEqBandGainCmd) Run(ctx *context, bus *BusCmdGroup, busEq *BusEqCmd
// BusEqBandFreqCmd defines the command for getting or setting the frequency of a specific EQ band of a bus.
type BusEqBandFreqCmd struct {
Freq *float64 `arg:"" help:"The frequency to set for the EQ band (in Hz). If not provided, the current frequency will be returned."`
Freq *float64 `arg:"" help:"The frequency to set for the EQ band (in Hz). If not provided, the current frequency will be returned." optional:""`
}
// 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.
@@ -284,7 +284,7 @@ func (cmd *BusEqBandFreqCmd) Run(ctx *context, bus *BusCmdGroup, busEq *BusEqCmd
// BusEqBandQCmd defines the command for getting or setting the Q factor of a specific EQ band of a bus.
type BusEqBandQCmd struct {
Q *float64 `arg:"" help:"The Q factor to set for the EQ band. If not provided, the current Q factor will be returned."`
Q *float64 `arg:"" help:"The Q factor to set for the EQ band. If not provided, the current Q factor will be returned." optional:""`
}
// 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.
@@ -389,7 +389,7 @@ func (cmd *BusCompModeCmd) Run(ctx *context, bus *BusCmdGroup) error {
// BusCompThresholdCmd defines the command for getting or setting the compressor threshold of a bus.
type BusCompThresholdCmd struct {
Threshold *float64 `arg:"" help:"The compressor threshold to set (in dB). If not provided, the current compressor threshold will be returned."`
Threshold *float64 `arg:"" help:"The compressor threshold to set (in dB). If not provided, the current compressor threshold will be returned." optional:""`
}
// Run executes the BusCompThresholdCmd command, either retrieving the current compressor threshold of the bus or setting it based on the provided argument.
@@ -412,7 +412,7 @@ func (cmd *BusCompThresholdCmd) Run(ctx *context, bus *BusCmdGroup) error {
// BusCompRatioCmd defines the command for getting or setting the compressor ratio of a bus.
type BusCompRatioCmd struct {
Ratio *float64 `arg:"" help:"The compressor ratio to set. If not provided, the current compressor ratio will be returned."`
Ratio *float64 `arg:"" help:"The compressor ratio to set. If not provided, the current compressor ratio will be returned." optional:""`
}
// Run executes the BusCompRatioCmd command, either retrieving the current compressor ratio of the bus or setting it based on the provided argument.
@@ -435,7 +435,7 @@ func (cmd *BusCompRatioCmd) Run(ctx *context, bus *BusCmdGroup) error {
// BusCompMixCmd defines the command for getting or setting the compressor mix level of a bus.
type BusCompMixCmd struct {
Mix *float64 `arg:"" help:"The compressor mix level to set (in %). If not provided, the current compressor mix level will be returned."`
Mix *float64 `arg:"" help:"The compressor mix level to set (in %). If not provided, the current compressor mix level will be returned." optional:""`
}
// Run executes the BusCompMixCmd command, either retrieving the current compressor mix level of the bus or setting it based on the provided argument.
@@ -458,7 +458,7 @@ func (cmd *BusCompMixCmd) Run(ctx *context, bus *BusCmdGroup) error {
// BusCompMakeupCmd defines the command for getting or setting the compressor makeup gain of a bus.
type BusCompMakeupCmd struct {
Makeup *float64 `arg:"" help:"The compressor makeup gain to set (in dB). If not provided, the current compressor makeup gain will be returned."`
Makeup *float64 `arg:"" help:"The compressor makeup gain to set (in dB). If not provided, the current compressor makeup gain will be returned." optional:""`
}
// Run executes the BusCompMakeupCmd command, either retrieving the current compressor makeup gain of the bus or setting it based on the provided argument.
@@ -481,7 +481,7 @@ func (cmd *BusCompMakeupCmd) Run(ctx *context, bus *BusCmdGroup) error {
// BusCompAttackCmd defines the command for getting or setting the compressor attack time of a bus.
type BusCompAttackCmd struct {
Attack *float64 `arg:"" help:"The compressor attack time to set (in ms). If not provided, the current compressor attack time will be returned."`
Attack *float64 `arg:"" help:"The compressor attack time to set (in ms). If not provided, the current compressor attack time will be returned." optional:""`
}
// Run executes the BusCompAttackCmd command, either retrieving the current compressor attack time of the bus or setting it based on the provided argument.
@@ -504,7 +504,7 @@ func (cmd *BusCompAttackCmd) Run(ctx *context, bus *BusCmdGroup) error {
// BusCompHoldCmd defines the command for getting or setting the compressor hold time of a bus.
type BusCompHoldCmd struct {
Hold *float64 `arg:"" help:"The compressor hold time to set (in ms). If not provided, the current compressor hold time will be returned."`
Hold *float64 `arg:"" help:"The compressor hold time to set (in ms). If not provided, the current compressor hold time will be returned." optional:""`
}
// Run executes the BusCompHoldCmd command, either retrieving the current compressor hold time of the bus or setting it based on the provided argument.
@@ -527,7 +527,7 @@ func (cmd *BusCompHoldCmd) Run(ctx *context, bus *BusCmdGroup) error {
// BusCompReleaseCmd defines the command for getting or setting the compressor release time of a bus.
type BusCompReleaseCmd struct {
Release *float64 `arg:"" help:"The compressor release time to set (in ms). If not provided, the current compressor release time will be returned."`
Release *float64 `arg:"" help:"The compressor release time to set (in ms). If not provided, the current compressor release time will be returned." optional:""`
}
// Run executes the BusCompReleaseCmd command, either retrieving the current compressor release time of the bus or setting it based on the provided argument.

View File

@@ -19,7 +19,7 @@ type HeadampCmdGroup struct {
// HeadampGainCmd defines the command for getting or setting the gain of a headamp, allowing users to specify the gain in dB and an optional duration for a gradual fade when setting the gain.
type HeadampGainCmd struct {
Duration time.Duration `help:"The duration of the fade in/out when setting the gain." default:"5s"`
Gain *float64 `help:"The gain of the headamp in dB." arg:""`
Gain *float64 `help:"The gain of the headamp in dB." arg:"" optional:""`
}
// Run executes the HeadampGainCmd command, either retrieving the current gain of the headamp or setting it based on the provided argument, with an optional fade duration for smooth transitions.

View File

@@ -1,6 +1,7 @@
package xair
var xairAddressMap = map[string]string{
"main": "/lr",
"strip": "/ch/%02d",
"bus": "/bus/%01d",
"headamp": "/headamp/%02d",
@@ -8,9 +9,12 @@ var xairAddressMap = map[string]string{
}
var x32AddressMap = map[string]string{
"strip": "/ch/%02d",
"bus": "/bus/%02d",
"headamp": "/headamp/%02d",
"main": "/main/st",
"mainmono": "/main/mono",
"strip": "/ch/%02d",
"bus": "/bus/%02d",
"headamp": "/headamp/%02d",
"snapshot": "/-snap",
}
func addressMapForMixerKind(kind MixerKind) map[string]string {

View File

@@ -10,10 +10,6 @@ import (
"github.com/hypebeast/go-osc/osc"
)
type parser interface {
Parse(data []byte) (*osc.Message, error)
}
type Client struct {
engine
Main *Main
@@ -60,10 +56,11 @@ func NewClient(mixerIP string, mixerPort int, opts ...Option) (*Client, error) {
c := &Client{
engine: *e,
}
c.Main = newMain(c)
c.Main = newMainStereo(c)
c.Strip = NewStrip(c)
c.Bus = NewBus(c)
c.HeadAmp = NewHeadAmp(c)
c.Snapshot = NewSnapshot(c)
return c, nil
}

View File

@@ -9,6 +9,10 @@ import (
"github.com/hypebeast/go-osc/osc"
)
type parser interface {
Parse(data []byte) (*osc.Message, error)
}
type engine struct {
Kind MixerKind
conn *net.UDPConn

View File

@@ -3,18 +3,30 @@ package xair
import "fmt"
type Main struct {
client *Client
baseAddress string
client *Client
}
func newMain(c *Client) *Main {
func newMainStereo(c *Client) *Main {
return &Main{
client: c,
baseAddress: c.addressMap["main"],
client: c,
}
}
/* Still considering the best way to implement main mono support.
func newMainMono(c *Client) *Main {
return &Main{
baseAddress: c.addressMap["mainmono"],
client: c,
}
}
*/
// Fader requests the current main L/R fader level
func (m *Main) Fader() (float64, error) {
err := m.client.SendMessage("/lr/mix/fader")
address := m.baseAddress + "/mix/fader"
err := m.client.SendMessage(address)
if err != nil {
return 0, err
}
@@ -29,12 +41,14 @@ func (m *Main) Fader() (float64, error) {
// SetFader sets the main L/R fader level
func (m *Main) SetFader(level float64) error {
return m.client.SendMessage("/lr/mix/fader", float32(mustDbInto(level)))
address := m.baseAddress + "/mix/fader"
return m.client.SendMessage(address, float32(mustDbInto(level)))
}
// Mute requests the current main L/R mute status
func (m *Main) Mute() (bool, error) {
err := m.client.SendMessage("/lr/mix/on")
address := m.baseAddress + "/mix/on"
err := m.client.SendMessage(address)
if err != nil {
return false, err
}
@@ -49,9 +63,10 @@ func (m *Main) Mute() (bool, error) {
// SetMute sets the main L/R mute status
func (m *Main) SetMute(muted bool) error {
address := m.baseAddress + "/mix/on"
var value int32
if !muted {
value = 1
}
return m.client.SendMessage("/lr/mix/on", value)
return m.client.SendMessage(address, value)
}

4
lr.go
View File

@@ -16,7 +16,7 @@ type MainCmdGroup struct {
// MainMuteCmd defines the command for getting or setting the mute state of the Main L/R output, allowing users to specify the desired state as "true"/"on" or "false"/"off".
type MainMuteCmd struct {
Mute *bool `arg:"" help:"The mute state to set. If not provided, the current state will be printed."`
Mute *bool `arg:"" help:"The mute state to set. If not provided, the current state will be printed." optional:""`
}
// Run executes the MainMuteCmd command, either retrieving the current mute state of the Main L/R output or setting it based on the provided argument.
@@ -39,7 +39,7 @@ func (cmd *MainMuteCmd) Run(ctx *context) error {
// MainFaderCmd defines the command for getting or setting the fader level of the Main L/R output, allowing users to specify the desired level in dB.
type MainFaderCmd struct {
Level *float64 `arg:"" help:"The fader level to set. If not provided, the current level will be printed."`
Level *float64 `arg:"" help:"The fader level to set. If not provided, the current level will be printed." optional:""`
}
// Run executes the MainFaderCmd command, either retrieving the current fader level of the Main L/R output or setting it based on the provided argument.

View File

@@ -32,9 +32,9 @@ type context struct {
}
type Config struct {
Host string `default:"mixer.local" help:"The host of the X-Air device." env:"XAIR_CLI_HOST"`
Port int `default:"10024" help:"The port of the X-Air device." env:"XAIR_CLI_PORT"`
Kind string `default:"xr18" help:"The kind of the X-Air device." env:"XAIR_CLI_KIND"`
Host string `default:"mixer.local" help:"The host of the X-Air device." env:"XAIR_CLI_HOST" short:"H"`
Port int `default:"10024" help:"The port of the X-Air device." env:"XAIR_CLI_PORT" short:"P"`
Kind string `default:"xr18" help:"The kind of the X-Air device." env:"XAIR_CLI_KIND" short:"K"`
}
// CLI is the main struct for the command-line interface.

6
raw.go
View File

@@ -7,9 +7,9 @@ import (
// RawCmd represents the command to send raw OSC messages to the mixer.
type RawCmd struct {
Timeout time.Duration `help:"Timeout for the OSC message send operation." default:"200ms" short:"t"`
Address string `help:"The OSC address to send the message to." arg:""`
Args []string `help:"The arguments to include in the OSC message." arg:"" optional:""`
Timeout time.Duration `help:"Timeout for the OSC message send operation." default:"100ms" short:"t" env:"XAIR_CLI_RAW_TIMEOUT"`
Address string `help:"The OSC address to send the message to." arg:""`
Args []string `help:"The arguments to include in the OSC message." arg:"" optional:""`
}
// Run executes the RawCmd by sending the specified OSC message to the mixer and optionally waiting for a response.