mirror of
https://github.com/onyx-and-iris/voicemeeter.git
synced 2025-04-20 04:03:53 +01:00
Compare commits
No commits in common. "359c2d61b5724c2b6c39c6fbee40f1be71a5fa74" and "07018d17039a22a08de3e57a1f458943b720283c" have entirely different histories.
359c2d61b5
...
07018d1703
13
CHANGELOG.md
13
CHANGELOG.md
@ -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.
|
||||||
|
24
README.md
24
README.md
@ -1,14 +1,16 @@
|
|||||||
[](https://pkg.go.dev/github.com/onyx-and-iris/voicemeeter/v2)
|
[](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`
|
||||||
|
34
base.go
34
base.go
@ -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
|
||||||
|
67
remote.go
67
remote.go
@ -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
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user