diff --git a/cmd/bus.go b/cmd/bus.go index 883b4d0..40f75fc 100644 --- a/cmd/bus.go +++ b/cmd/bus.go @@ -254,16 +254,63 @@ var busNameCmd = &cobra.Command{ }, } +// busEqCmd represents the bus EQ command. +var busEqCmd = &cobra.Command{ + Short: "Commands to control bus EQ settings", + Long: `Commands to control the EQ of individual buses, including turning the EQ on or off.`, + Use: "eq", + Run: func(cmd *cobra.Command, _ []string) { + cmd.Help() + }, +} + +// busEqOnCmd represents the bus EQ on/off command. +var busEqOnCmd = &cobra.Command{ + Short: "Get or set the bus EQ on/off status", + Long: `Get or set the EQ on/off status of a specific bus.`, + Use: "on [bus number] [true|false]", + RunE: func(cmd *cobra.Command, args []string) error { + client := ClientFromContext(cmd.Context()) + if client == nil { + return fmt.Errorf("OSC client not found in context") + } + + if len(args) < 2 { + return fmt.Errorf("Please provide bus number and EQ on status (true/false)") + } + + busNum := mustConvToInt(args[0]) + var eqOn bool + switch args[1] { + case "true", "1": + eqOn = true + case "false", "0": + eqOn = false + default: + return fmt.Errorf("Invalid EQ on status. Use true/false or 1/0") + } + + err := client.Bus.Eq.SetOn(busNum, eqOn) + if err != nil { + return fmt.Errorf("Error setting bus EQ on status: %w", err) + } + + cmd.Printf("Bus %d EQ on set to %v\n", busNum, eqOn) + return nil + }, +} + func init() { rootCmd.AddCommand(busCmd) busCmd.AddCommand(busMuteCmd) - busCmd.AddCommand(busFaderCmd) busCmd.AddCommand(busFadeOutCmd) busFadeOutCmd.Flags().DurationP("duration", "d", 5*time.Second, "Duration for fade out in seconds") busCmd.AddCommand(busFadeInCmd) busFadeInCmd.Flags().DurationP("duration", "d", 5*time.Second, "Duration for fade in in seconds") - busCmd.AddCommand(busNameCmd) + + busCmd.AddCommand(busEqCmd) + busEqCmd.AddCommand(busEqOnCmd) } diff --git a/cmd/strip.go b/cmd/strip.go index 9e56955..a4db0d2 100644 --- a/cmd/strip.go +++ b/cmd/strip.go @@ -203,7 +203,7 @@ var stripFadeInCmd = &cobra.Command{ stripIndex := mustConvToInt(args[0]) - duration, err := cmd.Flags().GetFloat64("duration") + duration, err := cmd.Flags().GetDuration("duration") if err != nil { return fmt.Errorf("Error getting duration flag: %w", err) } @@ -224,7 +224,7 @@ var stripFadeInCmd = &cobra.Command{ return nil } - stepDelay := time.Duration(duration*1000/totalSteps) * time.Millisecond + stepDelay := time.Duration(duration.Seconds()*1000/totalSteps) * time.Millisecond for currentFader < target { currentFader += 1.0 @@ -235,7 +235,7 @@ var stripFadeInCmd = &cobra.Command{ time.Sleep(stepDelay) } - cmd.Printf("Strip %d faded in to %.2f dB over %.2f seconds\n", stripIndex, target, duration) + cmd.Printf("Strip %d faded in to %.2f dB over %.2f seconds\n", stripIndex, target, duration.Seconds()) return nil }, } @@ -333,18 +333,89 @@ If a name argument is provided, the strip name is set to that value.`, }, } +// stripEqCmd represents the strip EQ command. +var stripEqCmd = &cobra.Command{ + Short: "Commands to control the EQ of individual strips.", + Long: `Commands to control the EQ of individual strips, including turning the EQ on or off.`, + Use: "eq", + Run: func(cmd *cobra.Command, _ []string) { + cmd.Help() + }, +} + +// stripEqOnCmd represents the strip EQ on command. +var stripEqOnCmd = &cobra.Command{ + Short: "Get or set the EQ on/off status of a strip", + Long: `Get or set the EQ on/off status of a specific strip. + +If no status argument is provided, the current EQ status is retrieved. +If "true" or "1" is provided as an argument, the EQ is turned on. +If "false" or "0" is provided, the EQ is turned off.`, + Use: "on [strip number] [true|false]", + Example: ` # Get the current EQ status of strip 1 + xair-cli strip eq on 1 + + # Turn on EQ for strip 1 + xair-cli strip eq on 1 true + # Turn off EQ for strip 1 + xair-cli strip eq on 1 false`, + RunE: func(cmd *cobra.Command, args []string) error { + client := ClientFromContext(cmd.Context()) + if client == nil { + return fmt.Errorf("OSC client not found in context") + } + + if len(args) < 1 { + return fmt.Errorf("Please provide a strip number") + } + + stripIndex := mustConvToInt(args[0]) + + if len(args) == 1 { + on, err := client.Strip.Eq.On(stripIndex) + if err != nil { + return fmt.Errorf("Error getting strip EQ on status: %w", err) + } + cmd.Printf("Strip %d EQ on: %v\n", stripIndex, on) + return nil + } + + var on bool + switch args[1] { + case "true", "1": + on = true + case "false", "0": + on = false + default: + return fmt.Errorf("Invalid EQ status. Use true/false or 1/0") + } + + err := client.Strip.Eq.SetOn(stripIndex, on) + if err != nil { + return fmt.Errorf("Error setting strip EQ on status: %w", err) + } + + if on { + cmd.Printf("Strip %d EQ turned on successfully\n", stripIndex) + } else { + cmd.Printf("Strip %d EQ turned off successfully\n", stripIndex) + } + return nil + }, +} + func init() { rootCmd.AddCommand(stripCmd) stripCmd.AddCommand(stripMuteCmd) - stripCmd.AddCommand(stripFaderCmd) stripCmd.AddCommand(stripFadeOutCmd) stripFadeOutCmd.Flags().DurationP("duration", "d", 5*time.Second, "Duration of the fade out in seconds") stripCmd.AddCommand(stripFadeInCmd) stripFadeInCmd.Flags().DurationP("duration", "d", 5*time.Second, "Duration of the fade in in seconds") - stripCmd.AddCommand(stripSendCmd) - stripCmd.AddCommand(stripNameCmd) + + stripCmd.AddCommand(stripEqCmd) + stripEqCmd.AddCommand(stripEqOnCmd) } diff --git a/internal/xair/bus.go b/internal/xair/bus.go index 9ca83d2..8dc50a7 100644 --- a/internal/xair/bus.go +++ b/internal/xair/bus.go @@ -4,13 +4,17 @@ import "fmt" type Bus struct { baseAddress string - client Client + client *Client + Eq *Eq + Comp *Comp } -func NewBus(c Client) *Bus { +func NewBus(c *Client) *Bus { return &Bus{ baseAddress: c.addressMap["bus"], client: c, + Eq: newEqForBus(c), + Comp: newCompForBus(c), } } diff --git a/internal/xair/comp.go b/internal/xair/comp.go new file mode 100644 index 0000000..a62e85e --- /dev/null +++ b/internal/xair/comp.go @@ -0,0 +1,20 @@ +package xair + +type Comp struct { + client *Client + baseAddress string +} + +func newCompForStrip(c *Client) *Comp { + return &Comp{ + client: c, + baseAddress: c.addressMap["strip"], + } +} + +func newCompForBus(c *Client) *Comp { + return &Comp{ + client: c, + baseAddress: c.addressMap["bus"], + } +} diff --git a/internal/xair/eq.go b/internal/xair/eq.go new file mode 100644 index 0000000..28f8eb5 --- /dev/null +++ b/internal/xair/eq.go @@ -0,0 +1,70 @@ +package xair + +import "fmt" + +type Eq struct { + client *Client + baseAddress string +} + +// Helper function to create Eq instance for Strip +func newEqForStrip(c *Client) *Eq { + return &Eq{ + client: c, + baseAddress: c.addressMap["strip"], + } +} + +// Helper function to create Eq instance for Bus +func newEqForBus(c *Client) *Eq { + return &Eq{ + client: c, + baseAddress: c.addressMap["bus"], + } +} + +func (e *Eq) On(index int) (bool, error) { + address := fmt.Sprintf(e.baseAddress, index) + "/eq/on" + err := e.client.SendMessage(address) + if err != nil { + return false, err + } + + resp := <-e.client.respChan + val, ok := resp.Arguments[0].(int32) + if !ok { + return false, fmt.Errorf("unexpected argument type for EQ on value") + } + return val != 0, nil +} + +func (e *Eq) SetOn(index int, on bool) error { + address := fmt.Sprintf(e.baseAddress, index) + "/eq/on" + var value int32 + if on { + value = 1 + } + return e.client.SendMessage(address, value) +} + +// 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) { + address := fmt.Sprintf(e.baseAddress, index) + fmt.Sprintf("/eq/%d/g", band) + err := e.client.SendMessage(address) + if err != nil { + return 0, err + } + + resp := <-e.client.respChan + val, ok := resp.Arguments[0].(float32) + if !ok { + return 0, fmt.Errorf("unexpected argument type for EQ gain value") + } + return float64(val), nil +} + +// 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 { + address := fmt.Sprintf(e.baseAddress, index) + fmt.Sprintf("/eq/%d/g", band) + return e.client.SendMessage(address, float32(gain)) +} diff --git a/internal/xair/gate.go b/internal/xair/gate.go new file mode 100644 index 0000000..4baec98 --- /dev/null +++ b/internal/xair/gate.go @@ -0,0 +1,9 @@ +package xair + +type Gate struct { + client *Client +} + +func newGate(c *Client) *Gate { + return &Gate{client: c} +} diff --git a/internal/xair/strip.go b/internal/xair/strip.go index 3177e4a..5d7561b 100644 --- a/internal/xair/strip.go +++ b/internal/xair/strip.go @@ -4,13 +4,19 @@ import "fmt" type Strip struct { baseAddress string - client Client + client *Client + Gate *Gate + Eq *Eq + Comp *Comp } -func NewStrip(c Client) *Strip { +func NewStrip(c *Client) *Strip { return &Strip{ baseAddress: c.addressMap["strip"], client: c, + Gate: newGate(c), + Eq: newEqForStrip(c), + Comp: newCompForStrip(c), } }