6 Commits

Author SHA1 Message Date
28945b72c5 modify example_commands to show multiple instructions per line
Add note in README about change.
2024-07-02 10:14:25 +01:00
97fc9ca9ce use strtok to walk through the input string
vflag added for extra console output (toggle, set operations)
2024-07-02 10:13:37 +01:00
12a55a52f2 Merge branch 'main' of https://github.com/onyx-and-iris/vmrcli 2024-07-01 07:35:35 +01:00
d4afbfa881 upd heading 2024-07-01 07:35:32 +01:00
ea1f05d323 remove shift one char 2024-07-01 04:43:15 +01:00
900ed23ebf Create LICENSE 2024-07-01 03:46:09 +01:00
5 changed files with 81 additions and 55 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Onyx and Iris
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,4 +1,4 @@
# VMRCLI Command Line Utility # Voicemeeter Remote Command Line Utility
## `Tested against` ## `Tested against`
@@ -68,6 +68,8 @@ Scripts can be loaded from text files, for example in Powershell:
./vmrcli.exe -D1 $(Get-Content .\example_commands.txt) ./vmrcli.exe -D1 $(Get-Content .\example_commands.txt)
``` ```
Multiple API commands can be in a single line but they should be space separated.
## `Build` ## `Build`
Run the included `makefile` with [GNU Make](https://www.gnu.org/software/make/). Run the included `makefile` with [GNU Make](https://www.gnu.org/software/make/).

View File

@@ -1,8 +1,3 @@
strip[0].mute strip[0].mute !strip[0].mute strip[0].mute strip[0].gain strip[0].label=podmic strip[0].label
!strip[0].mute strip[1].mute=1 strip[1].mute
strip[0].mute bus[0].label bus[0].gain=-8.3
strip[1].mute=1
strip[1].mute
strip[0].gain
strip[0].label=podmic
strip[0].label

View File

@@ -14,23 +14,23 @@ enum kind
POTATOX64, POTATOX64,
}; };
long login(T_VBVMR_INTERFACE *iVMR, int kind); long login(T_VBVMR_INTERFACE *vmr, int kind);
long logout(T_VBVMR_INTERFACE *iVMR); long logout(T_VBVMR_INTERFACE *vmr);
long run_voicemeeter(T_VBVMR_INTERFACE *iVMR, int kind); long run_voicemeeter(T_VBVMR_INTERFACE *vmr, int kind);
long type(T_VBVMR_INTERFACE *iVMR, long *type); long type(T_VBVMR_INTERFACE *vmr, long *type);
long version(T_VBVMR_INTERFACE *iVMR, long *version); long version(T_VBVMR_INTERFACE *vmr, long *version);
bool is_pdirty(T_VBVMR_INTERFACE *iVMR); bool is_pdirty(T_VBVMR_INTERFACE *vmr);
long get_parameter_float(T_VBVMR_INTERFACE *iVMR, char *param, float *f); long get_parameter_float(T_VBVMR_INTERFACE *vmr, char *param, float *f);
long get_parameter_string(T_VBVMR_INTERFACE *iVMR, char *param, unsigned short *s); long get_parameter_string(T_VBVMR_INTERFACE *vmr, char *param, unsigned short *s);
long set_parameter_float(T_VBVMR_INTERFACE *iVMR, char *param, float val); long set_parameter_float(T_VBVMR_INTERFACE *vmr, char *param, float val);
long set_parameter_string(T_VBVMR_INTERFACE *iVMR, char *param, char *s); long set_parameter_string(T_VBVMR_INTERFACE *vmr, char *param, char *s);
long set_parameters(T_VBVMR_INTERFACE *iVMR, char *command); long set_parameters(T_VBVMR_INTERFACE *vmr, char *command);
bool is_mdirty(T_VBVMR_INTERFACE *iVMR); bool is_mdirty(T_VBVMR_INTERFACE *vmr);
long macrobutton_getstatus(T_VBVMR_INTERFACE *iVMR, long n, float *val, long mode); long macrobutton_getstatus(T_VBVMR_INTERFACE *vmr, long n, float *val, long mode);
long macrobutton_setstatus(T_VBVMR_INTERFACE *iVMR, long n, float val, long mode); long macrobutton_setstatus(T_VBVMR_INTERFACE *vmr, long n, float val, long mode);
void clear_dirty(T_VBVMR_INTERFACE *iVMR); void clear_dirty(T_VBVMR_INTERFACE *vmr);
#endif #endif /* __VMR_H__ */

View File

@@ -29,9 +29,12 @@ void help(void);
enum kind set_kind(char *kval); enum kind set_kind(char *kval);
int init_voicemeeter(T_VBVMR_INTERFACE *vmr, int kind); int init_voicemeeter(T_VBVMR_INTERFACE *vmr, int kind);
void interactive(T_VBVMR_INTERFACE *vmr); void interactive(T_VBVMR_INTERFACE *vmr);
void parse_input(T_VBVMR_INTERFACE *vmr, char *input, int len);
void parse_command(T_VBVMR_INTERFACE *vmr, char *command); void parse_command(T_VBVMR_INTERFACE *vmr, char *command);
void get(T_VBVMR_INTERFACE *vmr, char *command, struct result *res); void get(T_VBVMR_INTERFACE *vmr, char *command, struct result *res);
bool vflag = false;
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
bool iflag = false; bool iflag = false;
@@ -48,7 +51,7 @@ int main(int argc, char *argv[])
log_set_level(LOG_WARN); log_set_level(LOG_WARN);
while ((opt = getopt(argc, argv, "k:ihD:")) != -1) while ((opt = getopt(argc, argv, "k:ihD:v")) != -1)
{ {
switch (opt) switch (opt)
{ {
@@ -75,6 +78,9 @@ int main(int argc, char *argv[])
"Log level will default to LOG_WARN (3).\n"); "Log level will default to LOG_WARN (3).\n");
} }
break; break;
case 'v':
vflag = true;
break;
default: default:
abort(); abort();
} }
@@ -98,7 +104,7 @@ int main(int argc, char *argv[])
{ {
for (int i = optind; i < argc; i++) for (int i = optind; i < argc; i++)
{ {
parse_command(vmr, argv[i]); parse_input(vmr, argv[i], strlen(argv[i]));
} }
} }
@@ -116,12 +122,13 @@ int main(int argc, char *argv[])
void help() void help()
{ {
puts( puts(
"Usage: ./vmrcli.exe [-h] [-i] [-k] [-D] <api commands>\n" "Usage: ./vmrcli.exe [-h] [-i] [-k] [-D] [-v] <api commands>\n"
"Where: \n" "Where: \n"
"\th: Prints the help dialogue\n" "\th: Prints the help dialogue\n"
"\ti: Enable interactive mode\n" "\ti: Enable interactive mode\n"
"\tk: The kind of Voicemeeter (basic, banana, potato)\n" "\tk: The kind of Voicemeeter (basic, banana, potato)\n"
"\tD: Set log level 0=TRACE, 1=DEBUG, 2=INFO, 3=WARN, 4=ERROR, 5=FATAL"); "\tD: Set log level 0=TRACE, 1=DEBUG, 2=INFO, 3=WARN, 4=ERROR, 5=FATAL"
"\tv: Enable extra console output (toggle, set messages)\n");
} }
/** /**
@@ -188,9 +195,7 @@ int init_voicemeeter(T_VBVMR_INTERFACE *vmr, int kind)
void interactive(T_VBVMR_INTERFACE *vmr) void interactive(T_VBVMR_INTERFACE *vmr)
{ {
char input[MAX_LINE], command[MAX_LINE]; char input[MAX_LINE];
char *p = input;
int i;
size_t len; size_t len;
printf(">> "); printf(">> ");
@@ -201,33 +206,26 @@ void interactive(T_VBVMR_INTERFACE *vmr)
if (len == 1 && toupper(input[0]) == 'Q') if (len == 1 && toupper(input[0]) == 'Q')
break; break;
replace_multiple_space_with_one(input, len); parse_input(vmr, input, len);
while (*p)
{
if (isspace(*p))
{
p++;
continue;
}
log_trace("commands still in buffer: %s", p);
i = 0;
while (*p && !isspace(*p))
command[i++] = *p++;
command[i] = '\0';
p++; /* shift to next char */
if (command[0] != '\0')
parse_command(vmr, command);
memset(command, '\0', MAX_LINE);
}
p = input; /* reset pointer */
memset(input, '\0', MAX_LINE); /* reset input buffer */ memset(input, '\0', MAX_LINE); /* reset input buffer */
printf(">> "); printf(">> ");
} }
} }
void parse_input(T_VBVMR_INTERFACE *vmr, char *input, int len)
{
char *token;
replace_multiple_space_with_one(input, len);
token = strtok(input, " ");
while (token != NULL)
{
parse_command(vmr, token);
token = strtok(NULL, " ");
}
}
void parse_command(T_VBVMR_INTERFACE *vmr, char *command) void parse_command(T_VBVMR_INTERFACE *vmr, char *command)
{ {
log_debug("Parsing %s", command); log_debug("Parsing %s", command);
@@ -241,7 +239,13 @@ void parse_command(T_VBVMR_INTERFACE *vmr, char *command)
if (res.type == FLOAT_T) if (res.type == FLOAT_T)
{ {
if (res.val.f == 1 || res.val.f == 0) if (res.val.f == 1 || res.val.f == 0)
{
set_parameter_float(vmr, command, 1 - res.val.f); set_parameter_float(vmr, command, 1 - res.val.f);
if (vflag)
{
printf("Toggling %s\n", command);
}
}
else else
log_warn("%s does not appear to be a boolean parameter", command); log_warn("%s does not appear to be a boolean parameter", command);
} }
@@ -251,6 +255,10 @@ void parse_command(T_VBVMR_INTERFACE *vmr, char *command)
if (strchr(command, '=') != NULL) /* set */ if (strchr(command, '=') != NULL) /* set */
{ {
set_parameters(vmr, command); set_parameters(vmr, command);
if (vflag)
{
printf("Setting %s\n", command);
}
} }
else /* get */ else /* get */
{ {
@@ -260,10 +268,10 @@ void parse_command(T_VBVMR_INTERFACE *vmr, char *command)
switch (res.type) switch (res.type)
{ {
case FLOAT_T: case FLOAT_T:
printf("%.1f\n", res.val.f); printf("%s: %.1f\n", command, res.val.f);
break; break;
case STRING_T: case STRING_T:
printf("%ls\n", res.val.s); printf("%s: %ls\n", command, res.val.s);
break; break;
default: default:
break; break;