diff --git a/.gitignore b/.gitignore index 8d32870..2795224 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # quick tests -quick.go +quick # Binaries for programs and plugins *.exe diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cfbb7f..4cc91ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,3 +10,84 @@ Before any major/minor/patch bump all unit tests will be run to verify they pass ## [Unreleased] - [x] + +## [1.2.0] - 2022-07-10 + +### Added + +- docstrings added to types, methods and functions +- version retractions added to go.mod + +### Changed + +- Entry method renamed from GetRemote to NewRemote +- Readme updated to reflect latest changes + +## [1.1.0] - 2022-06-30 + +### Added + +- Level updates implemented in Pooler struct. Runs in its own goroutine. + +### Fixed + +- Fixed bug with identifier in outputs struct. + +### Changed + +- Package files moved into root of repository. +- Remote struct now exported type + +## [1.0.0] - 2022-06-30 + +### Added + +- recorder, device structs implemented +- gainlayers field in strip struct implemented +- levels field in strip, bus structs implemented +- pooler ratelimit set at 33ms + +## [0.0.3] - 2022-06-25 + +### Added + +- pre-commit.ps1 added for use with git hook +- unit tests for factory functions added +- vban parameter methods added +- support for observers added. publisher/observer structs defined +- Pooler struct added, pdirty, mdirty now updated continously in a goroutine + +### Changed + +- NewRemote factory method now uses director, builder types to create Remote types. +- cdll renamed to path +- test suite now using testify/assert + +## [0.0.2] - 2022-06-23 + +### Added + +- physicalStrip, virtualStrip, physicalBus and virtualBus types defined. +- factory methods for strip, bus now cast return values to interface types. +- parameter methods added to strip, bus types. +- command struct implemented +- bus, vban unit tests added + +### Changed + +- strip, bus slices in remote type defined as interface slice types. +- bindings in base now prepended with vm. +- vban fields added to kind structs + +## [0.0.1] - 2022-06-22 + +### Added + +- interface entry point defined in remote +- some base functions are exported through forwarding methods in Remote type (Login, Logout etc) +- wrapper around the CAPI defined in base +- path helper functions defined in cdll +- kind structs defined in kinds. These describe the layout for each version. +- channel, strip, bus structs getter/setter procedures defined. +- button struct fully implemented. +- initial test commit diff --git a/README.md b/README.md index 8a412c5..87c53ce 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Add to your `go.mod` file: `require github.com/onyx-and-iris/voicemeeter-api-go vX.X.X` -replace `vX.X.X` with the version you need +where `vX.X.X` is the version you require. #### GO GET @@ -48,7 +48,7 @@ import ( func main() { kindId := "banana" - vmRem := voicemeeter.GetRemote(kindId) + vmRem := voicemeeter.NewRemote(kindId) vmRem.Login() @@ -130,7 +130,7 @@ returns True iff a macrobutton paramter has changed ### Strip -The following functions are available +The following methods are available - `GetMute() bool` - `SetMute(val bool)` @@ -167,7 +167,7 @@ vmRem.Strip[4].SetA1(true) - `vmRem.Strip[i].GainLayer()[j]` -The following functions are available +The following methods are available - `Get() float64` - `Set(val float32)` @@ -182,7 +182,7 @@ vmRem.Strip[6].GainLayer()[3].Set(-13.6) - `vmRem.Strip[i].Levels()` -The following functions are available +The following methods are available - `PreFader() []float32` - `PostFader() []float32` @@ -196,7 +196,7 @@ fmt.Println(vmRem.Strip[5].Levels().PreFader()) ### Bus -The following functions are available +The following methods are available - `String() string` - `GetMute() bool` @@ -219,7 +219,7 @@ fmt.Println(vmRem.Bus[0].GetLabel()) - `vmRem.Bus[i].Mode()` -The following functions are available +The following methods are available - `SetNormal(val bool)` - `GetNormal() bool` @@ -257,7 +257,7 @@ vmRem.Bus[4].Mode().SetCenterOnly(true) - `vmRem.Bus[i].Levels()` -The following functions are available +The following methods are available - `All() []float32` @@ -269,7 +269,7 @@ fmt.Println(vmRem.Bus[1].Levels().All()) ### Button -The following functions are available +The following methods are available - `GetState() bool` - `SetState(val bool)` @@ -287,7 +287,7 @@ fmt.Println(vmRem.Button[64].GetStateOnly()) ### Command -The following functions are available +The following methods are available - `Show()` Show Voicemeeter GUI if it's hidden - `Hide()` Hide Voicemeeter GUI if it's shown @@ -310,7 +310,7 @@ vmRem.Command.Show() - `vmRem.Vban.InStream` `vmRem.Vban.OutStream` -The following functions are available +The following methods are available - `GetOn() bool` - `SetOn(val bool)` @@ -346,7 +346,7 @@ vmRem.Vban.OutStream[3].SetBit(24) ### Device -The following functions are available +The following methods are available - `Ins` - `Outs` @@ -363,7 +363,7 @@ for i := 0; i < int(vmRem.Device.Ins()); i++ { ### Recorder -The following functions are available +The following methods are available - `Play()` - `Stop()` diff --git a/base.go b/base.go index 48801e9..856468f 100644 --- a/base.go +++ b/base.go @@ -40,7 +40,8 @@ var ( ) // login logs into the API, -// then attempts to launch Voicemeeter if it's not running. +// attempts to launch Voicemeeter if it's not running, +// initializes dirty parameters. func login(kindId string) { res, _, _ := vmLogin.Call() if res == 1 { @@ -112,6 +113,7 @@ func mdirty() bool { return int(res) == 1 } +// ldirty returns true iff a level value has changed func ldirty(k *kind) bool { _levelCache.stripLevelsBuff = make([]float32, (2*k.physIn)+(8*k.virtIn)) _levelCache.busLevelsBuff = make([]float32, 8*k.numBus()) @@ -252,7 +254,8 @@ func setMacroStatus(id, state, mode int) { } } -func get_num_devices(dir string) uint64 { +// getNumDevices returns the number of hardware input/output devices +func getNumDevices(dir string) uint64 { if strings.Compare(dir, "in") == 0 { res, _, _ := vmGetDevNumIn.Call() return uint64(res) @@ -262,7 +265,8 @@ func get_num_devices(dir string) uint64 { } } -func get_device_description(i int, dir string) (string, uint64, string) { +// getDeviceDescription returns name, driver type and hwid for a given device +func getDeviceDescription(i int, dir string) (string, uint64, string) { var t_ uint64 var b1 [512]byte var b2 [512]byte diff --git a/bus.go b/bus.go index 1f2bfbe..57832ef 100644 --- a/bus.go +++ b/bus.go @@ -2,9 +2,11 @@ package voicemeeter import ( "fmt" + "time" ) -type t_bus interface { +// iBus defines the interface bus types must satisfy +type iBus interface { String() string GetMute() bool SetMute(val bool) @@ -16,8 +18,10 @@ type t_bus interface { SetLabel(val string) GetGain() float64 SetGain(val float32) - Mode() t_busMode + Mode() iBusMode Levels() *levels + FadeTo(target float32, time_ int) + FadeBy(change float32, time_ int) } // bus represents a bus channel @@ -78,25 +82,39 @@ func (b *bus) SetGain(val float32) { } // Mode returns address of a busMode struct -func (b *bus) Mode() t_busMode { +func (b *bus) Mode() iBusMode { return &b.mode } -// Levels returns the gainlayer field +// Levels returns the levels field func (b *bus) Levels() *levels { return &b.levels } +// FadeTo sets the value of gain to target over at time interval of time_ +func (b *bus) FadeTo(target float32, time_ int) { + b.setter_string("FadeTo", fmt.Sprintf("(\"%f\", %d)", target, time_)) + time.Sleep(time.Millisecond) +} + +// FadeBy adjusts the value of gain by change over a time interval of time_ +func (b *bus) FadeBy(change float32, time_ int) { + b.setter_string("FadeBy", fmt.Sprintf("(\"%f\", %d)", change, time_)) + time.Sleep(time.Millisecond) +} + +//physicalBus represents a single physical bus type physicalBus struct { bus } -func newPhysicalBus(i int, k *kind) t_bus { +// newPhysicalBus returns a physicalBus type cast to an iBus +func newPhysicalBus(i int, k *kind) iBus { b := newBusMode(i) l := newBusLevels(i, k) pb := physicalBus{bus{iRemote{fmt.Sprintf("bus[%d]", i), i}, b, l}} - return t_bus(&pb) + return iBus(&pb) } // String implements the fmt.stringer interface @@ -104,15 +122,17 @@ func (p *physicalBus) String() string { return fmt.Sprintf("PhysicalBus%d", p.index) } +//virtualBus represents a single virtual bus type virtualBus struct { bus } -func newVirtualBus(i int, k *kind) t_bus { +// newVirtualBus returns a virtualBus type cast to an iBus +func newVirtualBus(i int, k *kind) iBus { b := newBusMode(i) l := newBusLevels(i, k) vb := virtualBus{bus{iRemote{fmt.Sprintf("bus[%d]", i), i}, b, l}} - return t_bus(&vb) + return iBus(&vb) } // String implements the fmt.stringer interface @@ -120,7 +140,8 @@ func (v *virtualBus) String() string { return fmt.Sprintf("VirtualBus%d", v.index) } -type t_busMode interface { +// iBusMode defines the interface busMode type must satisfy +type iBusMode interface { SetNormal(val bool) GetNormal() bool SetAmix(val bool) @@ -147,119 +168,147 @@ type t_busMode interface { GetRearOnly() bool } +// busMode offers methods for getting/setting bus mode states type busMode struct { iRemote } +// newBusMode returns a busMode struct func newBusMode(i int) busMode { return busMode{iRemote{fmt.Sprintf("bus[%d].mode", i), i}} } -func (bm *busMode) SetNormal(val bool) { - bm.setter_bool("Normal", val) -} - +// GetNormal gets the value of the Mode.Normal parameter func (bm *busMode) GetNormal() bool { return bm.getter_bool("Normal") } -func (bm *busMode) SetAmix(val bool) { - bm.setter_bool("Amix", val) +// SetNormal sets the value of the Mode.Normal parameter +func (bm *busMode) SetNormal(val bool) { + bm.setter_bool("Normal", val) } +// GetAmix gets the value of the Mode.Amix parameter func (bm *busMode) GetAmix() bool { return bm.getter_bool("Amix") } -func (bm *busMode) SetBmix(val bool) { - bm.setter_bool("Bmix", val) +// SetAmix sets the value of the Mode.Amix parameter +func (bm *busMode) SetAmix(val bool) { + bm.setter_bool("Amix", val) } +// GetBmix gets the value of the Mode.Bmix parameter func (bm *busMode) GetBmix() bool { return bm.getter_bool("Bmix") } -func (bm *busMode) SetRepeat(val bool) { - bm.setter_bool("Repeat", val) +// SetBmix sets the value of the Mode.Bmix parameter +func (bm *busMode) SetBmix(val bool) { + bm.setter_bool("Bmix", val) } +// GetRepeat gets the value of the Mode.Repeat parameter func (bm *busMode) GetRepeat() bool { return bm.getter_bool("Repeat") } -func (bm *busMode) SetComposite(val bool) { - bm.setter_bool("Composite", val) +// SetRepeat sets the value of the Mode.Repeat parameter +func (bm *busMode) SetRepeat(val bool) { + bm.setter_bool("Repeat", val) } +// GetComposite gets the value of the Mode.Composite parameter func (bm *busMode) GetComposite() bool { return bm.getter_bool("Composite") } -func (bm *busMode) SetTvMix(val bool) { - bm.setter_bool("TvMix", val) +// SetComposite sets the value of the Mode.Composite parameter +func (bm *busMode) SetComposite(val bool) { + bm.setter_bool("Composite", val) } +// GetTvMix gets the value of the Mode.TvMix parameter func (bm *busMode) GetTvMix() bool { return bm.getter_bool("TvMix") } -func (bm *busMode) SetUpMix21(val bool) { - bm.setter_bool("UpMix21", val) +// SetTvMix sets the value of the Mode.TvMix parameter +func (bm *busMode) SetTvMix(val bool) { + bm.setter_bool("TvMix", val) } +// GetUpMix21 gets the value of the Mode.UpMix21 parameter func (bm *busMode) GetUpMix21() bool { return bm.getter_bool("UpMix21") } -func (bm *busMode) SetUpMix41(val bool) { - bm.setter_bool("UpMix41", val) +// SetUpMix21 sets the value of the Mode.UpMix21 parameter +func (bm *busMode) SetUpMix21(val bool) { + bm.setter_bool("UpMix21", val) } +// GetUpMix41 gets the value of the Mode.UpMix41 parameter func (bm *busMode) GetUpMix41() bool { return bm.getter_bool("UpMix41") } -func (bm *busMode) SetUpMix61(val bool) { - bm.setter_bool("UpMix61", val) +// SetUpMix41 sets the value of the Mode.UpMix41 parameter +func (bm *busMode) SetUpMix41(val bool) { + bm.setter_bool("UpMix41", val) } +// GetUpMix61 gets the value of the Mode.UpMix61 parameter func (bm *busMode) GetUpMix61() bool { return bm.getter_bool("UpMix61") } -func (bm *busMode) SetCenterOnly(val bool) { - bm.setter_bool("CenterOnly", val) +// SetUpMix61 sets the value of the Mode.UpMix61 parameter +func (bm *busMode) SetUpMix61(val bool) { + bm.setter_bool("UpMix61", val) } +// GetCenterOnly gets the value of the Mode.CenterOnly parameter func (bm *busMode) GetCenterOnly() bool { return bm.getter_bool("CenterOnly") } -func (bm *busMode) SetLfeOnly(val bool) { - bm.setter_bool("LfeOnly", val) +// SetCenterOnly sets the value of the Mode.CenterOnly parameter +func (bm *busMode) SetCenterOnly(val bool) { + bm.setter_bool("CenterOnly", val) } +// GetLfeOnly gets the value of the Mode.LFE parameter func (bm *busMode) GetLfeOnly() bool { return bm.getter_bool("LfeOnly") } -func (bm *busMode) SetRearOnly(val bool) { - bm.setter_bool("RearOnly", val) +// SetLfeOnly sets the value of the Mode.LFE parameter +func (bm *busMode) SetLfeOnly(val bool) { + bm.setter_bool("LfeOnly", val) } +// GetRearOnly gets the value of the Mode.RearOnly parameter func (bm *busMode) GetRearOnly() bool { return bm.getter_bool("RearOnly") } +// SetRearOnly sets the value of the Mode.RearOnly parameter +func (bm *busMode) SetRearOnly(val bool) { + bm.setter_bool("RearOnly", val) +} + +// newBusLevels represents the levels field for a channel func newBusLevels(i int, k *kind) levels { init := i * 8 return levels{iRemote{fmt.Sprintf("bus[%d]", i), i}, k, init, 8, "bus"} } +// All returns the level values for a bus func (l *levels) All() []float32 { var levels []float32 for i := l.init; i < l.init+l.offset; i++ { - levels = append(levels, l.convertLevel(_levelCache.busLevels[i])) + levels = append(levels, convertLevel(_levelCache.busLevels[i])) } return levels } diff --git a/button.go b/button.go index ab1aa2e..080a891 100644 --- a/button.go +++ b/button.go @@ -2,7 +2,7 @@ package voicemeeter import "fmt" -// custom strip type, struct forwarding channel +// button represents a single macrobuttton type button struct { index int } diff --git a/command.go b/command.go index 93726ad..cb71fef 100644 --- a/command.go +++ b/command.go @@ -1,9 +1,11 @@ package voicemeeter +//command represents command (action) type parameters type command struct { iRemote } +// newCommand returns a pointer to a command type func newCommand() *command { return &command{iRemote{"command", 0}} } @@ -29,7 +31,6 @@ func (c *command) Restart() { } // Lock locks or unlocks the Voiceemeter GUI -// it accepts a boolean value func (c *command) Lock(val bool) { var value float32 if val { diff --git a/device.go b/device.go index b37e9e7..90a037d 100644 --- a/device.go +++ b/device.go @@ -13,16 +13,16 @@ func newDevice() *device { // Ins returns the total number of physical input devices func (d *device) Ins() int { - return int(get_num_devices("in")) + return int(getNumDevices("in")) } // Ins returns the total number of physical input devices func (d *device) Outs() int { - return int(get_num_devices("out")) + return int(getNumDevices("out")) } func (d *device) Input(i int) devDesc { - n, t_, id := get_device_description(i, "in") + n, t_, id := getDeviceDescription(i, "in") vals := map[uint64]string{ 1: "mme", 3: "wdm", @@ -33,7 +33,7 @@ func (d *device) Input(i int) devDesc { } func (d *device) Output(i int) devDesc { - n, t_, id := get_device_description(i, "out") + n, t_, id := getDeviceDescription(i, "out") vals := map[uint64]string{ 1: "mme", 3: "wdm", diff --git a/examples/observer/observer.go b/examples/observer/observer.go index 48eca0e..5ed77d0 100644 --- a/examples/observer/observer.go +++ b/examples/observer/observer.go @@ -34,7 +34,7 @@ func (o observer) OnUpdate(subject string) { } func main() { - vmRem := voicemeeter.GetRemote("potato") + vmRem := voicemeeter.NewRemote("potato") vmRem.Login() o := observer{vmRem} diff --git a/go.mod b/go.mod index ff32be2..7f1631f 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,11 @@ module github.com/onyx-and-iris/voicemeeter-api-go go 1.18 +retract ( + // package files moved into root of repository + [v1.0.0, v1.1.0] +) + require ( github.com/stretchr/testify v1.8.0 golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d diff --git a/iremote.go b/iremote.go index ff69873..f69246c 100644 --- a/iremote.go +++ b/iremote.go @@ -4,12 +4,14 @@ import ( "fmt" ) -// iRemote provides a set of common forwarding methods +// iRemote provides an interface between higher methods and lower functions +// expected to be embedded type iRemote struct { _identifier string index int } +// identifier returns a string identifier func (ir *iRemote) identifier() string { return ir._identifier } diff --git a/levels.go b/levels.go index 3d440b5..77ed90d 100644 --- a/levels.go +++ b/levels.go @@ -1,8 +1,6 @@ package voicemeeter -import "math" - -// levels +// levels represents the levels field for a channel type levels struct { iRemote k *kind @@ -11,12 +9,15 @@ type levels struct { id string } -func (l *levels) convertLevel(i float32) float32 { - if i > 0 { - val := 20 * math.Log10(float64(i)) - return float32(roundFloat(float64(val), 1)) +// returns true if any levels value for a strip/bus have been updated +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 -200.0 + return !allTrue(vals, l.offset) } var _levelCache *levelCache diff --git a/outputs.go b/outputs.go index c8fded0..c775e48 100644 --- a/outputs.go +++ b/outputs.go @@ -1,6 +1,7 @@ package voicemeeter -type t_outputs interface { +// iOutputs defines the interface outputs type must satisfy +type iOutputs interface { GetA1() bool SetA1(val bool) GetA2() bool @@ -19,10 +20,13 @@ type t_outputs interface { SetB3(val bool) } +// outputs represents the outputs field (A1 - A5, B1 - B3) +// expected to be embedded type outputs struct { iRemote } +// newOutputs returns an outputs type func newOutputs(id string, i int) outputs { o := outputs{iRemote{id, i}} return o diff --git a/recorder.go b/recorder.go index 804e647..797114e 100644 --- a/recorder.go +++ b/recorder.go @@ -1,10 +1,12 @@ package voicemeeter +// recorder represents the recorder type recorder struct { iRemote outputs } +// newRecorder returns an address to a recorder struct func newRecorder() *recorder { o := newOutputs("recorder", 0) return &recorder{iRemote{"recorder", 0}, o} diff --git a/remote.go b/remote.go index ce573ea..4e26079 100644 --- a/remote.go +++ b/remote.go @@ -8,8 +8,8 @@ import ( // A Remote type represents the API for a kind type Remote struct { kind *kind - Strip []t_strip - Bus []t_bus + Strip []iStrip + Bus []iBus Button []button Command *command Vban *vban @@ -114,10 +114,10 @@ func (b *genericBuilder) setKind() remoteBuilder { } // makeStrip makes a strip slice and assigns it to remote.Strip -// []t_strip comprises of both physical and virtual strip types +// []iStrip comprises of both physical and virtual strip types func (b *genericBuilder) makeStrip() remoteBuilder { fmt.Println("building strip") - _strip := make([]t_strip, b.k.numStrip()) + _strip := make([]iStrip, b.k.numStrip()) for i := 0; i < b.k.numStrip(); i++ { if i < b.k.physIn { _strip[i] = newPhysicalStrip(i, b.k) @@ -133,7 +133,7 @@ func (b *genericBuilder) makeStrip() remoteBuilder { // []t_bus comprises of both physical and virtual bus types func (b *genericBuilder) makeBus() remoteBuilder { fmt.Println("building bus") - _bus := make([]t_bus, b.k.numBus()) + _bus := make([]iBus, b.k.numBus()) for i := 0; i < b.k.numBus(); i++ { if i < b.k.physOut { _bus[i] = newPhysicalBus(i, b.k) @@ -216,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 +// NewRemote returns a Remote type for a kind // this is the interface entry point -func GetRemote(kindId string) *Remote { +func NewRemote(kindId string) *Remote { _kind, ok := kindMap[kindId] if !ok { err := fmt.Errorf("unknown Voicemeeter kind '%s'", kindId) diff --git a/remote_test.go b/remote_test.go index 16e44f5..1097bd4 100644 --- a/remote_test.go +++ b/remote_test.go @@ -8,7 +8,7 @@ import ( func TestGetBasicRemote(t *testing.T) { //t.Skip("skipping test") - __rem := GetRemote("basic") + __rem := NewRemote("basic") t.Run("Should return a remote basic type", func(t *testing.T) { assert.NotNil(t, __rem) }) @@ -34,7 +34,7 @@ func TestGetBasicRemote(t *testing.T) { func TestGetBananaRemote(t *testing.T) { //t.Skip("skipping test") - __rem := GetRemote("banana") + __rem := NewRemote("banana") t.Run("Should return a remote banana type", func(t *testing.T) { assert.NotNil(t, __rem) }) @@ -60,7 +60,7 @@ func TestGetBananaRemote(t *testing.T) { func TestGetPotatoRemote(t *testing.T) { //t.Skip("skipping test") - __rem := GetRemote("potato") + __rem := NewRemote("potato") t.Run("Should return a remote basic type", func(t *testing.T) { assert.NotNil(t, __rem) }) diff --git a/strip.go b/strip.go index 4efcdf7..58ecfe0 100644 --- a/strip.go +++ b/strip.go @@ -2,9 +2,11 @@ package voicemeeter import ( "fmt" + "time" ) -type t_strip interface { +// iStrip defines the interface bus types must satisfy +type iStrip interface { String() string GetMute() bool SetMute(val bool) @@ -28,7 +30,11 @@ type t_strip interface { SetAudibility(val float32) GainLayer() []gainLayer Levels() *levels - t_outputs + FadeTo(target float32, time_ int) + FadeBy(change float32, time_ int) + AppGain(name string, gain float32) + AppMute(name string, val bool) + iOutputs } // strip represents a strip channel @@ -104,16 +110,30 @@ func (s *strip) GainLayer() []gainLayer { return s.gainLayer } -// Levels returns the gainlayer field +// Levels returns the levels field func (s *strip) Levels() *levels { return &s.levels } +// FadeTo sets the value of gain to target over at time interval of time_ +func (s *strip) FadeTo(target float32, time_ int) { + s.setter_string("FadeTo", fmt.Sprintf("(\"%f\", %d)", target, time_)) + time.Sleep(time.Millisecond) +} + +// FadeBy adjusts the value of gain by change over a time interval of time_ +func (s *strip) FadeBy(change float32, time_ int) { + s.setter_string("FadeBy", fmt.Sprintf("(\"%f\", %d)", change, time_)) + time.Sleep(time.Millisecond) +} + +//physicalStrip represents a single physical strip type physicalStrip struct { strip } -func newPhysicalStrip(i int, k *kind) t_strip { +// newPhysicalStrip returns a physicalStrip type cast to an iStrip +func newPhysicalStrip(i int, k *kind) iStrip { o := newOutputs(fmt.Sprintf("strip[%d]", i), i) gl := make([]gainLayer, 8) for j := 0; j < 8; j++ { @@ -121,10 +141,10 @@ func newPhysicalStrip(i int, k *kind) t_strip { } l := newStripLevels(i, k) ps := physicalStrip{strip{iRemote{fmt.Sprintf("strip[%d]", i), i}, o, gl, l}} - return t_strip(&ps) + return iStrip(&ps) } -// implement fmt.stringer interface in fmt +// String implements fmt.stringer interface func (p *physicalStrip) String() string { return fmt.Sprintf("PhysicalStrip%d", p.index) } @@ -169,11 +189,13 @@ func (p *physicalStrip) SetMc(val bool) { panic("invalid parameter MC for physicalStrip") } +//virtualStrip represents a single virtual strip type virtualStrip struct { strip } -func newVirtualStrip(i int, k *kind) t_strip { +// newVirtualStrip returns a virtualStrip type cast to an iStrip +func newVirtualStrip(i int, k *kind) iStrip { o := newOutputs(fmt.Sprintf("strip[%d]", i), i) gl := make([]gainLayer, 8) for j := 0; j < 8; j++ { @@ -181,10 +203,10 @@ func newVirtualStrip(i int, k *kind) t_strip { } l := newStripLevels(i, k) vs := virtualStrip{strip{iRemote{fmt.Sprintf("strip[%d]", i), i}, o, gl, l}} - return t_strip(&vs) + return iStrip(&vs) } -// implement fmt.stringer interface in fmt +// String implements fmt.stringer interface func (v *virtualStrip) String() string { return fmt.Sprintf("VirtualStrip%d", v.index) } @@ -229,23 +251,44 @@ func (v *virtualStrip) SetAudibility(val float32) { panic("invalid parameter Audibility for virtualStrip") } +// AppGain sets the gain in db by val for the app matching name. +func (v *strip) AppGain(name string, val float32) { + v.setter_string("AppGain", fmt.Sprintf("(\"%s\", %f)", name, val)) +} + +// AppMute sets mute state as val for the app matching name. +func (v *strip) AppMute(name string, val bool) { + var value int + if val { + value = 1 + } else { + value = 0 + } + v.setter_string("AppMute", fmt.Sprintf("(\"%s\", %f)", name, float32(value))) +} + +// gainLayer represents the 8 gainlayers for a single strip type gainLayer struct { iRemote index int } +// newGainLayer returns a gainlayer struct func newGainLayer(i, j int) gainLayer { return gainLayer{iRemote{fmt.Sprintf("strip[%d]", i), i}, j} } +// Get gets the gain value for a single gainlayer func (gl *gainLayer) Get() float64 { return gl.getter_float(fmt.Sprintf("gainlayer[%d]", gl.index)) } +// Set sets the gain value for a single gainlayer func (gl *gainLayer) Set(val float32) { gl.setter_float(fmt.Sprintf("gainlayer[%d]", gl.index), val) } +// newStripLevels returns a levels struct func newStripLevels(i int, k *kind) levels { var init int var os int @@ -259,39 +302,32 @@ func newStripLevels(i int, k *kind) levels { return levels{iRemote{fmt.Sprintf("strip[%d]", i), i}, k, init, os, "strip"} } +// PreFader returns the level valuess for this strip, PREFADER mode 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(_levelCache.stripLevels[i])) + levels = append(levels, convertLevel(_levelCache.stripLevels[i])) } return levels } +// PreFader returns the level valuess for this strip, POSTFADER mode 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(_levelCache.stripLevels[i])) + levels = append(levels, convertLevel(_levelCache.stripLevels[i])) } return levels } +// PreFader returns the level valuess for this strip, POSTMUTE mode 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(_levelCache.stripLevels[i])) + levels = append(levels, 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) -} diff --git a/tests/helper_test.go b/tests/helper_test.go index d75af4c..2450d97 100644 --- a/tests/helper_test.go +++ b/tests/helper_test.go @@ -9,7 +9,7 @@ import ( ) var ( - vmRem = voicemeeter.GetRemote("potato") + vmRem = voicemeeter.NewRemote("potato") ) func TestMain(m *testing.M) { diff --git a/tests/pre-commit.ps1 b/tests/pre-commit.ps1 index 8053dd7..d4d08f4 100644 --- a/tests/pre-commit.ps1 +++ b/tests/pre-commit.ps1 @@ -1,6 +1,6 @@ Function RunTests { + $run_int_tests = "go clean -testcache; go test -v ." $run_ext_tests = "go clean -testcache; go test -v .\tests\" - $run_int_tests = "go clean -testcache; go test -v .\voicemeeter\" Invoke-Expression $run_ext_tests Invoke-Expression $run_int_tests diff --git a/util.go b/util.go index 70e95be..e709ed4 100644 --- a/util.go +++ b/util.go @@ -12,13 +12,24 @@ func allTrue(s []bool, sz int) bool { return true } +// update copies the contents of one float slice into another func update(s1 []float32, s2 []float32, sz int) { for i := 0; i < sz; i++ { s1[i] = s2[i] } } +// roundFloat rounds a float value to a given precision func roundFloat(val float64, precision uint) float64 { ratio := math.Pow(10, float64(precision)) return math.Round(val*ratio) / ratio } + +// convertLevel performs the necessary math for a channel level +func convertLevel(i float32) float32 { + if i > 0 { + val := 20 * math.Log10(float64(i)) + return float32(roundFloat(float64(val), 1)) + } + return -200.0 +} diff --git a/util_test.go b/util_test.go new file mode 100644 index 0000000..3dc1fea --- /dev/null +++ b/util_test.go @@ -0,0 +1,41 @@ +package voicemeeter + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAllTrue(t *testing.T) { + //t.Skip("skipping test") + s := []bool{true, true, true, true, true, true} + t.Run("Should return true", func(t *testing.T) { + assert.True(t, allTrue(s, len(s))) + }) + s = []bool{true, true, true, true, false, true} + t.Run("Should return false", func(t *testing.T) { + assert.False(t, allTrue(s, len(s))) + }) +} + +func TestUpdate(t *testing.T) { + //t.Skip("skipping test") + s1 := []float32{3.6, 8.7, 1.8, 18.2} + s2 := make([]float32, len(s1)) + update(s2, s1, len(s1)) + t.Run("Should return true", func(t *testing.T) { + assert.Equal(t, s1, s2) + }) +} + +func TestConvertLevel(t *testing.T) { + //t.Skip("skipping test") + res := convertLevel(0.02) + t.Run("Should be equal", func(t *testing.T) { + assert.Equal(t, float32(-34), res) + }) + res = convertLevel(-0.02) + t.Run("Should be equal", func(t *testing.T) { + assert.Equal(t, float32(-200), res) + }) +} diff --git a/vban.go b/vban.go index c762a42..0d1b58c 100644 --- a/vban.go +++ b/vban.go @@ -2,7 +2,8 @@ package voicemeeter import "fmt" -type t_vban interface { +// iVban defines the interface vban types must satisfy +type iVban interface { GetOn() bool SetOn(val bool) GetName() string @@ -133,9 +134,9 @@ type vbanInStream struct { vbanStream } -func newVbanInStream(i int) t_vban { +func newVbanInStream(i int) iVban { vbi := vbanInStream{vbanStream{iRemote{fmt.Sprintf("vban.instream[%d]", i), i}}} - return t_vban(&vbi) + return iVban(&vbi) } // SetSr panics reason read only @@ -157,22 +158,22 @@ type vbanOutStream struct { vbanStream } -func newVbanOutStream(i int) t_vban { +func newVbanOutStream(i int) iVban { vbo := vbanOutStream{vbanStream{iRemote{fmt.Sprintf("vban.outstream[%d]", i), i}}} - return t_vban(&vbo) + return iVban(&vbo) } type vban struct { - InStream []t_vban - OutStream []t_vban + InStream []iVban + OutStream []iVban } func newVban(k *kind) *vban { - _vbanIn := make([]t_vban, k.vbanIn) + _vbanIn := make([]iVban, k.vbanIn) for i := 0; i < k.vbanIn; i++ { _vbanIn[i] = newVbanInStream(i) } - _vbanOut := make([]t_vban, k.vbanOut) + _vbanOut := make([]iVban, k.vbanOut) for i := 0; i < k.vbanOut; i++ { _vbanOut[i] = newVbanOutStream(i) }