summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2020-04-06 00:47:02 +0200
committerChristian Pointner <equinox@spreadspace.org>2020-04-06 00:47:02 +0200
commitdfb57bb771d5b8c06e932ef90ae09a3c8bf70dca (patch)
tree046f0c691fb8dea288e9a029d1b6b6ca705f61ab
parentmixer: basic osc message handling for /info operation (diff)
new mixer interface mostly done, remaining issues with floats and rounding errors...
-rw-r--r--cmd/dolmetschctld/dolmetschctld.go4
-rw-r--r--cmd/dolmetschctld/statemachine.go9
-rw-r--r--pkg/mixer/mixer.go231
3 files changed, 113 insertions, 131 deletions
diff --git a/cmd/dolmetschctld/dolmetschctld.go b/cmd/dolmetschctld/dolmetschctld.go
index a6d9ed8..3242dde 100644
--- a/cmd/dolmetschctld/dolmetschctld.go
+++ b/cmd/dolmetschctld/dolmetschctld.go
@@ -67,8 +67,8 @@ func main() {
log.Printf("state machine successfully initialized!")
// TODO: make this configurable
- addLanguage(sm, "en", 0x20, 0x24)
- addLanguage(sm, "de", 0x22, 0x25)
+ addLanguage(sm, "en", "auxin/01", "auxin/05")
+ addLanguage(sm, "de", "auxin/03", "auxin/06")
sm.Start()
defer sm.Shutdown()
diff --git a/cmd/dolmetschctld/statemachine.go b/cmd/dolmetschctld/statemachine.go
index 15f0e41..b6d46ba 100644
--- a/cmd/dolmetschctld/statemachine.go
+++ b/cmd/dolmetschctld/statemachine.go
@@ -178,12 +178,7 @@ func (sm *StateMachine) handleMixerEvent(ev mixer.Event) {
// make sure that our state and the mixer are in sync
func (sm *StateMachine) initMixer() {
for _, mcs := range sm.languages {
- sm.mixer.SetLevel(mcs.original.num, mixer.FaderLevel0db-1)
- sm.mixer.SetLevel(mcs.original.num, mixer.FaderLevel0db)
mcs.original.target.level = mixer.FaderLevel0db
-
- sm.mixer.SetLevel(mcs.interpreter.num, mixer.FaderLevelOff+1)
- sm.mixer.SetLevel(mcs.interpreter.num, mixer.FaderLevelOff)
mcs.interpreter.target.level = mixer.FaderLevelOff
}
sm.language = ""
@@ -226,9 +221,9 @@ func calcNextLevel(target, current mixer.FaderLevel) mixer.FaderLevel {
next := target
if current != mixer.FaderLevelUnknown {
if next > current {
- next = current + 1
+ next = current + 0.01
} else {
- next = current - 1
+ next = current - 0.01
}
}
return next
diff --git a/pkg/mixer/mixer.go b/pkg/mixer/mixer.go
index ef94eba..58ae20b 100644
--- a/pkg/mixer/mixer.go
+++ b/pkg/mixer/mixer.go
@@ -26,15 +26,20 @@ import (
"container/list"
"errors"
"fmt"
- // "log"
+ "log"
"net"
+ "strings"
"sync"
"time"
"github.com/scgolang/osc"
)
-type Channel uint8
+const (
+ OSCSubscriptionTimeFactor = 0
+)
+
+type Channel string
type EventType int
const (
@@ -79,7 +84,7 @@ func (fl FaderLevel) String() string {
}
}
-type Mute int8
+type Mute int
const (
MuteUnknown = Mute(-1)
@@ -106,7 +111,7 @@ type Event struct {
}
func (e Event) String() string {
- return fmt.Sprintf("Event(%s) for channel %d: level=%s, muted=%s", e.Type, e.Channel, e.Level, e.Mute)
+ return fmt.Sprintf("Event(%s) for channel '%s': level=%s, muted=%s", e.Type, e.Channel, e.Level, e.Mute)
}
type subscriber struct {
@@ -199,57 +204,6 @@ func (m *Mixer) String() string {
return fmt.Sprintf("Model %s (Firmware-Version: %s)", m.info.ConsoleModel, m.info.ConsoleVersion)
}
-// func (m *Mixer) reopenInput() {
-// for {
-// time.Sleep(time.Second)
-
-// devices, err := midi.Devices()
-// if err != nil {
-// log.Printf("mixer: error listing midi devices: %v, retrying...", err)
-// continue
-// }
-
-// if m.devIn, err = openDevice(devices, m.config.DevIn); err != nil {
-// log.Printf("mixer: error re-opening midi input device: %v, retrying...", err)
-// continue
-// }
-
-// if err = m.Init(); err != nil {
-// log.Printf("mixer: error re-initializing midi input device: %v, retrying...", err)
-
-// continue
-// }
-
-// log.Printf("mixer: successfully re-initialized midi input device")
-// break
-// }
-// }
-
-// func (m *Mixer) reopenOutput() {
-// for {
-// time.Sleep(time.Second)
-
-// devices, err := midi.Devices()
-// if err != nil {
-// log.Printf("mixer: error listing midi devices: %v, retrying...", err)
-// continue
-// }
-
-// newOut, err := openDevice(devices, m.config.DevOut)
-// if err != nil {
-// log.Printf("mixer: error re-opening midi output device: %v, retrying...", err)
-// continue
-// }
-
-// log.Printf("mixer: successfully re-opened midi output device")
-
-// m.devOutLock.Lock()
-// defer m.devOutLock.Unlock()
-// m.devOut = newOut
-// break
-// }
-// }
-
func (m *Mixer) publishEvent(ev Event) {
m.subscribersLock.Lock()
defer m.subscribersLock.Unlock()
@@ -283,52 +237,80 @@ func (m *Mixer) publishEvent(ev Event) {
}
}
-// func (m *Mixer) handleMidiPacket(p midi.Packet) {
-// ev := Event{Level: FaderLevelUnknown, Mute: MuteUnknown}
-// ev.Channel = Channel(p.Data[1])
-// switch p.Data[0] {
-// case CC_FADER:
-// ev.Type = EventFaderChange
-// ev.Level = FaderLevel(p.Data[2])
-// case CC_MUTE:
-// ev.Type = EventMute
-// ev.Mute = MuteUnmuted
-// if p.Data[2] > 0 {
-// ev.Mute = MuteMuted
-// }
-// default:
-// return
-// }
-// m.publishEvent(ev)
-// }
+type oscDispatcher struct {
+ mixer *Mixer
+}
+
+func (d oscDispatcher) Dispatch(bundle osc.Bundle, exactMatch bool) error {
+ // TODO: X32 seems to not use bundles at the momemnt - ingoring them for now
+ return nil
+}
+
+func (d oscDispatcher) Invoke(msg osc.Message, exactMatch bool) error {
+ addrParts := strings.Split(strings.TrimPrefix(msg.Address, "/"), "/")
+ if len(addrParts) < 4 {
+ return nil
+ }
+ if addrParts[2] != "mix" {
+ return nil
+ }
+ if len(msg.Arguments) != 1 {
+ return nil
+ }
+
+ ev := Event{Level: FaderLevelUnknown, Mute: MuteUnknown}
+ ev.Channel = Channel(addrParts[0] + "/" + addrParts[1])
+ switch addrParts[3] {
+ case "on":
+ ev.Type = EventMute
+ arg, err := msg.Arguments[0].ReadInt32()
+ if err != nil {
+ return err
+ }
+ ev.Mute = Mute(arg)
+ case "fader":
+ ev.Type = EventFaderChange
+ arg, err := msg.Arguments[0].ReadFloat32()
+ if err != nil {
+ return err
+ }
+ ev.Level = FaderLevel(arg)
+ default:
+ return nil
+ }
+
+ d.mixer.publishEvent(ev)
+ return nil
+}
func (m *Mixer) Init() error {
+ go func() {
+ for {
+ dispatcher := oscDispatcher{mixer: m}
+ err := m.client.Serve(1, dispatcher)
+ if err != nil {
+ log.Printf("mixer: failed to dispatch message: %v", err)
+ time.Sleep(time.Second)
+ }
+ }
+ }()
+
+ go func() {
+ for {
+ time.Sleep(5 * time.Second)
+ err := m.client.Send(osc.Message{Address: "/renew"})
+ if err != nil {
+ log.Printf("mixer: failed to renew subsciptions: %v", err)
+ }
+ }
+ }()
- // ch, err := m.devIn.Packets()
- // if err != nil {
- // return err
- // }
-
- // go func() {
- // for {
- // ps := <-ch
- // for _, p := range ps {
- // if p.Err != nil {
- // log.Printf("mixer: got fatal error from midi input device: %v, trying to reopen it...", p.Err)
- // // m.devIn.Close()
- // // m.devIn = nil
- // // go m.reopenInput()
- // // return
- // }
- // // m.handleMidiPacket(p)
- // }
- // }
- // }()
return nil
}
func (m *Mixer) Shutdown() error {
if m.client != nil {
+ m.client.Send(osc.Message{Address: "/unsubscribe"})
m.client.Close()
m.client = nil
}
@@ -353,56 +335,61 @@ func (m *Mixer) Shutdown() error {
return nil
}
-func (m *Mixer) sendOSCMessage(msg []byte) error {
- // if m.devOut == nil {
- // return errors.New("mixer: output device is not ready.")
- // }
-
- // n, err := m.devOut.Write(msg)
- // if err != nil {
- // log.Printf("mixer: got fatal error from midi output device: %v, trying to reopen it...", err)
- // m.devOut.Close()
- // m.devOut = nil
- // go m.reopenOutput()
- // return err
- // }
- // if n != len(msg) {
- // return errors.New("sending midi message failed: short write")
- // }
- return nil
-}
-
-func (m *Mixer) sendMute(channel byte, value byte) error {
- return nil // m.sendMidiMessage([]byte{CC_MUTE, channel, value})
+func (m *Mixer) sendMute(channel Channel, value string) error {
+ msg := osc.Message{Address: "/" + string(channel) + "/mix/on"}
+ msg.Arguments = append(msg.Arguments, osc.String(value))
+ return m.client.Send(msg)
}
func (m *Mixer) Mute(ch Channel) error {
- return m.sendMute(byte(ch), 0x7F)
+ return m.sendMute(ch, "OFF")
}
func (m *Mixer) Unmute(ch Channel) error {
- return m.sendMute(byte(ch), 0x00)
+ return m.sendMute(ch, "ON")
}
-func (m *Mixer) SetLevel(ch Channel, level FaderLevel) error {
+func (m *Mixer) SetLevel(channel Channel, level FaderLevel) error {
if level > FaderLevelMax {
level = FaderLevelMax
}
- return nil // m.sendMidiMessage([]byte{CC_FADER, byte(ch), byte(level)})
+ msg := osc.Message{Address: "/" + string(channel) + "/mix/fader"}
+ msg.Arguments = append(msg.Arguments, osc.Float(level))
+ return m.client.Send(msg)
}
-func (m *Mixer) Subscribe(ch Channel, out chan<- Event) chan<- struct{} {
+func (m *Mixer) sendSubscribe(channel Channel) (err error) {
+ msg := osc.Message{Address: "/subscribe"}
+ msg.Arguments = append(msg.Arguments, osc.String("/"+string(channel)+"/mix/on"), osc.Int(OSCSubscriptionTimeFactor))
+ if err = m.client.Send(msg); err != nil {
+ return
+ }
+
+ msg = osc.Message{Address: "/subscribe"}
+ msg.Arguments = append(msg.Arguments, osc.String("/"+string(channel)+"/mix/fader"), osc.Int(OSCSubscriptionTimeFactor))
+ if err = m.client.Send(msg); err != nil {
+ return
+ }
+
+ return
+}
+
+func (m *Mixer) Subscribe(channel Channel, out chan<- Event) (chan<- struct{}, error) {
m.subscribersLock.Lock()
defer m.subscribersLock.Unlock()
- subs, exists := m.subscribers[ch]
+ subs, exists := m.subscribers[channel]
if !exists {
subs = list.New()
- m.subscribers[ch] = subs
+ m.subscribers[channel] = subs
+ }
+
+ if err := m.sendSubscribe(channel); err != nil {
+ return nil, err
}
// log.Printf("mixer: subscribing '%v' to events for channel: %v", out, ch)
unsubscribe := make(chan struct{})
subs.PushBack(subscriber{publish: out, unsubscribe: unsubscribe})
- return unsubscribe
+ return unsubscribe, nil
}