voicemeeter/publisher.go
onyx-and-iris c4f00a3dbd pooler now accepts channels
done channels used to clean up pooler if GUI goes down

InitPooler() added to Remote type, useful for reinitiating the Pooler.
For this reason Pooler now defined as singleton type.
2022-12-08 10:50:00 +00:00

193 lines
3.4 KiB
Go

package voicemeeter
import (
"time"
log "github.com/sirupsen/logrus"
)
// publisher defines the list of observer channels
type publisher struct {
observers []chan string
}
// Register adds an observer channel to the channelList
func (p *publisher) Register(channel chan string) {
p.observers = append(p.observers, channel)
}
type event struct {
pdirty bool
mdirty bool
midi bool
ldirty bool
}
func newEvent() *event {
return &event{true, true, true, false}
}
func (e *event) Add(events ...string) {
for _, event := range events {
switch event {
case "pdirty":
e.pdirty = true
case "mdirty":
e.mdirty = true
case "midi":
e.midi = true
case "ldirty":
e.ldirty = true
}
log.Info(event, " added to the pooler")
}
}
func (e *event) Remove(events ...string) {
for _, event := range events {
switch event {
case "pdirty":
e.pdirty = false
case "mdirty":
e.mdirty = false
case "midi":
e.midi = false
case "ldirty":
e.ldirty = false
}
log.Info(event, " removed from the pooler")
}
}
var p *pooler
// pooler continuously polls the dirty parameters
// it is expected to be run in a goroutine
type pooler struct {
k *kind
run bool
event *event
pdirtyDone chan bool
mdirtyDone chan bool
midiDone chan bool
ldirtyDone chan bool
publisher
}
func newPooler(k *kind) *pooler {
if p == nil {
p = &pooler{
k: k,
run: true,
event: newEvent(),
pdirtyDone: make(chan bool),
mdirtyDone: make(chan bool),
midiDone: make(chan bool),
ldirtyDone: make(chan bool),
}
go p.done()
go p.parameters()
go p.macrobuttons()
go p.midi()
go p.levels()
}
return p
}
func (p *pooler) done() {
for {
select {
case _, ok := <-p.pdirtyDone:
if !ok {
p.pdirtyDone = nil
}
case _, ok := <-p.mdirtyDone:
if !ok {
p.mdirtyDone = nil
}
case _, ok := <-p.midiDone:
if !ok {
p.midiDone = nil
}
case _, ok := <-p.ldirtyDone:
if !ok {
p.ldirtyDone = nil
}
}
if p.pdirtyDone == nil && p.mdirtyDone == nil && p.midiDone == nil && p.ldirtyDone == nil {
for _, ch := range p.observers {
close(ch)
}
break
}
}
}
func (p *pooler) parameters() {
for p.run {
pdirty, err := pdirty()
if err != nil {
close(p.pdirtyDone)
break
}
if p.event.pdirty && pdirty {
for _, ch := range p.observers {
ch <- "pdirty"
}
}
time.Sleep(33 * time.Millisecond)
}
}
func (p *pooler) macrobuttons() {
for p.run {
mdirty, err := mdirty()
if err != nil {
close(p.mdirtyDone)
break
}
if p.event.mdirty && mdirty {
for _, ch := range p.observers {
ch <- "mdirty"
}
}
time.Sleep(33 * time.Millisecond)
}
}
func (p *pooler) midi() {
for p.run {
midi, err := getMidiMessage()
if err != nil {
close(p.midiDone)
break
}
if p.event.midi && midi {
for _, ch := range p.observers {
ch <- "midi"
}
}
time.Sleep(33 * time.Millisecond)
}
}
func (p *pooler) levels() {
_levelCache = newLevelCache(p.k)
for p.run {
ldirty, err := ldirty(p.k)
if err != nil {
close(p.ldirtyDone)
break
}
if p.event.ldirty && ldirty {
update(_levelCache.stripLevels, _levelCache.stripLevelsBuff, (2*p.k.PhysIn)+(8*p.k.VirtIn))
update(_levelCache.busLevels, _levelCache.busLevelsBuff, 8*p.k.NumBus())
for _, ch := range p.observers {
ch <- "ldirty"
}
}
time.Sleep(33 * time.Millisecond)
}
}