mirror of
https://github.com/onyx-and-iris/xair-cli.git
synced 2026-04-09 02:13:35 +00:00
litn fixes
This commit is contained in:
@@ -9,7 +9,7 @@ type Bus struct {
|
||||
Comp *Comp
|
||||
}
|
||||
|
||||
// newBus creates a new Bus instance
|
||||
// newBus creates a new Bus instance.
|
||||
func newBus(c *client) *Bus {
|
||||
return &Bus{
|
||||
client: c,
|
||||
@@ -19,7 +19,7 @@ func newBus(c *client) *Bus {
|
||||
}
|
||||
}
|
||||
|
||||
// Mute requests the current mute status for a bus
|
||||
// Mute requests the current mute status for a bus.
|
||||
func (b *Bus) Mute(bus int) (bool, error) {
|
||||
address := fmt.Sprintf(b.baseAddress, bus) + "/mix/on"
|
||||
err := b.client.SendMessage(address)
|
||||
@@ -38,7 +38,7 @@ func (b *Bus) Mute(bus int) (bool, error) {
|
||||
return val == 0, nil
|
||||
}
|
||||
|
||||
// SetMute sets the mute status for a specific bus (1-based indexing)
|
||||
// SetMute sets the mute status for a specific bus (1-based indexing).
|
||||
func (b *Bus) SetMute(bus int, muted bool) error {
|
||||
address := fmt.Sprintf(b.baseAddress, bus) + "/mix/on"
|
||||
var value int32
|
||||
@@ -48,7 +48,7 @@ func (b *Bus) SetMute(bus int, muted bool) error {
|
||||
return b.client.SendMessage(address, value)
|
||||
}
|
||||
|
||||
// Fader requests the current fader level for a bus
|
||||
// Fader requests the current fader level for a bus.
|
||||
func (b *Bus) Fader(bus int) (float64, error) {
|
||||
address := fmt.Sprintf(b.baseAddress, bus) + "/mix/fader"
|
||||
err := b.client.SendMessage(address)
|
||||
@@ -68,18 +68,18 @@ func (b *Bus) Fader(bus int) (float64, error) {
|
||||
return mustDbFrom(float64(val)), nil
|
||||
}
|
||||
|
||||
// SetFader sets the fader level for a specific bus (1-based indexing)
|
||||
// SetFader sets the fader level for a specific bus (1-based indexing).
|
||||
func (b *Bus) SetFader(bus int, level float64) error {
|
||||
address := fmt.Sprintf(b.baseAddress, bus) + "/mix/fader"
|
||||
return b.client.SendMessage(address, float32(mustDbInto(level)))
|
||||
}
|
||||
|
||||
// Name requests the name for a specific bus
|
||||
// Name requests the name for a specific bus.
|
||||
func (b *Bus) Name(bus int) (string, error) {
|
||||
address := fmt.Sprintf(b.baseAddress, bus) + "/config/name"
|
||||
err := b.client.SendMessage(address)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to send bus name request: %v", err)
|
||||
return "", fmt.Errorf("failed to send bus name request: %w", err)
|
||||
}
|
||||
|
||||
msg, err := b.client.ReceiveMessage()
|
||||
@@ -93,7 +93,7 @@ func (b *Bus) Name(bus int) (string, error) {
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// SetName sets the name for a specific bus
|
||||
// SetName sets the name for a specific bus.
|
||||
func (b *Bus) SetName(bus int, name string) error {
|
||||
address := fmt.Sprintf(b.baseAddress, bus) + "/config/name"
|
||||
return b.client.SendMessage(address, name)
|
||||
|
||||
@@ -5,11 +5,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
|
||||
"github.com/hypebeast/go-osc/osc"
|
||||
)
|
||||
|
||||
// XAirClient is a client for controlling XAir mixers
|
||||
// XAirClient is a client for controlling XAir mixers.
|
||||
type XAirClient struct {
|
||||
client
|
||||
Main *Main
|
||||
@@ -20,7 +19,7 @@ type XAirClient struct {
|
||||
DCA *DCA
|
||||
}
|
||||
|
||||
// NewXAirClient creates a new XAirClient instance with optional engine configuration
|
||||
// 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 {
|
||||
@@ -40,7 +39,7 @@ func NewXAirClient(mixerIP string, mixerPort int, opts ...EngineOption) (*XAirCl
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// X32Client is a client for controlling X32 mixers
|
||||
// X32Client is a client for controlling X32 mixers.
|
||||
type X32Client struct {
|
||||
client
|
||||
Main *Main
|
||||
@@ -53,7 +52,7 @@ type X32Client struct {
|
||||
DCA *DCA
|
||||
}
|
||||
|
||||
// NewX32Client creates a new X32Client instance with optional engine configuration
|
||||
// NewX32Client creates a new X32Client instance with optional engine configuration.
|
||||
func NewX32Client(mixerIP string, mixerPort int, opts ...EngineOption) (*X32Client, error) {
|
||||
e, err := newEngine(mixerIP, mixerPort, kindX32, opts...)
|
||||
if err != nil {
|
||||
@@ -80,28 +79,28 @@ type client struct {
|
||||
Info InfoResponse
|
||||
}
|
||||
|
||||
// Start begins listening for messages in a goroutine
|
||||
// Start begins listening for messages in a goroutine.
|
||||
func (c *client) StartListening() {
|
||||
go c.engine.receiveLoop()
|
||||
go c.receiveLoop()
|
||||
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() {
|
||||
close(c.engine.done)
|
||||
if c.engine.conn != nil {
|
||||
c.engine.conn.Close()
|
||||
close(c.done)
|
||||
if c.conn != nil {
|
||||
c.conn.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 {
|
||||
return c.engine.sendToAddress(c.mixerAddr, address, args...)
|
||||
return c.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) {
|
||||
t := time.Tick(c.engine.timeout)
|
||||
t := time.Tick(c.timeout)
|
||||
select {
|
||||
case <-t:
|
||||
return nil, fmt.Errorf("timeout waiting for response")
|
||||
@@ -113,7 +112,7 @@ func (c *client) ReceiveMessage() (*osc.Message, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// RequestInfo requests mixer information
|
||||
// RequestInfo requests mixer information.
|
||||
func (c *client) RequestInfo() (InfoResponse, error) {
|
||||
var info InfoResponse
|
||||
err := c.SendMessage("/xinfo")
|
||||
@@ -144,12 +143,12 @@ func (c *client) RequestInfo() (InfoResponse, error) {
|
||||
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 {
|
||||
return c.SendMessage("/xremote")
|
||||
}
|
||||
|
||||
// RequestStatus requests mixer status
|
||||
// RequestStatus requests mixer status.
|
||||
func (c *client) RequestStatus() error {
|
||||
return c.SendMessage("/status")
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ type Comp struct {
|
||||
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 {
|
||||
comp := &Comp{
|
||||
client: c,
|
||||
|
||||
@@ -69,9 +69,9 @@ func (d *DCA) SetName(group int, name string) error {
|
||||
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"
|
||||
// Colour requests the current colour for a DCA group
|
||||
func (d *DCA) Colour(group int) (int32, error) {
|
||||
address := fmt.Sprintf(d.baseAddress, group) + "/config/colour"
|
||||
err := d.client.SendMessage(address)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -81,15 +81,15 @@ func (d *DCA) Color(group int) (int32, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
color, ok := msg.Arguments[0].(int32)
|
||||
colour, ok := msg.Arguments[0].(int32)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("unexpected argument type for DCA color value")
|
||||
return 0, fmt.Errorf("unexpected argument type for DCA colour value")
|
||||
}
|
||||
return color, nil
|
||||
return colour, 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)
|
||||
// SetColor sets the colour for a specific DCA group (1-based indexing)
|
||||
func (d *DCA) SetColor(group int, colour int32) error {
|
||||
address := fmt.Sprintf(d.baseAddress, group) + "/config/colour"
|
||||
return d.client.SendMessage(address, colour)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package xair
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
@@ -26,21 +27,26 @@ type engine struct {
|
||||
respChan chan *osc.Message
|
||||
}
|
||||
|
||||
func newEngine(mixerIP string, mixerPort int, kind mixerKind, opts ...EngineOption) (*engine, error) {
|
||||
func newEngine(
|
||||
mixerIP string,
|
||||
mixerPort int,
|
||||
kind mixerKind,
|
||||
opts ...EngineOption,
|
||||
) (*engine, error) {
|
||||
localAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", 0))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to resolve local address: %v", err)
|
||||
return nil, fmt.Errorf("failed to resolve local address: %w", err)
|
||||
}
|
||||
|
||||
conn, err := net.ListenUDP("udp", localAddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create UDP connection: %v", err)
|
||||
return nil, fmt.Errorf("failed to create UDP connection: %w", err)
|
||||
}
|
||||
|
||||
mixerAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", mixerIP, mixerPort))
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("failed to resolve mixer address: %v", err)
|
||||
return nil, fmt.Errorf("failed to resolve mixer address: %w", err)
|
||||
}
|
||||
|
||||
log.Debugf("Local UDP connection: %s ", conn.LocalAddr().String())
|
||||
@@ -62,7 +68,7 @@ func newEngine(mixerIP string, mixerPort int, kind mixerKind, opts ...EngineOpti
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// receiveLoop handles incoming OSC messages
|
||||
// receiveLoop handles incoming OSC messages.
|
||||
func (e *engine) receiveLoop() {
|
||||
buffer := make([]byte, 4096)
|
||||
|
||||
@@ -75,7 +81,8 @@ func (e *engine) receiveLoop() {
|
||||
e.conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
|
||||
n, _, err := e.conn.ReadFromUDP(buffer)
|
||||
if err != nil {
|
||||
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
|
||||
var netErr net.Error
|
||||
if errors.As(err, &netErr) {
|
||||
// Timeout is expected, continue loop
|
||||
continue
|
||||
}
|
||||
@@ -99,7 +106,7 @@ func (e *engine) receiveLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
// parseOSCMessage parses raw bytes into an OSC message with improved error handling
|
||||
// parseOSCMessage parses raw bytes into an OSC message with improved error handling.
|
||||
func (e *engine) parseOSCMessage(data []byte) (*osc.Message, error) {
|
||||
msg, err := e.parser.Parse(data)
|
||||
if err != nil {
|
||||
@@ -109,7 +116,7 @@ func (e *engine) parseOSCMessage(data []byte) (*osc.Message, error) {
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// sendToAddress sends an OSC message to a specific address (enables replying to different ports)
|
||||
// sendToAddress sends an OSC message to a specific address (enables replying to different ports).
|
||||
func (e *engine) sendToAddress(addr *net.UDPAddr, oscAddress string, args ...any) error {
|
||||
msg := osc.NewMessage(oscAddress)
|
||||
for _, arg := range args {
|
||||
@@ -130,7 +137,7 @@ func (e *engine) sendToAddress(addr *net.UDPAddr, oscAddress string, args ...any
|
||||
|
||||
data, err := msg.MarshalBinary()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal message: %v", err)
|
||||
return fmt.Errorf("failed to marshal message: %w", err)
|
||||
}
|
||||
|
||||
_, err = e.conn.WriteToUDP(data, addr)
|
||||
|
||||
@@ -11,7 +11,7 @@ type Eq struct {
|
||||
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 {
|
||||
eq := &Eq{
|
||||
client: c,
|
||||
@@ -82,7 +82,7 @@ func (e *Eq) SetMode(index int, mode string) error {
|
||||
}
|
||||
|
||||
// Gain retrieves the gain for a specific EQ band on a strip or bus (1-based indexing).
|
||||
func (e *Eq) Gain(index int, band int) (float64, error) {
|
||||
func (e *Eq) Gain(index, band int) (float64, error) {
|
||||
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/g", band)
|
||||
err := e.client.SendMessage(address)
|
||||
if err != nil {
|
||||
@@ -101,13 +101,13 @@ func (e *Eq) Gain(index int, band int) (float64, error) {
|
||||
}
|
||||
|
||||
// SetGain sets the gain for a specific EQ band on a strip or bus (1-based indexing).
|
||||
func (e *Eq) SetGain(index int, band int, gain float64) error {
|
||||
func (e *Eq) SetGain(index, band int, gain float64) error {
|
||||
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/g", band)
|
||||
return e.client.SendMessage(address, float32(linSet(-15, 15, gain)))
|
||||
}
|
||||
|
||||
// Frequency retrieves the frequency for a specific EQ band on a strip or bus (1-based indexing).
|
||||
func (e *Eq) Frequency(index int, band int) (float64, error) {
|
||||
func (e *Eq) Frequency(index, band int) (float64, error) {
|
||||
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/f", band)
|
||||
err := e.client.SendMessage(address)
|
||||
if err != nil {
|
||||
@@ -126,13 +126,13 @@ func (e *Eq) Frequency(index int, band int) (float64, error) {
|
||||
}
|
||||
|
||||
// SetFrequency sets the frequency for a specific EQ band on a strip or bus (1-based indexing).
|
||||
func (e *Eq) SetFrequency(index int, band int, frequency float64) error {
|
||||
func (e *Eq) SetFrequency(index, band int, frequency float64) error {
|
||||
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/f", band)
|
||||
return e.client.SendMessage(address, float32(logSet(20, 20000, frequency)))
|
||||
}
|
||||
|
||||
// Q retrieves the Q factor for a specific EQ band on a strip or bus (1-based indexing).
|
||||
func (e *Eq) Q(index int, band int) (float64, error) {
|
||||
func (e *Eq) Q(index, band int) (float64, error) {
|
||||
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/q", band)
|
||||
err := e.client.SendMessage(address)
|
||||
if err != nil {
|
||||
@@ -151,13 +151,13 @@ func (e *Eq) Q(index int, band int) (float64, error) {
|
||||
}
|
||||
|
||||
// SetQ sets the Q factor for a specific EQ band on a strip or bus (1-based indexing).
|
||||
func (e *Eq) SetQ(index int, band int, q float64) error {
|
||||
func (e *Eq) SetQ(index, band int, q float64) error {
|
||||
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/q", band)
|
||||
return e.client.SendMessage(address, float32(1.0-logSet(0.3, 10, q)))
|
||||
}
|
||||
|
||||
// Type retrieves the type for a specific EQ band on a strip or bus (1-based indexing).
|
||||
func (e *Eq) Type(index int, band int) (string, error) {
|
||||
func (e *Eq) Type(index, band int) (string, error) {
|
||||
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/type", band)
|
||||
err := e.client.SendMessage(address)
|
||||
if err != nil {
|
||||
@@ -178,7 +178,7 @@ func (e *Eq) Type(index int, band int) (string, error) {
|
||||
}
|
||||
|
||||
// SetType sets the type for a specific EQ band on a strip or bus (1-based indexing).
|
||||
func (e *Eq) SetType(index int, band int, eqType string) error {
|
||||
func (e *Eq) SetType(index, band int, eqType string) error {
|
||||
address := e.AddressFunc(e.baseAddress, index) + fmt.Sprintf("/%d/type", band)
|
||||
possibleTypes := []string{"lcut", "lshv", "peq", "veq", "hshv", "hcut"}
|
||||
return e.client.SendMessage(address, int32(indexOf(possibleTypes, eqType)))
|
||||
|
||||
@@ -9,7 +9,7 @@ type Gate struct {
|
||||
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 {
|
||||
gate := &Gate{
|
||||
client: c,
|
||||
|
||||
@@ -9,7 +9,7 @@ type Main struct {
|
||||
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 {
|
||||
addressFunc := func(fmtString string, args ...any) string {
|
||||
return fmtString
|
||||
@@ -23,7 +23,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 {
|
||||
addressFunc := func(fmtString string, args ...any) string {
|
||||
return fmtString
|
||||
@@ -37,7 +37,7 @@ func newMainMono(c *client) *Main {
|
||||
}
|
||||
}
|
||||
|
||||
// Fader requests the current main L/R fader level
|
||||
// Fader requests the current main L/R fader level.
|
||||
func (m *Main) Fader() (float64, error) {
|
||||
address := m.baseAddress + "/mix/fader"
|
||||
err := m.client.SendMessage(address)
|
||||
@@ -56,13 +56,13 @@ func (m *Main) Fader() (float64, error) {
|
||||
return mustDbFrom(float64(val)), nil
|
||||
}
|
||||
|
||||
// SetFader sets the main L/R fader level
|
||||
// SetFader sets the main L/R fader level.
|
||||
func (m *Main) SetFader(level float64) error {
|
||||
address := m.baseAddress + "/mix/fader"
|
||||
return m.client.SendMessage(address, float32(mustDbInto(level)))
|
||||
}
|
||||
|
||||
// Mute requests the current main L/R mute status
|
||||
// Mute requests the current main L/R mute status.
|
||||
func (m *Main) Mute() (bool, error) {
|
||||
address := m.baseAddress + "/mix/on"
|
||||
err := m.client.SendMessage(address)
|
||||
@@ -81,7 +81,7 @@ func (m *Main) Mute() (bool, error) {
|
||||
return val == 0, nil
|
||||
}
|
||||
|
||||
// SetMute sets the main L/R mute status
|
||||
// SetMute sets the main L/R mute status.
|
||||
func (m *Main) SetMute(muted bool) error {
|
||||
address := m.baseAddress + "/mix/on"
|
||||
var value int32
|
||||
|
||||
@@ -9,7 +9,7 @@ type Matrix struct {
|
||||
Comp *Comp
|
||||
}
|
||||
|
||||
// newMatrix creates a new Matrix instance
|
||||
// newMatrix creates a new Matrix instance.
|
||||
func newMatrix(c *client) *Matrix {
|
||||
return &Matrix{
|
||||
client: c,
|
||||
@@ -19,7 +19,7 @@ func newMatrix(c *client) *Matrix {
|
||||
}
|
||||
}
|
||||
|
||||
// Fader requests the current main L/R fader level
|
||||
// Fader requests the current main L/R fader level.
|
||||
func (m *Matrix) Fader(index int) (float64, error) {
|
||||
address := fmt.Sprintf(m.baseAddress, index) + "/mix/fader"
|
||||
err := m.client.SendMessage(address)
|
||||
@@ -38,13 +38,13 @@ func (m *Matrix) Fader(index int) (float64, error) {
|
||||
return mustDbFrom(float64(val)), nil
|
||||
}
|
||||
|
||||
// SetFader sets the matrix fader level
|
||||
// SetFader sets the matrix fader level.
|
||||
func (m *Matrix) SetFader(index int, level float64) error {
|
||||
address := fmt.Sprintf(m.baseAddress, index) + "/mix/fader"
|
||||
return m.client.SendMessage(address, float32(mustDbInto(level)))
|
||||
}
|
||||
|
||||
// Mute requests the current matrix mute status
|
||||
// Mute requests the current matrix mute status.
|
||||
func (m *Matrix) Mute(index int) (bool, error) {
|
||||
address := fmt.Sprintf(m.baseAddress, index) + "/mix/on"
|
||||
err := m.client.SendMessage(address)
|
||||
@@ -63,7 +63,7 @@ func (m *Matrix) Mute(index int) (bool, error) {
|
||||
return val == 0, nil
|
||||
}
|
||||
|
||||
// SetMute sets the matrix mute status
|
||||
// SetMute sets the matrix mute status.
|
||||
func (m *Matrix) SetMute(index int, muted bool) error {
|
||||
address := fmt.Sprintf(m.baseAddress, index) + "/mix/on"
|
||||
var value int32
|
||||
|
||||
@@ -4,7 +4,7 @@ import "time"
|
||||
|
||||
type EngineOption func(*engine)
|
||||
|
||||
// WithTimeout sets the timeout duration for OSC message responses
|
||||
// WithTimeout sets the timeout duration for OSC message responses.
|
||||
func WithTimeout(timeout time.Duration) EngineOption {
|
||||
return func(e *engine) {
|
||||
e.timeout = timeout
|
||||
@@ -13,7 +13,7 @@ func WithTimeout(timeout time.Duration) EngineOption {
|
||||
|
||||
type CompOption func(*Comp)
|
||||
|
||||
// WithCompAddressFunc allows customization of the OSC address formatting for Comp parameters
|
||||
// WithCompAddressFunc allows customization of the OSC address formatting for Comp parameters.
|
||||
func WithCompAddressFunc(f func(fmtString string, args ...any) string) CompOption {
|
||||
return func(c *Comp) {
|
||||
c.AddressFunc = f
|
||||
@@ -22,7 +22,7 @@ func WithCompAddressFunc(f func(fmtString string, args ...any) string) CompOptio
|
||||
|
||||
type EqOption func(*Eq)
|
||||
|
||||
// WithEqAddressFunc allows customization of the OSC address formatting for Eq parameters
|
||||
// WithEqAddressFunc allows customization of the OSC address formatting for Eq parameters.
|
||||
func WithEqAddressFunc(f func(fmtString string, args ...any) string) EqOption {
|
||||
return func(e *Eq) {
|
||||
e.AddressFunc = f
|
||||
@@ -31,7 +31,7 @@ func WithEqAddressFunc(f func(fmtString string, args ...any) string) EqOption {
|
||||
|
||||
type GateOption func(*Gate)
|
||||
|
||||
// WithGateAddressFunc allows customization of the OSC address formatting for Gate parameters
|
||||
// WithGateAddressFunc allows customization of the OSC address formatting for Gate parameters.
|
||||
func WithGateAddressFunc(f func(fmtString string, args ...any) string) GateOption {
|
||||
return func(g *Gate) {
|
||||
g.AddressFunc = f
|
||||
|
||||
@@ -10,14 +10,13 @@ import (
|
||||
"github.com/hypebeast/go-osc/osc"
|
||||
)
|
||||
|
||||
type xairParser struct {
|
||||
}
|
||||
type xairParser struct{}
|
||||
|
||||
func newParser() *xairParser {
|
||||
return &xairParser{}
|
||||
}
|
||||
|
||||
// parseOSCMessage parses raw bytes into an OSC message with improved error handling
|
||||
// parseOSCMessage parses raw bytes into an OSC message with improved error handling.
|
||||
func (p *xairParser) Parse(data []byte) (*osc.Message, error) {
|
||||
log.Debug("=== PARSING OSC MESSAGE BEGIN ===")
|
||||
defer log.Debug("=== PARSING OSC MESSAGE END ===")
|
||||
@@ -47,7 +46,7 @@ func (p *xairParser) Parse(data []byte) (*osc.Message, error) {
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// validateOSCData performs basic validation on OSC message data
|
||||
// validateOSCData performs basic validation on OSC message data.
|
||||
func (p *xairParser) validateOSCData(data []byte) error {
|
||||
if len(data) < 4 {
|
||||
return fmt.Errorf("data too short for OSC message")
|
||||
@@ -58,7 +57,7 @@ func (p *xairParser) validateOSCData(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// extractOSCAddress extracts the OSC address from the message data
|
||||
// extractOSCAddress extracts the OSC address from the message data.
|
||||
func (p *xairParser) extractOSCAddress(data []byte) (address string, nextPos int, err error) {
|
||||
nullPos := bytes.IndexByte(data, 0)
|
||||
if nullPos <= 0 {
|
||||
@@ -73,8 +72,11 @@ func (p *xairParser) extractOSCAddress(data []byte) (address string, nextPos int
|
||||
return address, nextPos, nil
|
||||
}
|
||||
|
||||
// extractOSCTypeTags extracts and validates OSC type tags
|
||||
func (p *xairParser) extractOSCTypeTags(data []byte, start int) (typeTags string, nextPos int, err error) {
|
||||
// extractOSCTypeTags extracts and validates OSC type tags.
|
||||
func (p *xairParser) extractOSCTypeTags(
|
||||
data []byte,
|
||||
start int,
|
||||
) (typeTags string, nextPos int, err error) {
|
||||
if start >= len(data) {
|
||||
return "", start, nil // No type tags available
|
||||
}
|
||||
@@ -97,8 +99,13 @@ func (p *xairParser) extractOSCTypeTags(data []byte, start int) (typeTags string
|
||||
return typeTags, nextPos, nil
|
||||
}
|
||||
|
||||
// parseOSCArguments parses OSC arguments based on type tags
|
||||
func (p *xairParser) parseOSCArguments(data []byte, argsStart int, typeTags string, msg *osc.Message) error {
|
||||
// parseOSCArguments parses OSC arguments based on type tags.
|
||||
func (p *xairParser) parseOSCArguments(
|
||||
data []byte,
|
||||
argsStart int,
|
||||
typeTags string,
|
||||
msg *osc.Message,
|
||||
) error {
|
||||
argData := data[argsStart:]
|
||||
argNum := 0
|
||||
|
||||
@@ -138,7 +145,7 @@ func (p *xairParser) parseOSCArguments(data []byte, argsStart int, typeTags stri
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseStringArgument parses a string argument from OSC data
|
||||
// parseStringArgument parses a string argument from OSC data.
|
||||
func (p *xairParser) parseStringArgument(data []byte, msg *osc.Message, argNum int) (int, error) {
|
||||
nullPos := bytes.IndexByte(data, 0)
|
||||
if nullPos < 0 {
|
||||
@@ -153,7 +160,7 @@ func (p *xairParser) parseStringArgument(data []byte, msg *osc.Message, argNum i
|
||||
return ((nullPos + 4) / 4) * 4, nil
|
||||
}
|
||||
|
||||
// parseInt32Argument parses an int32 argument from OSC data
|
||||
// parseInt32Argument parses an int32 argument from OSC data.
|
||||
func (p *xairParser) parseInt32Argument(data []byte, msg *osc.Message, argNum int) (int, error) {
|
||||
if len(data) < 4 {
|
||||
return 0, fmt.Errorf("insufficient data for int32")
|
||||
@@ -166,7 +173,7 @@ func (p *xairParser) parseInt32Argument(data []byte, msg *osc.Message, argNum in
|
||||
return 4, nil
|
||||
}
|
||||
|
||||
// parseFloat32Argument parses a float32 argument from OSC data
|
||||
// parseFloat32Argument parses a float32 argument from OSC data.
|
||||
func (p *xairParser) parseFloat32Argument(data []byte, msg *osc.Message, argNum int) (int, error) {
|
||||
if len(data) < 4 {
|
||||
return 0, fmt.Errorf("insufficient data for float32")
|
||||
@@ -179,7 +186,7 @@ func (p *xairParser) parseFloat32Argument(data []byte, msg *osc.Message, argNum
|
||||
return 4, nil
|
||||
}
|
||||
|
||||
// parseBlobArgument parses a blob argument from OSC data
|
||||
// parseBlobArgument parses a blob argument from OSC data.
|
||||
func (p *xairParser) parseBlobArgument(data []byte, msg *osc.Message, argNum int) (int, error) {
|
||||
if len(data) < 4 {
|
||||
return 0, fmt.Errorf("insufficient data for blob size")
|
||||
@@ -203,7 +210,7 @@ func (p *xairParser) parseBlobArgument(data []byte, msg *osc.Message, argNum int
|
||||
return ((4 + int(size) + 3) / 4) * 4, nil
|
||||
}
|
||||
|
||||
// skipUnknownArgument skips an unknown argument type
|
||||
// skipUnknownArgument skips an unknown argument type.
|
||||
func (p *xairParser) skipUnknownArgument(data []byte) int {
|
||||
// Skip unknown types by moving 4 bytes if available
|
||||
if len(data) >= 4 {
|
||||
|
||||
@@ -7,7 +7,7 @@ type Snapshot struct {
|
||||
baseAddress string
|
||||
}
|
||||
|
||||
// newSnapshot creates a new Snapshot instance
|
||||
// newSnapshot creates a new Snapshot instance.
|
||||
func newSnapshot(c *client) *Snapshot {
|
||||
return &Snapshot{
|
||||
client: c,
|
||||
|
||||
@@ -81,7 +81,7 @@ func (s *Strip) Name(strip int) (string, error) {
|
||||
address := fmt.Sprintf(s.baseAddress, strip) + "/config/name"
|
||||
err := s.client.SendMessage(address)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to send strip name request: %v", err)
|
||||
return "", fmt.Errorf("failed to send strip name request: %w", err)
|
||||
}
|
||||
|
||||
msg, err := s.client.ReceiveMessage()
|
||||
@@ -101,12 +101,12 @@ func (s *Strip) SetName(strip int, name string) error {
|
||||
return s.client.SendMessage(address, name)
|
||||
}
|
||||
|
||||
// Color requests the color for a specific strip
|
||||
func (s *Strip) Color(strip int) (int32, error) {
|
||||
address := fmt.Sprintf(s.baseAddress, strip) + "/config/color"
|
||||
// Colour requests the colour for a specific strip
|
||||
func (s *Strip) Colour(strip int) (int32, error) {
|
||||
address := fmt.Sprintf(s.baseAddress, strip) + "/config/colour"
|
||||
err := s.client.SendMessage(address)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to send strip color request: %v", err)
|
||||
return 0, fmt.Errorf("failed to send strip colour request: %w", err)
|
||||
}
|
||||
|
||||
msg, err := s.client.ReceiveMessage()
|
||||
@@ -115,23 +115,23 @@ func (s *Strip) Color(strip int) (int32, error) {
|
||||
}
|
||||
val, ok := msg.Arguments[0].(int32)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("unexpected argument type for strip color value")
|
||||
return 0, fmt.Errorf("unexpected argument type for strip colour value")
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// SetColor sets the color for a specific strip (0-15)
|
||||
func (s *Strip) SetColor(strip int, color int32) error {
|
||||
address := fmt.Sprintf(s.baseAddress, strip) + "/config/color"
|
||||
return s.client.SendMessage(address, color)
|
||||
// SetColor sets the colour for a specific strip (0-15)
|
||||
func (s *Strip) SetColor(strip int, colour int32) error {
|
||||
address := fmt.Sprintf(s.baseAddress, strip) + "/config/colour"
|
||||
return s.client.SendMessage(address, colour)
|
||||
}
|
||||
|
||||
// SendLevel requests auxiliary send level for a send destination.
|
||||
func (s *Strip) SendLevel(strip int, bus int) (float64, error) {
|
||||
func (s *Strip) SendLevel(strip, bus int) (float64, error) {
|
||||
address := fmt.Sprintf(s.baseAddress, strip) + fmt.Sprintf("/mix/%02d/level", bus)
|
||||
err := s.client.SendMessage(address)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to send strip send level request: %v", err)
|
||||
return 0, fmt.Errorf("failed to send strip send level request: %w", err)
|
||||
}
|
||||
|
||||
msg, err := s.client.ReceiveMessage()
|
||||
@@ -146,7 +146,7 @@ func (s *Strip) SendLevel(strip int, bus int) (float64, error) {
|
||||
}
|
||||
|
||||
// SetSendLevel sets the auxiliary send level for a send destination.
|
||||
func (s *Strip) SetSendLevel(strip int, bus int, level float64) error {
|
||||
func (s *Strip) SetSendLevel(strip, bus int, level float64) error {
|
||||
address := fmt.Sprintf(s.baseAddress, strip) + fmt.Sprintf("/mix/%02d/level", bus)
|
||||
return s.client.SendMessage(address, float32(mustDbInto(level)))
|
||||
}
|
||||
|
||||
@@ -2,19 +2,19 @@ package xair
|
||||
|
||||
import "math"
|
||||
|
||||
func linGet(min float64, max float64, value float64) float64 {
|
||||
func linGet(min, max, value float64) float64 {
|
||||
return min + (max-min)*value
|
||||
}
|
||||
|
||||
func linSet(min float64, max float64, value float64) float64 {
|
||||
func linSet(min, max, value float64) float64 {
|
||||
return (value - min) / (max - min)
|
||||
}
|
||||
|
||||
func logGet(min float64, max float64, value float64) float64 {
|
||||
func logGet(min, max, value float64) float64 {
|
||||
return min * math.Exp(math.Log(max/min)*value)
|
||||
}
|
||||
|
||||
func logSet(min float64, max float64, value float64) float64 {
|
||||
func logSet(min, max, value float64) float64 {
|
||||
return math.Log(value/min) / math.Log(max/min)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user