14 Commits

Author SHA1 Message Date
6512b35155 added Option function sections to README. 2024-07-01 07:20:52 +01:00
5aabd0a343 added 2.1.0 section to CHANGELOG 2024-07-01 07:20:30 +01:00
0558e8f81d login() is now tested for up to {Remote}.timeout seconds
if timeout exceeded return an error

runVoicemeeter() now promotes types to x64bit on 64-bit OS unless overridden.

Option functions WithTimeout() and WithBits() added.
2024-07-01 07:20:05 +01:00
07018d1703 upd link for documentation 2024-01-03 09:30:57 +00:00
73627ddbf1 add go.work files to gitignore 2023-12-05 11:25:53 +00:00
dd55dd8fdf Merge pull request #4 from Francisco46018/dev
Add gain to Recorder
2023-10-04 15:02:08 +01:00
FranciscoFilipe
00d0be8055 Add gain to Recorder 2023-09-09 22:57:45 +01:00
418d04a08e fix docstrings 2022-12-15 11:27:39 +00:00
8038670203 update link to docs in readme 2022-12-15 11:26:10 +00:00
3319a8c4f4 upd pkg.go.dev badge in readme 2022-12-15 01:02:24 +00:00
b777025f88 upd installation in readme 2022-12-15 00:52:29 +00:00
93d5e2db67 upd docstring 2022-12-15 00:43:19 +00:00
a23a9f8598 update docstrings in observer example 2022-12-15 00:41:57 +00:00
195ee326a0 update go.mod files 2022-12-15 00:25:55 +00:00
11 changed files with 367 additions and 276 deletions

4
.gitignore vendored
View File

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

View File

@@ -11,6 +11,19 @@ Before any major/minor/patch bump all unit tests will be run to verify they pass
- [x]
## [2.1.0] - 2024-07-01
### Added
- Added a configurable 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
V2 introduces some breaking changes.

View File

@@ -1,16 +1,14 @@
[![Go Reference](https://pkg.go.dev/badge/github.com/onyx-and-iris/voicemeeter.svg)](https://pkg.go.dev/github.com/onyx-and-iris/voicemeeter)
[![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 Voicemeeter API
This package offers a Go interface for the Voicemeeter Remote C API.
# A Go Wrapper for the Voicemeeter API
For an outline of past/future changes refer to: [CHANGELOG](CHANGELOG.md)
## Tested against
- Basic 1.0.8.8
- Banana 2.0.6.8
- Potato 3.0.2.8
- Basic 1.1.1.1
- Banana 2.1.1.1
- Potato 3.1.1.1
## Requirements
@@ -23,7 +21,7 @@ Initialize your own module then `go get`
```
go mod init github.com/x/y
go get github.com/onyx-and-iris/voicemeeter
go get github.com/onyx-and-iris/voicemeeter/v2
```
## `Use`
@@ -67,7 +65,7 @@ func vmConnect() (*voicemeeter.Remote, error) {
}
```
## `voicemeeter.NewRemote(<kindId>, <delay>)`
## `voicemeeter.NewRemote(<kindId>, <delay>, opts ...Option)`
### `kindId`
@@ -83,6 +81,18 @@ Pass a delay in milliseconds to force the getters to wait for dirty parameters t
Useful if not listening for event updates.
### `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))`
### `voicemeeter.WithBits(timeout int)`
Set a login timeout, defaults to 2 seconds. For example to set it to 1s:
`voicemeeter.NewRemote("banana", 20, voicemeeter.WithBits(1))`
## `Remote Type`
#### `vm.Strip`

34
base.go
View File

@@ -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

View File

@@ -1,10 +1,10 @@
module main
module hotkeys
go 1.19
require (
github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203
github.com/onyx-and-iris/voicemeeter v1.10.1
github.com/onyx-and-iris/voicemeeter/v2 v2.0.0
github.com/sirupsen/logrus v1.9.0
)

View File

@@ -3,8 +3,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203 h1:XBBHcIb256gUJtLmY22n99HaZTz+r2Z51xUPi01m3wg=
github.com/eiannone/keyboard v0.0.0-20220611211555-0d226195f203/go.mod h1:E1jcSv8FaEny+OP/5k9UxZVw9YFWGj7eI4KR/iOBqCg=
github.com/onyx-and-iris/voicemeeter v1.10.1 h1:kpPN/cTYe1JG2aLUD+/m/bMUbp7wXrqrk1fL+sV8yko=
github.com/onyx-and-iris/voicemeeter v1.10.1/go.mod h1:LayUoN/MWSqKXSOGQ7AcLvwoefsL+zQ9CjncLs3WqsU=
github.com/onyx-and-iris/voicemeeter/v2 v2.0.0 h1:AXem+OMeKDuJd2KoLpzHEU70Rx2057p4XKgiOJkXCIo=
github.com/onyx-and-iris/voicemeeter/v2 v2.0.0/go.mod h1:ULRO0N2Wg7Ymj7CEg4TI7CJobx9yVEZ5Lbh7oWi7woA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=

View File

@@ -1,11 +1,11 @@
module main
module obs
go 1.18
require (
github.com/BurntSushi/toml v1.2.0
github.com/andreykaipov/goobs v0.10.0
github.com/onyx-and-iris/voicemeeter v1.10.1
github.com/onyx-and-iris/voicemeeter/v2 v2.0.0
github.com/sirupsen/logrus v1.9.0
)

View File

@@ -13,8 +13,8 @@ github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
github.com/onyx-and-iris/voicemeeter v1.10.1 h1:kpPN/cTYe1JG2aLUD+/m/bMUbp7wXrqrk1fL+sV8yko=
github.com/onyx-and-iris/voicemeeter v1.10.1/go.mod h1:LayUoN/MWSqKXSOGQ7AcLvwoefsL+zQ9CjncLs3WqsU=
github.com/onyx-and-iris/voicemeeter/v2 v2.0.0 h1:AXem+OMeKDuJd2KoLpzHEU70Rx2057p4XKgiOJkXCIo=
github.com/onyx-and-iris/voicemeeter/v2 v2.0.0/go.mod h1:ULRO0N2Wg7Ymj7CEg4TI7CJobx9yVEZ5Lbh7oWi7woA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=

View File

@@ -20,8 +20,7 @@ func newObserver(vm *voicemeeter.Remote) *observer {
return &observer{vm, make(chan string)}
}
// OnUpdate satisfies the observer interface defined in publisher.go
// for each event type an action is triggered when the event occurs.
// Listen registers the observer channel and listens for updates.
func (o observer) Listen() {
o.vm.Register(o.events)
@@ -47,13 +46,14 @@ func init() {
log.SetLevel(log.InfoLevel)
}
// runObserver initiates a single observer and
// starts its Listen() function in a goroutine.
func runObserver(vm *voicemeeter.Remote) {
o := newObserver(vm)
go o.Listen()
}
// main connects to Voiceemeter, registers observer for updates
// runs updates for 30 seconds and then deregisters observer.
// main connects to Voiceemeter and runs a single observer for 30 seconds.
func main() {
vm, err := vmConnect()
if err != nil {
@@ -67,6 +67,7 @@ func main() {
}
// vmConnect connects to Voicemeeter potato and logs into the API
// it also add ldirty to event updates.
func vmConnect() (*voicemeeter.Remote, error) {
vm, err := voicemeeter.NewRemote("basic", 0)
if err != nil {

View File

@@ -51,3 +51,13 @@ func (r *recorder) Rew() {
func (r *recorder) Loop(val bool) {
r.setter_bool("Mode.Loop", val)
}
// Gain returns the value of the Gain parameter
func (r *recorder) Gain() float64 {
return r.getter_float("Gain")
}
// SetGain sets the value of the Gain parameter
func (r *recorder) SetGain(val float64) {
r.setter_float("Gain", val)
}

View File

@@ -21,6 +21,8 @@ type Remote struct {
Midi *midi_t
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
}