voicemeeter/remote.go

418 lines
8.8 KiB
Go
Raw Permalink Normal View History

package voicemeeter
import (
"fmt"
"os"
"time"
log "github.com/sirupsen/logrus"
)
// Remote represents the API for a kind
type Remote struct {
Kind *kind
Strip []iStrip
Bus []iBus
Button []button
Command *command
Vban *vban
Device *device
Recorder *recorder
Midi *midi_t
pooler *pooler
timeout int
bits int
}
// String implements the fmt.stringer interface
func (r *Remote) String() string {
return fmt.Sprintf("Voicemeeter %s", r.Kind)
}
// Login logs into the API
// then it intializes the pooler
func (r *Remote) Login() error {
err := login(r.Kind.Name, r.timeout, r.bits)
if err != nil {
return err
}
r.InitPooler()
return nil
}
// Logout logs out of the API
// it also terminates the pooler
func (r *Remote) Logout() error {
2022-06-26 01:41:05 +01:00
r.pooler.run = false
err := logout(r.Kind.Name)
if err != nil {
return err
}
return nil
}
// InitPooler initiates the Pooler
func (r *Remote) InitPooler() {
r.pooler = newPooler(r.Kind)
}
// Run launches the Voicemeeter GUI for a kind.
func (r *Remote) Run(kindId string) error {
err := runVoicemeeter(kindId, r.bits)
if err != nil {
return err
}
return nil
}
2022-07-10 23:35:56 +01:00
// Type returns the type of Voicemeeter (basic, banana, potato)
func (r *Remote) Type() string {
val, err := getVMType()
if err != nil {
fmt.Println(err)
}
return val
}
2022-07-10 23:35:56 +01:00
// Version returns the version of Voicemeeter as a string
func (r *Remote) Version() string {
val, err := getVersion()
if err != nil {
fmt.Println(err)
}
return val
}
// Pdirty returns true iff a parameter value has changed
func (r *Remote) Pdirty() (bool, error) {
pdirty, err := pdirty()
return pdirty, err
}
// Mdirty returns true iff a macrobutton value has changed
func (r *Remote) Mdirty() (bool, error) {
mdirty, err := mdirty()
return mdirty, err
}
// Sync is a helper method that waits for dirty parameters to clear
func (r *Remote) Sync() {
time.Sleep(time.Duration(vmdelay) * time.Millisecond)
clear()
}
// GetFloat gets a float parameter value
func (r *Remote) GetFloat(name string) (float64, error) {
val, err := getParameterFloat(name)
if err != nil {
return 0, err
}
return val, nil
}
// SetFloat sets a float paramter value
func (r *Remote) SetFloat(name string, value float64) error {
err := setParameterFloat(name, value)
if err != nil {
return err
}
return nil
}
// GetString gets a string parameter value
func (r *Remote) GetString(name string) (string, error) {
val, err := getParameterString(name)
if err != nil {
return "", err
}
return val, nil
}
// SetString sets a string parameter value
func (r *Remote) SetString(name, value string) error {
err := setParameterString(name, value)
if err != nil {
return err
}
return nil
}
2022-07-10 23:35:56 +01:00
// SendText sets multiple parameters by script
func (r *Remote) SendText(script string) error {
err := setParametersMulti(script)
if err != nil {
return err
}
return nil
}
// Register forwards the register method to Pooler
func (r *Remote) Register(channel chan string) {
r.pooler.Register(channel)
}
// EventAdd adds events to the Pooler
func (r *Remote) EventAdd(events ...string) {
r.pooler.event.Add(events...)
}
// EventRemove removes events from the Pooler
func (r *Remote) EventRemove(events ...string) {
r.pooler.event.Remove(events...)
}
2022-07-10 23:35:56 +01:00
// remoteBuilder defines the interface builder types must satisfy
type remoteBuilder interface {
setKind() remoteBuilder
makeStrip() remoteBuilder
makeBus() remoteBuilder
makeButton() remoteBuilder
makeCommand() remoteBuilder
makeVban() remoteBuilder
makeDevice() remoteBuilder
makeRecorder() remoteBuilder
makeMidi() remoteBuilder
setDefaults() remoteBuilder
Build() remoteBuilder
Get() *Remote
}
// director is responsible for directing the genericBuilder
type director struct {
builder remoteBuilder
}
// SetBuilder sets the appropriate builder type for a kind
func (d *director) SetBuilder(b remoteBuilder) {
d.builder = b
}
// Construct calls the build function for the specific builder
func (d *director) Construct() {
d.builder.Build()
}
// Get forwards the Get method to the builder
func (d *director) Get() *Remote {
return d.builder.Get()
}
2022-07-10 23:35:56 +01:00
// genericBuilder represents a generic builder type
type genericBuilder struct {
k *kind
r Remote
}
2022-07-10 23:35:56 +01:00
// setKind sets the kind for a builder of a kind
func (b *genericBuilder) setKind() remoteBuilder {
b.r.Kind = b.k
return b
}
// makeStrip makes a strip slice and assigns it to remote.Strip
// []iStrip comprises of both physical and virtual strip types
func (b *genericBuilder) makeStrip() remoteBuilder {
log.Debug("building strip")
strip := make([]iStrip, b.k.NumStrip())
for i := 0; i < b.k.NumStrip(); i++ {
if i < b.k.PhysIn {
strip[i] = newPhysicalStrip(i, b.k)
} else {
strip[i] = newVirtualStrip(i, b.k)
}
}
b.r.Strip = strip
return b
}
// makeBus makes a bus slice and assigns it to remote.Bus
// []t_bus comprises of both physical and virtual bus types
func (b *genericBuilder) makeBus() remoteBuilder {
log.Debug("building bus")
bus := make([]iBus, b.k.NumBus())
for i := 0; i < b.k.NumBus(); i++ {
if i < b.k.PhysOut {
bus[i] = newPhysicalBus(i, b.k)
} else {
bus[i] = newVirtualBus(i, b.k)
}
}
b.r.Bus = bus
return b
}
// makeButton makes a button slice and assigns it to remote.Button
func (b *genericBuilder) makeButton() remoteBuilder {
log.Debug("building button")
button := make([]button, 80)
for i := 0; i < 80; i++ {
button[i] = newButton(i)
}
b.r.Button = button
return b
}
// makeCommand makes a command type and assigns it to remote.Command
func (b *genericBuilder) makeCommand() remoteBuilder {
log.Debug("building command")
b.r.Command = newCommand()
return b
}
// makeVban makes a vban type and assigns it to remote.Vban
func (b *genericBuilder) makeVban() remoteBuilder {
log.Debug("building vban")
b.r.Vban = newVban(b.k)
return b
}
// makeDevice makes a device type and assigns it to remote.Device
func (b *genericBuilder) makeDevice() remoteBuilder {
log.Debug("building device")
b.r.Device = newDevice()
return b
}
// makeRecorder makes a recorder type and assigns it to remote.Recorder
func (b *genericBuilder) makeRecorder() remoteBuilder {
log.Debug("building recorder")
b.r.Recorder = newRecorder()
return b
}
// makeMidi makes a midi type and assigns it to remote.Midi
func (b *genericBuilder) makeMidi() remoteBuilder {
log.Debug("building midi")
b.r.Midi = newMidi()
return b
}
// setDefaults sets defaults for optional members
func (b *genericBuilder) setDefaults() remoteBuilder {
b.r.bits = 64
b.r.timeout = 2
return b
}
// Get returns a fully constructed remote type for a kind
func (b *genericBuilder) Get() *Remote {
return &b.r
}
2022-07-10 23:35:56 +01:00
// basicBuilder represents a builder specific to basic type
type basicBuilder struct {
genericBuilder
}
// Build defines the steps required to build a basic type
func (basb *genericBuilder) Build() remoteBuilder {
return basb.setKind().
makeStrip().
makeBus().
makeButton().
makeCommand().
makeVban().
makeDevice().
makeMidi().
setDefaults()
}
2022-07-10 23:35:56 +01:00
// bananaBuilder represents a builder specific to banana type
type bananaBuilder struct {
genericBuilder
}
// Build defines the steps required to build a banana type
func (banb *bananaBuilder) Build() remoteBuilder {
return banb.setKind().
makeStrip().
makeBus().
makeButton().
makeCommand().
makeVban().
makeDevice().
makeRecorder().
makeMidi().
setDefaults()
}
2022-07-10 23:35:56 +01:00
// potatoBuilder represents a builder specific to potato type
type potatoBuilder struct {
genericBuilder
}
// Build defines the steps required to build a potato type
func (potb *potatoBuilder) Build() remoteBuilder {
return potb.setKind().
makeStrip().
makeBus().
makeButton().
makeCommand().
makeVban().
makeDevice().
makeRecorder().
makeMidi().
setDefaults()
}
var (
vmsync bool
vmdelay int
)
type Option func(*Remote)
func WithTimeout(timeout int) Option {
return func(r *Remote) {
r.timeout = timeout
}
}
func WithBits(bits int) Option {
return func(r *Remote) {
if bits == 32 || bits == 64 {
r.bits = bits
}
}
}
func init() {
log.SetOutput(os.Stdout)
log.SetLevel(log.WarnLevel)
}
// NewRemote returns a Remote type for a kind
// this is the interface entry point
func NewRemote(kindId string, delay int, opts ...Option) (*Remote, error) {
kind, ok := kindMap[kindId]
if !ok {
err := fmt.Errorf("unknown Voicemeeter kind '%s'", kindId)
return nil, err
}
if delay < 0 {
err := fmt.Errorf("invalid delay value. should be >= 0")
return nil, err
}
vmsync = delay > 0
vmdelay = delay
director := director{}
switch kind.Name {
case "basic":
director.SetBuilder(&basicBuilder{genericBuilder{kind, Remote{}}})
case "banana":
director.SetBuilder(&bananaBuilder{genericBuilder{kind, Remote{}}})
case "potato":
director.SetBuilder(&potatoBuilder{genericBuilder{kind, Remote{}}})
}
director.Construct()
r := director.Get()
for _, opt := range opts {
opt(r)
}
return r, nil
}