Compare commits

..

No commits in common. "dev" and "v2.0.1" have entirely different histories.
dev ... v2.0.1

9 changed files with 342 additions and 463 deletions

4
.gitignore vendored
View File

@ -19,7 +19,3 @@ config.toml
# Dependency directories (remove the comment below to include it) # Dependency directories (remove the comment below to include it)
# vendor/ # vendor/
# work files
go.work
go.work.sum

View File

@ -11,19 +11,6 @@ Before any major/minor/patch bump all unit tests will be run to verify they pass
- [x] - [x]
## [2.1.0] - 2024-07-01
### Added
- Added a configurable login timeout in seconds (defaults to 2).
- Option function added for overriding the type of Voicemeeter GUI runVoicemeeter() will launch.
- Explanation of Option functions added to README.
### Changed
- runVoicemeeter() now launches x64 GUIs for all kinds if on a 64 bit system.
- this can be overridden to force 32 bit GUI using voicemeeter.WithBits(32) Option function
## [2.0.0] - 2022-10-25 ## [2.0.0] - 2022-10-25
V2 introduces some breaking changes. V2 introduces some breaking changes.

View File

@ -1,14 +1,16 @@
[![Go Reference](https://pkg.go.dev/badge/github.com/onyx-and-iris/voicemeeter.svg)](https://pkg.go.dev/github.com/onyx-and-iris/voicemeeter/v2) [![Go Reference](https://pkg.go.dev/badge/github.com/onyx-and-iris/voicemeeter.svg)](https://pkg.go.dev/github.com/onyx-and-iris/voicemeeter/v2)
# A Go Wrapper for the Voicemeeter API # A Go Wrapper for Voicemeeter API
This package offers a Go interface for the Voicemeeter Remote C API.
For an outline of past/future changes refer to: [CHANGELOG](CHANGELOG.md) For an outline of past/future changes refer to: [CHANGELOG](CHANGELOG.md)
## Tested against ## Tested against
- Basic 1.1.1.1 - Basic 1.0.8.8
- Banana 2.1.1.1 - Banana 2.0.6.8
- Potato 3.1.1.1 - Potato 3.0.2.8
## Requirements ## Requirements
@ -65,7 +67,7 @@ func vmConnect() (*voicemeeter.Remote, error) {
} }
``` ```
## `voicemeeter.NewRemote(<kindId>, <delay>, opts ...Option)` ## `voicemeeter.NewRemote(<kindId>, <delay>)`
### `kindId` ### `kindId`
@ -81,18 +83,6 @@ Pass a delay in milliseconds to force the getters to wait for dirty parameters t
Useful if not listening for event updates. Useful if not listening for event updates.
### `voicemeeter.WithTimeout(timeout int)`
Set a login timeout, defaults to 2 seconds. For example to set it to 1s:
`voicemeeter.NewRemote("banana", 20, voicemeeter.WithTimeout(1))`
### `voicemeeter.WithBits(bits int)`
Override the type of Voicemeeter GUI to launch on 64 bit systems. For example, to force 32 bit GUI:
`voicemeeter.NewRemote("banana", 20, voicemeeter.WithBits(32))`
## `Remote Type` ## `Remote Type`
#### `vm.Strip` #### `vm.Strip`
@ -597,4 +587,4 @@ go test ./...
### Official Documentation ### Official Documentation
- [Voicemeeter Remote C API](https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/main/VoicemeeterRemoteAPI.pdf) - [Voicemeeter Remote C API](https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/update-docs/VoicemeeterRemoteAPI.pdf)

34
base.go
View File

@ -2,10 +2,8 @@ package voicemeeter
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"math" "math"
"runtime"
"strings" "strings"
"syscall" "syscall"
"time" "time"
@ -47,29 +45,16 @@ var (
// login logs into the API, // login logs into the API,
// attempts to launch Voicemeeter if it's not running, // attempts to launch Voicemeeter if it's not running,
// initializes dirty parameters. // initializes dirty parameters.
func login(kindId string, timeout, bits int) error { func login(kindId string) error {
res, _, _ := vmLogin.Call() res, _, _ := vmLogin.Call()
if res == 1 { if res == 1 {
runVoicemeeter(kindId, bits) runVoicemeeter(kindId)
time.Sleep(time.Second)
} else if res != 0 { } else if res != 0 {
err := fmt.Errorf("VBVMR_Login returned %d", res) err := fmt.Errorf("VBVMR_Login returned %d", res)
return err return err
} }
log.Info("Logged into Voicemeeter ", kindId)
var ver_s string
start := time.Now()
var err error
for time.Since(start).Seconds() < float64(timeout) {
time.Sleep(time.Duration(100) * time.Millisecond)
if ver_s, err = getVersion(); err == nil {
log.Infof("Logged into Voicemeeter %s v%s", kindMap[kindId], ver_s)
log.Debugf("Log in time: %.2f", time.Since(start).Seconds())
break
}
}
if err != nil {
return errors.New("timeout logging into the API")
}
clear() clear()
return nil return nil
} }
@ -83,22 +68,18 @@ func logout(kindId string) error {
err := fmt.Errorf("VBVMR_Logout returned %d", int32(res)) err := fmt.Errorf("VBVMR_Logout returned %d", int32(res))
return err return err
} }
log.Infof("Logged out of Voicemeeter %s", kindMap[kindId]) log.Info("Logged out of Voicemeeter ", kindId)
return nil return nil
} }
// runVoicemeeter attempts to launch a Voicemeeter GUI of a kind. // runVoicemeeter attempts to launch a Voicemeeter GUI of a kind.
func runVoicemeeter(kindId string, bits int) error { func runVoicemeeter(kindId string) error {
vals := map[string]uint64{ vals := map[string]uint64{
"basic": 1, "basic": 1,
"banana": 2, "banana": 2,
"potato": 3, "potato": 3,
} }
val := vals[kindId] res, _, _ := vmRunvm.Call(uintptr(vals[kindId]))
if strings.Contains(runtime.GOARCH, "64") && bits == 64 {
val += 3
}
res, _, _ := vmRunvm.Call(uintptr(val))
if int32(res) != 0 { if int32(res) != 0 {
err := fmt.Errorf("VBVMR_RunVoicemeeter returned %d", int32(res)) err := fmt.Errorf("VBVMR_RunVoicemeeter returned %d", int32(res))
return err return err
@ -112,7 +93,6 @@ func getVersion() (string, error) {
res, _, _ := vmGetvmVersion.Call(uintptr(unsafe.Pointer(&ver))) res, _, _ := vmGetvmVersion.Call(uintptr(unsafe.Pointer(&ver)))
if int32(res) != 0 { if int32(res) != 0 {
err := fmt.Errorf("VBVMR_GetVoicemeeterVersion returned %d", int32(res)) err := fmt.Errorf("VBVMR_GetVoicemeeterVersion returned %d", int32(res))
log.Error(err.Error())
return "", err return "", err
} }
v1 := (ver & 0xFF000000) >> 24 v1 := (ver & 0xFF000000) >> 24

View File

@ -1,4 +1,4 @@
module hotkeys module main
go 1.19 go 1.19

View File

@ -1,4 +1,4 @@
module obs module main
go 1.18 go 1.18

View File

@ -1,6 +1,6 @@
## About ## About
A Voicemeeter CLI, offers ability to toggle, get and set parameters. A simple voicemeeter-cli program. Offers ability to toggle, get and set parameters.
## Install ## Install
@ -8,32 +8,28 @@ First build and install it with `go install` (skip this step if using binary fro
## Use ## Use
Commands that begin with `!` will toggle a parameter, commands that contain `=` will set a parameter, all other commands will get a value. Toggle with `!` prefix, get by excluding `=` and set by including `=`. Mix and match arguments.
You may pass the following optional flags: You may pass the following optional flags:
- -h: Print the help message - -v: (-verbose) to toggle console output.
- -i: Enable interactive mode - -i: (-interactive) to toggle interactive mode.
- -k: The kind of Voicemeeter GUI to launch, defaults to Banana - -k: (-kind) to set the kind of Voicemeeter. Defaults to banana.
- -l: Log level (0 up to 6), defaults to 3, Warn Level - -d: (-delay) to set a delay on the getters. Defaults to 20ms.
- -d: Set the delay between commands, defaults to 20ms
- -v: Enable extra console output (toggle and set messages).
for example: for example:
`vm-cli.exe -v -l=4 -k=potato strip[0].mute=0 strip[0].mute !strip[0].mute strip[0].mute bus[0].gain=-8.8 command.lock=1` `vm-cli.exe -v -k=potato -d=25 strip[0].mute=0 strip[0].mute !strip[0].mute strip[0].mute bus[0].gain=-8.8 command.lock=1`
Expected output: Expected output:
``` ```
time="<timestamp>" level=info msg="Logged into Voicemeeter Potato v3.1.1.1" Running command strip[0].mute=0
Setting strip[0].mute=0 Value of strip[0].mute is: 0
strip[0].mute: 0.00
Toggling strip[0].mute Toggling strip[0].mute
strip[0].mute: 1.00 Value of strip[0].mute is: 1
Setting bus[0].gain=-8.8 Running command bus[0].gain=-8.8
Setting command.lock=1 Running command command.lock=1
time="<timestamp>" level=info msg="Logged out of Voicemeeter Potato"
``` ```
If running in interactive mode enter `Q`, to exit. If running in interactive mode enter `q`, `quit` or `<Enter>` to exit.

View File

@ -4,28 +4,18 @@ import (
"bufio" "bufio"
"flag" "flag"
"fmt" "fmt"
"log"
"os" "os"
"strings" "strings"
log "github.com/sirupsen/logrus"
"github.com/onyx-and-iris/voicemeeter/v2" "github.com/onyx-and-iris/voicemeeter/v2"
) )
const ( type (
FLOAT = iota verbosePrinter struct {
STRING
)
type result struct {
kind int
stringParam string
floatParam float64
}
type verbosePrinter struct {
verbose bool verbose bool
} }
)
func newVerbosePrinter() *verbosePrinter { func newVerbosePrinter() *verbosePrinter {
return &verbosePrinter{} return &verbosePrinter{}
@ -33,7 +23,7 @@ func newVerbosePrinter() *verbosePrinter {
func (v *verbosePrinter) printf(format string, a ...interface{}) { func (v *verbosePrinter) printf(format string, a ...interface{}) {
if v.verbose { if v.verbose {
fmt.Printf(format, a...) fmt.Printf(format+"\n", a...)
} }
} }
@ -50,68 +40,28 @@ func main() {
kind string kind string
delay int delay int
interactive bool interactive bool
loglevel int
help bool
) )
flag.Usage = usage
flag.BoolVar(&help, "help", false, "print the help message")
flag.BoolVar(&help, "h", false, "print the help message (shorthand)")
flag.StringVar(&kind, "kind", "banana", "kind of voicemeeter") flag.StringVar(&kind, "kind", "banana", "kind of voicemeeter")
flag.StringVar(&kind, "k", "banana", "kind of voicemeeter (shorthand)") flag.StringVar(&kind, "k", "banana", "kind of voicemeeter (shorthand)")
flag.IntVar(&delay, "delay", 20, "delay between commands") flag.IntVar(&delay, "delay", 20, "delay between commands")
flag.IntVar(&delay, "d", 20, "delay between commands (shorthand)") flag.IntVar(&delay, "d", 20, "delay between commands (shorthand)")
flag.BoolVar(&vPrinter.verbose, "verbose", false, "toggle console output")
flag.BoolVar(&vPrinter.verbose, "v", false, "toggle console output (shorthand)")
flag.BoolVar(&interactive, "interactive", false, "toggle interactive mode") flag.BoolVar(&interactive, "interactive", false, "toggle interactive mode")
flag.BoolVar(&interactive, "i", false, "toggle interactive mode (shorthand)") flag.BoolVar(&interactive, "i", false, "toggle interactive mode (shorthand)")
flag.IntVar(&loglevel, "loglevel", int(log.WarnLevel), "set the log level")
flag.IntVar(&loglevel, "l", int(log.WarnLevel), "set the log level (shorthand)")
flag.BoolVar(&vPrinter.verbose, "verbose", false, "enable extra console output (toggle and set messages)")
flag.BoolVar(&vPrinter.verbose, "v", false, "enable extra console output (toggle and set messages) (shorthand)")
flag.Parse() flag.Parse()
if help {
flag.Usage()
return
}
if loglevel >= int(log.PanicLevel) && loglevel <= int(log.TraceLevel) {
log.SetLevel(log.Level(loglevel))
}
vm, err := vmConnect(kind, delay) vm, err := vmConnect(kind, delay)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
defer vm.Logout() defer vm.Logout()
if interactive { err = runCommands(vm, interactive)
interactiveMode(vm) if err != nil {
return fmt.Println(err)
} }
args := flag.Args()
if len(args) == 0 {
flag.Usage()
return
}
for _, arg := range args {
if err := parse(vm, arg); err != nil {
log.Error(err.Error())
}
}
}
func usage() {
fmt.Println("usage: ./vm-cli.exe [-h] [-i] [-k] [-l] [-d] [-v]\n" +
"Where:\n" +
"\th: Print the help message\n" +
"\ti: Enable interactive mode\n" +
"\tk: The kind of Voicemeeter GUI to launch, defaults to Banana\n" +
"\tl: Log level 0 up to 6, (defaults to 3, Warn Level)\n" +
"\td: Set the delay between commands (defaults to 20ms)\n" +
"\tv: Enable extra console output (toggle and set messages).")
} }
func vmConnect(kind string, delay int) (*voicemeeter.Remote, error) { func vmConnect(kind string, delay int) (*voicemeeter.Remote, error) {
@ -128,23 +78,38 @@ func vmConnect(kind string, delay int) (*voicemeeter.Remote, error) {
return vm, nil return vm, nil
} }
func interactiveMode(vm *voicemeeter.Remote) error { func runCommands(vm *voicemeeter.Remote, interactive bool) error {
fmt.Println("Interactive mode enabled. Enter 'Q' to exit.") if interactive {
return interactiveMode(vm)
}
args := flag.Args()
if len(args) == 0 {
err := fmt.Errorf("must provide some commands to run")
return err
}
for _, arg := range args {
err := parse(vm, arg)
if err != nil {
vPrinter.printf(err.Error())
}
}
return nil
}
func interactiveMode(vm *voicemeeter.Remote) error {
vPrinter.printf("running in interactive mode... waiting for input")
scanner := bufio.NewScanner(os.Stdin) scanner := bufio.NewScanner(os.Stdin)
fmt.Printf(">> ")
for scanner.Scan() { for scanner.Scan() {
input := scanner.Text() input := scanner.Text()
if strings.ToUpper(input) == "Q" { if input == "q" || input == "quit" || input == "" {
break return nil
} }
for _, cmd := range strings.Split(input, " ") { for _, cmd := range strings.Split(input, " ") {
if err := parse(vm, cmd); err != nil { err := parse(vm, cmd)
log.Error(err.Error()) if err != nil {
vPrinter.printf(err.Error())
} }
} }
fmt.Printf(">> ")
} }
if scanner.Err() != nil { if scanner.Err() != nil {
return scanner.Err() return scanner.Err()
@ -154,60 +119,58 @@ func interactiveMode(vm *voicemeeter.Remote) error {
func parse(vm *voicemeeter.Remote, cmd string) error { func parse(vm *voicemeeter.Remote, cmd string) error {
if cmd[0] == '!' { if cmd[0] == '!' {
if err := toggleCmd(vm, cmd[1:]); err != nil { err := toggleCmd(vm, cmd[1:])
return err if err != nil {
}
} else if strings.Contains(cmd, "=") {
if err := setCmd(vm, cmd); err != nil {
return err return err
} }
} else { } else {
r := result{kind: FLOAT} if strings.Contains(cmd, "=") {
if err := getCmd(vm, cmd, &r); err != nil { err := setCmd(vm, cmd)
if err != nil {
return err
}
} else {
err := getCmd(vm, cmd)
if err != nil {
return err return err
} }
switch r.kind {
case FLOAT:
fmt.Printf("%s: %.2f\n", cmd, r.floatParam)
case STRING:
fmt.Printf("%s: %s\n", cmd, r.stringParam)
} }
} }
return nil return nil
} }
func toggleCmd(vm *voicemeeter.Remote, cmd string) error { func toggleCmd(vm *voicemeeter.Remote, cmd string) error {
r := result{kind: FLOAT} val, err := vm.GetFloat(cmd)
if err := getCmd(vm, cmd, &r); err != nil { if err != nil {
err = fmt.Errorf("unable to toggle %s", cmd)
return err return err
} }
if r.kind == FLOAT && (r.floatParam == 0 || r.floatParam == 1) { vm.SetFloat(cmd, 1-val)
vPrinter.printf("Toggling %s\n", cmd) vPrinter.printf("Toggling %s", cmd)
vm.SetFloat(cmd, 1-r.floatParam)
} else {
log.Warnf("%s does not appear to be a boolean parameter", cmd)
}
return nil return nil
} }
func setCmd(vm *voicemeeter.Remote, cmd string) error { func setCmd(vm *voicemeeter.Remote, cmd string) error {
if err := vm.SendText(cmd); err != nil { vPrinter.printf("Running command %s", cmd)
err := vm.SendText(cmd)
if err != nil {
err = fmt.Errorf("unable to set %s", cmd) err = fmt.Errorf("unable to set %s", cmd)
return err return err
} }
vPrinter.printf("Setting %s\n", cmd)
return nil return nil
} }
func getCmd(vm *voicemeeter.Remote, cmd string, r *result) error { func getCmd(vm *voicemeeter.Remote, cmd string) error {
if val, err := vm.GetFloat(cmd); err == nil { valF, err := vm.GetFloat(cmd)
r.floatParam = val if err != nil {
} else if val, err := vm.GetString(cmd); err == nil { valS, err := vm.GetString(cmd)
r.kind = STRING if err != nil {
r.stringParam = val err = fmt.Errorf("unable to get %s", cmd)
} else {
err := fmt.Errorf("unknown parameter '%s'", cmd)
return err return err
} }
fmt.Printf("Value of %s is: %s", cmd, valS)
} else {
fmt.Printf("Value of %s is: %v", cmd, valF)
}
return nil return nil
} }

View File

@ -21,8 +21,6 @@ type Remote struct {
Midi *midi_t Midi *midi_t
pooler *pooler pooler *pooler
timeout int
bits int
} }
// String implements the fmt.stringer interface // String implements the fmt.stringer interface
@ -33,7 +31,7 @@ func (r *Remote) String() string {
// Login logs into the API // Login logs into the API
// then it intializes the pooler // then it intializes the pooler
func (r *Remote) Login() error { func (r *Remote) Login() error {
err := login(r.Kind.Name, r.timeout, r.bits) err := login(r.Kind.Name)
if err != nil { if err != nil {
return err return err
} }
@ -59,10 +57,12 @@ func (r *Remote) InitPooler() {
// Run launches the Voicemeeter GUI for a kind. // Run launches the Voicemeeter GUI for a kind.
func (r *Remote) Run(kindId string) error { func (r *Remote) Run(kindId string) error {
err := runVoicemeeter(kindId, r.bits) err := runVoicemeeter(kindId)
if err != nil { if err != nil {
return err return err
} }
time.Sleep(time.Second)
clear()
return nil return nil
} }
@ -173,7 +173,6 @@ type remoteBuilder interface {
makeDevice() remoteBuilder makeDevice() remoteBuilder
makeRecorder() remoteBuilder makeRecorder() remoteBuilder
makeMidi() remoteBuilder makeMidi() remoteBuilder
setDefaults() remoteBuilder
Build() remoteBuilder Build() remoteBuilder
Get() *Remote Get() *Remote
} }
@ -213,7 +212,7 @@ func (b *genericBuilder) setKind() remoteBuilder {
// makeStrip makes a strip slice and assigns it to remote.Strip // makeStrip makes a strip slice and assigns it to remote.Strip
// []iStrip comprises of both physical and virtual strip types // []iStrip comprises of both physical and virtual strip types
func (b *genericBuilder) makeStrip() remoteBuilder { func (b *genericBuilder) makeStrip() remoteBuilder {
log.Debug("building strip") log.Info("building strip")
strip := make([]iStrip, b.k.NumStrip()) strip := make([]iStrip, b.k.NumStrip())
for i := 0; i < b.k.NumStrip(); i++ { for i := 0; i < b.k.NumStrip(); i++ {
if i < b.k.PhysIn { if i < b.k.PhysIn {
@ -229,7 +228,7 @@ func (b *genericBuilder) makeStrip() remoteBuilder {
// makeBus makes a bus slice and assigns it to remote.Bus // makeBus makes a bus slice and assigns it to remote.Bus
// []t_bus comprises of both physical and virtual bus types // []t_bus comprises of both physical and virtual bus types
func (b *genericBuilder) makeBus() remoteBuilder { func (b *genericBuilder) makeBus() remoteBuilder {
log.Debug("building bus") log.Info("building bus")
bus := make([]iBus, b.k.NumBus()) bus := make([]iBus, b.k.NumBus())
for i := 0; i < b.k.NumBus(); i++ { for i := 0; i < b.k.NumBus(); i++ {
if i < b.k.PhysOut { if i < b.k.PhysOut {
@ -244,7 +243,7 @@ func (b *genericBuilder) makeBus() remoteBuilder {
// makeButton makes a button slice and assigns it to remote.Button // makeButton makes a button slice and assigns it to remote.Button
func (b *genericBuilder) makeButton() remoteBuilder { func (b *genericBuilder) makeButton() remoteBuilder {
log.Debug("building button") log.Info("building button")
button := make([]button, 80) button := make([]button, 80)
for i := 0; i < 80; i++ { for i := 0; i < 80; i++ {
button[i] = newButton(i) button[i] = newButton(i)
@ -255,46 +254,39 @@ func (b *genericBuilder) makeButton() remoteBuilder {
// makeCommand makes a command type and assigns it to remote.Command // makeCommand makes a command type and assigns it to remote.Command
func (b *genericBuilder) makeCommand() remoteBuilder { func (b *genericBuilder) makeCommand() remoteBuilder {
log.Debug("building command") log.Info("building command")
b.r.Command = newCommand() b.r.Command = newCommand()
return b return b
} }
// makeVban makes a vban type and assigns it to remote.Vban // makeVban makes a vban type and assigns it to remote.Vban
func (b *genericBuilder) makeVban() remoteBuilder { func (b *genericBuilder) makeVban() remoteBuilder {
log.Debug("building vban") log.Info("building vban")
b.r.Vban = newVban(b.k) b.r.Vban = newVban(b.k)
return b return b
} }
// makeDevice makes a device type and assigns it to remote.Device // makeDevice makes a device type and assigns it to remote.Device
func (b *genericBuilder) makeDevice() remoteBuilder { func (b *genericBuilder) makeDevice() remoteBuilder {
log.Debug("building device") log.Info("building device")
b.r.Device = newDevice() b.r.Device = newDevice()
return b return b
} }
// makeRecorder makes a recorder type and assigns it to remote.Recorder // makeRecorder makes a recorder type and assigns it to remote.Recorder
func (b *genericBuilder) makeRecorder() remoteBuilder { func (b *genericBuilder) makeRecorder() remoteBuilder {
log.Debug("building recorder") log.Info("building recorder")
b.r.Recorder = newRecorder() b.r.Recorder = newRecorder()
return b return b
} }
// makeMidi makes a midi type and assigns it to remote.Midi // makeMidi makes a midi type and assigns it to remote.Midi
func (b *genericBuilder) makeMidi() remoteBuilder { func (b *genericBuilder) makeMidi() remoteBuilder {
log.Debug("building midi") log.Info("building midi")
b.r.Midi = newMidi() b.r.Midi = newMidi()
return b 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 // Get returns a fully constructed remote type for a kind
func (b *genericBuilder) Get() *Remote { func (b *genericBuilder) Get() *Remote {
return &b.r return &b.r
@ -314,8 +306,7 @@ func (basb *genericBuilder) Build() remoteBuilder {
makeCommand(). makeCommand().
makeVban(). makeVban().
makeDevice(). makeDevice().
makeMidi(). makeMidi()
setDefaults()
} }
// bananaBuilder represents a builder specific to banana type // bananaBuilder represents a builder specific to banana type
@ -333,8 +324,7 @@ func (banb *bananaBuilder) Build() remoteBuilder {
makeVban(). makeVban().
makeDevice(). makeDevice().
makeRecorder(). makeRecorder().
makeMidi(). makeMidi()
setDefaults()
} }
// potatoBuilder represents a builder specific to potato type // potatoBuilder represents a builder specific to potato type
@ -352,8 +342,7 @@ func (potb *potatoBuilder) Build() remoteBuilder {
makeVban(). makeVban().
makeDevice(). makeDevice().
makeRecorder(). makeRecorder().
makeMidi(). makeMidi()
setDefaults()
} }
var ( var (
@ -361,22 +350,6 @@ var (
vmdelay int 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() { func init() {
log.SetOutput(os.Stdout) log.SetOutput(os.Stdout)
log.SetLevel(log.WarnLevel) log.SetLevel(log.WarnLevel)
@ -384,7 +357,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, opts ...Option) (*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)
@ -407,11 +380,5 @@ func NewRemote(kindId string, delay int, opts ...Option) (*Remote, error) {
director.SetBuilder(&potatoBuilder{genericBuilder{kind, Remote{}}}) director.SetBuilder(&potatoBuilder{genericBuilder{kind, Remote{}}})
} }
director.Construct() director.Construct()
r := director.Get() return director.Get(), nil
for _, opt := range opts {
opt(r)
}
return r, nil
} }