mirror of
https://github.com/onyx-and-iris/voicemeeter.git
synced 2024-11-24 22:00:52 +00:00
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.
This commit is contained in:
parent
e01efb22eb
commit
c4f00a3dbd
126
publisher.go
126
publisher.go
@ -6,40 +6,14 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// observer defines the interface any registered observers must satisfy
|
// publisher defines the list of observer channels
|
||||||
type observer interface {
|
|
||||||
OnUpdate(subject string)
|
|
||||||
}
|
|
||||||
|
|
||||||
// publisher defines methods that support observers
|
|
||||||
type publisher struct {
|
type publisher struct {
|
||||||
observerList []observer
|
observers []chan string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register adds an observer to observerList
|
// Register adds an observer channel to the channelList
|
||||||
func (p *publisher) Register(o observer) {
|
func (p *publisher) Register(channel chan string) {
|
||||||
p.observerList = append(p.observerList, o)
|
p.observers = append(p.observers, channel)
|
||||||
}
|
|
||||||
|
|
||||||
// Deregister removes an observer from observerList
|
|
||||||
func (p *publisher) Deregister(o observer) {
|
|
||||||
var indexToRemove int
|
|
||||||
|
|
||||||
for i, observer := range p.observerList {
|
|
||||||
if observer == o {
|
|
||||||
indexToRemove = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p.observerList = append(p.observerList[:indexToRemove], p.observerList[indexToRemove+1:]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// notify updates observers of any changes
|
|
||||||
func (p *publisher) notify(subject string) {
|
|
||||||
for _, observer := range p.observerList {
|
|
||||||
observer.OnUpdate(subject)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type event struct {
|
type event struct {
|
||||||
@ -85,32 +59,81 @@ func (e *event) Remove(events ...string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pooler continuously polls the dirty paramters
|
var p *pooler
|
||||||
|
|
||||||
|
// pooler continuously polls the dirty parameters
|
||||||
// it is expected to be run in a goroutine
|
// it is expected to be run in a goroutine
|
||||||
type pooler struct {
|
type pooler struct {
|
||||||
k *kind
|
k *kind
|
||||||
run bool
|
run bool
|
||||||
event *event
|
event *event
|
||||||
|
pdirtyDone chan bool
|
||||||
|
mdirtyDone chan bool
|
||||||
|
midiDone chan bool
|
||||||
|
ldirtyDone chan bool
|
||||||
publisher
|
publisher
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPooler(k *kind) *pooler {
|
func newPooler(k *kind) *pooler {
|
||||||
p := &pooler{
|
if p == nil {
|
||||||
|
p = &pooler{
|
||||||
k: k,
|
k: k,
|
||||||
run: true,
|
run: true,
|
||||||
event: newEvent(),
|
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.parameters()
|
||||||
go p.macrobuttons()
|
go p.macrobuttons()
|
||||||
go p.midi()
|
go p.midi()
|
||||||
go p.levels()
|
go p.levels()
|
||||||
|
}
|
||||||
return p
|
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() {
|
func (p *pooler) parameters() {
|
||||||
for p.run {
|
for p.run {
|
||||||
if p.event.pdirty && pdirty() {
|
pdirty, err := pdirty()
|
||||||
p.notify("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)
|
time.Sleep(33 * time.Millisecond)
|
||||||
}
|
}
|
||||||
@ -118,8 +141,15 @@ func (p *pooler) parameters() {
|
|||||||
|
|
||||||
func (p *pooler) macrobuttons() {
|
func (p *pooler) macrobuttons() {
|
||||||
for p.run {
|
for p.run {
|
||||||
if p.event.mdirty && mdirty() {
|
mdirty, err := mdirty()
|
||||||
p.notify("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)
|
time.Sleep(33 * time.Millisecond)
|
||||||
}
|
}
|
||||||
@ -127,8 +157,15 @@ func (p *pooler) macrobuttons() {
|
|||||||
|
|
||||||
func (p *pooler) midi() {
|
func (p *pooler) midi() {
|
||||||
for p.run {
|
for p.run {
|
||||||
if p.event.midi && getMidiMessage() {
|
midi, err := getMidiMessage()
|
||||||
p.notify("midi")
|
if err != nil {
|
||||||
|
close(p.midiDone)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if p.event.midi && midi {
|
||||||
|
for _, ch := range p.observers {
|
||||||
|
ch <- "midi"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
time.Sleep(33 * time.Millisecond)
|
time.Sleep(33 * time.Millisecond)
|
||||||
}
|
}
|
||||||
@ -138,10 +175,17 @@ func (p *pooler) levels() {
|
|||||||
_levelCache = newLevelCache(p.k)
|
_levelCache = newLevelCache(p.k)
|
||||||
|
|
||||||
for p.run {
|
for p.run {
|
||||||
if p.event.ldirty && ldirty(p.k) {
|
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.stripLevels, _levelCache.stripLevelsBuff, (2*p.k.PhysIn)+(8*p.k.VirtIn))
|
||||||
update(_levelCache.busLevels, _levelCache.busLevelsBuff, 8*p.k.NumBus())
|
update(_levelCache.busLevels, _levelCache.busLevelsBuff, 8*p.k.NumBus())
|
||||||
p.notify("ldirty")
|
for _, ch := range p.observers {
|
||||||
|
ch <- "ldirty"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
time.Sleep(33 * time.Millisecond)
|
time.Sleep(33 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
39
remote.go
39
remote.go
@ -35,7 +35,7 @@ func (r *Remote) Login() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r.pooler = newPooler(r.Kind)
|
r.InitPooler()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +50,11 @@ func (r *Remote) Logout() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InitPooler initiates the Pooler
|
||||||
|
func (r *Remote) InitPooler() {
|
||||||
|
r.pooler = newPooler(r.Kind)
|
||||||
|
}
|
||||||
|
|
||||||
// Type returns the type of Voicemeeter (basic, banana, potato)
|
// Type returns the type of Voicemeeter (basic, banana, potato)
|
||||||
func (r *Remote) Type() string {
|
func (r *Remote) Type() string {
|
||||||
val, err := getVMType()
|
val, err := getVMType()
|
||||||
@ -69,20 +74,21 @@ func (r *Remote) Version() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pdirty returns true iff a parameter value has changed
|
// Pdirty returns true iff a parameter value has changed
|
||||||
func (r *Remote) Pdirty() bool {
|
func (r *Remote) Pdirty() (bool, error) {
|
||||||
return pdirty()
|
pdirty, err := pdirty()
|
||||||
|
return pdirty, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mdirty returns true iff a macrobutton value has changed
|
// Mdirty returns true iff a macrobutton value has changed
|
||||||
func (r *Remote) Mdirty() bool {
|
func (r *Remote) Mdirty() (bool, error) {
|
||||||
return mdirty()
|
mdirty, err := mdirty()
|
||||||
|
return mdirty, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync is a helper method that waits for dirty parameters to clear
|
// Sync is a helper method that waits for dirty parameters to clear
|
||||||
func (r *Remote) Sync() {
|
func (r *Remote) Sync() {
|
||||||
time.Sleep(time.Duration(vmdelay) * time.Millisecond)
|
time.Sleep(time.Duration(vmdelay) * time.Millisecond)
|
||||||
for r.Pdirty() || r.Mdirty() {
|
clear()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFloat gets a float parameter value
|
// GetFloat gets a float parameter value
|
||||||
@ -131,13 +137,8 @@ func (r *Remote) SendText(script string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register forwards the register method to Pooler
|
// Register forwards the register method to Pooler
|
||||||
func (r *Remote) Register(o observer) {
|
func (r *Remote) Register(channel chan string) {
|
||||||
r.pooler.Register(o)
|
r.pooler.Register(channel)
|
||||||
}
|
|
||||||
|
|
||||||
// Deregister forwards the deregister method to Pooler
|
|
||||||
func (r *Remote) Deregister(o observer) {
|
|
||||||
r.pooler.Deregister(o)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EventAdd adds events to the Pooler
|
// EventAdd adds events to the Pooler
|
||||||
@ -346,7 +347,7 @@ func init() {
|
|||||||
// NewRemote returns a Remote type for a kind
|
// NewRemote returns a Remote type for a kind
|
||||||
// this is the interface entry point
|
// this is the interface entry point
|
||||||
func NewRemote(kindId string, delay int) (*Remote, error) {
|
func NewRemote(kindId string, delay int) (*Remote, error) {
|
||||||
_kind, ok := kindMap[kindId]
|
kind, ok := kindMap[kindId]
|
||||||
if !ok {
|
if !ok {
|
||||||
err := fmt.Errorf("unknown Voicemeeter kind '%s'", kindId)
|
err := fmt.Errorf("unknown Voicemeeter kind '%s'", kindId)
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -359,13 +360,13 @@ func NewRemote(kindId string, delay int) (*Remote, error) {
|
|||||||
vmdelay = delay
|
vmdelay = delay
|
||||||
|
|
||||||
director := director{}
|
director := director{}
|
||||||
switch _kind.Name {
|
switch kind.Name {
|
||||||
case "basic":
|
case "basic":
|
||||||
director.SetBuilder(&basicBuilder{genericBuilder{_kind, Remote{}}})
|
director.SetBuilder(&basicBuilder{genericBuilder{kind, Remote{}}})
|
||||||
case "banana":
|
case "banana":
|
||||||
director.SetBuilder(&bananaBuilder{genericBuilder{_kind, Remote{}}})
|
director.SetBuilder(&bananaBuilder{genericBuilder{kind, Remote{}}})
|
||||||
case "potato":
|
case "potato":
|
||||||
director.SetBuilder(&potatoBuilder{genericBuilder{_kind, Remote{}}})
|
director.SetBuilder(&potatoBuilder{genericBuilder{kind, Remote{}}})
|
||||||
}
|
}
|
||||||
director.Construct()
|
director.Construct()
|
||||||
return director.Get(), nil
|
return director.Get(), nil
|
||||||
|
Loading…
Reference in New Issue
Block a user