Compare commits

...

9 Commits

5 changed files with 136 additions and 24 deletions

View File

@ -14,9 +14,18 @@ go install github.com/onyx-and-iris/xair-cli@latest
- --port/-P: Port of the mixer. - --port/-P: Port of the mixer.
- --kind/-k: The kind of mixer. May be one of (*xair*, *x32*). - --kind/-k: The kind of mixer. May be one of (*xair*, *x32*).
- Use this flag to connect to an x32 mixer. - Use this flag to connect to an x32 mixer.
- --loglevel/-L: The application's logging verbosity.
Pass `--host` and any other configuration as flags on the root commmand:
```console
xair-cli --host mixer.local --kind xair --timeout 50ms --help
```
#### Environment Variables #### Environment Variables
Or you may load them from your environment:
Example .envrc: Example .envrc:
```bash ```bash
@ -26,6 +35,7 @@ XAIR_CLI_HOST=mixer.local
XAIR_CLI_PORT=10024 XAIR_CLI_PORT=10024
XAIR_CLI_KIND=xair XAIR_CLI_KIND=xair
XAIR_CLI_TIMEOUT=100ms XAIR_CLI_TIMEOUT=100ms
XAIR_CLI_LOGLEVEL=warn
``` ```
### Use ### Use
@ -41,6 +51,7 @@ Flags:
-P, --port=10024 The port of the X-Air device ($XAIR_CLI_PORT). -P, --port=10024 The port of the X-Air device ($XAIR_CLI_PORT).
-K, --kind="xair" The kind of the X-Air device ($XAIR_CLI_KIND). -K, --kind="xair" The kind of the X-Air device ($XAIR_CLI_KIND).
-T, --timeout=100ms Timeout for OSC operations ($XAIR_CLI_TIMEOUT). -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 -v, --version Print xair-cli version information and quit
Commands: Commands:
@ -110,6 +121,13 @@ Headamp
headamp <index> gain Get or set the gain of the 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. 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. Run "xair-cli <command> --help" for more information on a command.
``` ```
@ -156,6 +174,11 @@ xair-cli raw /ch/01/config/name 'rode podmic'
xair-cli raw /ch/01/config/name xair-cli raw /ch/01/config/name
``` ```
*Save current mixer state to a snapshot*
```console
xair-cli snapshot 20 save 'twitch live'
```
### License ### License

View File

@ -13,7 +13,7 @@ var x32AddressMap = map[string]string{
"mainmono": "/main/mono", "mainmono": "/main/mono",
"strip": "/ch/%02d", "strip": "/ch/%02d",
"bus": "/bus/%02d", "bus": "/bus/%02d",
"headamp": "/headamp/%02d", "headamp": "/headamp/%03d",
"snapshot": "/-snap", "snapshot": "/-snap",
} }

View File

@ -16,7 +16,7 @@ func NewSnapshot(c *Client) *Snapshot {
// Name gets the name of the snapshot at the given index. // Name gets the name of the snapshot at the given index.
func (s *Snapshot) Name(index int) (string, error) { func (s *Snapshot) Name(index int) (string, error) {
address := s.baseAddress + fmt.Sprintf("/name/%d", index) address := s.baseAddress + fmt.Sprintf("/%02d/name", index)
err := s.client.SendMessage(address) err := s.client.SendMessage(address)
if err != nil { if err != nil {
return "", err return "", err
@ -35,24 +35,30 @@ func (s *Snapshot) Name(index int) (string, error) {
// SetName sets the name of the snapshot at the given index. // SetName sets the name of the snapshot at the given index.
func (s *Snapshot) SetName(index int, name string) error { func (s *Snapshot) SetName(index int, name string) error {
address := s.baseAddress + fmt.Sprintf("/name/%d", index) address := s.baseAddress + fmt.Sprintf("/%02d/name", index)
return s.client.SendMessage(address, name) return s.client.SendMessage(address, name)
} }
// Load loads the snapshot at the given index. // CurrentName sets the name of the current snapshot.
func (s *Snapshot) Load(index int) error { func (s *Snapshot) CurrentName(name string) error {
address := s.baseAddress + fmt.Sprintf("/load/%d", index) address := s.baseAddress + "/name"
return s.client.SendMessage(address) return s.client.SendMessage(address, name)
} }
// Save saves the current state to the snapshot at the given index. // CurrentLoad loads the snapshot at the given index.
func (s *Snapshot) Save(index int) error { func (s *Snapshot) CurrentLoad(index int) error {
address := s.baseAddress + fmt.Sprintf("/save/%d", index) address := s.baseAddress + "/load"
return s.client.SendMessage(address) return s.client.SendMessage(address, int32(index))
} }
// Delete deletes the snapshot at the given index. // CurrentSave saves the current state to the snapshot at the given index.
func (s *Snapshot) Delete(index int) error { func (s *Snapshot) CurrentSave(index int) error {
address := s.baseAddress + fmt.Sprintf("/delete/%d", index) address := s.baseAddress + "/save"
return s.client.SendMessage(address) return s.client.SendMessage(address, int32(index))
}
// CurrentDelete deletes the snapshot at the given index.
func (s *Snapshot) CurrentDelete(index int) error {
address := s.baseAddress + "/delete"
return s.client.SendMessage(address, int32(index))
} }

View File

@ -37,6 +37,7 @@ type Config struct {
Port int `default:"10024" help:"The port of the X-Air device." env:"XAIR_CLI_PORT" short:"P"` Port int `default:"10024" help:"The port of the X-Air device." env:"XAIR_CLI_PORT" short:"P"`
Kind string `default:"xair" help:"The kind of the X-Air device." env:"XAIR_CLI_KIND" short:"K" enum:"xair,x32"` Kind string `default:"xair" help:"The kind of the X-Air device." env:"XAIR_CLI_KIND" short:"K" enum:"xair,x32"`
Timeout time.Duration `default:"100ms" help:"Timeout for OSC operations." env:"XAIR_CLI_TIMEOUT" short:"T"` Timeout time.Duration `default:"100ms" help:"Timeout for OSC operations." env:"XAIR_CLI_TIMEOUT" short:"T"`
Loglevel string `default:"warn" help:"Log level for the CLI." env:"XAIR_CLI_LOGLEVEL" short:"L" enum:"debug,info,warn,error,fatal"`
} }
// CLI is the main struct for the command-line interface. // CLI is the main struct for the command-line interface.
@ -53,6 +54,7 @@ type CLI struct {
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"`
Headamp HeadampCmdGroup `help:"Control input gain and phantom power." cmd:"" group:"Headamp"` Headamp HeadampCmdGroup `help:"Control input gain and phantom power." cmd:"" group:"Headamp"`
Snapshot SnapshotCmdGroup `help:"Save and load mixer states." cmd:"" group:"Snapshot"`
} }
func main() { func main() {
@ -86,6 +88,12 @@ func main() {
// run is the main entry point for the CLI. // run is the main entry point for the CLI.
// It connects to the X-Air device, retrieves mixer info, and then runs the command. // It connects to the X-Air device, retrieves mixer info, and then runs the command.
func run(ctx *kong.Context, config Config) error { func run(ctx *kong.Context, config Config) error {
loglevel, err := log.ParseLevel(config.Loglevel)
if err != nil {
return fmt.Errorf("invalid log level: %w", err)
}
log.SetLevel(loglevel)
client, err := connect(config) client, err := connect(config)
if err != nil { if err != nil {
return fmt.Errorf("failed to connect to X-Air device: %w", err) return fmt.Errorf("failed to connect to X-Air device: %w", err)

75
snapshot.go Normal file
View File

@ -0,0 +1,75 @@
package main
import "fmt"
type SnapshotCmdGroup struct {
List ListCmd `help:"List all snapshots." cmd:"list"`
Index struct {
Index int `arg:"" help:"The index of the snapshot."`
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"`
Delete DeleteCmd `help:"Delete a snapshot." cmd:"delete"`
} `help:"The index of the snapshot." arg:""`
}
type ListCmd struct {
}
func (c *ListCmd) Run(ctx *context) error {
for i := range 64 {
name, err := ctx.Client.Snapshot.Name(i + 1)
if err != nil {
break
}
if name == "" {
continue
}
fmt.Fprintf(ctx.Out, "%d: %s\n", i+1, name)
}
return nil
}
type NameCmd struct {
Name *string `arg:"" help:"The name of the snapshot." optional:""`
}
func (c *NameCmd) Run(ctx *context, snapshot *SnapshotCmdGroup) error {
if c.Name == nil {
name, err := ctx.Client.Snapshot.Name(snapshot.Index.Index)
if err != nil {
return err
}
fmt.Fprintln(ctx.Out, name)
return nil
}
return ctx.Client.Snapshot.SetName(snapshot.Index.Index, *c.Name)
}
type SaveCmd struct {
Name string `arg:"" help:"The name of the snapshot."`
}
func (c *SaveCmd) Run(ctx *context, snapshot *SnapshotCmdGroup) error {
err := ctx.Client.Snapshot.CurrentName(c.Name)
if err != nil {
return err
}
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)
}
type DeleteCmd struct {
}
func (c *DeleteCmd) Run(ctx *context, snapshot *SnapshotCmdGroup) error {
return ctx.Client.Snapshot.CurrentDelete(snapshot.Index.Index)
}