5 Commits

Author SHA1 Message Date
49cf3ff49e upd Name methods 2026-02-04 11:18:17 +00:00
66ab937296 implement Snapshot on Client struct 2026-02-04 11:15:52 +00:00
6f995397a1 fix example 2026-02-04 10:46:20 +00:00
e6d6ac77f6 upd long desc 2026-02-04 10:45:26 +00:00
b39dc86236 add raw command for sending raw OSC messages 2026-02-04 10:44:06 +00:00
5 changed files with 138 additions and 7 deletions

View File

@@ -23,6 +23,7 @@ Available Commands:
headamp Commands to control headamp gain and phantom power headamp Commands to control headamp gain and phantom power
help Help about any command help Help about any command
main Commands to control the main output main Commands to control the main output
raw Send a raw OSC message to the mixer
strip Commands to control individual strips strip Commands to control individual strips
Flags: Flags:

58
cmd/raw.go Normal file
View File

@@ -0,0 +1,58 @@
package cmd
import (
"fmt"
"time"
"github.com/spf13/cobra"
)
// rawCmd represents the raw command
var rawCmd = &cobra.Command{
Short: "Send a raw OSC message to the mixer",
Long: `Send a raw OSC message to the mixer.
You need to provide the OSC address and any parameters as arguments.
Optionally provide a timeout duration to wait for a response from the mixer. Default is 200ms.`,
Use: "raw",
Example: ` xair-cli raw /xinfo
xair-cli raw /ch/01/mix/fader 0.75
xair-cli raw --timeout 500ms /bus/2/mix/on 1`,
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
client := ClientFromContext(cmd.Context())
if client == nil {
return fmt.Errorf("no client found in context")
}
command := args[0]
params := make([]any, len(args[1:]))
for i, arg := range args[1:] {
params[i] = arg
}
if err := client.SendMessage(command, params...); err != nil {
return fmt.Errorf("error sending message: %v", err)
}
timeout, err := cmd.Flags().GetDuration("timeout")
if err != nil {
return fmt.Errorf("error getting timeout flag: %v", err)
}
msg, err := client.ReceiveMessage(timeout)
if err != nil {
return fmt.Errorf("error receiving message: %v", err)
}
if msg != nil {
fmt.Printf("Received response: %v\n", msg)
}
return nil
},
}
func init() {
rootCmd.AddCommand(rawCmd)
rawCmd.Flags().DurationP("timeout", "t", 200*time.Millisecond, "Timeout duration for receiving a response")
}

View File

@@ -1,9 +1,10 @@
package xair package xair
var xairAddressMap = map[string]string{ var xairAddressMap = map[string]string{
"strip": "/ch/%02d", "strip": "/ch/%02d",
"bus": "/bus/%01d", "bus": "/bus/%01d",
"headamp": "/headamp/%02d", "headamp": "/headamp/%02d",
"snapshot": "/-snap",
} }
var x32AddressMap = map[string]string{ var x32AddressMap = map[string]string{

View File

@@ -3,6 +3,7 @@ package xair
import ( import (
"fmt" "fmt"
"net" "net"
"time"
"github.com/charmbracelet/log" "github.com/charmbracelet/log"
@@ -15,10 +16,11 @@ type parser interface {
type Client struct { type Client struct {
engine engine
Main *Main Main *Main
Strip *Strip Strip *Strip
Bus *Bus Bus *Bus
HeadAmp *HeadAmp HeadAmp *HeadAmp
Snapshot *Snapshot
} }
// NewClient creates a new XAirClient instance // NewClient creates a new XAirClient instance
@@ -85,6 +87,20 @@ 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
func (c *Client) ReceiveMessage(timeout time.Duration) (*osc.Message, error) {
t := time.Tick(timeout)
select {
case <-t:
return nil, nil
case val := <-c.respChan:
if val == nil {
return nil, fmt.Errorf("no message received")
}
return val, nil
}
}
// RequestInfo requests mixer information // RequestInfo requests mixer information
func (c *Client) RequestInfo() (error, InfoResponse) { func (c *Client) RequestInfo() (error, InfoResponse) {
err := c.SendMessage("/xinfo") err := c.SendMessage("/xinfo")

55
internal/xair/snapshot.go Normal file
View File

@@ -0,0 +1,55 @@
package xair
import "fmt"
type Snapshot struct {
baseAddress string
client *Client
}
func NewSnapshot(c *Client) *Snapshot {
return &Snapshot{
baseAddress: c.addressMap["snapshot"],
client: c,
}
}
// Name gets the name of the snapshot at the given index.
func (s *Snapshot) Name(index int) (string, error) {
address := s.baseAddress + fmt.Sprintf("/name/%d", index)
err := s.client.SendMessage(address)
if err != nil {
return "", err
}
resp := <-s.client.respChan
name, ok := resp.Arguments[0].(string)
if !ok {
return "", fmt.Errorf("unexpected argument type for snapshot name")
}
return name, nil
}
// SetName sets the name of the snapshot at the given index.
func (s *Snapshot) SetName(index int, name string) error {
address := s.baseAddress + fmt.Sprintf("/name/%d", index)
return s.client.SendMessage(address, name)
}
// Load loads the snapshot at the given index.
func (s *Snapshot) Load(index int) error {
address := s.baseAddress + fmt.Sprintf("/load/%d", index)
return s.client.SendMessage(address)
}
// Save saves the current state to the snapshot at the given index.
func (s *Snapshot) Save(index int) error {
address := s.baseAddress + fmt.Sprintf("/save/%d", index)
return s.client.SendMessage(address)
}
// Delete deletes the snapshot at the given index.
func (s *Snapshot) Delete(index int) error {
address := s.baseAddress + fmt.Sprintf("/delete/%d", index)
return s.client.SendMessage(address)
}