diff --git a/base.go b/base.go index b494e91..c964cb8 100644 --- a/base.go +++ b/base.go @@ -2,8 +2,10 @@ package voicemeeter import ( "bytes" + "errors" "fmt" "math" + "runtime" "strings" "syscall" "time" @@ -45,16 +47,29 @@ var ( // login logs into the API, // attempts to launch Voicemeeter if it's not running, // initializes dirty parameters. -func login(kindId string) error { +func login(kindId string, timeout, bits int) error { res, _, _ := vmLogin.Call() if res == 1 { - runVoicemeeter(kindId) - time.Sleep(time.Second) + runVoicemeeter(kindId, bits) } else if res != 0 { err := fmt.Errorf("VBVMR_Login returned %d", res) 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() return nil } @@ -68,18 +83,22 @@ func logout(kindId string) error { err := fmt.Errorf("VBVMR_Logout returned %d", int32(res)) return err } - log.Info("Logged out of Voicemeeter ", kindId) + log.Infof("Logged out of Voicemeeter %s", kindMap[kindId]) return nil } // runVoicemeeter attempts to launch a Voicemeeter GUI of a kind. -func runVoicemeeter(kindId string) error { +func runVoicemeeter(kindId string, bits int) error { vals := map[string]uint64{ "basic": 1, "banana": 2, "potato": 3, } - res, _, _ := vmRunvm.Call(uintptr(vals[kindId])) + val := vals[kindId] + if strings.Contains(runtime.GOARCH, "64") && bits == 64 { + val += 3 + } + res, _, _ := vmRunvm.Call(uintptr(val)) if int32(res) != 0 { err := fmt.Errorf("VBVMR_RunVoicemeeter returned %d", int32(res)) return err @@ -93,6 +112,7 @@ func getVersion() (string, error) { res, _, _ := vmGetvmVersion.Call(uintptr(unsafe.Pointer(&ver))) if int32(res) != 0 { err := fmt.Errorf("VBVMR_GetVoicemeeterVersion returned %d", int32(res)) + log.Error(err.Error()) return "", err } v1 := (ver & 0xFF000000) >> 24 diff --git a/remote.go b/remote.go index cf6c9d1..d59ab02 100644 --- a/remote.go +++ b/remote.go @@ -20,7 +20,9 @@ type Remote struct { Recorder *recorder Midi *midi_t - pooler *pooler + pooler *pooler + timeout int + bits int } // String implements the fmt.stringer interface @@ -31,7 +33,7 @@ func (r *Remote) String() string { // Login logs into the API // then it intializes the pooler func (r *Remote) Login() error { - err := login(r.Kind.Name) + err := login(r.Kind.Name, r.timeout, r.bits) if err != nil { return err } @@ -57,12 +59,10 @@ func (r *Remote) InitPooler() { // Run launches the Voicemeeter GUI for a kind. func (r *Remote) Run(kindId string) error { - err := runVoicemeeter(kindId) + err := runVoicemeeter(kindId, r.bits) if err != nil { return err } - time.Sleep(time.Second) - clear() return nil } @@ -173,6 +173,7 @@ type remoteBuilder interface { makeDevice() remoteBuilder makeRecorder() remoteBuilder makeMidi() remoteBuilder + setDefaults() remoteBuilder Build() remoteBuilder Get() *Remote } @@ -212,7 +213,7 @@ func (b *genericBuilder) setKind() remoteBuilder { // 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.Info("building strip") + log.Debug("building strip") strip := make([]iStrip, b.k.NumStrip()) for i := 0; i < b.k.NumStrip(); i++ { if i < b.k.PhysIn { @@ -228,7 +229,7 @@ func (b *genericBuilder) makeStrip() remoteBuilder { // 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.Info("building bus") + log.Debug("building bus") bus := make([]iBus, b.k.NumBus()) for i := 0; i < b.k.NumBus(); i++ { if i < b.k.PhysOut { @@ -243,7 +244,7 @@ func (b *genericBuilder) makeBus() remoteBuilder { // makeButton makes a button slice and assigns it to remote.Button func (b *genericBuilder) makeButton() remoteBuilder { - log.Info("building button") + log.Debug("building button") button := make([]button, 80) for i := 0; i < 80; i++ { button[i] = newButton(i) @@ -254,39 +255,46 @@ func (b *genericBuilder) makeButton() remoteBuilder { // makeCommand makes a command type and assigns it to remote.Command func (b *genericBuilder) makeCommand() remoteBuilder { - log.Info("building command") + 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.Info("building vban") + 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.Info("building device") + 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.Info("building recorder") + 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.Info("building midi") + 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 @@ -306,7 +314,8 @@ func (basb *genericBuilder) Build() remoteBuilder { makeCommand(). makeVban(). makeDevice(). - makeMidi() + makeMidi(). + setDefaults() } // bananaBuilder represents a builder specific to banana type @@ -324,7 +333,8 @@ func (banb *bananaBuilder) Build() remoteBuilder { makeVban(). makeDevice(). makeRecorder(). - makeMidi() + makeMidi(). + setDefaults() } // potatoBuilder represents a builder specific to potato type @@ -342,7 +352,8 @@ func (potb *potatoBuilder) Build() remoteBuilder { makeVban(). makeDevice(). makeRecorder(). - makeMidi() + makeMidi(). + setDefaults() } var ( @@ -350,6 +361,22 @@ var ( 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) @@ -357,7 +384,7 @@ func init() { // NewRemote returns a Remote type for a kind // this is the interface entry point -func NewRemote(kindId string, delay int) (*Remote, error) { +func NewRemote(kindId string, delay int, opts ...Option) (*Remote, error) { kind, ok := kindMap[kindId] if !ok { err := fmt.Errorf("unknown Voicemeeter kind '%s'", kindId) @@ -380,5 +407,11 @@ func NewRemote(kindId string, delay int) (*Remote, error) { director.SetBuilder(&potatoBuilder{genericBuilder{kind, Remote{}}}) } director.Construct() - return director.Get(), nil + r := director.Get() + + for _, opt := range opts { + opt(r) + } + + return r, nil }