mirror of
https://github.com/onyx-and-iris/voicemeeter.git
synced 2024-11-15 17:40:51 +00:00
add help dialogue
add guard for toggleCmd to prevent unsafe gain changes. use logrus for control of log levels. add an input prompt for interactive mode
This commit is contained in:
parent
359c2d61b5
commit
1b9d633217
@ -1,6 +1,6 @@
|
|||||||
## About
|
## About
|
||||||
|
|
||||||
A simple voicemeeter-cli program. Offers ability to toggle, get and set parameters.
|
A Voicemeeter CLI, offers ability to toggle, get and set parameters.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
@ -8,28 +8,31 @@ First build and install it with `go install` (skip this step if using binary fro
|
|||||||
|
|
||||||
## Use
|
## Use
|
||||||
|
|
||||||
Toggle with `!` prefix, get by excluding `=` and set by including `=`. Mix and match arguments.
|
Commands that begin with `!` will toggle a parameter, commands that contain `=` will set a parameter, all other commands will get a value.
|
||||||
|
|
||||||
You may pass the following optional flags:
|
You may pass the following optional flags:
|
||||||
|
|
||||||
- -v: (-verbose) to toggle console output.
|
- -h: Print the help dialogue
|
||||||
- -i: (-interactive) to toggle interactive mode.
|
- -i: Enable interactive mode
|
||||||
- -k: (-kind) to set the kind of Voicemeeter. Defaults to banana.
|
- -k: The kind of Voicemeeter GUI to launch, defaults to Banana
|
||||||
- -d: (-delay) to set a delay on the getters. Defaults to 20ms.
|
- -l: Log level (0 up to 6), defaults to 3, Warn Level
|
||||||
|
- -d: Set the delay between commands, defaults to 20ms
|
||||||
|
- -v: Enable extra console output (toggle and set messages).
|
||||||
|
|
||||||
for example:
|
for example:
|
||||||
|
|
||||||
`vm-cli.exe -v -k=potato -d=25 strip[0].mute=0 strip[0].mute !strip[0].mute strip[0].mute bus[0].gain=-8.8 command.lock=1`
|
`vm-cli.exe -v -l=4 -k=potato strip[0].mute=0 strip[0].mute !strip[0].mute strip[0].mute bus[0].gain=-8.8 command.lock=1`
|
||||||
|
|
||||||
Expected output:
|
Expected output:
|
||||||
|
|
||||||
```
|
```
|
||||||
Running command strip[0].mute=0
|
time="<timestamp>" level=info msg="Logged into Voicemeeter Banana v2.1.1.1"
|
||||||
Value of strip[0].mute is: 0
|
strip[0].mute: 1.00
|
||||||
Toggling strip[0].mute
|
Toggling strip[0].mute
|
||||||
Value of strip[0].mute is: 1
|
strip[0].mute: 0.00
|
||||||
Running command bus[0].gain=-8.8
|
Setting strip[0].label=podmic
|
||||||
Running command command.lock=1
|
strip[0].label: podmic
|
||||||
|
time="<timestamp>" level=info msg="Logged out of Voicemeeter Banana"
|
||||||
```
|
```
|
||||||
|
|
||||||
If running in interactive mode enter `q`, `quit` or `<Enter>` to exit.
|
If running in interactive mode enter `Q`, to exit.
|
||||||
|
@ -4,18 +4,28 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/onyx-and-iris/voicemeeter/v2"
|
"github.com/onyx-and-iris/voicemeeter/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
const (
|
||||||
verbosePrinter struct {
|
FLOAT = iota
|
||||||
|
STRING
|
||||||
|
)
|
||||||
|
|
||||||
|
type result struct {
|
||||||
|
kind int
|
||||||
|
stringParam string
|
||||||
|
floatParam float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type verbosePrinter struct {
|
||||||
verbose bool
|
verbose bool
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
func newVerbosePrinter() *verbosePrinter {
|
func newVerbosePrinter() *verbosePrinter {
|
||||||
return &verbosePrinter{}
|
return &verbosePrinter{}
|
||||||
@ -23,7 +33,7 @@ func newVerbosePrinter() *verbosePrinter {
|
|||||||
|
|
||||||
func (v *verbosePrinter) printf(format string, a ...interface{}) {
|
func (v *verbosePrinter) printf(format string, a ...interface{}) {
|
||||||
if v.verbose {
|
if v.verbose {
|
||||||
fmt.Printf(format+"\n", a...)
|
fmt.Printf(format, a...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,28 +50,66 @@ func main() {
|
|||||||
kind string
|
kind string
|
||||||
delay int
|
delay int
|
||||||
interactive bool
|
interactive bool
|
||||||
|
loglevel int
|
||||||
|
help bool
|
||||||
)
|
)
|
||||||
|
|
||||||
|
flag.BoolVar(&help, "help", false, "print the help dialogue")
|
||||||
|
flag.BoolVar(&help, "h", false, "print the help dialogue (shorthand)")
|
||||||
flag.StringVar(&kind, "kind", "banana", "kind of voicemeeter")
|
flag.StringVar(&kind, "kind", "banana", "kind of voicemeeter")
|
||||||
flag.StringVar(&kind, "k", "banana", "kind of voicemeeter (shorthand)")
|
flag.StringVar(&kind, "k", "banana", "kind of voicemeeter (shorthand)")
|
||||||
flag.IntVar(&delay, "delay", 20, "delay between commands")
|
flag.IntVar(&delay, "delay", 20, "delay between commands")
|
||||||
flag.IntVar(&delay, "d", 20, "delay between commands (shorthand)")
|
flag.IntVar(&delay, "d", 20, "delay between commands (shorthand)")
|
||||||
flag.BoolVar(&vPrinter.verbose, "verbose", false, "toggle console output")
|
|
||||||
flag.BoolVar(&vPrinter.verbose, "v", false, "toggle console output (shorthand)")
|
|
||||||
flag.BoolVar(&interactive, "interactive", false, "toggle interactive mode")
|
flag.BoolVar(&interactive, "interactive", false, "toggle interactive mode")
|
||||||
flag.BoolVar(&interactive, "i", false, "toggle interactive mode (shorthand)")
|
flag.BoolVar(&interactive, "i", false, "toggle interactive mode (shorthand)")
|
||||||
|
flag.IntVar(&loglevel, "loglevel", int(log.WarnLevel), "set the log level")
|
||||||
|
flag.IntVar(&loglevel, "l", int(log.WarnLevel), "set the log level (shorthand)")
|
||||||
|
flag.BoolVar(&vPrinter.verbose, "verbose", false, "toggle console output")
|
||||||
|
flag.BoolVar(&vPrinter.verbose, "v", false, "toggle console output (shorthand)")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
if help {
|
||||||
|
help_dialogue()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if loglevel >= int(log.PanicLevel) && loglevel <= int(log.TraceLevel) {
|
||||||
|
log.SetLevel(log.Level(loglevel))
|
||||||
|
}
|
||||||
|
|
||||||
vm, err := vmConnect(kind, delay)
|
vm, err := vmConnect(kind, delay)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer vm.Logout()
|
defer vm.Logout()
|
||||||
|
|
||||||
err = runCommands(vm, interactive)
|
if interactive {
|
||||||
if err != nil {
|
interactiveMode(vm)
|
||||||
fmt.Println(err)
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
args := flag.Args()
|
||||||
|
if len(args) == 0 {
|
||||||
|
help_dialogue()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, arg := range args {
|
||||||
|
if err := parse(vm, arg); err != nil {
|
||||||
|
log.Error(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func help_dialogue() {
|
||||||
|
fmt.Printf("usage: ./vm-cli [-h] [-i] [-k] [-l] [-d] [-v]\n" +
|
||||||
|
"Where:\n" +
|
||||||
|
"\th: Print the help dialogue\n" +
|
||||||
|
"\ti: Enable interactive mode\n" +
|
||||||
|
"\tk: The kind of Voicemeeter GUI to launch, defaults to Banana\n" +
|
||||||
|
"\tl: Log level 0 up to 6, (defaults to 3, Warn Level)\n" +
|
||||||
|
"\td: Set the delay between commands (defaults to 20ms)\n" +
|
||||||
|
"\tv: Enable extra console output (toggle and set messages).")
|
||||||
}
|
}
|
||||||
|
|
||||||
func vmConnect(kind string, delay int) (*voicemeeter.Remote, error) {
|
func vmConnect(kind string, delay int) (*voicemeeter.Remote, error) {
|
||||||
@ -78,38 +126,23 @@ func vmConnect(kind string, delay int) (*voicemeeter.Remote, error) {
|
|||||||
return vm, nil
|
return vm, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runCommands(vm *voicemeeter.Remote, interactive bool) error {
|
|
||||||
if interactive {
|
|
||||||
return interactiveMode(vm)
|
|
||||||
}
|
|
||||||
args := flag.Args()
|
|
||||||
if len(args) == 0 {
|
|
||||||
err := fmt.Errorf("must provide some commands to run")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, arg := range args {
|
|
||||||
err := parse(vm, arg)
|
|
||||||
if err != nil {
|
|
||||||
vPrinter.printf(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func interactiveMode(vm *voicemeeter.Remote) error {
|
func interactiveMode(vm *voicemeeter.Remote) error {
|
||||||
vPrinter.printf("running in interactive mode... waiting for input")
|
fmt.Println("Interactive mode enabled. Enter 'Q' to exit.")
|
||||||
|
|
||||||
scanner := bufio.NewScanner(os.Stdin)
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
|
fmt.Printf(">> ")
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
input := scanner.Text()
|
input := scanner.Text()
|
||||||
if input == "q" || input == "quit" || input == "" {
|
if strings.ToUpper(input) == "Q" {
|
||||||
return nil
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cmd := range strings.Split(input, " ") {
|
for _, cmd := range strings.Split(input, " ") {
|
||||||
err := parse(vm, cmd)
|
if err := parse(vm, cmd); err != nil {
|
||||||
if err != nil {
|
log.Error(err.Error())
|
||||||
vPrinter.printf(err.Error())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fmt.Printf(">> ")
|
||||||
}
|
}
|
||||||
if scanner.Err() != nil {
|
if scanner.Err() != nil {
|
||||||
return scanner.Err()
|
return scanner.Err()
|
||||||
@ -119,58 +152,60 @@ func interactiveMode(vm *voicemeeter.Remote) error {
|
|||||||
|
|
||||||
func parse(vm *voicemeeter.Remote, cmd string) error {
|
func parse(vm *voicemeeter.Remote, cmd string) error {
|
||||||
if cmd[0] == '!' {
|
if cmd[0] == '!' {
|
||||||
err := toggleCmd(vm, cmd[1:])
|
if err := toggleCmd(vm, cmd[1:]); err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
|
}
|
||||||
|
} else if strings.Contains(cmd, "=") {
|
||||||
|
if err := setCmd(vm, cmd); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if strings.Contains(cmd, "=") {
|
r := result{kind: FLOAT}
|
||||||
err := setCmd(vm, cmd)
|
if err := getCmd(vm, cmd, &r); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err := getCmd(vm, cmd)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
switch r.kind {
|
||||||
|
case FLOAT:
|
||||||
|
fmt.Printf("%s: %.2f\n", cmd, r.floatParam)
|
||||||
|
case STRING:
|
||||||
|
fmt.Printf("%s: %s\n", cmd, r.stringParam)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func toggleCmd(vm *voicemeeter.Remote, cmd string) error {
|
func toggleCmd(vm *voicemeeter.Remote, cmd string) error {
|
||||||
val, err := vm.GetFloat(cmd)
|
r := result{kind: FLOAT}
|
||||||
if err != nil {
|
if err := getCmd(vm, cmd, &r); err != nil {
|
||||||
err = fmt.Errorf("unable to toggle %s", cmd)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
vm.SetFloat(cmd, 1-val)
|
if r.kind == FLOAT && (r.floatParam == 0 || r.floatParam == 1) {
|
||||||
vPrinter.printf("Toggling %s", cmd)
|
vPrinter.printf("Toggling %s\n", cmd)
|
||||||
|
vm.SetFloat(cmd, 1-r.floatParam)
|
||||||
|
} else {
|
||||||
|
log.Warnf("%s does not appear to be a boolean parameter", cmd)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setCmd(vm *voicemeeter.Remote, cmd string) error {
|
func setCmd(vm *voicemeeter.Remote, cmd string) error {
|
||||||
vPrinter.printf("Running command %s", cmd)
|
if err := vm.SendText(cmd); err != nil {
|
||||||
err := vm.SendText(cmd)
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("unable to set %s", cmd)
|
err = fmt.Errorf("unable to set %s", cmd)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
vPrinter.printf("Setting %s\n", cmd)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCmd(vm *voicemeeter.Remote, cmd string) error {
|
func getCmd(vm *voicemeeter.Remote, cmd string, r *result) error {
|
||||||
valF, err := vm.GetFloat(cmd)
|
if val, err := vm.GetFloat(cmd); err == nil {
|
||||||
if err != nil {
|
r.floatParam = val
|
||||||
valS, err := vm.GetString(cmd)
|
} else if val, err := vm.GetString(cmd); err == nil {
|
||||||
if err != nil {
|
r.kind = STRING
|
||||||
err = fmt.Errorf("unable to get %s", cmd)
|
r.stringParam = val
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Printf("Value of %s is: %s", cmd, valS)
|
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("Value of %s is: %v", cmd, valF)
|
err := fmt.Errorf("unknown parameter '%s'", cmd)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user