mirror of
https://github.com/onyx-and-iris/voicemeeter.git
synced 2026-04-18 05:23:31 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70d69f5599 | ||
|
|
f16bed893f | ||
|
|
e7061ce855 | ||
|
|
39411ab332 | ||
|
|
6148d45b76 |
263
README.md
263
README.md
@@ -19,9 +19,13 @@ For an outline of past/future changes refer to: [CHANGELOG](CHANGELOG.md)
|
||||
|
||||
## Installation
|
||||
|
||||
#### GO.MOD
|
||||
|
||||
Add to your `go.mod` file:
|
||||
|
||||
`require github.com/onyx-and-iris/voicemeeter-api-go v1.0.0`
|
||||
`require github.com/onyx-and-iris/voicemeeter-api-go v1.0.2`
|
||||
|
||||
#### GO GET
|
||||
|
||||
Install voicemeeter-api-go package from your console
|
||||
|
||||
@@ -37,7 +41,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/onyx-and-iris/voicemeeter-api-go/voicemeeter"
|
||||
"github.com/onyx-and-iris/voicemeeter-api-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -54,7 +58,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## `kindId`
|
||||
|
||||
Pass the kind of Voicemeeter as an argument. kindId may be:
|
||||
@@ -64,34 +67,61 @@ Pass the kind of Voicemeeter as an argument. kindId may be:
|
||||
- `potato`
|
||||
|
||||
## `Remote Type`
|
||||
|
||||
#### `vmRem.Strip`
|
||||
|
||||
[]t_strip slice containing both physicalStrip and virtualStrip types
|
||||
|
||||
#### `vmRem.Bus`
|
||||
|
||||
[]t_bus slice containing both physicalBus and virtualBus types
|
||||
|
||||
#### `vmRem.Button`
|
||||
|
||||
[]button slice containing button types, one for each macrobutton
|
||||
|
||||
#### `vmRem.Command`
|
||||
|
||||
pointer to command type, represents action type functions
|
||||
|
||||
#### `vmRem.Vban`
|
||||
|
||||
pointer to vban type, containing both vbanInStream and vbanOutStream slices
|
||||
|
||||
#### `vmRem.Device`
|
||||
|
||||
pointer to device type, represents physical input/output hardware devices
|
||||
|
||||
#### `vmRem.Recorder`
|
||||
|
||||
pointer to recorder type, represents the recorder
|
||||
|
||||
#### `vmRem.Type()`
|
||||
|
||||
returns the type of Voicemeeter as a string
|
||||
|
||||
#### `vmRem.Version()`
|
||||
|
||||
returns the version of Voicemeeter as a string
|
||||
|
||||
#### `vmRem.SendText(<script>)`
|
||||
|
||||
sets many parameters in script format eg. ("Strip[0].Mute=1;Bus[3].Gain=3.6")
|
||||
|
||||
#### `vmRem.Register(o observer)`
|
||||
|
||||
register an object as an observer
|
||||
|
||||
#### `vmRem.Deregister(o observer)`
|
||||
|
||||
deregister an object as an observer
|
||||
|
||||
#### `vmRem.Pdirty()`
|
||||
|
||||
returns True iff a GUI parameter has changed
|
||||
|
||||
#### `vmRem.Mdirty()`
|
||||
|
||||
returns True iff a macrobutton paramter has changed
|
||||
|
||||
## `Available commands`
|
||||
@@ -100,26 +130,26 @@ returns True iff a macrobutton paramter has changed
|
||||
|
||||
The following functions are available
|
||||
|
||||
- `GetMute() bool`
|
||||
- `SetMute(val bool)`
|
||||
- `GetMono() bool`
|
||||
- `SetMono(val bool)`
|
||||
- `GetSolo() bool`
|
||||
- `SetSolo(val bool)`
|
||||
- `GetLimit() int`
|
||||
- `SetLimit(val int)` from -40 to 12
|
||||
- `GetLabel() string`
|
||||
- `SetLabel(val string)`
|
||||
- `GetGain() float64`
|
||||
- `SetGain(val float32)` from -60.0 to 12.0
|
||||
- `GetMc() bool`
|
||||
- `SetMc(val bool)`
|
||||
- `GetComp() float64`
|
||||
- `SetComp(val float32)` from 0.0 to 10.0
|
||||
- `GetGate() float64`
|
||||
- `SetGate(val float32)` from 0.0 to 10.0
|
||||
- `GetAudibility() float64`
|
||||
- `SetAudibility(val float32)` from 0.0 to 10.0
|
||||
- `GetMute() bool`
|
||||
- `SetMute(val bool)`
|
||||
- `GetMono() bool`
|
||||
- `SetMono(val bool)`
|
||||
- `GetSolo() bool`
|
||||
- `SetSolo(val bool)`
|
||||
- `GetLimit() int`
|
||||
- `SetLimit(val int)` from -40 to 12
|
||||
- `GetLabel() string`
|
||||
- `SetLabel(val string)`
|
||||
- `GetGain() float64`
|
||||
- `SetGain(val float32)` from -60.0 to 12.0
|
||||
- `GetMc() bool`
|
||||
- `SetMc(val bool)`
|
||||
- `GetComp() float64`
|
||||
- `SetComp(val float32)` from 0.0 to 10.0
|
||||
- `GetGate() float64`
|
||||
- `SetGate(val float32)` from 0.0 to 10.0
|
||||
- `GetAudibility() float64`
|
||||
- `SetAudibility(val float32)` from 0.0 to 10.0
|
||||
- `GetA1() bool - GetA5() bool`
|
||||
- `SetA1(val bool) - SetA5(val bool)`
|
||||
|
||||
@@ -131,21 +161,52 @@ fmt.Println(vmRem.Strip[0].GetLabel())
|
||||
vmRem.Strip[4].SetA1(true)
|
||||
```
|
||||
|
||||
##### Gainlayers
|
||||
|
||||
- `vmRem.Strip[i].GainLayer()[j]`
|
||||
|
||||
The following functions are available
|
||||
|
||||
- `Get() float64`
|
||||
- `Set(val float32)`
|
||||
|
||||
example:
|
||||
|
||||
```go
|
||||
vmRem.Strip[6].GainLayer()[3].Set(-13.6)
|
||||
```
|
||||
|
||||
##### Levels
|
||||
|
||||
- `vmRem.Strip[i].Levels()`
|
||||
|
||||
The following functions are available
|
||||
|
||||
- `PreFader() []float32`
|
||||
- `PostFader() []float32`
|
||||
- `PostMute() []float32`
|
||||
|
||||
example:
|
||||
|
||||
```go
|
||||
fmt.Println(vmRem.Strip[5].Levels().PreFader())
|
||||
```
|
||||
|
||||
### Bus
|
||||
|
||||
The following functions are available
|
||||
|
||||
- `String() string`
|
||||
- `GetMute() bool`
|
||||
- `SetMute(val bool)`
|
||||
- `GetEq() bool`
|
||||
- `SetEq(val bool)`
|
||||
- `GetMono() bool`
|
||||
- `SetMono(val bool)`
|
||||
- `GetLabel() string`
|
||||
- `SetLabel(val string)`
|
||||
- `GetGain() float64`
|
||||
- `SetGain(val float32)` from -60.0 to 12.0
|
||||
- `String() string`
|
||||
- `GetMute() bool`
|
||||
- `SetMute(val bool)`
|
||||
- `GetEq() bool`
|
||||
- `SetEq(val bool)`
|
||||
- `GetMono() bool`
|
||||
- `SetMono(val bool)`
|
||||
- `GetLabel() string`
|
||||
- `SetLabel(val string)`
|
||||
- `GetGain() float64`
|
||||
- `SetGain(val float32)` from -60.0 to 12.0
|
||||
|
||||
```go
|
||||
vmRem.Bus[3].SetEq(true)
|
||||
@@ -154,38 +215,66 @@ fmt.Println(vmRem.Bus[0].GetLabel())
|
||||
|
||||
##### Modes
|
||||
|
||||
- `vmRem.Bus[i].Mode()`
|
||||
- `vmRem.Bus[i].Mode()`
|
||||
|
||||
The following functions are available
|
||||
|
||||
- `normal`: boolean
|
||||
- `amix`: boolean
|
||||
- `bmix`: boolean
|
||||
- `composite`: boolean
|
||||
- `tvmix`: boolean
|
||||
- `upmix21`: boolean
|
||||
- `upmix41`: boolean
|
||||
- `upmix61`: boolean
|
||||
- `centeronly`: boolean
|
||||
- `lfeonly`: boolean
|
||||
- `rearonly`: boolean
|
||||
- `SetNormal(val bool)`
|
||||
- `GetNormal() bool`
|
||||
- `SetAmix(val bool)`
|
||||
- `GetAmix() bool`
|
||||
- `SetBmix(val bool)`
|
||||
- `GetBmix() bool`
|
||||
- `SetRepeat(val bool)`
|
||||
- `GetRepeat() bool`
|
||||
- `SetComposite(val bool)`
|
||||
- `GetComposite() bool`
|
||||
- `SetTvMix(val bool)`
|
||||
- `GetTvMix() bool`
|
||||
- `SetUpMix21(val bool)`
|
||||
- `GetUpMix21() bool`
|
||||
- `SetUpMix41(val bool)`
|
||||
- `GetUpMix41() bool`
|
||||
- `SetUpMix61(val bool)`
|
||||
- `GetUpMix61() bool`
|
||||
- `SetCenterOnly(val bool)`
|
||||
- `GetCenterOnly() bool`
|
||||
- `SetLfeOnly(val bool)`
|
||||
- `GetLfeOnly() bool`
|
||||
- `SetRearOnly(val bool)`
|
||||
- `GetRearOnly() bool`
|
||||
|
||||
example:
|
||||
|
||||
```go
|
||||
vmRem.Bus[3].Mode().SetAmix(true)
|
||||
vmRem.Bus[4].Mode().SetCenterOnly(true)
|
||||
```
|
||||
|
||||
##### Levels
|
||||
|
||||
- `vmRem.Bus[i].Levels()`
|
||||
|
||||
The following functions are available
|
||||
|
||||
- `All() []float32`
|
||||
|
||||
example:
|
||||
|
||||
```go
|
||||
fmt.Println(vmRem.Bus[1].Levels().All())
|
||||
```
|
||||
|
||||
### Button
|
||||
|
||||
The following functions are available
|
||||
|
||||
- `GetState() bool`
|
||||
- `SetState(val bool)`
|
||||
- `GetStateOnly() bool`
|
||||
- `SetStateOnly(val bool)`
|
||||
- `GetTrigger() bool`
|
||||
- `SetTrigger(val bool)`
|
||||
- `GetState() bool`
|
||||
- `SetState(val bool)`
|
||||
- `GetStateOnly() bool`
|
||||
- `SetStateOnly(val bool)`
|
||||
- `GetTrigger() bool`
|
||||
- `SetTrigger(val bool)`
|
||||
|
||||
example:
|
||||
|
||||
@@ -198,11 +287,11 @@ fmt.Println(vmRem.Button[64].GetStateOnly())
|
||||
|
||||
The following functions are available
|
||||
|
||||
- `Show()` Show Voicemeeter GUI if it's hidden
|
||||
- `Hide()` Hide Voicemeeter GUI if it's shown
|
||||
- `Shutdown()` Shuts down the GUI
|
||||
- `Restart()` Restart the audio engine
|
||||
- `Lock(val bool)` Lock the Voicemeeter GUI
|
||||
- `Show()` Show Voicemeeter GUI if it's hidden
|
||||
- `Hide()` Hide Voicemeeter GUI if it's shown
|
||||
- `Shutdown()` Shuts down the GUI
|
||||
- `Restart()` Restart the audio engine
|
||||
- `Lock(val bool)` Lock the Voicemeeter GUI
|
||||
|
||||
example:
|
||||
|
||||
@@ -221,24 +310,24 @@ vmRem.Command.Show()
|
||||
|
||||
The following functions are available
|
||||
|
||||
- `GetOn() bool`
|
||||
- `SetOn(val bool)`
|
||||
- `GetName() string`
|
||||
- `SetName(val string)`
|
||||
- `GetIp() string`
|
||||
- `SetIp(val string)`
|
||||
- `GetPort() int`
|
||||
- `SetPort(val int)` from 1024 to 65535
|
||||
- `GetSr() int`
|
||||
- `SetSr(val int)` (11025, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000)
|
||||
- `GetChannel() int`
|
||||
- `SetChannel(val int)` from 1 to 8
|
||||
- `GetBit() int`
|
||||
- `SetBit(val int)` 16 or 24
|
||||
- `GetQuality() int`
|
||||
- `SetQuality(val int)` from 0 to 4
|
||||
- `GetRoute() int`
|
||||
- `SetRoute(val int)` from 0 to 8
|
||||
- `GetOn() bool`
|
||||
- `SetOn(val bool)`
|
||||
- `GetName() string`
|
||||
- `SetName(val string)`
|
||||
- `GetIp() string`
|
||||
- `SetIp(val string)`
|
||||
- `GetPort() int`
|
||||
- `SetPort(val int)` from 1024 to 65535
|
||||
- `GetSr() int`
|
||||
- `SetSr(val int)` (11025, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000)
|
||||
- `GetChannel() int`
|
||||
- `SetChannel(val int)` from 1 to 8
|
||||
- `GetBit() int`
|
||||
- `SetBit(val int)` 16 or 24
|
||||
- `GetQuality() int`
|
||||
- `SetQuality(val int)` from 0 to 4
|
||||
- `GetRoute() int`
|
||||
- `SetRoute(val int)` from 0 to 8
|
||||
|
||||
example:
|
||||
|
||||
@@ -257,10 +346,10 @@ vmRem.Vban.OutStream[3].SetBit(24)
|
||||
|
||||
The following functions are available
|
||||
|
||||
- `Ins`
|
||||
- `Outs`
|
||||
- `Input(val int)`
|
||||
- `Output(val int)`
|
||||
- `Ins`
|
||||
- `Outs`
|
||||
- `Input(val int)`
|
||||
- `Output(val int)`
|
||||
|
||||
example:
|
||||
|
||||
@@ -274,13 +363,13 @@ for i := 0; i < int(vmRem.Device.Ins()); i++ {
|
||||
|
||||
The following functions are available
|
||||
|
||||
- `Play()`
|
||||
- `Stop()`
|
||||
- `Pause()`
|
||||
- `Replay()`
|
||||
- `Record()`
|
||||
- `Ff()`
|
||||
- `Rew()`
|
||||
- `Play()`
|
||||
- `Stop()`
|
||||
- `Pause()`
|
||||
- `Replay()`
|
||||
- `Record()`
|
||||
- `Ff()`
|
||||
- `Rew()`
|
||||
|
||||
example:
|
||||
|
||||
@@ -300,7 +389,7 @@ vmRem.Recorder.SetB2(false)
|
||||
To run all tests:
|
||||
|
||||
```
|
||||
go run test ./...
|
||||
go test ./...
|
||||
```
|
||||
|
||||
### Official Documentation
|
||||
|
||||
@@ -112,6 +112,21 @@ func mdirty() bool {
|
||||
return int(res) == 1
|
||||
}
|
||||
|
||||
func ldirty(k *kind) bool {
|
||||
_levelCache.stripLevelsBuff = make([]float32, (2*k.physIn)+(8*k.virtIn))
|
||||
_levelCache.busLevelsBuff = make([]float32, 8*k.numBus())
|
||||
|
||||
for i := 0; i < (2*k.physIn)+(8*k.virtIn); i++ {
|
||||
_levelCache.stripLevelsBuff[i] = float32(getLevel(_levelCache.stripMode, i))
|
||||
_levelCache.stripComp[i] = _levelCache.stripLevelsBuff[i] == _levelCache.stripLevels[i]
|
||||
}
|
||||
for i := 0; i < 8*k.numBus(); i++ {
|
||||
_levelCache.busLevelsBuff[i] = float32(getLevel(3, i))
|
||||
_levelCache.busComp[i] = _levelCache.busLevelsBuff[i] == _levelCache.busLevels[i]
|
||||
}
|
||||
return !(allTrue(_levelCache.stripComp, (2*k.physIn)+(8*k.virtIn)) && allTrue(_levelCache.busComp, 8*k.numBus()))
|
||||
}
|
||||
|
||||
// getVMType returns the type of Voicemeeter, as a string
|
||||
func getVMType() string {
|
||||
var type_ uint64
|
||||
@@ -253,13 +253,13 @@ func (bm *busMode) GetRearOnly() bool {
|
||||
|
||||
func newBusLevels(i int, k *kind) levels {
|
||||
init := i * 8
|
||||
return levels{iRemote{fmt.Sprintf("bus[%d]", i), i}, k, init, 8}
|
||||
return levels{iRemote{fmt.Sprintf("bus[%d]", i), i}, k, init, 8, "bus"}
|
||||
}
|
||||
|
||||
func (l *levels) All() []float32 {
|
||||
var levels []float32
|
||||
for i := l.init; i < l.init+l.offset; i++ {
|
||||
levels = append(levels, l.convertLevel(getLevel(3, i)))
|
||||
levels = append(levels, l.convertLevel(_levelCache.busLevels[i]))
|
||||
}
|
||||
return levels
|
||||
}
|
||||
@@ -2,37 +2,45 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/onyx-and-iris/voicemeeter-api-go/voicemeeter"
|
||||
"github.com/onyx-and-iris/voicemeeter-api-go"
|
||||
)
|
||||
|
||||
type observer struct {
|
||||
i int
|
||||
vm *voicemeeter.Remote
|
||||
}
|
||||
|
||||
func (o observer) OnUpdate(subject string) {
|
||||
fmt.Println(o.i, subject)
|
||||
if strings.Compare(subject, "pdirty") == 0 {
|
||||
fmt.Println("pdirty!")
|
||||
}
|
||||
if strings.Compare(subject, "mdirty") == 0 {
|
||||
fmt.Println("mdirty!")
|
||||
}
|
||||
if strings.Compare(subject, "ldirty") == 0 {
|
||||
fmt.Printf("%v %v %v %v %v %v %v %v\n",
|
||||
o.vm.Bus[0].Levels().IsDirty(),
|
||||
o.vm.Bus[1].Levels().IsDirty(),
|
||||
o.vm.Bus[2].Levels().IsDirty(),
|
||||
o.vm.Bus[3].Levels().IsDirty(),
|
||||
o.vm.Bus[4].Levels().IsDirty(),
|
||||
o.vm.Bus[5].Levels().IsDirty(),
|
||||
o.vm.Bus[6].Levels().IsDirty(),
|
||||
o.vm.Bus[7].Levels().IsDirty(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
vmRem := voicemeeter.GetRemote("banana")
|
||||
vmRem := voicemeeter.GetRemote("potato")
|
||||
vmRem.Login()
|
||||
|
||||
o := observer{1}
|
||||
o2 := observer{2}
|
||||
o3 := observer{3}
|
||||
o4 := observer{4}
|
||||
o := observer{vmRem}
|
||||
vmRem.Register(o)
|
||||
vmRem.Register(o2)
|
||||
vmRem.Register(o3)
|
||||
vmRem.Register(o4)
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
vmRem.Deregister(o2)
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
time.Sleep(30 * time.Second)
|
||||
vmRem.Deregister(o)
|
||||
|
||||
vmRem.Logout()
|
||||
}
|
||||
|
||||
4
go.mod
4
go.mod
@@ -3,8 +3,8 @@ module github.com/onyx-and-iris/voicemeeter-api-go
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/stretchr/testify v1.7.5
|
||||
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664
|
||||
github.com/stretchr/testify v1.8.0
|
||||
golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
8
go.sum
8
go.sum
@@ -6,10 +6,10 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.5 h1:s5PTfem8p8EbKQOctVV53k6jCJt3UX4IEJzwh+C324Q=
|
||||
github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664 h1:wEZYwx+kK+KlZ0hpvP2Ls1Xr4+RWnlzGFwPP0aiDjIU=
|
||||
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d h1:/m5NbqQelATgoSPVC2Z23sR4kVNokFwDDyWh/3rGY+I=
|
||||
golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -2,7 +2,6 @@ package voicemeeter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// iRemote provides a set of common forwarding methods
|
||||
@@ -68,18 +67,3 @@ func (ir *iRemote) setter_string(p, v string) {
|
||||
param := fmt.Sprintf("%s.%s", ir.identifier(), p)
|
||||
setParameterString(param, v)
|
||||
}
|
||||
|
||||
type levels struct {
|
||||
iRemote
|
||||
k *kind
|
||||
init int
|
||||
offset int
|
||||
}
|
||||
|
||||
func (l *levels) convertLevel(i float32) float32 {
|
||||
if i > 0 {
|
||||
val := 20 * math.Log10(float64(i))
|
||||
return float32(val)
|
||||
}
|
||||
return -200.0
|
||||
}
|
||||
45
levels.go
Normal file
45
levels.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package voicemeeter
|
||||
|
||||
import "math"
|
||||
|
||||
// levels
|
||||
type levels struct {
|
||||
iRemote
|
||||
k *kind
|
||||
init int
|
||||
offset int
|
||||
id string
|
||||
}
|
||||
|
||||
func (l *levels) convertLevel(i float32) float32 {
|
||||
if i > 0 {
|
||||
val := 20 * math.Log10(float64(i))
|
||||
return float32(roundFloat(float64(val), 1))
|
||||
}
|
||||
return -200.0
|
||||
}
|
||||
|
||||
var _levelCache *levelCache
|
||||
|
||||
// levelCache defines level slices used by the pooler to track updates
|
||||
type levelCache struct {
|
||||
stripMode int
|
||||
stripLevels []float32
|
||||
busLevels []float32
|
||||
stripLevelsBuff []float32
|
||||
busLevelsBuff []float32
|
||||
stripComp []bool
|
||||
busComp []bool
|
||||
}
|
||||
|
||||
// newLevelCache returns a levelCache struct address
|
||||
func newLevelCache(k *kind) *levelCache {
|
||||
stripLevels := make([]float32, (2*k.physIn)+(8*k.virtIn))
|
||||
busLevels := make([]float32, 8*k.numBus())
|
||||
stripComp := make([]bool, (2*k.physIn)+(8*k.virtIn))
|
||||
busComp := make([]bool, 8*k.numBus())
|
||||
if _levelCache == nil {
|
||||
_levelCache = &levelCache{stripMode: 0, stripLevels: stripLevels, busLevels: busLevels, stripComp: stripComp, busComp: busComp}
|
||||
}
|
||||
return _levelCache
|
||||
}
|
||||
@@ -43,15 +43,18 @@ func (p *publisher) notify(subject string) {
|
||||
// pooler continuously polls the dirty paramters
|
||||
// it is expected to be run in a goroutine
|
||||
type pooler struct {
|
||||
k *kind
|
||||
run bool
|
||||
publisher
|
||||
}
|
||||
|
||||
func newPooler() *pooler {
|
||||
func newPooler(k *kind) *pooler {
|
||||
p := &pooler{
|
||||
k: k,
|
||||
run: true,
|
||||
}
|
||||
go p.runner()
|
||||
go p.levels()
|
||||
return p
|
||||
}
|
||||
|
||||
@@ -66,3 +69,16 @@ func (p *pooler) runner() {
|
||||
time.Sleep(33 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pooler) levels() {
|
||||
_levelCache = newLevelCache(p.k)
|
||||
|
||||
for p.run {
|
||||
if ldirty(p.k) {
|
||||
update(_levelCache.stripLevels, _levelCache.stripLevelsBuff, (2*p.k.physIn)+(8*p.k.virtIn))
|
||||
update(_levelCache.busLevels, _levelCache.busLevelsBuff, 8*p.k.numBus())
|
||||
p.notify("ldirty")
|
||||
}
|
||||
time.Sleep(33 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,8 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// A remote type represents the API for a kind,
|
||||
// comprised of slices representing each member
|
||||
type remote struct {
|
||||
// A Remote type represents the API for a kind
|
||||
type Remote struct {
|
||||
kind *kind
|
||||
Strip []t_strip
|
||||
Bus []t_bus
|
||||
@@ -21,53 +20,53 @@ type remote struct {
|
||||
}
|
||||
|
||||
// String implements the fmt.stringer interface
|
||||
func (r *remote) String() string {
|
||||
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() {
|
||||
r.pooler = newPooler()
|
||||
func (r *Remote) Login() {
|
||||
login(r.kind.name)
|
||||
r.pooler = newPooler(r.kind)
|
||||
}
|
||||
|
||||
// Logout logs out of the API
|
||||
// it also terminates the pooler
|
||||
func (r *remote) Logout() {
|
||||
func (r *Remote) Logout() {
|
||||
r.pooler.run = false
|
||||
logout()
|
||||
}
|
||||
|
||||
func (r *remote) Type() string {
|
||||
func (r *Remote) Type() string {
|
||||
return getVMType()
|
||||
}
|
||||
|
||||
func (r *remote) Version() string {
|
||||
func (r *Remote) Version() string {
|
||||
return getVersion()
|
||||
}
|
||||
|
||||
// Pdirty returns true iff a parameter value has changed
|
||||
func (r *remote) Pdirty() bool {
|
||||
func (r *Remote) Pdirty() bool {
|
||||
return pdirty()
|
||||
}
|
||||
|
||||
// Mdirty returns true iff a macrobutton value has changed
|
||||
func (r *remote) Mdirty() bool {
|
||||
func (r *Remote) Mdirty() bool {
|
||||
return mdirty()
|
||||
}
|
||||
|
||||
func (r *remote) SendText(script string) {
|
||||
func (r *Remote) SendText(script string) {
|
||||
setParametersMulti(script)
|
||||
}
|
||||
|
||||
// Register forwards the register method to Pooler
|
||||
func (r *remote) Register(o observer) {
|
||||
func (r *Remote) Register(o observer) {
|
||||
r.pooler.Register(o)
|
||||
}
|
||||
|
||||
// Register forwards the deregister method to Pooler
|
||||
func (r *remote) Deregister(o observer) {
|
||||
func (r *Remote) Deregister(o observer) {
|
||||
r.pooler.Deregister(o)
|
||||
}
|
||||
|
||||
@@ -81,7 +80,7 @@ type remoteBuilder interface {
|
||||
makeDevice() remoteBuilder
|
||||
makeRecorder() remoteBuilder
|
||||
Build() remoteBuilder
|
||||
Get() *remote
|
||||
Get() *Remote
|
||||
}
|
||||
|
||||
// directory is responsible for directing the genericBuilder
|
||||
@@ -100,13 +99,13 @@ func (d *director) Construct() {
|
||||
}
|
||||
|
||||
// Get forwards the Get method to the builder
|
||||
func (d *director) Get() *remote {
|
||||
func (d *director) Get() *Remote {
|
||||
return d.builder.Get()
|
||||
}
|
||||
|
||||
type genericBuilder struct {
|
||||
k *kind
|
||||
r remote
|
||||
r Remote
|
||||
}
|
||||
|
||||
func (b *genericBuilder) setKind() remoteBuilder {
|
||||
@@ -157,28 +156,28 @@ func (b *genericBuilder) makeButton() remoteBuilder {
|
||||
return b
|
||||
}
|
||||
|
||||
// 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 {
|
||||
fmt.Println("building command")
|
||||
b.r.Command = newCommand()
|
||||
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 {
|
||||
fmt.Println("building vban")
|
||||
b.r.Vban = newVban(b.k)
|
||||
return b
|
||||
}
|
||||
|
||||
// makeVban makes a Vban type and assigns it to remote.Vban
|
||||
// makeDevice makes a device type and assigns it to remote.Device
|
||||
func (b *genericBuilder) makeDevice() remoteBuilder {
|
||||
fmt.Println("building device")
|
||||
b.r.Device = newDevice()
|
||||
return b
|
||||
}
|
||||
|
||||
// makeRecorder makes a recorder type and assigns it to remote.Vban
|
||||
// makeRecorder makes a recorder type and assigns it to remote.Recorder
|
||||
func (b *genericBuilder) makeRecorder() remoteBuilder {
|
||||
fmt.Println("building recorder")
|
||||
b.r.Recorder = newRecorder()
|
||||
@@ -186,7 +185,7 @@ func (b *genericBuilder) makeRecorder() remoteBuilder {
|
||||
}
|
||||
|
||||
// Get returns a fully constructed remote type for a kind
|
||||
func (b *genericBuilder) Get() *remote {
|
||||
func (b *genericBuilder) Get() *Remote {
|
||||
return &b.r
|
||||
}
|
||||
|
||||
@@ -217,9 +216,9 @@ func (potb *potatoBuilder) Build() remoteBuilder {
|
||||
return potb.setKind().makeStrip().makeBus().makeButton().makeCommand().makeVban().makeDevice().makeRecorder()
|
||||
}
|
||||
|
||||
// GetRemote returns a remote type for a kind
|
||||
// GetRemote returns a Remote type for a kind
|
||||
// this is the interface entry point
|
||||
func GetRemote(kindId string) *remote {
|
||||
func GetRemote(kindId string) *Remote {
|
||||
_kind, ok := kindMap[kindId]
|
||||
if !ok {
|
||||
err := fmt.Errorf("unknown Voicemeeter kind '%s'", kindId)
|
||||
@@ -230,11 +229,11 @@ func GetRemote(kindId string) *remote {
|
||||
director := director{}
|
||||
switch _kind.name {
|
||||
case "basic":
|
||||
director.SetBuilder(&basicBuilder{genericBuilder{_kind, remote{}}})
|
||||
director.SetBuilder(&basicBuilder{genericBuilder{_kind, Remote{}}})
|
||||
case "banana":
|
||||
director.SetBuilder(&bananaBuilder{genericBuilder{_kind, remote{}}})
|
||||
director.SetBuilder(&bananaBuilder{genericBuilder{_kind, Remote{}}})
|
||||
case "potato":
|
||||
director.SetBuilder(&potatoBuilder{genericBuilder{_kind, remote{}}})
|
||||
director.SetBuilder(&potatoBuilder{genericBuilder{_kind, Remote{}}})
|
||||
}
|
||||
director.Construct()
|
||||
return director.Get()
|
||||
@@ -256,29 +256,42 @@ func newStripLevels(i int, k *kind) levels {
|
||||
init = (k.physIn * 2) + ((i - k.physIn) * 8)
|
||||
os = 8
|
||||
}
|
||||
return levels{iRemote{fmt.Sprintf("strip[%d]", i), i}, k, init, os}
|
||||
return levels{iRemote{fmt.Sprintf("strip[%d]", i), i}, k, init, os, "strip"}
|
||||
}
|
||||
|
||||
func (l *levels) PreFader() []float32 {
|
||||
_levelCache.stripMode = 0
|
||||
var levels []float32
|
||||
for i := l.init; i < l.init+l.offset; i++ {
|
||||
levels = append(levels, l.convertLevel(getLevel(0, i)))
|
||||
levels = append(levels, l.convertLevel(_levelCache.stripLevels[i]))
|
||||
}
|
||||
return levels
|
||||
}
|
||||
|
||||
func (l *levels) PostFader() []float32 {
|
||||
_levelCache.stripMode = 1
|
||||
var levels []float32
|
||||
for i := l.init; i < l.init+l.offset; i++ {
|
||||
levels = append(levels, l.convertLevel(getLevel(1, i)))
|
||||
levels = append(levels, l.convertLevel(_levelCache.stripLevels[i]))
|
||||
}
|
||||
return levels
|
||||
}
|
||||
|
||||
func (l *levels) PostMute() []float32 {
|
||||
_levelCache.stripMode = 2
|
||||
var levels []float32
|
||||
for i := l.init; i < l.init+l.offset; i++ {
|
||||
levels = append(levels, l.convertLevel(getLevel(2, i)))
|
||||
levels = append(levels, l.convertLevel(_levelCache.stripLevels[i]))
|
||||
}
|
||||
return levels
|
||||
}
|
||||
|
||||
func (l *levels) IsDirty() bool {
|
||||
var vals []bool
|
||||
if l.id == "strip" {
|
||||
vals = _levelCache.stripComp[l.init : l.init+l.offset]
|
||||
} else if l.id == "bus" {
|
||||
vals = _levelCache.busComp[l.init : l.init+l.offset]
|
||||
}
|
||||
return !allTrue(vals, l.offset)
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/onyx-and-iris/voicemeeter-api-go/voicemeeter"
|
||||
"github.com/onyx-and-iris/voicemeeter-api-go"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
24
util.go
Normal file
24
util.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package voicemeeter
|
||||
|
||||
import "math"
|
||||
|
||||
// allTrue accepts a boolean slice and evaluates if all elements are True
|
||||
func allTrue(s []bool, sz int) bool {
|
||||
for i := 0; i < sz; i++ {
|
||||
if !s[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func update(s1 []float32, s2 []float32, sz int) {
|
||||
for i := 0; i < sz; i++ {
|
||||
s1[i] = s2[i]
|
||||
}
|
||||
}
|
||||
|
||||
func roundFloat(val float64, precision uint) float64 {
|
||||
ratio := math.Pow(10, float64(precision))
|
||||
return math.Round(val*ratio) / ratio
|
||||
}
|
||||
Reference in New Issue
Block a user