5 Commits

Author SHA1 Message Date
onyx-and-iris
70d69f5599 package module moved into root of repository.
example in readme updated.

level pooler implemented, runs in its own goroutine.

Remote type now exported

observers example updated.
2022-07-09 19:01:58 +01:00
onyx-and-iris
f16bed893f markup change 2022-07-07 14:29:15 +01:00
onyx-and-iris
e7061ce855 add heading to installation section 2022-07-02 12:30:45 +01:00
onyx-and-iris
39411ab332 gainlayers, levels added to readme.
bus mode methods fixed
2022-07-01 14:03:01 +01:00
onyx-and-iris
6148d45b76 upd minor ver in readme 2022-07-01 01:41:43 +01:00
32 changed files with 354 additions and 161 deletions

263
README.md
View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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