diff --git a/examples/vm-cli/README.md b/examples/vm-cli/README.md index 7a64c57..f4962e1 100644 --- a/examples/vm-cli/README.md +++ b/examples/vm-cli/README.md @@ -1,6 +1,6 @@ ## 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 @@ -8,28 +8,31 @@ First build and install it with `go install` (skip this step if using binary fro ## 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: -- -v: (-verbose) to toggle console output. -- -i: (-interactive) to toggle interactive mode. -- -k: (-kind) to set the kind of Voicemeeter. Defaults to banana. -- -d: (-delay) to set a delay on the getters. Defaults to 20ms. +- -h: Print the help dialogue +- -i: Enable interactive mode +- -k: The kind of Voicemeeter GUI to launch, defaults to Banana +- -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: -`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: ``` -Running command strip[0].mute=0 -Value of strip[0].mute is: 0 +time="" level=info msg="Logged into Voicemeeter Banana v2.1.1.1" +strip[0].mute: 1.00 Toggling strip[0].mute -Value of strip[0].mute is: 1 -Running command bus[0].gain=-8.8 -Running command command.lock=1 +strip[0].mute: 0.00 +Setting strip[0].label=podmic +strip[0].label: podmic +time="" level=info msg="Logged out of Voicemeeter Banana" ``` -If running in interactive mode enter `q`, `quit` or `` to exit. +If running in interactive mode enter `Q`, to exit. diff --git a/examples/vm-cli/main.go b/examples/vm-cli/main.go index 4aef409..0d8d0d6 100644 --- a/examples/vm-cli/main.go +++ b/examples/vm-cli/main.go @@ -4,26 +4,36 @@ import ( "bufio" "flag" "fmt" - "log" "os" "strings" + log "github.com/sirupsen/logrus" + "github.com/onyx-and-iris/voicemeeter/v2" ) -type ( - verbosePrinter struct { - verbose bool - } +const ( + FLOAT = iota + STRING ) +type result struct { + kind int + stringParam string + floatParam float64 +} + +type verbosePrinter struct { + verbose bool +} + func newVerbosePrinter() *verbosePrinter { return &verbosePrinter{} } func (v *verbosePrinter) printf(format string, a ...interface{}) { if v.verbose { - fmt.Printf(format+"\n", a...) + fmt.Printf(format, a...) } } @@ -40,28 +50,66 @@ func main() { kind string delay int 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, "k", "banana", "kind of voicemeeter (shorthand)") flag.IntVar(&delay, "delay", 20, "delay between commands") 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, "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() + if help { + help_dialogue() + return + } + + if loglevel >= int(log.PanicLevel) && loglevel <= int(log.TraceLevel) { + log.SetLevel(log.Level(loglevel)) + } + vm, err := vmConnect(kind, delay) if err != nil { log.Fatal(err) } defer vm.Logout() - err = runCommands(vm, interactive) - if err != nil { - fmt.Println(err) + if interactive { + interactiveMode(vm) + 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) { @@ -78,38 +126,23 @@ func vmConnect(kind string, delay int) (*voicemeeter.Remote, error) { 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 { - vPrinter.printf("running in interactive mode... waiting for input") + fmt.Println("Interactive mode enabled. Enter 'Q' to exit.") + scanner := bufio.NewScanner(os.Stdin) + fmt.Printf(">> ") for scanner.Scan() { input := scanner.Text() - if input == "q" || input == "quit" || input == "" { - return nil + if strings.ToUpper(input) == "Q" { + break } + for _, cmd := range strings.Split(input, " ") { - err := parse(vm, cmd) - if err != nil { - vPrinter.printf(err.Error()) + if err := parse(vm, cmd); err != nil { + log.Error(err.Error()) } } + fmt.Printf(">> ") } if scanner.Err() != nil { return scanner.Err() @@ -119,58 +152,60 @@ func interactiveMode(vm *voicemeeter.Remote) error { func parse(vm *voicemeeter.Remote, cmd string) error { if cmd[0] == '!' { - err := toggleCmd(vm, cmd[1:]) - if err != nil { + if err := toggleCmd(vm, cmd[1:]); err != nil { + return err + } + } else if strings.Contains(cmd, "=") { + if err := setCmd(vm, cmd); err != nil { return err } } else { - if strings.Contains(cmd, "=") { - err := setCmd(vm, cmd) - if err != nil { - return err - } - } else { - err := getCmd(vm, cmd) - if err != nil { - return err - } + r := result{kind: FLOAT} + if err := getCmd(vm, cmd, &r); err != nil { + 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 } func toggleCmd(vm *voicemeeter.Remote, cmd string) error { - val, err := vm.GetFloat(cmd) - if err != nil { - err = fmt.Errorf("unable to toggle %s", cmd) + r := result{kind: FLOAT} + if err := getCmd(vm, cmd, &r); err != nil { return err } - vm.SetFloat(cmd, 1-val) - vPrinter.printf("Toggling %s", cmd) + if r.kind == FLOAT && (r.floatParam == 0 || r.floatParam == 1) { + 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 } func setCmd(vm *voicemeeter.Remote, cmd string) error { - vPrinter.printf("Running command %s", cmd) - err := vm.SendText(cmd) - if err != nil { + if err := vm.SendText(cmd); err != nil { err = fmt.Errorf("unable to set %s", cmd) return err } + vPrinter.printf("Setting %s\n", cmd) + return nil +} + +func getCmd(vm *voicemeeter.Remote, cmd string, r *result) error { + if val, err := vm.GetFloat(cmd); err == nil { + r.floatParam = val + } else if val, err := vm.GetString(cmd); err == nil { + r.kind = STRING + r.stringParam = val + } else { + err := fmt.Errorf("unknown parameter '%s'", cmd) + return err + } return nil } - -func getCmd(vm *voicemeeter.Remote, cmd string) error { - valF, err := vm.GetFloat(cmd) - if err != nil { - valS, err := vm.GetString(cmd) - if err != nil { - err = fmt.Errorf("unable to get %s", cmd) - return err - } - fmt.Printf("Value of %s is: %s", cmd, valS) - } else { - fmt.Printf("Value of %s is: %v", cmd, valF) - } - return nil -}