diff options
author | Christian Pointner <equinox@spreadspace.org> | 2020-04-06 00:47:02 +0200 |
---|---|---|
committer | Christian Pointner <equinox@spreadspace.org> | 2020-04-06 00:47:02 +0200 |
commit | dfb57bb771d5b8c06e932ef90ae09a3c8bf70dca (patch) | |
tree | 046f0c691fb8dea288e9a029d1b6b6ca705f61ab /pkg | |
parent | mixer: basic osc message handling for /info operation (diff) |
new mixer interface mostly done, remaining issues with floats and rounding errors...
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/mixer/mixer.go | 231 |
1 files changed, 109 insertions, 122 deletions
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 } |