9 Commits

Author SHA1 Message Date
8d9e70b79a patch bump 2024-07-09 13:14:52 +01:00
d7d42e4b21 upd makefile to compile for c2x
replace fallthrough comment with fallthrough attribute
2024-07-09 12:59:46 +01:00
babec7abbb revert func signatures, we're getting compile warnings anyway 2024-07-09 12:58:06 +01:00
b2bdd21da5 add USAGE, OPTSTR macros
rename help() to usage()

log_warn() an unknown option

condense set_kind()
2024-07-09 12:43:32 +01:00
88fe1f5782 reword 2024-07-08 18:02:35 +01:00
82823687db minor bump 2024-07-08 18:01:10 +01:00
3d00c7dd4f upd parse_input() desc 2024-07-08 17:31:24 +01:00
c95ff0e163 add :, delimiters to parse_input()
remove replace_blanks_with_single_space()
2024-07-08 17:29:23 +01:00
48bb15e8f2 upd util.h 2024-07-08 16:39:03 +01:00
8 changed files with 81 additions and 132 deletions

View File

@@ -78,7 +78,7 @@ You may also pipe a scripts contents to the CLI:
$(Get-Content .\example_commands.txt) | .\vmrcli.exe -D1 -i $(Get-Content .\example_commands.txt) | .\vmrcli.exe -D1 -i
``` ```
Multiple API commands can be in a single line but they should be space separated. Multiple API commands can be in a single line, they may be separated by space, `;` or `,`.
## `Build` ## `Build`

View File

@@ -687,43 +687,43 @@ extern "C"
/* 'C' STRUCTURED INTERFACE */ /* 'C' STRUCTURED INTERFACE */
/******************************************************************************/ /******************************************************************************/
typedef long long(__stdcall *T_VBVMR_Login)(void); typedef long(__stdcall *T_VBVMR_Login)(void);
typedef long long(__stdcall *T_VBVMR_Logout)(void); typedef long(__stdcall *T_VBVMR_Logout)(void);
typedef long long(__stdcall *T_VBVMR_RunVoicemeeter)(long vType); typedef long(__stdcall *T_VBVMR_RunVoicemeeter)(long vType);
typedef long long(__stdcall *T_VBVMR_GetVoicemeeterType)(long *pType); typedef long(__stdcall *T_VBVMR_GetVoicemeeterType)(long *pType);
typedef long long(__stdcall *T_VBVMR_GetVoicemeeterVersion)(long *pVersion); typedef long(__stdcall *T_VBVMR_GetVoicemeeterVersion)(long *pVersion);
typedef long long(__stdcall *T_VBVMR_IsParametersDirty)(void); typedef long(__stdcall *T_VBVMR_IsParametersDirty)(void);
typedef long long(__stdcall *T_VBVMR_GetParameterFloat)(char *szParamName, float *pValue); typedef long(__stdcall *T_VBVMR_GetParameterFloat)(char *szParamName, float *pValue);
typedef long long(__stdcall *T_VBVMR_GetParameterStringA)(char *szParamName, char *szString); typedef long(__stdcall *T_VBVMR_GetParameterStringA)(char *szParamName, char *szString);
typedef long long(__stdcall *T_VBVMR_GetParameterStringW)(char *szParamName, unsigned short *wszString); typedef long(__stdcall *T_VBVMR_GetParameterStringW)(char *szParamName, unsigned short *wszString);
typedef long long(__stdcall *T_VBVMR_GetLevel)(long nType, long nuChannel, float *pValue); typedef long(__stdcall *T_VBVMR_GetLevel)(long nType, long nuChannel, float *pValue);
typedef long long(__stdcall *T_VBVMR_GetMidiMessage)(unsigned char *pMIDIBuffer, long nbByteMax); typedef long(__stdcall *T_VBVMR_GetMidiMessage)(unsigned char *pMIDIBuffer, long nbByteMax);
typedef long long(__stdcall *T_VBVMR_SendMidiMessage)(unsigned char *pMIDIBuffer, long nbByteMax); typedef long(__stdcall *T_VBVMR_SendMidiMessage)(unsigned char *pMIDIBuffer, long nbByteMax);
typedef long long(__stdcall *T_VBVMR_SetParameterFloat)(char *szParamName, float Value); typedef long(__stdcall *T_VBVMR_SetParameterFloat)(char *szParamName, float Value);
typedef long long(__stdcall *T_VBVMR_SetParameters)(char *szParamScript); typedef long(__stdcall *T_VBVMR_SetParameters)(char *szParamScript);
typedef long long(__stdcall *T_VBVMR_SetParametersW)(unsigned short *szParamScript); typedef long(__stdcall *T_VBVMR_SetParametersW)(unsigned short *szParamScript);
typedef long long(__stdcall *T_VBVMR_SetParameterStringA)(char *szParamName, char *szString); typedef long(__stdcall *T_VBVMR_SetParameterStringA)(char *szParamName, char *szString);
typedef long long(__stdcall *T_VBVMR_SetParameterStringW)(char *szParamName, unsigned short *wszString); typedef long(__stdcall *T_VBVMR_SetParameterStringW)(char *szParamName, unsigned short *wszString);
typedef long long(__stdcall *T_VBVMR_Output_GetDeviceNumber)(void); typedef long(__stdcall *T_VBVMR_Output_GetDeviceNumber)(void);
typedef long long(__stdcall *T_VBVMR_Output_GetDeviceDescA)(long zindex, long *nType, char *szDeviceName, char *szHardwareId); typedef long(__stdcall *T_VBVMR_Output_GetDeviceDescA)(long zindex, long *nType, char *szDeviceName, char *szHardwareId);
typedef long long(__stdcall *T_VBVMR_Output_GetDeviceDescW)(long zindex, long *nType, unsigned short *wszDeviceName, unsigned short *wszHardwareId); typedef long(__stdcall *T_VBVMR_Output_GetDeviceDescW)(long zindex, long *nType, unsigned short *wszDeviceName, unsigned short *wszHardwareId);
typedef long long(__stdcall *T_VBVMR_Input_GetDeviceNumber)(void); typedef long(__stdcall *T_VBVMR_Input_GetDeviceNumber)(void);
typedef long long(__stdcall *T_VBVMR_Input_GetDeviceDescA)(long zindex, long *nType, char *szDeviceName, char *szHardwareId); typedef long(__stdcall *T_VBVMR_Input_GetDeviceDescA)(long zindex, long *nType, char *szDeviceName, char *szHardwareId);
typedef long long(__stdcall *T_VBVMR_Input_GetDeviceDescW)(long zindex, long *nType, unsigned short *wszDeviceName, unsigned short *wszHardwareId); typedef long(__stdcall *T_VBVMR_Input_GetDeviceDescW)(long zindex, long *nType, unsigned short *wszDeviceName, unsigned short *wszHardwareId);
typedef long long(__stdcall *T_VBVMR_AudioCallbackRegister)(long mode, T_VBVMR_VBAUDIOCALLBACK pCallback, void *lpUser, char szClientName[64]); typedef long(__stdcall *T_VBVMR_AudioCallbackRegister)(long mode, T_VBVMR_VBAUDIOCALLBACK pCallback, void *lpUser, char szClientName[64]);
typedef long long(__stdcall *T_VBVMR_AudioCallbackStart)(void); typedef long(__stdcall *T_VBVMR_AudioCallbackStart)(void);
typedef long long(__stdcall *T_VBVMR_AudioCallbackStop)(void); typedef long(__stdcall *T_VBVMR_AudioCallbackStop)(void);
typedef long long(__stdcall *T_VBVMR_AudioCallbackUnregister)(void); typedef long(__stdcall *T_VBVMR_AudioCallbackUnregister)(void);
typedef long long(__stdcall *T_VBVMR_MacroButton_IsDirty)(void); typedef long(__stdcall *T_VBVMR_MacroButton_IsDirty)(void);
typedef long long(__stdcall *T_VBVMR_MacroButton_GetStatus)(long nuLogicalButton, float *pValue, long bitmode); typedef long(__stdcall *T_VBVMR_MacroButton_GetStatus)(long nuLogicalButton, float *pValue, long bitmode);
typedef long long(__stdcall *T_VBVMR_MacroButton_SetStatus)(long nuLogicalButton, float fValue, long bitmode); typedef long(__stdcall *T_VBVMR_MacroButton_SetStatus)(long nuLogicalButton, float fValue, long bitmode);
typedef struct tagVBVMR_INTERFACE typedef struct tagVBVMR_INTERFACE
{ {

View File

@@ -8,9 +8,8 @@
#ifndef __UTIL_H__ #ifndef __UTIL_H__
#define __UTIL_H__ #define __UTIL_H__
void remove_last_part_of_path(char *szPath); void remove_last_part_of_path(char *fullpath);
int replace_blanks_with_single_space(char *s, size_t len);
char *kind_as_string(char *s, int kind, int n); char *kind_as_string(char *s, int kind, int n);
char *version_as_string(char *, long v, int n); char *version_as_string(char *s, long v, int n);
#endif /* __UTIL_H__ */ #endif /* __UTIL_H__ */

View File

@@ -15,7 +15,7 @@ ifeq ($(LOG_USE_COLOR), yes)
else else
CPPFLAGS := -Iinclude -MMD -MP CPPFLAGS := -Iinclude -MMD -MP
endif endif
CFLAGS = -O -Wall -W -pedantic -ansi -std=c99 CFLAGS = -O -Wall -W -pedantic -ansi -std=c2x
LDFLAGS := -Llib LDFLAGS := -Llib
LDLIBS := -lm LDLIBS := -lm

View File

@@ -3,7 +3,7 @@
* @author Vincent Burel, Onyx and Iris (code@onyxandiris.online) * @author Vincent Burel, Onyx and Iris (code@onyxandiris.online)
* @brief Functions for initializing the iVMR interface. * @brief Functions for initializing the iVMR interface.
* Defines a single public function that returns a pointer to the interface. * Defines a single public function that returns a pointer to the interface.
* @version 0.5.0 * @version 0.7.0
* @date 2024-07-06 * @date 2024-07-06
* *
* @copyright Vincent Burel(c)2015-2021 All Rights Reserved * @copyright Vincent Burel(c)2015-2021 All Rights Reserved

View File

@@ -2,7 +2,7 @@
* @file util.c * @file util.c
* @author Onyx and Iris (code@onyxandiris.online) * @author Onyx and Iris (code@onyxandiris.online)
* @brief Utility functions. * @brief Utility functions.
* @version 0.5.0 * @version 0.7.0
* @date 2024-07-06 * @date 2024-07-06
* *
* @copyright Copyright (c) 2024 * @copyright Copyright (c) 2024
@@ -31,47 +31,6 @@ void remove_last_part_of_path(char *fullpath)
} }
} }
/**
* @brief Replaces multiple spaces and tabs with single spaces
*
* @param s The string to be reduced
* @param len Current length of the string
* @return int New length of the string
*/
int replace_blanks_with_single_space(char *s, size_t len)
{
int j = 0;
int count = 0;
if (len == 1 && isblank(s[0]))
{
s[0] = '\0';
return len;
}
if (len < 2)
return len;
for (int i = 0; s[i] != '\0'; i++)
{
if (isblank(s[i]))
{
count++;
}
else
{
if (count >= 1)
{
count = 0;
s[j++] = ' ';
}
s[j++] = s[i];
}
}
s[j] = '\0';
return j;
}
/** /**
* @brief Converts Voicemeeter's kind into a string. * @brief Converts Voicemeeter's kind into a string.
* *

View File

@@ -2,7 +2,7 @@
* @file vmrcli.c * @file vmrcli.c
* @author Onyx and Iris (code@onyxandiris.online) * @author Onyx and Iris (code@onyxandiris.online)
* @brief A Voicemeeter Remote Command Line Interface * @brief A Voicemeeter Remote Command Line Interface
* @version 0.5.0 * @version 0.7.0
* @date 2024-07-06 * @date 2024-07-06
* *
* @copyright Copyright (c) 2024 * @copyright Copyright (c) 2024
@@ -21,6 +21,17 @@
#include "log.h" #include "log.h"
#include "util.h" #include "util.h"
#define USAGE "Usage: .\\vmrcli.exe [-h] [-i] [-k] [-D] [-v] [-c] [-m] [-s] <api commands>\n" \
"Where: \n" \
"\th: Prints the help message\n" \
"\ti: Enable interactive mode\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\n" \
"\tv: Enable extra console output (toggle, set messages)\n" \
"\tc: Load a user configuration (give the full file path)\n" \
"\tm: Launch the MacroButtons application\n" \
"\ts: Launch the StreamerView application"
#define OPTSTR ":hk:msc:iD:v"
#define MAX_LINE 512 #define MAX_LINE 512
/** /**
@@ -47,10 +58,10 @@ struct result
static bool vflag = false; static bool vflag = false;
void help(void); static void usage(void);
enum kind set_kind(char *kval); enum kind set_kind(char *kval);
void interactive(PT_VMR vmr); void interactive(PT_VMR vmr);
void parse_input(PT_VMR vmr, char *input, int len); void parse_input(PT_VMR vmr, char *input);
void parse_command(PT_VMR vmr, char *command); void parse_command(PT_VMR vmr, char *command);
void get(PT_VMR vmr, char *command, struct result *res); void get(PT_VMR vmr, char *command, struct result *res);
@@ -67,19 +78,16 @@ int main(int argc, char *argv[])
if (argc == 1) if (argc == 1)
{ {
help(); usage();
exit(EXIT_SUCCESS);
} }
log_set_level(LOG_WARN); log_set_level(LOG_WARN);
while ((opt = getopt(argc, argv, "hk:msc:iD:v")) != -1) opterr = 0;
while ((opt = getopt(argc, argv, OPTSTR)) != -1)
{ {
switch (opt) switch (opt)
{ {
case 'h':
help();
exit(EXIT_SUCCESS);
case 'k': case 'k':
kind = set_kind(optarg); kind = set_kind(optarg);
if (kind == UNKNOWN) if (kind == UNKNOWN)
@@ -117,8 +125,20 @@ int main(int argc, char *argv[])
case 'v': case 'v':
vflag = true; vflag = true;
break; break;
case '?':
log_warn("unknown option -- '%c'\n"
"Try .\\vmrcli.exe -h for more information.",
optopt);
exit(EXIT_FAILURE);
case ':':
log_warn("missing argument for option -- '%c'\n"
"Try .\\vmrcli.exe -h for more information.",
optopt);
exit(EXIT_FAILURE);
case 'h':
[[fallthrough]];
default: default:
abort(); usage();
} }
} }
@@ -160,7 +180,7 @@ int main(int argc, char *argv[])
{ {
for (int i = optind; i < argc; i++) for (int i = optind; i < argc; i++)
{ {
parse_input(vmr, argv[i], strlen(argv[i])); parse_input(vmr, argv[i]);
} }
} }
@@ -179,19 +199,10 @@ int main(int argc, char *argv[])
/** /**
* @brief prints the help message * @brief prints the help message
*/ */
void help() static void usage()
{ {
puts( puts(USAGE);
"Usage: .\\vmrcli.exe [-h] [-i] [-k] [-D] [-v] [-c] [-m] [-s] <api commands>\n" exit(EXIT_SUCCESS);
"Where: \n"
"\th: Prints the help message\n"
"\ti: Enable interactive mode\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\n"
"\tv: Enable extra console output (toggle, set messages)\n"
"\tc: Load a user configuration (give the full file path)\n"
"\tm: Launch the MacroButtons application\n"
"\ts: Launch the StreamerView application");
} }
/** /**
@@ -204,30 +215,13 @@ void help()
enum kind set_kind(char *kval) enum kind set_kind(char *kval)
{ {
if (strcmp(kval, "basic") == 0) if (strcmp(kval, "basic") == 0)
{ return sizeof(void *) == 8 ? BASICX64 : BASIC;
if (sizeof(void *) == 8)
return BASICX64;
else
return BASIC;
}
else if (strcmp(kval, "banana") == 0) else if (strcmp(kval, "banana") == 0)
{ return sizeof(void *) == 8 ? BANANAX64 : BANANA;
if (sizeof(void *) == 8)
return BANANAX64;
else
return BANANA;
}
else if (strcmp(kval, "potato") == 0) else if (strcmp(kval, "potato") == 0)
{ return sizeof(void *) == 8 ? POTATOX64 : POTATO;
if (sizeof(void *) == 8)
return POTATOX64;
else
return POTATO;
}
else else
{
return UNKNOWN; return UNKNOWN;
}
} }
/** /**
@@ -240,16 +234,15 @@ enum kind set_kind(char *kval)
void interactive(PT_VMR vmr) void interactive(PT_VMR vmr)
{ {
char input[MAX_LINE]; char input[MAX_LINE];
size_t len;
printf(">> "); printf(">> ");
while (fgets(input, MAX_LINE, stdin) != NULL) while (fgets(input, MAX_LINE, stdin) != NULL)
{ {
input[strcspn(input, "\n")] = 0; input[strcspn(input, "\n")] = 0;
if ((len = strlen(input)) == 1 && toupper(input[0]) == 'Q') if (strlen(input) == 1 && toupper(input[0]) == 'Q')
break; break;
parse_input(vmr, input, len); parse_input(vmr, input);
memset(input, 0, MAX_LINE); /* reset input buffer */ memset(input, 0, MAX_LINE); /* reset input buffer */
printf(">> "); printf(">> ");
@@ -257,23 +250,21 @@ void interactive(PT_VMR vmr)
} }
/** /**
* @brief Walks through each line split by a space delimiter. * @brief Walks through each line split by " \t;," delimiters.
* Each token is passed to parse_command() * Each token is passed to parse_command()
* *
* @param vmr Pointer to the iVMR interface * @param vmr Pointer to the iVMR interface
* @param input Each input line, from stdin or CLI args * @param input Each input line, from stdin or CLI args
* @param len The length of the input line
*/ */
void parse_input(PT_VMR vmr, char *input, int len) void parse_input(PT_VMR vmr, char *input)
{ {
char *token; char *token, *p;
replace_blanks_with_single_space(input, len); token = strtok_r(input, " \t;,", &p);
token = strtok(input, " ");
while (token != NULL) while (token != NULL)
{ {
parse_command(vmr, token); parse_command(vmr, token);
token = strtok(NULL, " "); token = strtok_r(NULL, " \t;,", &p);
} }
} }

View File

@@ -2,7 +2,7 @@
* @file wrapper.c * @file wrapper.c
* @author Onyx and Iris (code@onyxandiris.online) * @author Onyx and Iris (code@onyxandiris.online)
* @brief Provides public functions that wrap the iVMR calls * @brief Provides public functions that wrap the iVMR calls
* @version 0.5.0 * @version 0.7.0
* @date 2024-07-06 * @date 2024-07-06
* *
* @copyright Copyright (c) 2024 * @copyright Copyright (c) 2024