mirror of
https://github.com/onyx-and-iris/vmrcli.git
synced 2025-12-13 18:17:51 +00:00
Compare commits
No commits in common. "main" and "v0.7.1" have entirely different histories.
5
.gitignore
vendored
5
.gitignore
vendored
@ -51,9 +51,4 @@ Module.symvers
|
|||||||
Mkfile.old
|
Mkfile.old
|
||||||
dkms.conf
|
dkms.conf
|
||||||
|
|
||||||
# Task Runner
|
|
||||||
.task/
|
|
||||||
|
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
test*
|
|
||||||
51
README.md
51
README.md
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
## `Tested against`
|
## `Tested against`
|
||||||
|
|
||||||
- Basic 1.1.1.9
|
- Basic 1.1.1.1
|
||||||
- Banana 2.1.1.9
|
- Banana 2.1.1.1
|
||||||
- Potato 3.1.1.9
|
- Potato 3.1.1.1
|
||||||
|
|
||||||
## `Requirements`
|
## `Requirements`
|
||||||
|
|
||||||
@ -13,19 +13,16 @@
|
|||||||
## `Use`
|
## `Use`
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\vmrcli.exe [-h] [-v] [-i|-I] [-f] [-k] [-l] [-e] [-c] [-m] [-s] <api commands>
|
.\vmrcli.exe [-h] [-i] [-k] [-D] [-v] [-c] [-m] [-s] <api commands>
|
||||||
```
|
```
|
||||||
|
|
||||||
Where:
|
Where:
|
||||||
|
|
||||||
- `h`: Print the help message.
|
- `h`: Prints the help message.
|
||||||
- `v`: Print the version of vmrcli.
|
- `i`: Enable interactive mode. If set, any api commands passed on the command line will be ignored.
|
||||||
- `i`: Enable interactive mode, use (-I) to disable the '>>' prompt.
|
|
||||||
- If set, any api commands passed on the command line will be ignored.
|
|
||||||
- `f`: Do not split input on spaces.
|
|
||||||
- `k`: The kind of Voicemeeter (basic, banana or potato). Use this to launch the GUI.
|
- `k`: The kind of Voicemeeter (basic, banana or potato). Use this to launch the GUI.
|
||||||
- `l`: Set log level, must be one of TRACE, DEBUG, INFO, WARN, ERROR, or FATAL
|
- `D`: Set log level 0=TRACE, 1=DEBUG, 2=INFO, 3=WARN, 4=ERROR, 5=FATAL
|
||||||
- `e`: Enable extra console output (toggle, set messages)
|
- `v`: Enable extra console output (toggle, set messages)
|
||||||
- `c`: Load a user configuration (give the full file path)
|
- `c`: Load a user configuration (give the full file path)
|
||||||
- `m`: Launch the MacroButtons application
|
- `m`: Launch the MacroButtons application
|
||||||
- `s`: Launch the StreamerView application
|
- `s`: Launch the StreamerView application
|
||||||
@ -41,37 +38,15 @@ Examples:
|
|||||||
Launch basic GUI, set log level to INFO, Toggle Strip 0 Mute, print its new value, then decrease Bus 0 Gain by 3.8
|
Launch basic GUI, set log level to INFO, Toggle Strip 0 Mute, print its new value, then decrease Bus 0 Gain by 3.8
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\vmrcli.exe -kbasic -lINFO !strip[0].mute strip[0].mute bus[0].gain-=3.8
|
.\vmrcli.exe -kbasic -D2 !strip[0].mute strip[0].mute bus[0].gain-=3.8
|
||||||
```
|
```
|
||||||
|
|
||||||
Launch banana GUI, set log level to DEBUG, set Strip 0 label to podmic then print Strip 2 label
|
Launch banana GUI, set log level to DEBUG, set Strip 0 label to podmic then print Strip 2 label
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\vmrcli.exe -kbanana -lDEBUG strip[0].label=podmic strip[2].label
|
.\vmrcli.exe -kbanana -D1 strip[0].label=podmic strip[2].label
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `String Commands With Spaces`
|
|
||||||
|
|
||||||
It may be desirable to send a string request containing spaces, for example to change an output device. By default the CLI splits such strings, to avoid this pass the `-f` flag. It's probably best to use this with single commands only due to its effect on how the CLI parses strings. Also note the inclusion of the double quotation marks, it seems the C API requires them.
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
.\vmrcli.exe -lDEBUG -f bus[1].device.wdm='"Realtek Digital Output (Realtek(R) Audio)"'
|
|
||||||
|
|
||||||
.\vmrcli.exe -lDEBUG -f strip[0].label='"My Podmic"'
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `Quick Commands`
|
|
||||||
|
|
||||||
A short list of quick commands are available:
|
|
||||||
|
|
||||||
- `lock`: command.lock=1
|
|
||||||
- `unlock`: command.lock=0
|
|
||||||
- `show`: command.show=1
|
|
||||||
- `hide`: command.show=0
|
|
||||||
- `restart`: command.restart=1
|
|
||||||
|
|
||||||
They may be used in direct or interactive mode.
|
|
||||||
|
|
||||||
## `Interactive Mode`
|
## `Interactive Mode`
|
||||||
|
|
||||||
Running the following command in Powershell:
|
Running the following command in Powershell:
|
||||||
@ -94,19 +69,17 @@ API commands follow the same rules as listed above. Entering `Q` or `q` will exi
|
|||||||
Scripts can be loaded from text files, for example in Powershell:
|
Scripts can be loaded from text files, for example in Powershell:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
.\vmrcli.exe -lDEBUG $(Get-Content .\example_commands.txt)
|
.\vmrcli.exe -D1 $(Get-Content .\example_commands.txt)
|
||||||
```
|
```
|
||||||
|
|
||||||
You may also pipe a scripts contents to the CLI:
|
You may also pipe a scripts contents to the CLI:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
$(Get-Content .\example_commands.txt) | .\vmrcli.exe -lDEBUG -I
|
$(Get-Content .\example_commands.txt) | .\vmrcli.exe -D1 -i
|
||||||
```
|
```
|
||||||
|
|
||||||
Multiple API commands can be in a single line, they may be separated by space, `;` or `,`.
|
Multiple API commands can be in a single line, they may be separated by space, `;` or `,`.
|
||||||
|
|
||||||
Lines starting with `#` will be interpreted as comments.
|
|
||||||
|
|
||||||
## `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/).
|
||||||
|
|||||||
71
Taskfile.yml
71
Taskfile.yml
@ -1,71 +0,0 @@
|
|||||||
version: '3'
|
|
||||||
|
|
||||||
dotenv: ['.env']
|
|
||||||
|
|
||||||
vars:
|
|
||||||
PROGRAM: vmrcli
|
|
||||||
SHELL: pwsh
|
|
||||||
|
|
||||||
CC: gcc
|
|
||||||
|
|
||||||
SRC_DIR: src
|
|
||||||
INC_DIR: include
|
|
||||||
OBJ_DIR: obj
|
|
||||||
BIN_DIR: bin
|
|
||||||
|
|
||||||
CPPFLAGS: -I{{.INC_DIR}} -MMD -MP {{if eq .LOG_USE_COLOR "yes"}}-DLOG_USE_COLOR{{end}}
|
|
||||||
|
|
||||||
CFLAGS: -O -Wall -W -pedantic -ansi -std=c2x
|
|
||||||
LDFLAGS: -Llib
|
|
||||||
LDLIBS: -lm
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
default:
|
|
||||||
desc: Build vmrcli for Windows
|
|
||||||
deps: [build]
|
|
||||||
|
|
||||||
build:
|
|
||||||
desc: Build vmrcli for Windows
|
|
||||||
deps: [link]
|
|
||||||
|
|
||||||
link:
|
|
||||||
desc: Link all files in obj/ for Windows
|
|
||||||
deps: [compile]
|
|
||||||
cmds:
|
|
||||||
- |
|
|
||||||
{{.SHELL}} -Command "
|
|
||||||
if (!(Test-Path -Path '{{.BIN_DIR}}')) {
|
|
||||||
New-Item -ItemType Directory -Path '{{.BIN_DIR}}'
|
|
||||||
}
|
|
||||||
|
|
||||||
{{.CC}} {{.LDFLAGS}} {{.OBJ_DIR}}/*.o {{.LDLIBS}} -o {{.BIN_DIR}}/{{.PROGRAM}}.exe"
|
|
||||||
sources:
|
|
||||||
- '{{.OBJ_DIR}}/**'
|
|
||||||
generates:
|
|
||||||
- '{{.BIN_DIR}}/{{.PROGRAM}}.exe'
|
|
||||||
|
|
||||||
compile:
|
|
||||||
desc: Compile all files in src/ and include/ for Windows
|
|
||||||
cmds:
|
|
||||||
- |
|
|
||||||
{{.SHELL}} -Command "
|
|
||||||
if (!(Test-Path -Path '{{.OBJ_DIR}}')) {
|
|
||||||
New-Item -ItemType Directory -Path '{{.OBJ_DIR}}'
|
|
||||||
}
|
|
||||||
|
|
||||||
Get-ChildItem -Path '{{.SRC_DIR}}' -Filter '*.c' |
|
|
||||||
ForEach-Object { \$_.Name -replace '\.c$', '' } |
|
|
||||||
ForEach-Object { {{.CC}} {{.CPPFLAGS}} {{.CFLAGS}} -c {{.SRC_DIR}}/\$_.c -o {{.OBJ_DIR}}/\$_.o }"
|
|
||||||
sources:
|
|
||||||
- '{{.SRC_DIR}}/**'
|
|
||||||
- '{{.INC_DIR}}/**'
|
|
||||||
generates:
|
|
||||||
- '{{.OBJ_DIR}}/**'
|
|
||||||
|
|
||||||
clean:
|
|
||||||
desc: Remove all files in obj/ and bin/
|
|
||||||
cmds:
|
|
||||||
- |
|
|
||||||
{{.SHELL}} -Command "
|
|
||||||
if (Test-Path -Path '{{.OBJ_DIR}}') { Remove-Item -Path '{{.OBJ_DIR}}' -Recurse -Force }
|
|
||||||
if (Test-Path -Path '{{.BIN_DIR}}') { Remove-Item -Path '{{.BIN_DIR}}' -Recurse -Force }"
|
|
||||||
@ -1,14 +1,5 @@
|
|||||||
# Strip 0
|
|
||||||
strip[0].mute !strip[0].mute strip[0].mute strip[0].gain strip[0].label=podmic strip[0].label
|
strip[0].mute !strip[0].mute strip[0].mute strip[0].gain strip[0].label=podmic strip[0].label
|
||||||
|
|
||||||
# Strip 1
|
|
||||||
strip[1].mute=1 strip[1].mute strip[1].limit-=8
|
strip[1].mute=1 strip[1].mute strip[1].limit-=8
|
||||||
|
|
||||||
# Strip 2
|
|
||||||
strip[2].gain-=5 strip[2].comp+=4.8
|
strip[2].gain-=5 strip[2].comp+=4.8
|
||||||
|
|
||||||
# Bus 0
|
|
||||||
bus[0].label
|
bus[0].label
|
||||||
|
|
||||||
# Bus 1
|
|
||||||
bus[1].gain-=5.8
|
bus[1].gain-=5.8
|
||||||
@ -10,8 +10,6 @@
|
|||||||
|
|
||||||
#include "VoicemeeterRemote.h"
|
#include "VoicemeeterRemote.h"
|
||||||
|
|
||||||
#define IS_64_BIT sizeof(void *) == 8
|
|
||||||
|
|
||||||
PT_VMR create_interface();
|
PT_VMR create_interface();
|
||||||
|
|
||||||
#endif /* __IVMR_H__ */
|
#endif /* __IVMR_H__ */
|
||||||
@ -8,17 +8,8 @@
|
|||||||
#ifndef __UTIL_H__
|
#ifndef __UTIL_H__
|
||||||
#define __UTIL_H__
|
#define __UTIL_H__
|
||||||
|
|
||||||
struct quickcommand
|
|
||||||
{
|
|
||||||
char *name;
|
|
||||||
char *fullcommand;
|
|
||||||
};
|
|
||||||
|
|
||||||
void remove_last_part_of_path(char *fullpath);
|
void remove_last_part_of_path(char *fullpath);
|
||||||
int log_level_from_string(const char *level);
|
|
||||||
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 *s, long v, int n);
|
char *version_as_string(char *s, long v, int n);
|
||||||
bool is_comment(char *s);
|
|
||||||
struct quickcommand *command_in_quickcommands(const char *command, const struct quickcommand *quickcommands, int n);
|
|
||||||
|
|
||||||
#endif /* __UTIL_H__ */
|
#endif /* __UTIL_H__ */
|
||||||
@ -11,7 +11,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "voicemeeterRemote.h"
|
#include "voicemeeterRemote.h"
|
||||||
|
|
||||||
enum kind : int
|
enum kind
|
||||||
{
|
{
|
||||||
UNKNOWN = -1,
|
UNKNOWN = -1,
|
||||||
BASIC = 1,
|
BASIC = 1,
|
||||||
@ -32,7 +32,7 @@ long version(PT_VMR vmr, long *version);
|
|||||||
|
|
||||||
bool is_pdirty(PT_VMR vmr);
|
bool is_pdirty(PT_VMR vmr);
|
||||||
long get_parameter_float(PT_VMR vmr, char *param, float *f);
|
long get_parameter_float(PT_VMR vmr, char *param, float *f);
|
||||||
long get_parameter_string(PT_VMR vmr, char *param, wchar_t *s);
|
long get_parameter_string(PT_VMR vmr, char *param, unsigned short *s);
|
||||||
long set_parameter_float(PT_VMR vmr, char *param, float val);
|
long set_parameter_float(PT_VMR vmr, char *param, float val);
|
||||||
long set_parameter_string(PT_VMR vmr, char *param, char *s);
|
long set_parameter_string(PT_VMR vmr, char *param, char *s);
|
||||||
long set_parameters(PT_VMR vmr, char *command);
|
long set_parameters(PT_VMR vmr, char *command);
|
||||||
@ -41,6 +41,6 @@ bool is_mdirty(PT_VMR vmr);
|
|||||||
long macrobutton_getstatus(PT_VMR vmr, long n, float *val, long mode);
|
long macrobutton_getstatus(PT_VMR vmr, long n, float *val, long mode);
|
||||||
long macrobutton_setstatus(PT_VMR vmr, long n, float val, long mode);
|
long macrobutton_setstatus(PT_VMR vmr, long n, float val, long mode);
|
||||||
|
|
||||||
void clear(PT_VMR vmr, bool (*f)(PT_VMR));
|
void clear_dirty(PT_VMR vmr);
|
||||||
|
|
||||||
#endif /* __WRAPPER_H__ */
|
#endif /* __WRAPPER_H__ */
|
||||||
17
makefile
17
makefile
@ -1,53 +1,38 @@
|
|||||||
# Program name
|
|
||||||
program = vmrcli
|
program = vmrcli
|
||||||
|
|
||||||
# Compiler
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
|
|
||||||
# Directories
|
|
||||||
SRC_DIR := src
|
SRC_DIR := src
|
||||||
OBJ_DIR := obj
|
OBJ_DIR := obj
|
||||||
BIN_DIR := bin
|
BIN_DIR := bin
|
||||||
|
|
||||||
# Executable and source/object files
|
|
||||||
EXE := $(BIN_DIR)/$(program).exe
|
EXE := $(BIN_DIR)/$(program).exe
|
||||||
SRC := $(wildcard $(SRC_DIR)/*.c)
|
SRC := $(wildcard $(SRC_DIR)/*.c)
|
||||||
OBJ := $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
|
OBJ := $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
|
||||||
|
|
||||||
# Conditional compilation flags for logging
|
|
||||||
LOG_USE_COLOR ?= yes
|
LOG_USE_COLOR ?= yes
|
||||||
ifeq ($(LOG_USE_COLOR), yes)
|
ifeq ($(LOG_USE_COLOR), yes)
|
||||||
CPPFLAGS := -Iinclude -MMD -MP -DLOG_USE_COLOR
|
CPPFLAGS := -Iinclude -MMD -MP -DLOG_USE_COLOR
|
||||||
else
|
else
|
||||||
CPPFLAGS := -Iinclude -MMD -MP
|
CPPFLAGS := -Iinclude -MMD -MP
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Compiler and linker flags
|
|
||||||
CFLAGS = -O -Wall -W -pedantic -ansi -std=c2x
|
CFLAGS = -O -Wall -W -pedantic -ansi -std=c2x
|
||||||
LDFLAGS := -Llib
|
LDFLAGS := -Llib
|
||||||
LDLIBS := -lm
|
LDLIBS := -lm
|
||||||
|
|
||||||
# Phony targets
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
|
|
||||||
# Default target
|
|
||||||
all: $(EXE)
|
all: $(EXE)
|
||||||
|
|
||||||
# Link the executable
|
|
||||||
$(EXE): $(OBJ) | $(BIN_DIR)
|
$(EXE): $(OBJ) | $(BIN_DIR)
|
||||||
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
|
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
|
||||||
|
|
||||||
# Compile source files to object files
|
|
||||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
|
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
# Create necessary directories
|
|
||||||
$(BIN_DIR) $(OBJ_DIR):
|
$(BIN_DIR) $(OBJ_DIR):
|
||||||
pwsh -Command New-Item -Path $@ -ItemType Directory
|
pwsh -Command New-Item -Path $@ -ItemType Directory
|
||||||
|
|
||||||
# Clean up generated files
|
|
||||||
clean:
|
clean:
|
||||||
pwsh -Command Remove-Item -Recurse $(BIN_DIR), $(OBJ_DIR) -force
|
pwsh -Command Remove-Item -Recurse $(EXE), $(OBJ_DIR)
|
||||||
|
|
||||||
# Include dependency files
|
|
||||||
-include $(OBJ:.o=.d)
|
-include $(OBJ:.o=.d)
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* @file interface.c
|
* @file ivmr.c
|
||||||
* @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.11.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
|
||||||
@ -13,49 +13,41 @@
|
|||||||
* https://github.com/onyx-and-iris/vmrcli/blob/main/LICENSE
|
* https://github.com/onyx-and-iris/vmrcli/blob/main/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include "interface.h"
|
#include "ivmr.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
#define PRAGMA_IgnoreWCastIncompatibleFuncTypes \
|
static T_VBVMR_INTERFACE iVMR;
|
||||||
_Pragma("GCC diagnostic push") \
|
|
||||||
_Pragma("GCC diagnostic ignored \"-Wcast-function-type\"")
|
|
||||||
|
|
||||||
#define PRAGMA_Pop \
|
|
||||||
_Pragma("GCC diagnostic pop")
|
|
||||||
|
|
||||||
static long initialize_dll_interfaces(PT_VMR vmr);
|
static long initialize_dll_interfaces(PT_VMR vmr);
|
||||||
static bool registry_get_voicemeeter_folder(char *dll_fullpath);
|
static bool registry_get_voicemeeter_folder(char *szDir);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create an interface object
|
* @brief Create an interface object
|
||||||
*
|
*
|
||||||
* @return PT_VMR Pointer to the iVMR interface
|
* @return PT_VMR Pointer to the iVMR interface
|
||||||
* May return NULL if the interface fails to initialize
|
|
||||||
*/
|
*/
|
||||||
PT_VMR create_interface()
|
PT_VMR create_interface()
|
||||||
{
|
{
|
||||||
PT_VMR vmr = malloc(sizeof(T_VBVMR_INTERFACE));
|
PT_VMR vmr = &iVMR;
|
||||||
if (vmr == NULL)
|
int rep;
|
||||||
{
|
|
||||||
log_error("malloc failed to allocate memory");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
LONG rep = initialize_dll_interfaces(vmr);
|
rep = initialize_dll_interfaces(vmr);
|
||||||
if (rep < 0)
|
if (rep < 0)
|
||||||
{
|
{
|
||||||
if (rep == -100)
|
if (rep == -100)
|
||||||
{
|
{
|
||||||
log_fatal("Voicemeeter is not installed");
|
log_fatal("Voicemeeter is not installed");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log_fatal("Error loading Voicemeeter dll with code %d", rep);
|
log_fatal("Error loading Voicemeeter dll with code %d\n", rep);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
free(vmr);
|
|
||||||
vmr = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return vmr;
|
return vmr;
|
||||||
@ -64,35 +56,29 @@ PT_VMR create_interface()
|
|||||||
/*******************************************************************************/
|
/*******************************************************************************/
|
||||||
/** GET DLL INTERFACE **/
|
/** GET DLL INTERFACE **/
|
||||||
/*******************************************************************************/
|
/*******************************************************************************/
|
||||||
#define DLL_FULLPATH_SZ 1024
|
|
||||||
#define DLL64_NAME "\\VoicemeeterRemote64.dll"
|
|
||||||
#define DLL32_NAME "\\VoicemeeterRemote.dll"
|
|
||||||
|
|
||||||
static long initialize_dll_interfaces(PT_VMR vmr)
|
static long initialize_dll_interfaces(PT_VMR vmr)
|
||||||
{
|
{
|
||||||
HMODULE G_H_Module = NULL;
|
HMODULE G_H_Module = NULL;
|
||||||
char dll_fullpath[DLL_FULLPATH_SZ];
|
char szDllName[1024];
|
||||||
memset(vmr, 0, sizeof(T_VBVMR_INTERFACE));
|
memset(vmr, 0, sizeof(T_VBVMR_INTERFACE));
|
||||||
|
|
||||||
// get Voicemeeter installation directory
|
// get Voicemeeter installation directory
|
||||||
if (!registry_get_voicemeeter_folder(dll_fullpath))
|
if (!registry_get_voicemeeter_folder(szDllName))
|
||||||
{
|
{
|
||||||
// Voicemeeter not installed
|
// Voicemeeter not installed
|
||||||
return -100;
|
return -100;
|
||||||
}
|
}
|
||||||
// use right dll according to O/S type
|
// use right dll according to O/S type
|
||||||
if (IS_64_BIT)
|
if (sizeof(void *) == 8)
|
||||||
strncat(dll_fullpath, DLL64_NAME, DLL_FULLPATH_SZ - strlen(DLL64_NAME) - 1);
|
strcat(szDllName, "\\VoicemeeterRemote64.dll");
|
||||||
else
|
else
|
||||||
strncat(dll_fullpath, DLL32_NAME, DLL_FULLPATH_SZ - strlen(DLL32_NAME) - 1);
|
strcat(szDllName, "\\VoicemeeterRemote.dll");
|
||||||
|
|
||||||
// Load Dll
|
// Load Dll
|
||||||
G_H_Module = LoadLibrary(dll_fullpath);
|
G_H_Module = LoadLibrary(szDllName);
|
||||||
if (G_H_Module == NULL)
|
if (G_H_Module == NULL)
|
||||||
return -101;
|
return -101;
|
||||||
|
|
||||||
PRAGMA_IgnoreWCastIncompatibleFuncTypes;
|
|
||||||
|
|
||||||
// Get function pointers
|
// Get function pointers
|
||||||
vmr->VBVMR_Login = (T_VBVMR_Login)GetProcAddress(G_H_Module, "VBVMR_Login");
|
vmr->VBVMR_Login = (T_VBVMR_Login)GetProcAddress(G_H_Module, "VBVMR_Login");
|
||||||
vmr->VBVMR_Logout = (T_VBVMR_Logout)GetProcAddress(G_H_Module, "VBVMR_Logout");
|
vmr->VBVMR_Logout = (T_VBVMR_Logout)GetProcAddress(G_H_Module, "VBVMR_Logout");
|
||||||
@ -124,41 +110,39 @@ static long initialize_dll_interfaces(PT_VMR vmr)
|
|||||||
vmr->VBVMR_MacroButton_GetStatus = (T_VBVMR_MacroButton_GetStatus)GetProcAddress(G_H_Module, "VBVMR_MacroButton_GetStatus");
|
vmr->VBVMR_MacroButton_GetStatus = (T_VBVMR_MacroButton_GetStatus)GetProcAddress(G_H_Module, "VBVMR_MacroButton_GetStatus");
|
||||||
vmr->VBVMR_MacroButton_SetStatus = (T_VBVMR_MacroButton_SetStatus)GetProcAddress(G_H_Module, "VBVMR_MacroButton_SetStatus");
|
vmr->VBVMR_MacroButton_SetStatus = (T_VBVMR_MacroButton_SetStatus)GetProcAddress(G_H_Module, "VBVMR_MacroButton_SetStatus");
|
||||||
|
|
||||||
PRAGMA_Pop;
|
|
||||||
|
|
||||||
// check pointers are valid
|
// check pointers are valid
|
||||||
if (vmr->VBVMR_Login == NULL)
|
if (vmr->VBVMR_Login == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
if (vmr->VBVMR_Logout == NULL)
|
if (vmr->VBVMR_Logout == NULL)
|
||||||
return -2;
|
return -2;
|
||||||
if (vmr->VBVMR_RunVoicemeeter == NULL)
|
if (vmr->VBVMR_RunVoicemeeter == NULL)
|
||||||
return -3;
|
return -2;
|
||||||
if (vmr->VBVMR_GetVoicemeeterType == NULL)
|
if (vmr->VBVMR_GetVoicemeeterType == NULL)
|
||||||
return -4;
|
return -3;
|
||||||
if (vmr->VBVMR_GetVoicemeeterVersion == NULL)
|
if (vmr->VBVMR_GetVoicemeeterVersion == NULL)
|
||||||
return -5;
|
return -4;
|
||||||
if (vmr->VBVMR_IsParametersDirty == NULL)
|
if (vmr->VBVMR_IsParametersDirty == NULL)
|
||||||
return -6;
|
return -5;
|
||||||
if (vmr->VBVMR_GetParameterFloat == NULL)
|
if (vmr->VBVMR_GetParameterFloat == NULL)
|
||||||
return -7;
|
return -6;
|
||||||
if (vmr->VBVMR_GetParameterStringA == NULL)
|
if (vmr->VBVMR_GetParameterStringA == NULL)
|
||||||
return -8;
|
return -7;
|
||||||
if (vmr->VBVMR_GetParameterStringW == NULL)
|
if (vmr->VBVMR_GetParameterStringW == NULL)
|
||||||
return -9;
|
return -8;
|
||||||
if (vmr->VBVMR_GetLevel == NULL)
|
if (vmr->VBVMR_GetLevel == NULL)
|
||||||
return -10;
|
return -9;
|
||||||
if (vmr->VBVMR_SetParameterFloat == NULL)
|
if (vmr->VBVMR_SetParameterFloat == NULL)
|
||||||
return -11;
|
return -10;
|
||||||
if (vmr->VBVMR_SetParameters == NULL)
|
if (vmr->VBVMR_SetParameters == NULL)
|
||||||
return -12;
|
return -11;
|
||||||
if (vmr->VBVMR_SetParametersW == NULL)
|
if (vmr->VBVMR_SetParametersW == NULL)
|
||||||
return -13;
|
return -12;
|
||||||
if (vmr->VBVMR_SetParameterStringA == NULL)
|
if (vmr->VBVMR_SetParameterStringA == NULL)
|
||||||
return -14;
|
return -13;
|
||||||
if (vmr->VBVMR_SetParameterStringW == NULL)
|
if (vmr->VBVMR_SetParameterStringW == NULL)
|
||||||
return -15;
|
return -14;
|
||||||
if (vmr->VBVMR_GetMidiMessage == NULL)
|
if (vmr->VBVMR_GetMidiMessage == NULL)
|
||||||
return -16;
|
return -15;
|
||||||
|
|
||||||
if (vmr->VBVMR_Output_GetDeviceNumber == NULL)
|
if (vmr->VBVMR_Output_GetDeviceNumber == NULL)
|
||||||
return -30;
|
return -30;
|
||||||
@ -187,48 +171,50 @@ static long initialize_dll_interfaces(PT_VMR vmr)
|
|||||||
/** GET VOICEMEETER DIRECTORY **/
|
/** GET VOICEMEETER DIRECTORY **/
|
||||||
/*******************************************************************************/
|
/*******************************************************************************/
|
||||||
|
|
||||||
#define INSTALLER_DIR_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
|
|
||||||
#define INSTALLER_UNINST_KEY "VB:Voicemeeter {17359A74-1236-5467}"
|
#define INSTALLER_UNINST_KEY "VB:Voicemeeter {17359A74-1236-5467}"
|
||||||
|
|
||||||
#ifndef KEY_WOW64_32KEY
|
#ifndef KEY_WOW64_32KEY
|
||||||
#define KEY_WOW64_32KEY 0x0200
|
#define KEY_WOW64_32KEY 0x0200
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define UNINSTALL_KEY_SZ 256
|
static bool registry_get_voicemeeter_folder(char *szDir)
|
||||||
#define UNINSTALL_PATH_SZ 1024
|
|
||||||
|
|
||||||
static bool registry_get_voicemeeter_folder(char *dll_fullpath)
|
|
||||||
{
|
{
|
||||||
|
char szKey[256];
|
||||||
|
char sss[1024];
|
||||||
|
DWORD nnsize = 1024;
|
||||||
|
HKEY hkResult;
|
||||||
|
LONG rep;
|
||||||
|
DWORD pptype = REG_SZ;
|
||||||
|
sss[0] = 0;
|
||||||
|
const char uninstDirKey[] = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
|
||||||
|
|
||||||
// build Voicemeeter uninstallation key
|
// build Voicemeeter uninstallation key
|
||||||
char uninstall_key[UNINSTALL_KEY_SZ];
|
strcpy(szKey, uninstDirKey);
|
||||||
snprintf(uninstall_key, UNINSTALL_KEY_SZ, "%s\\%s", INSTALLER_DIR_KEY, INSTALLER_UNINST_KEY);
|
strcat(szKey, "\\");
|
||||||
|
strcat(szKey, INSTALLER_UNINST_KEY);
|
||||||
|
|
||||||
// open key
|
// open key
|
||||||
HKEY result;
|
rep = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ, &hkResult);
|
||||||
LONG rep = RegOpenKeyEx(HKEY_LOCAL_MACHINE, uninstall_key, 0, KEY_READ, &result);
|
|
||||||
if (rep != ERROR_SUCCESS)
|
if (rep != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
// if not present we consider running in 64bit mode and force to read 32bit registry
|
// if not present we consider running in 64bit mode and force to read 32bit registry
|
||||||
rep = RegOpenKeyEx(HKEY_LOCAL_MACHINE, uninstall_key, 0, KEY_READ | KEY_WOW64_32KEY, &result);
|
rep = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ | KEY_WOW64_32KEY, &hkResult);
|
||||||
}
|
}
|
||||||
if (rep != ERROR_SUCCESS)
|
if (rep != ERROR_SUCCESS)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// read uninstall path from registry
|
// read uninstall path from registry
|
||||||
DWORD pptype = REG_SZ;
|
rep = RegQueryValueEx(hkResult, "UninstallString", 0, &pptype, (unsigned char *)sss, &nnsize);
|
||||||
DWORD len_uninstall_path = UNINSTALL_PATH_SZ;
|
RegCloseKey(hkResult);
|
||||||
char uninstall_path[UNINSTALL_PATH_SZ] = {0};
|
|
||||||
rep = RegQueryValueEx(result, "UninstallString", 0, &pptype, (unsigned char *)uninstall_path, &len_uninstall_path);
|
|
||||||
RegCloseKey(result);
|
|
||||||
|
|
||||||
if (pptype != REG_SZ)
|
if (pptype != REG_SZ)
|
||||||
return false;
|
return false;
|
||||||
if (rep != ERROR_SUCCESS)
|
if (rep != ERROR_SUCCESS)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// remove name to get the path only
|
// remove name to get the path only
|
||||||
remove_last_part_of_path(uninstall_path);
|
remove_last_part_of_path(sss);
|
||||||
snprintf(dll_fullpath, DLL_FULLPATH_SZ, uninstall_path);
|
if (nnsize > 512)
|
||||||
|
nnsize = 512;
|
||||||
|
strncpy(szDir, sss, nnsize);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -118,7 +118,7 @@ void log_set_quiet(bool enable)
|
|||||||
|
|
||||||
int log_add_callback(log_LogFn fn, void *udata, int level)
|
int log_add_callback(log_LogFn fn, void *udata, int level)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAX_CALLBACKS; ++i)
|
for (int i = 0; i < MAX_CALLBACKS; i++)
|
||||||
{
|
{
|
||||||
if (!L.callbacks[i].fn)
|
if (!L.callbacks[i].fn)
|
||||||
{
|
{
|
||||||
@ -163,7 +163,7 @@ void log_log(int level, const char *file, int line, const char *fmt, ...)
|
|||||||
va_end(ev.ap);
|
va_end(ev.ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; ++i)
|
for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++)
|
||||||
{
|
{
|
||||||
Callback *cb = &L.callbacks[i];
|
Callback *cb = &L.callbacks[i];
|
||||||
if (level >= cb->level)
|
if (level >= cb->level)
|
||||||
|
|||||||
69
src/util.c
69
src/util.c
@ -2,22 +2,24 @@
|
|||||||
* @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.11.0
|
* @version 0.7.0
|
||||||
* @date 2024-07-06
|
* @date 2024-07-06
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2024
|
* @copyright Copyright (c) 2024
|
||||||
* https://github.com/onyx-and-iris/vmrcli/blob/main/LICENSE
|
* https://github.com/onyx-and-iris/vmrcli/blob/main/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "wrapper.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Removes the last part of a path
|
* @brief Removes the last part of a path
|
||||||
*
|
*
|
||||||
* @param fullpath
|
* @param fullpath The entire path
|
||||||
*/
|
*/
|
||||||
void remove_last_part_of_path(char *fullpath)
|
void remove_last_part_of_path(char *fullpath)
|
||||||
{
|
{
|
||||||
@ -29,33 +31,10 @@ void remove_last_part_of_path(char *fullpath)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Gets log level as int from string
|
|
||||||
* @param level Log level as string
|
|
||||||
* @return int Log level as int, or -1 if not found
|
|
||||||
*/
|
|
||||||
int log_level_from_string(const char *level)
|
|
||||||
{
|
|
||||||
if (strcmp(level, "TRACE") == 0)
|
|
||||||
return LOG_TRACE;
|
|
||||||
else if (strcmp(level, "DEBUG") == 0)
|
|
||||||
return LOG_DEBUG;
|
|
||||||
else if (strcmp(level, "INFO") == 0)
|
|
||||||
return LOG_INFO;
|
|
||||||
else if (strcmp(level, "WARN") == 0)
|
|
||||||
return LOG_WARN;
|
|
||||||
else if (strcmp(level, "ERROR") == 0)
|
|
||||||
return LOG_ERROR;
|
|
||||||
else if (strcmp(level, "FATAL") == 0)
|
|
||||||
return LOG_FATAL;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Converts Voicemeeter's kind into a string.
|
* @brief Converts Voicemeeter's kind into a string.
|
||||||
*
|
*
|
||||||
* @param s Pointer to a character buffer receiving the kind
|
* @param s Pointer to a character buffer
|
||||||
* @param kind The kind of Voicemeeter.
|
* @param kind The kind of Voicemeeter.
|
||||||
* @param n Maximum number of characters to be written to the buffer
|
* @param n Maximum number of characters to be written to the buffer
|
||||||
* @return char* String representation of the kind of Voicemeeter.
|
* @return char* String representation of the kind of Voicemeeter.
|
||||||
@ -77,7 +56,7 @@ char *kind_as_string(char *s, int kind, int n)
|
|||||||
/**
|
/**
|
||||||
* @brief Converts Voicemeeter's version into a string.
|
* @brief Converts Voicemeeter's version into a string.
|
||||||
*
|
*
|
||||||
* @param s Pointer to a character buffer receiving the version
|
* @param s Pointer to a character buffer
|
||||||
* @param v Unprocessed version as a long int
|
* @param v Unprocessed version as a long int
|
||||||
* @param n Maximum number of characters to be written to the buffer
|
* @param n Maximum number of characters to be written to the buffer
|
||||||
* @return char* String representation of the Voicemeeter version
|
* @return char* String representation of the Voicemeeter version
|
||||||
@ -91,37 +70,3 @@ char *version_as_string(char *s, long v, int n)
|
|||||||
snprintf(s, n, "%i.%i.%i.%i", (int)v1, (int)v2, (int)v3, (int)v4);
|
snprintf(s, n, "%i.%i.%i.%i", (int)v1, (int)v2, (int)v3, (int)v4);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Is the current input a comment
|
|
||||||
*
|
|
||||||
* @param s Pointer to the current input
|
|
||||||
* @return true
|
|
||||||
* @return false
|
|
||||||
*/
|
|
||||||
bool is_comment(char *s)
|
|
||||||
{
|
|
||||||
return s[0] == '#';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Searches the quickcommands array for a quickcommand
|
|
||||||
* corresponding to the command_key.
|
|
||||||
*
|
|
||||||
* @param command_key The key used to search for the quickcommand
|
|
||||||
* @param quickcommands Pointer to an array of quickcommands
|
|
||||||
* @param n The number of quickcommands
|
|
||||||
* @return struct quickcommand* Pointer to the found quickcommand
|
|
||||||
* May return NULL if quickcommand not found.
|
|
||||||
*/
|
|
||||||
struct quickcommand *command_in_quickcommands(const char *command_key, const struct quickcommand *quickcommands, int n)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < n; ++i)
|
|
||||||
{
|
|
||||||
if (strcmp(command_key, quickcommands[i].name) == 0)
|
|
||||||
{
|
|
||||||
return (struct quickcommand *)(quickcommands + i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|||||||
204
src/vmrcli.c
204
src/vmrcli.c
@ -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.11.0
|
* @version 0.7.0
|
||||||
* @date 2024-07-06
|
* @date 2024-07-06
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2024
|
* @copyright Copyright (c) 2024
|
||||||
@ -11,76 +11,68 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include "interface.h"
|
#include "ivmr.h"
|
||||||
#include "wrapper.h"
|
#include "wrapper.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define USAGE "Usage: .\\vmrcli.exe [-h] [-v] [-i|-I] [-f] [-k] [-l] [-e] [-c] [-m] [-s] <api commands>\n" \
|
#define USAGE "Usage: .\\vmrcli.exe [-h] [-i] [-k] [-D] [-v] [-c] [-m] [-s] <api commands>\n" \
|
||||||
"Where: \n" \
|
"Where: \n" \
|
||||||
"\th: Print the help message\n" \
|
"\th: Prints the help message\n" \
|
||||||
"\tv: Print the version number\n" \
|
"\ti: Enable interactive mode\n" \
|
||||||
"\ti: Enable interactive mode, use (-I) to disable the '>>' prompt\n" \
|
|
||||||
"\tf: Do not split input on spaces\n" \
|
|
||||||
"\tk: The kind of Voicemeeter (basic, banana, potato)\n" \
|
"\tk: The kind of Voicemeeter (basic, banana, potato)\n" \
|
||||||
"\tl: Set log level, must be one of TRACE, DEBUG, INFO, WARN, ERROR, or FATAL\n" \
|
"\tD: Set log level 0=TRACE, 1=DEBUG, 2=INFO, 3=WARN, 4=ERROR, 5=FATAL\n" \
|
||||||
"\te: Enable extra console output (toggle, set messages)\n" \
|
"\tv: Enable extra console output (toggle, set messages)\n" \
|
||||||
"\tc: Load a user configuration (give the full file path)\n" \
|
"\tc: Load a user configuration (give the full file path)\n" \
|
||||||
"\tm: Launch the MacroButtons application\n" \
|
"\tm: Launch the MacroButtons application\n" \
|
||||||
"\ts: Launch the StreamerView application"
|
"\ts: Launch the StreamerView application"
|
||||||
#define OPTSTR ":hvk:msc:iIfl:e"
|
#define OPTSTR ":hk:msc:iD:v"
|
||||||
#define MAX_LINE 4096 /* Size of the input buffer */
|
#define MAX_LINE 512
|
||||||
#define RES_SZ 512 /* Size of the buffer passed to VBVMR_GetParameterStringW */
|
|
||||||
#define COUNT_OF(x) (sizeof(x) / sizeof(x[0]))
|
|
||||||
#define DELIMITERS " \t;,"
|
|
||||||
#define VERSION "0.12.0"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @enum The kind of values a get call may return.
|
* @enum The kind of values a get call may return.
|
||||||
*/
|
*/
|
||||||
enum restype : int
|
enum
|
||||||
{
|
{
|
||||||
FLOAT_T,
|
FLOAT_T,
|
||||||
STRING_T,
|
STRING_T,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct A struct used for:
|
* @struct A struct holding the result of a get call.
|
||||||
* - tracking the type of value stored
|
|
||||||
* - storing the result of a get call
|
|
||||||
*/
|
*/
|
||||||
struct result
|
struct result
|
||||||
{
|
{
|
||||||
enum restype type;
|
int type;
|
||||||
union val
|
union val
|
||||||
{
|
{
|
||||||
float f;
|
float f;
|
||||||
wchar_t s[RES_SZ];
|
wchar_t s[MAX_LINE];
|
||||||
} val;
|
} val;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool eflag = false;
|
static bool vflag = false;
|
||||||
|
|
||||||
static void terminate(PT_VMR vmr, char *msg);
|
static void usage(void);
|
||||||
static void usage();
|
enum kind set_kind(char *kval);
|
||||||
static enum kind set_kind(char *kval);
|
void interactive(PT_VMR vmr);
|
||||||
static void interactive(PT_VMR vmr, bool with_prompt, char *delimiters);
|
void parse_input(PT_VMR vmr, char *input);
|
||||||
static void parse_input(PT_VMR vmr, char *input, char *delimiters);
|
void parse_command(PT_VMR vmr, char *command);
|
||||||
static void parse_command(PT_VMR vmr, char *command);
|
void get(PT_VMR vmr, char *command, struct result *res);
|
||||||
static void get(PT_VMR vmr, char *command, struct result *res);
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
bool iflag = false,
|
bool iflag = false,
|
||||||
mflag = false,
|
mflag = false,
|
||||||
sflag = false,
|
sflag = false,
|
||||||
cflag = false,
|
cflag = false;
|
||||||
fflag = false,
|
|
||||||
with_prompt = true;
|
|
||||||
int opt;
|
int opt;
|
||||||
int log_level = LOG_WARN;
|
int dvalue;
|
||||||
char *cvalue;
|
char *cvalue;
|
||||||
enum kind kind = BANANAX64;
|
enum kind kind = BANANAX64;
|
||||||
|
|
||||||
@ -89,16 +81,13 @@ int main(int argc, char *argv[])
|
|||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
|
|
||||||
log_set_level(log_level);
|
log_set_level(LOG_WARN);
|
||||||
|
|
||||||
opterr = 0;
|
opterr = 0;
|
||||||
while ((opt = getopt(argc, argv, OPTSTR)) != -1)
|
while ((opt = getopt(argc, argv, OPTSTR)) != -1)
|
||||||
{
|
{
|
||||||
switch (opt)
|
switch (opt)
|
||||||
{
|
{
|
||||||
case 'v':
|
|
||||||
printf("vmrcli version %s\n", VERSION);
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
case 'k':
|
case 'k':
|
||||||
kind = set_kind(optarg);
|
kind = set_kind(optarg);
|
||||||
if (kind == UNKNOWN)
|
if (kind == UNKNOWN)
|
||||||
@ -117,30 +106,24 @@ int main(int argc, char *argv[])
|
|||||||
cflag = true;
|
cflag = true;
|
||||||
cvalue = optarg;
|
cvalue = optarg;
|
||||||
break;
|
break;
|
||||||
case 'I':
|
|
||||||
with_prompt = false;
|
|
||||||
[[fallthrough]];
|
|
||||||
case 'i':
|
case 'i':
|
||||||
iflag = true;
|
iflag = true;
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'D':
|
||||||
fflag = true;
|
dvalue = atoi(optarg);
|
||||||
break;
|
if (dvalue >= LOG_TRACE && dvalue <= LOG_FATAL)
|
||||||
case 'l':
|
|
||||||
log_level = log_level_from_string(optarg);
|
|
||||||
if (log_level != -1)
|
|
||||||
{
|
{
|
||||||
log_set_level(log_level);
|
log_set_level(dvalue);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log_warn(
|
log_warn(
|
||||||
"-l arg out of range, expected TRACE, DEBUG, INFO, WARN, ERROR, or FATAL\n"
|
"-D arg out of range, expected value from 0 up to 5\n"
|
||||||
"Log level will default to LOG_WARN (3).\n");
|
"Log level will default to LOG_WARN (3).\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'v':
|
||||||
eflag = true;
|
vflag = true;
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
log_fatal("unknown option -- '%c'\n"
|
log_fatal("unknown option -- '%c'\n"
|
||||||
@ -160,85 +143,61 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
PT_VMR vmr = create_interface();
|
PT_VMR vmr = create_interface();
|
||||||
if (vmr == NULL)
|
|
||||||
{
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
long rep = login(vmr, kind);
|
int rep = login(vmr, kind);
|
||||||
if (rep != 0)
|
if (rep != 0)
|
||||||
{
|
{
|
||||||
if (rep == -2)
|
log_fatal("Error logging into the Voicemeeter API");
|
||||||
terminate(vmr, "Timeout logging into the API.");
|
exit(EXIT_FAILURE);
|
||||||
else
|
|
||||||
terminate(vmr, "Error logging into the Voicemeeter API");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mflag)
|
if (mflag)
|
||||||
{
|
{
|
||||||
run_voicemeeter(vmr, MACROBUTTONS);
|
|
||||||
log_info("MacroButtons app launched");
|
log_info("MacroButtons app launched");
|
||||||
|
run_voicemeeter(vmr, MACROBUTTONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sflag)
|
if (sflag)
|
||||||
{
|
{
|
||||||
run_voicemeeter(vmr, STREAMERVIEW);
|
|
||||||
log_info("StreamerView app launched");
|
log_info("StreamerView app launched");
|
||||||
|
run_voicemeeter(vmr, STREAMERVIEW);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cflag)
|
if (cflag)
|
||||||
{
|
{
|
||||||
set_parameter_string(vmr, "command.load", cvalue);
|
|
||||||
log_info("Profile %s loaded", cvalue);
|
log_info("Profile %s loaded", cvalue);
|
||||||
|
set_parameter_string(vmr, "command.load", cvalue);
|
||||||
Sleep(300);
|
Sleep(300);
|
||||||
clear(vmr, is_pdirty);
|
clear_dirty(vmr);
|
||||||
}
|
|
||||||
|
|
||||||
char *delimiter_ptr = DELIMITERS;
|
|
||||||
if (fflag)
|
|
||||||
{
|
|
||||||
delimiter_ptr++; /* skip space delimiter */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iflag)
|
if (iflag)
|
||||||
{
|
{
|
||||||
puts("Interactive mode enabled. Enter 'Q' to exit.");
|
puts("Interactive mode enabled. Enter 'Q' to exit.");
|
||||||
interactive(vmr, with_prompt, delimiter_ptr);
|
interactive(vmr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = optind; i < argc; ++i)
|
for (int i = optind; i < argc; i++)
|
||||||
{
|
{
|
||||||
parse_input(vmr, argv[i], delimiter_ptr);
|
parse_input(vmr, argv[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rep = logout(vmr);
|
rep = logout(vmr);
|
||||||
if (rep != 0)
|
if (rep == 0)
|
||||||
{
|
{
|
||||||
terminate(vmr, "Error logging out of the Voicemeeter API");
|
|
||||||
}
|
|
||||||
|
|
||||||
log_info("Successfully logged out of the Voicemeeter API");
|
|
||||||
free(vmr);
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
/**
|
|
||||||
* @brief Write fatal error log, free dyn allocated memory then exit
|
|
||||||
*
|
|
||||||
* @param vmr Pointer to the iVMR interface
|
|
||||||
* @param msg Fatal error message
|
|
||||||
*/
|
|
||||||
static void terminate(PT_VMR vmr, char *msg)
|
|
||||||
{
|
{
|
||||||
log_fatal(msg);
|
log_fatal("Error logging out of the Voicemeeter API");
|
||||||
free(vmr);
|
return EXIT_FAILURE;
|
||||||
exit(EXIT_FAILURE);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Prints the help message
|
* @brief prints the help message
|
||||||
*/
|
*/
|
||||||
static void usage()
|
static void usage()
|
||||||
{
|
{
|
||||||
@ -253,14 +212,14 @@ static void usage()
|
|||||||
* @param kval Value of the -k flag
|
* @param kval Value of the -k flag
|
||||||
* @return enum kind
|
* @return enum kind
|
||||||
*/
|
*/
|
||||||
static enum kind set_kind(char *kval)
|
enum kind set_kind(char *kval)
|
||||||
{
|
{
|
||||||
if (strcmp(kval, "basic") == 0)
|
if (strcmp(kval, "basic") == 0)
|
||||||
return IS_64_BIT ? BASICX64 : BASIC;
|
return sizeof(void *) == 8 ? BASICX64 : BASIC;
|
||||||
else if (strcmp(kval, "banana") == 0)
|
else if (strcmp(kval, "banana") == 0)
|
||||||
return IS_64_BIT ? BANANAX64 : BANANA;
|
return sizeof(void *) == 8 ? BANANAX64 : BANANA;
|
||||||
else if (strcmp(kval, "potato") == 0)
|
else if (strcmp(kval, "potato") == 0)
|
||||||
return IS_64_BIT ? POTATOX64 : POTATO;
|
return sizeof(void *) == 8 ? POTATOX64 : POTATO;
|
||||||
else
|
else
|
||||||
return UNKNOWN;
|
return UNKNOWN;
|
||||||
}
|
}
|
||||||
@ -271,50 +230,41 @@ static enum kind set_kind(char *kval)
|
|||||||
* Each line is passed to parse_input()
|
* Each line is passed to parse_input()
|
||||||
*
|
*
|
||||||
* @param vmr Pointer to the iVMR interface
|
* @param vmr Pointer to the iVMR interface
|
||||||
* @param with_prompt If true, prints the interactive prompt '>>'
|
|
||||||
* @param delimiters A string of delimiter characters to split each input line
|
|
||||||
*/
|
*/
|
||||||
static void interactive(PT_VMR vmr, bool with_prompt, char *delimiters)
|
void interactive(PT_VMR vmr)
|
||||||
{
|
{
|
||||||
char input[MAX_LINE];
|
char input[MAX_LINE];
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (with_prompt)
|
|
||||||
printf(">> ");
|
printf(">> ");
|
||||||
while (fgets(input, MAX_LINE, stdin) != NULL)
|
while (fgets(input, MAX_LINE, stdin) != NULL)
|
||||||
{
|
{
|
||||||
input[(len = strcspn(input, "\n"))] = 0;
|
input[strcspn(input, "\n")] = 0;
|
||||||
if (len == 1 && toupper(input[0]) == 'Q')
|
if (strlen(input) == 1 && toupper(input[0]) == 'Q')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
parse_input(vmr, input, delimiters);
|
parse_input(vmr, input);
|
||||||
|
|
||||||
if (with_prompt)
|
memset(input, 0, MAX_LINE); /* reset input buffer */
|
||||||
printf(">> ");
|
printf(">> ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns early if input is a comment
|
* @brief Walks through each line split by " \t;," delimiters.
|
||||||
* 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 delimiters A string of delimiter characters to split each input line
|
|
||||||
*/
|
*/
|
||||||
static void parse_input(PT_VMR vmr, char *input, char *delimiters)
|
void parse_input(PT_VMR vmr, char *input)
|
||||||
{
|
{
|
||||||
if (is_comment(input))
|
|
||||||
return;
|
|
||||||
|
|
||||||
char *token, *p;
|
char *token, *p;
|
||||||
|
|
||||||
token = strtok_r(input, delimiters, &p);
|
token = strtok_r(input, " \t;,", &p);
|
||||||
while (token != NULL)
|
while (token != NULL)
|
||||||
{
|
{
|
||||||
parse_command(vmr, token);
|
parse_command(vmr, token);
|
||||||
token = strtok_r(NULL, delimiters, &p);
|
token = strtok_r(NULL, " \t;,", &p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,28 +276,10 @@ static void parse_input(PT_VMR vmr, char *input, char *delimiters)
|
|||||||
* @param vmr Pointer to the iVMR interface
|
* @param vmr Pointer to the iVMR interface
|
||||||
* @param command Each token from the input line as its own command string
|
* @param command Each token from the input line as its own command string
|
||||||
*/
|
*/
|
||||||
static void parse_command(PT_VMR vmr, char *command)
|
void parse_command(PT_VMR vmr, char *command)
|
||||||
{
|
{
|
||||||
log_debug("Parsing %s", command);
|
log_debug("Parsing %s", command);
|
||||||
|
|
||||||
static const struct quickcommand quickcommands[] = {
|
|
||||||
{.name = "lock", .fullcommand = "command.lock=1"},
|
|
||||||
{.name = "unlock", .fullcommand = "command.lock=0"},
|
|
||||||
{.name = "show", .fullcommand = "command.show=1"},
|
|
||||||
{.name = "hide", .fullcommand = "command.show=0"},
|
|
||||||
{.name = "restart", .fullcommand = "command.restart=1"}};
|
|
||||||
|
|
||||||
struct quickcommand *qc_ptr = command_in_quickcommands(command, quickcommands, (int)COUNT_OF(quickcommands));
|
|
||||||
if (qc_ptr != NULL)
|
|
||||||
{
|
|
||||||
set_parameters(vmr, qc_ptr->fullcommand);
|
|
||||||
if (eflag)
|
|
||||||
{
|
|
||||||
printf("Setting %s\n", qc_ptr->fullcommand);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command[0] == '!') /* toggle */
|
if (command[0] == '!') /* toggle */
|
||||||
{
|
{
|
||||||
command++;
|
command++;
|
||||||
@ -359,7 +291,7 @@ static void parse_command(PT_VMR vmr, char *command)
|
|||||||
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 (eflag)
|
if (vflag)
|
||||||
{
|
{
|
||||||
printf("Toggling %s\n", command);
|
printf("Toggling %s\n", command);
|
||||||
}
|
}
|
||||||
@ -373,7 +305,7 @@ static void parse_command(PT_VMR vmr, char *command)
|
|||||||
if (strchr(command, '=') != NULL) /* set */
|
if (strchr(command, '=') != NULL) /* set */
|
||||||
{
|
{
|
||||||
set_parameters(vmr, command);
|
set_parameters(vmr, command);
|
||||||
if (eflag)
|
if (vflag)
|
||||||
{
|
{
|
||||||
printf("Setting %s\n", command);
|
printf("Setting %s\n", command);
|
||||||
}
|
}
|
||||||
@ -404,11 +336,11 @@ static void parse_command(PT_VMR vmr, char *command)
|
|||||||
*
|
*
|
||||||
* @param vmr Pointer to the iVMR interface
|
* @param vmr Pointer to the iVMR interface
|
||||||
* @param command A parsed 'get' command as a string
|
* @param command A parsed 'get' command as a string
|
||||||
* @param res Pointer to a struct holding the result of the API call.
|
* @param res A struct holding the result of the API call.
|
||||||
*/
|
*/
|
||||||
static void get(PT_VMR vmr, char *command, struct result *res)
|
void get(PT_VMR vmr, char *command, struct result *res)
|
||||||
{
|
{
|
||||||
clear(vmr, is_pdirty);
|
clear_dirty(vmr);
|
||||||
if (get_parameter_float(vmr, command, &res->val.f) != 0)
|
if (get_parameter_float(vmr, command, &res->val.f) != 0)
|
||||||
{
|
{
|
||||||
res->type = STRING_T;
|
res->type = STRING_T;
|
||||||
|
|||||||
149
src/wrapper.c
149
src/wrapper.c
@ -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.11.0
|
* @version 0.7.0
|
||||||
* @date 2024-07-06
|
* @date 2024-07-06
|
||||||
*
|
*
|
||||||
* @copyright Copyright (c) 2024
|
* @copyright Copyright (c) 2024
|
||||||
@ -10,13 +10,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
#include "wrapper.h"
|
#include "wrapper.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define KIND_STR_LEN 64
|
#define KIND_STR_LEN 64
|
||||||
#define VERSION_STR_LEN 32
|
#define VERSION_STR_LEN 32
|
||||||
#define LOGIN_TIMEOUT 2
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Logs into the API.
|
* @brief Logs into the API.
|
||||||
@ -25,13 +26,11 @@
|
|||||||
*
|
*
|
||||||
* @param vmr Pointer to the iVMR interface
|
* @param vmr Pointer to the iVMR interface
|
||||||
* @param kind The kind of Voicemeeter Gui to launch.
|
* @param kind The kind of Voicemeeter Gui to launch.
|
||||||
* @return long
|
* @return long VBVMR_Login return value
|
||||||
* 0: OK (no error).
|
|
||||||
* -2: Login timed out.
|
|
||||||
*/
|
*/
|
||||||
long login(PT_VMR vmr, int kind)
|
long login(PT_VMR vmr, int kind)
|
||||||
{
|
{
|
||||||
long rep;
|
int rep;
|
||||||
long v;
|
long v;
|
||||||
|
|
||||||
log_trace("VBVMR_Login()");
|
log_trace("VBVMR_Login()");
|
||||||
@ -45,6 +44,7 @@ long login(PT_VMR vmr, int kind)
|
|||||||
kind_as_string(kind_s, kind, KIND_STR_LEN));
|
kind_as_string(kind_s, kind, KIND_STR_LEN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int timeout = 2;
|
||||||
time_t start = time(NULL);
|
time_t start = time(NULL);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -54,12 +54,15 @@ long login(PT_VMR vmr, int kind)
|
|||||||
log_info(
|
log_info(
|
||||||
"Successfully logged into the Voicemeeter API v%s",
|
"Successfully logged into the Voicemeeter API v%s",
|
||||||
version_as_string(version_s, v, VERSION_STR_LEN));
|
version_as_string(version_s, v, VERSION_STR_LEN));
|
||||||
clear(vmr, is_pdirty);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Sleep(50);
|
Sleep(50);
|
||||||
} while (difftime(time(NULL), start) < LOGIN_TIMEOUT);
|
} while (time(NULL) < start + timeout);
|
||||||
|
|
||||||
|
if (rep == 0)
|
||||||
|
{
|
||||||
|
clear_dirty(vmr);
|
||||||
|
}
|
||||||
return rep;
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,201 +71,95 @@ long login(PT_VMR vmr, int kind)
|
|||||||
* final instruction to complete.
|
* final instruction to complete.
|
||||||
*
|
*
|
||||||
* @param vmr Pointer to the iVMR interface
|
* @param vmr Pointer to the iVMR interface
|
||||||
* @return long See:
|
* @return long VBVMR_Logout return value
|
||||||
* https://github.com/onyx-and-iris/vmrcli/blob/main/include/VoicemeeterRemote.h#L56
|
|
||||||
*/
|
*/
|
||||||
long logout(PT_VMR vmr)
|
long logout(PT_VMR vmr)
|
||||||
{
|
{
|
||||||
|
int rep;
|
||||||
|
|
||||||
Sleep(20); /* give time for last command */
|
Sleep(20); /* give time for last command */
|
||||||
log_trace("VBVMR_Logout()");
|
log_trace("VBVMR_Logout()");
|
||||||
return vmr->VBVMR_Logout();
|
rep = vmr->VBVMR_Logout();
|
||||||
|
if (rep == 0)
|
||||||
|
log_info("Successfully logged out of the Voicemeeter API");
|
||||||
|
return rep;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Launches Voicemeeter or other utility apps
|
|
||||||
*
|
|
||||||
* @param vmr Pointer to the iVMR interface
|
|
||||||
* @param kind The kind of app to launch
|
|
||||||
* @return long See:
|
|
||||||
* https://github.com/onyx-and-iris/vmrcli/blob/main/include/VoicemeeterRemote.h#L66
|
|
||||||
*/
|
|
||||||
long run_voicemeeter(PT_VMR vmr, int kind)
|
long run_voicemeeter(PT_VMR vmr, int kind)
|
||||||
{
|
{
|
||||||
log_trace("VBVMR_RunVoicemeeter(%d)", kind);
|
log_trace("VBVMR_RunVoicemeeter(%d)", kind);
|
||||||
return vmr->VBVMR_RunVoicemeeter((long)kind);
|
return vmr->VBVMR_RunVoicemeeter((long)kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get Voicemeeter type
|
|
||||||
*
|
|
||||||
* @param vmr Pointer to the iVMR interface
|
|
||||||
* @param type Pointer to a long object receiving the type
|
|
||||||
* @return long See:
|
|
||||||
* https://github.com/onyx-and-iris/vmrcli/blob/main/include/VoicemeeterRemote.h#L107
|
|
||||||
*/
|
|
||||||
long type(PT_VMR vmr, long *type)
|
long type(PT_VMR vmr, long *type)
|
||||||
{
|
{
|
||||||
log_trace("VBVMR_GetVoicemeeterType(<long> *t)");
|
log_trace("VBVMR_GetVoicemeeterType(<long> *t)");
|
||||||
return vmr->VBVMR_GetVoicemeeterType(type);
|
return vmr->VBVMR_GetVoicemeeterType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get Voicemeeter version
|
|
||||||
*
|
|
||||||
* @param vmr Pointer to the iVMR interface
|
|
||||||
* @param version Pointer to a long object receiving the version
|
|
||||||
* @return long See:
|
|
||||||
* https://github.com/onyx-and-iris/vmrcli/blob/main/include/VoicemeeterRemote.h#L122
|
|
||||||
*/
|
|
||||||
long version(PT_VMR vmr, long *version)
|
long version(PT_VMR vmr, long *version)
|
||||||
{
|
{
|
||||||
log_trace("VBVMR_GetVoicemeeterVersion(<long> *v)");
|
log_trace("VBVMR_GetVoicemeeterVersion(<long> *v)");
|
||||||
return vmr->VBVMR_GetVoicemeeterVersion(version);
|
return vmr->VBVMR_GetVoicemeeterVersion(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Polling function, use it to determine if there are parameter
|
|
||||||
* states to be updated.
|
|
||||||
*
|
|
||||||
* @param vmr Pointer to the iVMR interface
|
|
||||||
* @return true New parameters yet to be updated
|
|
||||||
* @return false No new parameters, safe to make a get call
|
|
||||||
*/
|
|
||||||
bool is_pdirty(PT_VMR vmr)
|
bool is_pdirty(PT_VMR vmr)
|
||||||
{
|
{
|
||||||
log_trace("VBVMR_IsParametersDirty()");
|
log_trace("VBVMR_IsParametersDirty()");
|
||||||
return vmr->VBVMR_IsParametersDirty() == 1;
|
return vmr->VBVMR_IsParametersDirty() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the parameter float object
|
|
||||||
*
|
|
||||||
* @param vmr Pointer to the iVMR interface
|
|
||||||
* @param param The parameter to be queried
|
|
||||||
* @param f Pointer to a float object receiving the value
|
|
||||||
* @return long See:
|
|
||||||
* https://github.com/onyx-and-iris/vmrcli/blob/main/include/VoicemeeterRemote.h#L159
|
|
||||||
*/
|
|
||||||
long get_parameter_float(PT_VMR vmr, char *param, float *f)
|
long get_parameter_float(PT_VMR vmr, char *param, float *f)
|
||||||
{
|
{
|
||||||
log_trace("VBVMR_GetParameterFloat(%s, <float> *f)", param);
|
log_trace("VBVMR_GetParameterFloat(%s, <float> *f)", param);
|
||||||
return vmr->VBVMR_GetParameterFloat(param, f);
|
return vmr->VBVMR_GetParameterFloat(param, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
long get_parameter_string(PT_VMR vmr, char *param, unsigned short *s)
|
||||||
* @brief Get the parameter string object
|
|
||||||
*
|
|
||||||
* @param vmr Pointer to the iVMR interface
|
|
||||||
* @param param The parameter to be queried
|
|
||||||
* @param s Pointer to a character buffer receiving the string value
|
|
||||||
* @return long See:
|
|
||||||
* https://github.com/onyx-and-iris/vmrcli/blob/main/include/VoicemeeterRemote.h#L173
|
|
||||||
*/
|
|
||||||
long get_parameter_string(PT_VMR vmr, char *param, wchar_t *s)
|
|
||||||
{
|
{
|
||||||
log_trace("VBVMR_GetParameterStringW(%s, <wchar_t> *s)", param);
|
log_trace("VBVMR_GetParameterStringW(%s, <unsigned short> *s)", param);
|
||||||
return vmr->VBVMR_GetParameterStringW(param, s);
|
return vmr->VBVMR_GetParameterStringW(param, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the parameter float object
|
|
||||||
*
|
|
||||||
* @param vmr Pointer to the iVMR interface
|
|
||||||
* @param param The parameter to be updated
|
|
||||||
* @param val The new value
|
|
||||||
* @return long See:
|
|
||||||
* https://github.com/onyx-and-iris/vmrcli/blob/main/include/VoicemeeterRemote.h#L309
|
|
||||||
*/
|
|
||||||
long set_parameter_float(PT_VMR vmr, char *param, float val)
|
long set_parameter_float(PT_VMR vmr, char *param, float val)
|
||||||
{
|
{
|
||||||
log_trace("VBVMR_SetParameterFloat(%s, %.1f)", param, val);
|
log_trace("VBVMR_SetParameterFloat(%s, %.1f)", param, val);
|
||||||
return vmr->VBVMR_SetParameterFloat(param, val);
|
return vmr->VBVMR_SetParameterFloat(param, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the parameter string object
|
|
||||||
*
|
|
||||||
* @param vmr Pointer to the iVMR interface
|
|
||||||
* @param param The parameter to be updated
|
|
||||||
* @param s Pointer to a char[] object containing the new value
|
|
||||||
* @return long See:
|
|
||||||
* https://github.com/onyx-and-iris/vmrcli/blob/main/include/VoicemeeterRemote.h#L327
|
|
||||||
*/
|
|
||||||
long set_parameter_string(PT_VMR vmr, char *param, char *s)
|
long set_parameter_string(PT_VMR vmr, char *param, char *s)
|
||||||
{
|
{
|
||||||
log_trace("VBVMR_SetParameterStringA(%s, %s)", param, s);
|
log_trace("VBVMR_SetParameterStringA(%s, %s)", param, s);
|
||||||
return vmr->VBVMR_SetParameterStringA(param, s);
|
return vmr->VBVMR_SetParameterStringA(param, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Run a script possibly containing multiple instructions
|
|
||||||
*
|
|
||||||
* @param vmr Pointer to the iVMR interface
|
|
||||||
* @param command Pointer to a char[] object containing the script
|
|
||||||
* @return long See:
|
|
||||||
* https://github.com/onyx-and-iris/vmrcli/blob/main/include/VoicemeeterRemote.h#L351
|
|
||||||
*/
|
|
||||||
long set_parameters(PT_VMR vmr, char *command)
|
long set_parameters(PT_VMR vmr, char *command)
|
||||||
{
|
{
|
||||||
log_trace("VBVMR_SetParameters(%s)", command);
|
log_trace("VBVMR_SetParameters(%s)", command);
|
||||||
return vmr->VBVMR_SetParameters(command);
|
return vmr->VBVMR_SetParameters(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Polling function, use it to determine if there are macrobutton
|
|
||||||
* states to be updated.
|
|
||||||
*
|
|
||||||
* @param vmr Pointer to the iVMR interface
|
|
||||||
* @return true Macrobutton states yet to be udpated
|
|
||||||
* @return false No new macrobutton states
|
|
||||||
*/
|
|
||||||
bool is_mdirty(PT_VMR vmr)
|
bool is_mdirty(PT_VMR vmr)
|
||||||
{
|
{
|
||||||
log_trace("VBVMR_MacroButton_IsDirty()");
|
log_trace("VBVMR_MacroButton_IsDirty()");
|
||||||
return vmr->VBVMR_MacroButton_IsDirty() >= 0;
|
return vmr->VBVMR_MacroButton_IsDirty() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the current status of macrobutton[n].{mode}
|
|
||||||
*
|
|
||||||
* @param vmr Pointer to the iVMR interface
|
|
||||||
* @param n Index of the macrobutton
|
|
||||||
* @param val Pointer to a float object the current value will be stored in
|
|
||||||
* @param mode The mode (stateonly, state, trigger)
|
|
||||||
* @return long See:
|
|
||||||
* https://github.com/onyx-and-iris/vmrcli/blob/main/include/VoicemeeterRemote.h#L663
|
|
||||||
*/
|
|
||||||
long macrobutton_getstatus(PT_VMR vmr, long n, float *val, long mode)
|
long macrobutton_getstatus(PT_VMR vmr, long n, float *val, long mode)
|
||||||
{
|
{
|
||||||
log_trace("VBVMR_MacroButton_GetStatus(%ld, <float> *v, %ld)", n, mode);
|
log_trace("VBVMR_MacroButton_GetStatus(%ld, <float> *v, %ld)", n, mode);
|
||||||
return vmr->VBVMR_MacroButton_GetStatus(n, val, mode);
|
return vmr->VBVMR_MacroButton_GetStatus(n, val, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Set the current status of macrobutton[n].{mode}
|
|
||||||
*
|
|
||||||
* @param vmr Pointer to the iVMR interface
|
|
||||||
* @param n Index of the macrobutton
|
|
||||||
* @param val Value to be updated
|
|
||||||
* @param mode The mode (stateonly, state, trigger)
|
|
||||||
* @return long See:
|
|
||||||
* https://github.com/onyx-and-iris/vmrcli/blob/main/include/VoicemeeterRemote.h#L677
|
|
||||||
*/
|
|
||||||
long macrobutton_setstatus(PT_VMR vmr, long n, float val, long mode)
|
long macrobutton_setstatus(PT_VMR vmr, long n, float val, long mode)
|
||||||
{
|
{
|
||||||
log_trace("VBVMR_MacroButton_SetStatus(%ld, %d, %ld)", n, (int)val, mode);
|
log_trace("VBVMR_MacroButton_SetStatus(%ld, %d, %ld)", n, (int)val, mode);
|
||||||
return vmr->VBVMR_MacroButton_SetStatus(n, val, mode);
|
return vmr->VBVMR_MacroButton_SetStatus(n, val, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void clear_dirty(PT_VMR vmr)
|
||||||
* @brief Continuously polls an is_{}dirty function until it clears.
|
|
||||||
*
|
|
||||||
* @param vmr Pointer to the iVMR interface
|
|
||||||
* @param f Pointer to a polling function
|
|
||||||
*/
|
|
||||||
void clear(PT_VMR vmr, bool (*f)(PT_VMR))
|
|
||||||
{
|
{
|
||||||
Sleep(30);
|
Sleep(30);
|
||||||
while (f(vmr))
|
while (is_pdirty(vmr))
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user