21 Commits

Author SHA1 Message Date
09793afafa upd instruction for -c.
giving file name is unreliable.
2024-07-05 12:05:50 +01:00
8bdbfe9b04 change -p for -c, seems more intuitive 2024-07-05 11:28:29 +01:00
f87977165a add -p flag for loading a user configuration file.
add -p explanation to README
2024-07-05 11:21:46 +01:00
36eadb4b58 remove func prototype 2024-07-05 10:51:26 +01:00
930093da7f add create_interface() to cdll.c.
Use it to initialize the dll interface and return a pointer to it.
2024-07-05 10:41:07 +01:00
a28db25bcc define mb function pointers in the iVMR interface.
add trace logs for login, logout and mb functions
2024-07-04 12:19:04 +01:00
83a85fd7c5 add new typedef struct *PT_VMR
use it to pass around references to the iVMR instance
2024-07-04 09:14:14 +01:00
f6437fcbe7 make static 2024-07-03 17:52:08 +01:00
fb54c4a492 fixes compiler error 'Incompatible pointer types' 2024-07-03 15:25:16 +01:00
8aeb793a41 fixes compiler error 'Forward declaration of enums' 2024-07-03 15:24:44 +01:00
b6b4b04a8a upd includes 2024-07-03 13:57:58 +01:00
b7fa15d87d log_warn an incorrect -D arg.
log_fatal possible exit points.
2024-07-03 12:58:34 +01:00
b95c40265c fix s flag in help message 2024-07-02 17:59:44 +01:00
4b64ae95fd add -m flag for launching macrobuttons app.
add -s flag for launching streamerview app

add -m, -s flags to Use section in README.
2024-07-02 17:49:51 +01:00
f8d2f80cbf remove the extra call to version 2024-07-02 14:49:42 +01:00
4b79b7f849 add -= example to README 2024-07-02 12:00:16 +01:00
3ec98ea391 add note about += and -= to README
add increment/decrement instructions to example_commands
2024-07-02 11:55:34 +01:00
faad5bc2c8 add doc comments 2024-07-02 11:15:17 +01:00
cc0ec73ef4 fix help dialogue 2024-07-02 10:25:25 +01:00
c45df11286 add -v flag to README use section 2024-07-02 10:24:07 +01:00
a383aaa36b reword
add link defs
2024-07-02 10:21:37 +01:00
10 changed files with 863 additions and 838 deletions

View File

@@ -13,28 +13,32 @@
## `Use` ## `Use`
```powershell ```powershell
./vmrcli.exe [-h] [-i] [-k] [-D] <api commands> ./vmrcli.exe [-h] [-i] [-k] [-D] [-v] [-c] [-m] [-s] <api commands>
``` ```
Where: Where:
- `h`: Prints the help dialogue. - `h`: Prints the help message.
- `i`: Enable interactive mode. If set, any api commands passed on the command line will be ignored. - `i`: Enable interactive mode. If set, any api commands passed on the command line will be ignored.
- `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.
- `D`: Set log level 0=TRACE, 1=DEBUG, 2=INFO, 3=WARN, 4=ERROR, 5=FATAL - `D`: Set log level 0=TRACE, 1=DEBUG, 2=INFO, 3=WARN, 4=ERROR, 5=FATAL
- `v`: Enable extra console output (toggle, set messages)
- `c`: Load a user configuration (give the full file path)
- `m`: Launch the MacroButtons application
- `s`: Launch the StreamerView application
## `API Commands` ## `API Commands`
- Commands starting with `!` will be toggled, use it with boolean parameters. - Commands starting with `!` will be toggled, use it with boolean parameters.
- Commands containing `=` will set a value. - Commands containing `=` will set a value. (use `+=` and `-=` to increment/decrement)
- All other commands with get a value. - All other commands with get a value.
Examples: Examples:
Launch basic GUI, set log level to INFO, Toggle Strip 0 Mute, then print its new value 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 -D2 !strip[0].mute strip[0].mute ./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
@@ -74,14 +78,19 @@ Multiple API commands can be in a single line but they should be space separated
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/).
By default the log.c module is built with coloured logging enabled. To disable this you can override the `LOG_USE_COLOR` variable, for example: The binary in [Releases][releases] is compiled with coloured logging enabled. To disable this you can override the `LOG_USE_COLOR` variable, for example:
`make LOG_USE_COLOR=no` `make LOG_USE_COLOR=no`
## `Official Documentation` ## `Official Documentation`
- [Voicemeeter Remote C API](https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/main/VoicemeeterRemoteAPI.pdf) - [Voicemeeter Remote C API][remoteapi-docs]
## `Special Thanks` ## `Special Thanks`
- [rxi](https://github.com/rxi) for writing the [log.c](https://github.com/rxi/log.c) package - [rxi][rxi-user] for writing the [log.c][log-c] package
[releases]: https://github.com/onyx-and-iris/vmrcli/releases
[remoteapi-docs]: https://github.com/onyx-and-iris/Voicemeeter-SDK/blob/main/VoicemeeterRemoteAPI.pdf
[rxi-user]: https://github.com/rxi
[log-c]: https://github.com/rxi/log.c

View File

@@ -1,3 +1,5 @@
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].mute=1 strip[1].mute strip[1].mute=1 strip[1].mute strip[1].limit-=8
bus[0].label bus[0].gain=-8.3 strip[2].gain-=5 strip[2].comp+=4.8
bus[0].label
bus[1].gain-=5.8

View File

@@ -1,5 +1,5 @@
/******************************************************************************/ /******************************************************************************/
/* Voicemeeter Remote API. V.Burel©2015-2023 */ /* Voicemeeter Remote API. V.Burel<EFBFBD>2015-2023 */
/******************************************************************************/ /******************************************************************************/
/* This Library allows communication with Voicemeeter applications */ /* This Library allows communication with Voicemeeter applications */
/* 4 Client Applications can be connected to remote Voicemeeter. */ /* 4 Client Applications can be connected to remote Voicemeeter. */
@@ -19,15 +19,14 @@
/* long = 32 bit integer */ /* long = 32 bit integer */
/******************************************************************************/ /******************************************************************************/
#ifndef __VOICEMEETER_REMOTE_H__ #ifndef __VOICEMEETER_REMOTE_H__
#define __VOICEMEETER_REMOTE_H__ #define __VOICEMEETER_REMOTE_H__
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C"
{
#endif #endif
#define VBVMR_RESULT_OK 0 #define VBVMR_RESULT_OK 0
/******************************************************************************/ /******************************************************************************/
@@ -56,7 +55,6 @@ long __stdcall VBVMR_Login(void);
long __stdcall VBVMR_Logout(void); long __stdcall VBVMR_Logout(void);
/** /**
@brief Run Voicemeeter Application (get installation directory and run Voicemeeter Application). @brief Run Voicemeeter Application (get installation directory and run Voicemeeter Application).
@param vType : Voicemeeter type (1 = Voicemeeter, 2= Voicemeeter Banana, 3= Voicemeeter Potato, 6 = Potato x64 bits). @param vType : Voicemeeter type (1 = Voicemeeter, 2= Voicemeeter Banana, 3= Voicemeeter Potato, 6 = Potato x64 bits).
@@ -67,19 +65,8 @@ long __stdcall VBVMR_Logout(void);
long __stdcall VBVMR_RunVoicemeeter(long vType); long __stdcall VBVMR_RunVoicemeeter(long vType);
/** @} */ /** @} */
/******************************************************************************/ /******************************************************************************/
/* */ /* */
/* General Information */ /* General Information */
@@ -134,26 +121,8 @@ long __stdcall VBVMR_GetVoicemeeterType(long * pType);
long __stdcall VBVMR_GetVoicemeeterVersion(long *pVersion); long __stdcall VBVMR_GetVoicemeeterVersion(long *pVersion);
/** @} */ /** @} */
/******************************************************************************/ /******************************************************************************/
/* */ /* */
/* Get parameters */ /* Get parameters */
@@ -205,14 +174,6 @@ long __stdcall VBVMR_GetParameterStringW(char * szParamName, unsigned short * ws
/** @} */ /** @} */
/******************************************************************************/ /******************************************************************************/
/* */ /* */
/* Get levels */ /* Get levels */
@@ -283,7 +244,6 @@ long __stdcall VBVMR_GetParameterStringW(char * szParamName, unsigned short * ws
long __stdcall VBVMR_GetLevel(long nType, long nuChannel, float *pValue); long __stdcall VBVMR_GetLevel(long nType, long nuChannel, float *pValue);
/** /**
@brief Get MIDI message from M.I.D.I. input device used by Voicemeeter M.I.D.I. mapping. @brief Get MIDI message from M.I.D.I. input device used by Voicemeeter M.I.D.I. mapping.
(this function must be called from one thread only) (this function must be called from one thread only)
@@ -301,10 +261,8 @@ long __stdcall VBVMR_GetLevel(long nType, long nuChannel, float * pValue);
-6: no MIDI data -6: no MIDI data
*/ */
long __stdcall VBVMR_GetMidiMessage(unsigned char *pMIDIBuffer, long nbByteMax); long __stdcall VBVMR_GetMidiMessage(unsigned char *pMIDIBuffer, long nbByteMax);
/** /**
@brief Send MIDI message to M.I.D.I. output device used by Voicemeeter M.I.D.I. mapping. @brief Send MIDI message to M.I.D.I. output device used by Voicemeeter M.I.D.I. mapping.
(this function must be called from one thread only) (this function must be called from one thread only)
@@ -319,21 +277,10 @@ long __stdcall VBVMR_GetMidiMessage(unsigned char *pMIDIBuffer, long nbByteMax);
-5: cannot send MIDI data -5: cannot send MIDI data
*/ */
long __stdcall VBVMR_SendMidiMessage(unsigned char *pMIDIBuffer, long nbByte); long __stdcall VBVMR_SendMidiMessage(unsigned char *pMIDIBuffer, long nbByte);
/** @} */ /** @} */
/******************************************************************************/ /******************************************************************************/
/* */ /* */
/* Set Parameters */ /* Set Parameters */
@@ -361,8 +308,6 @@ long __stdcall VBVMR_SendMidiMessage(unsigned char *pMIDIBuffer, long nbByte);
long __stdcall VBVMR_SetParameterFloat(char *szParamName, float Value); long __stdcall VBVMR_SetParameterFloat(char *szParamName, float Value);
/** /**
@brief Set a single string parameters . @brief Set a single string parameters .
@param szParamName : Null Terminal ASCII String giving the name of the parameter (see parameters name table) @param szParamName : Null Terminal ASCII String giving the name of the parameter (see parameters name table)
@@ -379,13 +324,9 @@ long __stdcall VBVMR_SetParameterFloat(char * szParamName, float Value);
*/ */
long __stdcall VBVMR_SetParameterStringA(char *szParamName, char *szString); long __stdcall VBVMR_SetParameterStringA(char *szParamName, char *szString);
long __stdcall VBVMR_SetParameterStringW(char *szParamName, unsigned short *wszString); long __stdcall VBVMR_SetParameterStringW(char *szParamName, unsigned short *wszString);
/** /**
@brief Set one or several parameters by a script ( < 48 kB ). @brief Set one or several parameters by a script ( < 48 kB ).
@param szParamName : Null Terminal ASCII String giving the script @param szParamName : Null Terminal ASCII String giving the script
@@ -410,24 +351,12 @@ long __stdcall VBVMR_SetParameterStringW(char * szParamName, unsigned short * ws
long __stdcall VBVMR_SetParameters(char *szParamScript); long __stdcall VBVMR_SetParameters(char *szParamScript);
long __stdcall VBVMR_SetParametersW(unsigned short *szParamScript); long __stdcall VBVMR_SetParametersW(unsigned short *szParamScript);
/** @} */ /** @} */
/******************************************************************************/ /******************************************************************************/
/* DEVICES ENUMERATOR */ /* DEVICES ENUMERATOR */
/******************************************************************************/ /******************************************************************************/
/** @name Device Enumeration Functions /** @name Device Enumeration Functions
* @{ */ * @{ */
@@ -474,15 +403,8 @@ long __stdcall VBVMR_Input_GetDeviceNumber(void);
long __stdcall VBVMR_Input_GetDeviceDescA(long zindex, long *nType, char *szDeviceName, char *szHardwareId); long __stdcall VBVMR_Input_GetDeviceDescA(long zindex, long *nType, char *szDeviceName, char *szHardwareId);
long __stdcall VBVMR_Input_GetDeviceDescW(long zindex, long *nType, unsigned short *wszDeviceName, unsigned short *wszHardwareId); long __stdcall VBVMR_Input_GetDeviceDescW(long zindex, long *nType, unsigned short *wszDeviceName, unsigned short *wszHardwareId);
/** @} */ /** @} */
/******************************************************************************/ /******************************************************************************/
/* VB-AUDIO CALLBACK */ /* VB-AUDIO CALLBACK */
/******************************************************************************/ /******************************************************************************/
@@ -497,14 +419,12 @@ long __stdcall VBVMR_Input_GetDeviceDescW(long zindex, long * nType, unsigned sh
/** @name VB-Audio Callback Functions /** @name VB-Audio Callback Functions
* @{ */ * @{ */
typedef struct tagVBVMR_AUDIOINFO typedef struct tagVBVMR_AUDIOINFO
{ {
long samplerate; long samplerate;
long nbSamplePerFrame; long nbSamplePerFrame;
} VBVMR_T_AUDIOINFO, *VBVMR_PT_AUDIOINFO, *VBVMR_LPT_AUDIOINFO; } VBVMR_T_AUDIOINFO, *VBVMR_PT_AUDIOINFO, *VBVMR_LPT_AUDIOINFO;
typedef struct tagVBVMR_AUDIOBUFFER typedef struct tagVBVMR_AUDIOBUFFER
{ {
long audiobuffer_sr; // Sampling Rate long audiobuffer_sr; // Sampling Rate
@@ -515,7 +435,6 @@ typedef struct tagVBVMR_AUDIOBUFFER
float *audiobuffer_w[128]; // nbo output pointers containing frame of nbs sample (of 32bits float) float *audiobuffer_w[128]; // nbo output pointers containing frame of nbs sample (of 32bits float)
} VBVMR_T_AUDIOBUFFER, *VBVMR_PT_AUDIOBUFFER, *VBVMR_LPT_AUDIOBUFFER; } VBVMR_T_AUDIOBUFFER, *VBVMR_PT_AUDIOBUFFER, *VBVMR_LPT_AUDIOBUFFER;
/** /**
@brief VB-AUDIO Callback is called for different task to Initialize, perform and end your process. @brief VB-AUDIO Callback is called for different task to Initialize, perform and end your process.
VB-AUDIO Callback is part of single TIME CRITICAL Thread. VB-AUDIO Callback is part of single TIME CRITICAL Thread.
@@ -533,10 +452,8 @@ typedef struct tagVBVMR_AUDIOBUFFER
@return : 0: always 0 (unused). @return : 0: always 0 (unused).
*/ */
typedef long(__stdcall *T_VBVMR_VBAUDIOCALLBACK)(void *lpUser, long nCommand, void *lpData, long nnn); typedef long(__stdcall *T_VBVMR_VBAUDIOCALLBACK)(void *lpUser, long nCommand, void *lpData, long nnn);
#define VBVMR_CBCOMMAND_STARTING 1 // command to initialize data according SR and buffer size #define VBVMR_CBCOMMAND_STARTING 1 // command to initialize data according SR and buffer size
// info = (VBVMR_LPT_AUDIOINFO)lpData // info = (VBVMR_LPT_AUDIOINFO)lpData
@@ -696,7 +613,6 @@ long __stdcall VBVMR_AudioCallbackRegister(long mode, T_VBVMR_VBAUDIOCALLBACK pC
long __stdcall VBVMR_AudioCallbackStart(void); long __stdcall VBVMR_AudioCallbackStart(void);
long __stdcall VBVMR_AudioCallbackStop(void); long __stdcall VBVMR_AudioCallbackStop(void);
/** /**
@brief unregister your callback to release voicemeeter virtual driver @brief unregister your callback to release voicemeeter virtual driver
(this function will automatically call VBVMR_AudioCallbackStop() function) (this function will automatically call VBVMR_AudioCallbackStop() function)
@@ -708,15 +624,8 @@ long __stdcall VBVMR_AudioCallbackStop(void);
long __stdcall VBVMR_AudioCallbackUnregister(void); long __stdcall VBVMR_AudioCallbackUnregister(void);
/** @} */ /** @} */
/******************************************************************************/ /******************************************************************************/
/* */ /* */
/* Macro Buttons */ /* Macro Buttons */
@@ -772,62 +681,49 @@ long __stdcall VBVMR_MacroButton_SetStatus(long nuLogicalButton, float fValue, l
#define VBVMR_MACROBUTTON_MODE_TRIGGER 0x00000003 // change Trigger State #define VBVMR_MACROBUTTON_MODE_TRIGGER 0x00000003 // change Trigger State
#define VBVMR_MACROBUTTON_MODE_COLOR 0x00000004 // change color #define VBVMR_MACROBUTTON_MODE_COLOR 0x00000004 // change color
/** @} */ /** @} */
/******************************************************************************/ /******************************************************************************/
/* 'C' STRUCTURED INTERFACE */ /* 'C' STRUCTURED INTERFACE */
/******************************************************************************/ /******************************************************************************/
typedef long (__stdcall *T_VBVMR_Login)(void); typedef long long(__stdcall *T_VBVMR_Login)(void);
typedef long (__stdcall *T_VBVMR_Logout)(void); typedef long long(__stdcall *T_VBVMR_Logout)(void);
typedef long (__stdcall *T_VBVMR_RunVoicemeeter)(long vType); typedef long long(__stdcall *T_VBVMR_RunVoicemeeter)(long vType);
typedef long (__stdcall *T_VBVMR_GetVoicemeeterType)(long * pType); typedef long long(__stdcall *T_VBVMR_GetVoicemeeterType)(long *pType);
typedef long (__stdcall *T_VBVMR_GetVoicemeeterVersion)(long * pVersion); typedef long long(__stdcall *T_VBVMR_GetVoicemeeterVersion)(long *pVersion);
typedef long (__stdcall *T_VBVMR_IsParametersDirty)(void); typedef long long(__stdcall *T_VBVMR_IsParametersDirty)(void);
typedef long (__stdcall *T_VBVMR_GetParameterFloat)(char * szParamName, float * pValue); typedef long long(__stdcall *T_VBVMR_GetParameterFloat)(char *szParamName, float *pValue);
typedef long (__stdcall *T_VBVMR_GetParameterStringA)(char * szParamName, char * szString); typedef long long(__stdcall *T_VBVMR_GetParameterStringA)(char *szParamName, char *szString);
typedef long (__stdcall *T_VBVMR_GetParameterStringW)(char * szParamName, unsigned short * wszString); typedef long 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 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_GetLevel)(long nType, long nuChannel, float * pValue); typedef long long(__stdcall *T_VBVMR_SetParameterFloat)(char *szParamName, float Value);
typedef long (__stdcall *T_VBVMR_GetMidiMessage)(unsigned char *pMIDIBuffer, long nbByteMax); typedef long long(__stdcall *T_VBVMR_SetParameters)(char *szParamScript);
typedef long (__stdcall *T_VBVMR_SendMidiMessage)(unsigned char *pMIDIBuffer, long nbByteMax); typedef long long(__stdcall *T_VBVMR_SetParametersW)(unsigned short *szParamScript);
typedef long 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_SetParameterFloat)(char * szParamName, float Value); typedef long long(__stdcall *T_VBVMR_Output_GetDeviceNumber)(void);
typedef long (__stdcall *T_VBVMR_SetParameters)(char * szParamScript); typedef long long(__stdcall *T_VBVMR_Output_GetDeviceDescA)(long zindex, long *nType, char *szDeviceName, char *szHardwareId);
typedef long (__stdcall *T_VBVMR_SetParametersW)(unsigned short * szParamScript); typedef long long(__stdcall *T_VBVMR_Output_GetDeviceDescW)(long zindex, long *nType, unsigned short *wszDeviceName, unsigned short *wszHardwareId);
typedef long (__stdcall *T_VBVMR_SetParameterStringA)(char * szParamName, char * szString); typedef long long(__stdcall *T_VBVMR_Input_GetDeviceNumber)(void);
typedef long (__stdcall *T_VBVMR_SetParameterStringW)(char * szParamName, unsigned short * wszString); typedef long 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_Output_GetDeviceNumber)(void);
typedef long (__stdcall *T_VBVMR_Output_GetDeviceDescA)(long zindex, long * nType, char * szDeviceName, char * szHardwareId);
typedef long (__stdcall *T_VBVMR_Output_GetDeviceDescW)(long zindex, long * nType, unsigned short * wszDeviceName, unsigned short * wszHardwareId);
typedef long (__stdcall *T_VBVMR_Input_GetDeviceNumber)(void);
typedef long (__stdcall *T_VBVMR_Input_GetDeviceDescA)(long zindex, long * nType, char * szDeviceName, char * szHardwareId);
typedef long (__stdcall *T_VBVMR_Input_GetDeviceDescW)(long zindex, long * nType, unsigned short * wszDeviceName, unsigned short * wszHardwareId);
typedef long (__stdcall *T_VBVMR_AudioCallbackRegister)(long mode, T_VBVMR_VBAUDIOCALLBACK pCallback, void * lpUser, char szClientName[64]);
typedef long (__stdcall *T_VBVMR_AudioCallbackStart)(void);
typedef long (__stdcall *T_VBVMR_AudioCallbackStop)(void);
typedef long (__stdcall *T_VBVMR_AudioCallbackUnregister)(void);
typedef long (__stdcall *T_VBVMR_MacroButton_IsDirty)(void);
typedef long (__stdcall *T_VBVMR_MacroButton_GetStatus)(long nuLogicalButton, float * pValue, long bitmode);
typedef long (__stdcall *T_VBVMR_MacroButton_SetStatus)(long nuLogicalButton, float fValue, long bitmode);
typedef long 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 long(__stdcall *T_VBVMR_AudioCallbackStop)(void);
typedef long long(__stdcall *T_VBVMR_AudioCallbackUnregister)(void);
typedef long long(__stdcall *T_VBVMR_MacroButton_IsDirty)(void);
typedef long 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 struct tagVBVMR_INTERFACE typedef struct tagVBVMR_INTERFACE
{ {
@@ -867,20 +763,13 @@ typedef struct tagVBVMR_INTERFACE
T_VBVMR_MacroButton_GetStatus VBVMR_MacroButton_GetStatus; T_VBVMR_MacroButton_GetStatus VBVMR_MacroButton_GetStatus;
T_VBVMR_MacroButton_SetStatus VBVMR_MacroButton_SetStatus; T_VBVMR_MacroButton_SetStatus VBVMR_MacroButton_SetStatus;
} T_VBVMR_INTERFACE, *PT_VBVMR_INTERFACE, *LPT_VBVMR_INTERFACE, *PT_VMR;
} T_VBVMR_INTERFACE, *PT_VBVMR_INTERFACE, *LPT_VBVMR_INTERFACE;
#ifdef VBUSE_LOCALLIB #ifdef VBUSE_LOCALLIB
// internal used (not public) // internal used (not public)
void __stdcall VBVMR_SetHinstance(HINSTANCE hinst); void __stdcall VBVMR_SetHinstance(HINSTANCE hinst);
#endif #endif
/******************************************************************************/ /******************************************************************************/
/* VBAN RT PACKET */ /* VBAN RT PACKET */
/******************************************************************************/ /******************************************************************************/
@@ -971,7 +860,6 @@ typedef struct tagVBAN_VMRT_PACKET //packedt ident: 0
#define VMRTSTATE_MODE_SEL 0x10000000 #define VMRTSTATE_MODE_SEL 0x10000000
#define VMRTSTATE_MODE_MONITOR 0x20000000 #define VMRTSTATE_MODE_MONITOR 0x20000000
#pragma pack(1) #pragma pack(1)
// long = 4 bytes // long = 4 bytes
@@ -1046,7 +934,6 @@ typedef struct tagVBAN_VMPARAM_STRIP
#define VMRT_EQTYPE_LOSHELF 5 #define VMRT_EQTYPE_LOSHELF 5
#define VMRT_EQTYPE_HISHELF 6 #define VMRT_EQTYPE_HISHELF 6
#define expected_size_T_VBAN_VMPARAM_STRIP (8 + (8 * sizeof(short)) + (2 * 6) + (3 * 6 * sizeof(float)) + ((11 + 9 + 6 + 7) * sizeof(short))) #define expected_size_T_VBAN_VMPARAM_STRIP (8 + (8 * sizeof(short)) + (2 * 6) + (3 * 6 * sizeof(float)) + ((11 + 9 + 6 + 7) * sizeof(short)))
// 170 // 170
@@ -1080,14 +967,8 @@ long VBVMR_LoginEx(long properties);
long VBVMR_MB_PushSettings(void *lpParam); long VBVMR_MB_PushSettings(void *lpParam);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /*__VOICEMEETER_REMOTE_H__*/ #endif /*__VOICEMEETER_REMOTE_H__*/

View File

@@ -1,9 +1,8 @@
#ifndef __CDLL_H__ #ifndef __CDLL_H__
#define __CDLL_H__ #define __CDLL_H__
#include <windows.h>
#include "VoicemeeterRemote.h" #include "VoicemeeterRemote.h"
long initialize_dll_interfaces(T_VBVMR_INTERFACE *iVMR); PT_VMR create_interface();
#endif /*__CDLL_H__*/ #endif /*__CDLL_H__*/

View File

@@ -3,7 +3,7 @@
void remove_name_in_path(char *szPath); void remove_name_in_path(char *szPath);
int replace_multiple_space_with_one(char *s, size_t len); int replace_multiple_space_with_one(char *s, size_t len);
char *kind_as_string(char *s, enum kind 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 *, long v, int n);
#endif /* __UTIL_H__ */ #endif /* __UTIL_H__ */

View File

@@ -6,31 +6,34 @@
enum kind enum kind
{ {
UNKNOWN = -1,
BASIC = 1, BASIC = 1,
BANANA, BANANA,
POTATO, POTATO,
BASICX64, BASICX64,
BANANAX64, BANANAX64,
POTATOX64, POTATOX64,
MACROBUTTONS = 11,
STREAMERVIEW
}; };
long login(T_VBVMR_INTERFACE *vmr, int kind); long login(PT_VMR vmr, int kind);
long logout(T_VBVMR_INTERFACE *vmr); long logout(PT_VMR vmr);
long run_voicemeeter(T_VBVMR_INTERFACE *vmr, int kind); long run_voicemeeter(PT_VMR vmr, int kind);
long type(T_VBVMR_INTERFACE *vmr, long *type); long type(PT_VMR vmr, long *type);
long version(T_VBVMR_INTERFACE *vmr, long *version); long version(PT_VMR vmr, long *version);
bool is_pdirty(T_VBVMR_INTERFACE *vmr); bool is_pdirty(PT_VMR vmr);
long get_parameter_float(T_VBVMR_INTERFACE *vmr, char *param, float *f); long get_parameter_float(PT_VMR vmr, char *param, float *f);
long get_parameter_string(T_VBVMR_INTERFACE *vmr, char *param, unsigned short *s); long get_parameter_string(PT_VMR vmr, char *param, unsigned short *s);
long set_parameter_float(T_VBVMR_INTERFACE *vmr, char *param, float val); long set_parameter_float(PT_VMR vmr, char *param, float val);
long set_parameter_string(T_VBVMR_INTERFACE *vmr, char *param, char *s); long set_parameter_string(PT_VMR vmr, char *param, char *s);
long set_parameters(T_VBVMR_INTERFACE *vmr, char *command); long set_parameters(PT_VMR vmr, char *command);
bool is_mdirty(T_VBVMR_INTERFACE *vmr); bool is_mdirty(PT_VMR vmr);
long macrobutton_getstatus(T_VBVMR_INTERFACE *vmr, long n, float *val, long mode); long macrobutton_getstatus(PT_VMR vmr, long n, float *val, long mode);
long macrobutton_setstatus(T_VBVMR_INTERFACE *vmr, long n, float val, long mode); long macrobutton_setstatus(PT_VMR vmr, long n, float val, long mode);
void clear_dirty(T_VBVMR_INTERFACE *vmr); void clear_dirty(PT_VMR vmr);
#endif /* __VMR_H__ */ #endif /* __VMR_H__ */

View File

@@ -1,7 +1,151 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <windows.h>
#include "cdll.h" #include "cdll.h"
#include "util.h" #include "util.h"
#include "log.h"
static T_VBVMR_INTERFACE iVMR;
static long initialize_dll_interfaces(PT_VMR vmr);
static bool registry_get_voicemeeter_folder(char *szDir);
PT_VMR create_interface()
{
PT_VMR vmr = &iVMR;
int rep;
rep = initialize_dll_interfaces(vmr);
if (rep < 0)
{
if (rep == -100)
{
log_fatal("Voicemeeter is not installed");
exit(EXIT_FAILURE);
}
else
{
log_fatal("Error loading Voicemeeter dll with code %d\n", rep);
exit(EXIT_FAILURE);
}
}
return vmr;
}
/*******************************************************************************/
/** GET DLL INTERFACE **/
/*******************************************************************************/
static long initialize_dll_interfaces(PT_VMR vmr)
{
HMODULE G_H_Module = NULL;
char szDllName[1024];
memset(vmr, 0, sizeof(T_VBVMR_INTERFACE));
// get Voicemeeter installation directory
if (!registry_get_voicemeeter_folder(szDllName))
{
// Voicemeeter not installed
return -100;
}
// use right dll according to O/S type
if (sizeof(void *) == 8)
strcat(szDllName, "\\VoicemeeterRemote64.dll");
else
strcat(szDllName, "\\VoicemeeterRemote.dll");
// Load Dll
G_H_Module = LoadLibrary(szDllName);
if (G_H_Module == NULL)
return -101;
// Get function pointers
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_RunVoicemeeter = (T_VBVMR_RunVoicemeeter)GetProcAddress(G_H_Module, "VBVMR_RunVoicemeeter");
vmr->VBVMR_GetVoicemeeterType = (T_VBVMR_GetVoicemeeterType)GetProcAddress(G_H_Module, "VBVMR_GetVoicemeeterType");
vmr->VBVMR_GetVoicemeeterVersion = (T_VBVMR_GetVoicemeeterVersion)GetProcAddress(G_H_Module, "VBVMR_GetVoicemeeterVersion");
vmr->VBVMR_IsParametersDirty = (T_VBVMR_IsParametersDirty)GetProcAddress(G_H_Module, "VBVMR_IsParametersDirty");
vmr->VBVMR_GetParameterFloat = (T_VBVMR_GetParameterFloat)GetProcAddress(G_H_Module, "VBVMR_GetParameterFloat");
vmr->VBVMR_GetParameterStringA = (T_VBVMR_GetParameterStringA)GetProcAddress(G_H_Module, "VBVMR_GetParameterStringA");
vmr->VBVMR_GetParameterStringW = (T_VBVMR_GetParameterStringW)GetProcAddress(G_H_Module, "VBVMR_GetParameterStringW");
vmr->VBVMR_GetLevel = (T_VBVMR_GetLevel)GetProcAddress(G_H_Module, "VBVMR_GetLevel");
vmr->VBVMR_GetMidiMessage = (T_VBVMR_GetMidiMessage)GetProcAddress(G_H_Module, "VBVMR_GetMidiMessage");
vmr->VBVMR_SetParameterFloat = (T_VBVMR_SetParameterFloat)GetProcAddress(G_H_Module, "VBVMR_SetParameterFloat");
vmr->VBVMR_SetParameters = (T_VBVMR_SetParameters)GetProcAddress(G_H_Module, "VBVMR_SetParameters");
vmr->VBVMR_SetParametersW = (T_VBVMR_SetParametersW)GetProcAddress(G_H_Module, "VBVMR_SetParametersW");
vmr->VBVMR_SetParameterStringA = (T_VBVMR_SetParameterStringA)GetProcAddress(G_H_Module, "VBVMR_SetParameterStringA");
vmr->VBVMR_SetParameterStringW = (T_VBVMR_SetParameterStringW)GetProcAddress(G_H_Module, "VBVMR_SetParameterStringW");
vmr->VBVMR_Output_GetDeviceNumber = (T_VBVMR_Output_GetDeviceNumber)GetProcAddress(G_H_Module, "VBVMR_Output_GetDeviceNumber");
vmr->VBVMR_Output_GetDeviceDescA = (T_VBVMR_Output_GetDeviceDescA)GetProcAddress(G_H_Module, "VBVMR_Output_GetDeviceDescA");
vmr->VBVMR_Output_GetDeviceDescW = (T_VBVMR_Output_GetDeviceDescW)GetProcAddress(G_H_Module, "VBVMR_Output_GetDeviceDescW");
vmr->VBVMR_Input_GetDeviceNumber = (T_VBVMR_Input_GetDeviceNumber)GetProcAddress(G_H_Module, "VBVMR_Input_GetDeviceNumber");
vmr->VBVMR_Input_GetDeviceDescA = (T_VBVMR_Input_GetDeviceDescA)GetProcAddress(G_H_Module, "VBVMR_Input_GetDeviceDescA");
vmr->VBVMR_Input_GetDeviceDescW = (T_VBVMR_Input_GetDeviceDescW)GetProcAddress(G_H_Module, "VBVMR_Input_GetDeviceDescW");
vmr->VBVMR_MacroButton_IsDirty = (T_VBVMR_MacroButton_IsDirty)GetProcAddress(G_H_Module, "VBVMR_MacroButton_IsDirty");
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");
// check pointers are valid
if (vmr->VBVMR_Login == NULL)
return -1;
if (vmr->VBVMR_Logout == NULL)
return -2;
if (vmr->VBVMR_RunVoicemeeter == NULL)
return -2;
if (vmr->VBVMR_GetVoicemeeterType == NULL)
return -3;
if (vmr->VBVMR_GetVoicemeeterVersion == NULL)
return -4;
if (vmr->VBVMR_IsParametersDirty == NULL)
return -5;
if (vmr->VBVMR_GetParameterFloat == NULL)
return -6;
if (vmr->VBVMR_GetParameterStringA == NULL)
return -7;
if (vmr->VBVMR_GetParameterStringW == NULL)
return -8;
if (vmr->VBVMR_GetLevel == NULL)
return -9;
if (vmr->VBVMR_SetParameterFloat == NULL)
return -10;
if (vmr->VBVMR_SetParameters == NULL)
return -11;
if (vmr->VBVMR_SetParametersW == NULL)
return -12;
if (vmr->VBVMR_SetParameterStringA == NULL)
return -13;
if (vmr->VBVMR_SetParameterStringW == NULL)
return -14;
if (vmr->VBVMR_GetMidiMessage == NULL)
return -15;
if (vmr->VBVMR_Output_GetDeviceNumber == NULL)
return -30;
if (vmr->VBVMR_Output_GetDeviceDescA == NULL)
return -31;
if (vmr->VBVMR_Output_GetDeviceDescW == NULL)
return -32;
if (vmr->VBVMR_Input_GetDeviceNumber == NULL)
return -33;
if (vmr->VBVMR_Input_GetDeviceDescA == NULL)
return -34;
if (vmr->VBVMR_Input_GetDeviceDescW == NULL)
return -35;
if (vmr->VBVMR_MacroButton_IsDirty == NULL)
return -36;
if (vmr->VBVMR_MacroButton_GetStatus == NULL)
return -37;
if (vmr->VBVMR_MacroButton_SetStatus == NULL)
return -38;
return 0;
}
/*******************************************************************************/ /*******************************************************************************/
/** GET VOICEMEETER DIRECTORY **/ /** GET VOICEMEETER DIRECTORY **/
@@ -13,7 +157,7 @@
#define KEY_WOW64_32KEY 0x0200 #define KEY_WOW64_32KEY 0x0200
#endif #endif
bool __cdecl registry_get_voicemeeter_folder(char *szDir) static bool registry_get_voicemeeter_folder(char *szDir)
{ {
char szKey[256]; char szKey[256];
char sss[1024]; char sss[1024];
@@ -54,106 +198,3 @@ bool __cdecl registry_get_voicemeeter_folder(char *szDir)
return true; return true;
} }
/*******************************************************************************/
/** GET DLL INTERFACE **/
/*******************************************************************************/
long initialize_dll_interfaces(T_VBVMR_INTERFACE *iVMR)
{
HMODULE G_H_Module = NULL;
char szDllName[1024];
memset(iVMR, 0, sizeof(T_VBVMR_INTERFACE));
// get Voicemeeter installation directory
if (!registry_get_voicemeeter_folder(szDllName))
{
// Voicemeeter not installed
return -100;
}
// use right dll according to O/S type
if (sizeof(void *) == 8)
strcat(szDllName, "\\VoicemeeterRemote64.dll");
else
strcat(szDllName, "\\VoicemeeterRemote.dll");
// Load Dll
G_H_Module = LoadLibrary(szDllName);
if (G_H_Module == NULL)
return -101;
// Get function pointers
iVMR->VBVMR_Login = (T_VBVMR_Login)GetProcAddress(G_H_Module, "VBVMR_Login");
iVMR->VBVMR_Logout = (T_VBVMR_Logout)GetProcAddress(G_H_Module, "VBVMR_Logout");
iVMR->VBVMR_RunVoicemeeter = (T_VBVMR_RunVoicemeeter)GetProcAddress(G_H_Module, "VBVMR_RunVoicemeeter");
iVMR->VBVMR_GetVoicemeeterType = (T_VBVMR_GetVoicemeeterType)GetProcAddress(G_H_Module, "VBVMR_GetVoicemeeterType");
iVMR->VBVMR_GetVoicemeeterVersion = (T_VBVMR_GetVoicemeeterVersion)GetProcAddress(G_H_Module, "VBVMR_GetVoicemeeterVersion");
iVMR->VBVMR_IsParametersDirty = (T_VBVMR_IsParametersDirty)GetProcAddress(G_H_Module, "VBVMR_IsParametersDirty");
iVMR->VBVMR_GetParameterFloat = (T_VBVMR_GetParameterFloat)GetProcAddress(G_H_Module, "VBVMR_GetParameterFloat");
iVMR->VBVMR_GetParameterStringA = (T_VBVMR_GetParameterStringA)GetProcAddress(G_H_Module, "VBVMR_GetParameterStringA");
iVMR->VBVMR_GetParameterStringW = (T_VBVMR_GetParameterStringW)GetProcAddress(G_H_Module, "VBVMR_GetParameterStringW");
iVMR->VBVMR_GetLevel = (T_VBVMR_GetLevel)GetProcAddress(G_H_Module, "VBVMR_GetLevel");
iVMR->VBVMR_GetMidiMessage = (T_VBVMR_GetMidiMessage)GetProcAddress(G_H_Module, "VBVMR_GetMidiMessage");
iVMR->VBVMR_SetParameterFloat = (T_VBVMR_SetParameterFloat)GetProcAddress(G_H_Module, "VBVMR_SetParameterFloat");
iVMR->VBVMR_SetParameters = (T_VBVMR_SetParameters)GetProcAddress(G_H_Module, "VBVMR_SetParameters");
iVMR->VBVMR_SetParametersW = (T_VBVMR_SetParametersW)GetProcAddress(G_H_Module, "VBVMR_SetParametersW");
iVMR->VBVMR_SetParameterStringA = (T_VBVMR_SetParameterStringA)GetProcAddress(G_H_Module, "VBVMR_SetParameterStringA");
iVMR->VBVMR_SetParameterStringW = (T_VBVMR_SetParameterStringW)GetProcAddress(G_H_Module, "VBVMR_SetParameterStringW");
iVMR->VBVMR_Output_GetDeviceNumber = (T_VBVMR_Output_GetDeviceNumber)GetProcAddress(G_H_Module, "VBVMR_Output_GetDeviceNumber");
iVMR->VBVMR_Output_GetDeviceDescA = (T_VBVMR_Output_GetDeviceDescA)GetProcAddress(G_H_Module, "VBVMR_Output_GetDeviceDescA");
iVMR->VBVMR_Output_GetDeviceDescW = (T_VBVMR_Output_GetDeviceDescW)GetProcAddress(G_H_Module, "VBVMR_Output_GetDeviceDescW");
iVMR->VBVMR_Input_GetDeviceNumber = (T_VBVMR_Input_GetDeviceNumber)GetProcAddress(G_H_Module, "VBVMR_Input_GetDeviceNumber");
iVMR->VBVMR_Input_GetDeviceDescA = (T_VBVMR_Input_GetDeviceDescA)GetProcAddress(G_H_Module, "VBVMR_Input_GetDeviceDescA");
iVMR->VBVMR_Input_GetDeviceDescW = (T_VBVMR_Input_GetDeviceDescW)GetProcAddress(G_H_Module, "VBVMR_Input_GetDeviceDescW");
// check pointers are valid
if (iVMR->VBVMR_Login == NULL)
return -1;
if (iVMR->VBVMR_Logout == NULL)
return -2;
if (iVMR->VBVMR_RunVoicemeeter == NULL)
return -2;
if (iVMR->VBVMR_GetVoicemeeterType == NULL)
return -3;
if (iVMR->VBVMR_GetVoicemeeterVersion == NULL)
return -4;
if (iVMR->VBVMR_IsParametersDirty == NULL)
return -5;
if (iVMR->VBVMR_GetParameterFloat == NULL)
return -6;
if (iVMR->VBVMR_GetParameterStringA == NULL)
return -7;
if (iVMR->VBVMR_GetParameterStringW == NULL)
return -8;
if (iVMR->VBVMR_GetLevel == NULL)
return -9;
if (iVMR->VBVMR_SetParameterFloat == NULL)
return -10;
if (iVMR->VBVMR_SetParameters == NULL)
return -11;
if (iVMR->VBVMR_SetParametersW == NULL)
return -12;
if (iVMR->VBVMR_SetParameterStringA == NULL)
return -13;
if (iVMR->VBVMR_SetParameterStringW == NULL)
return -14;
if (iVMR->VBVMR_GetMidiMessage == NULL)
return -15;
if (iVMR->VBVMR_Output_GetDeviceNumber == NULL)
return -30;
if (iVMR->VBVMR_Output_GetDeviceDescA == NULL)
return -31;
if (iVMR->VBVMR_Output_GetDeviceDescW == NULL)
return -32;
if (iVMR->VBVMR_Input_GetDeviceNumber == NULL)
return -33;
if (iVMR->VBVMR_Input_GetDeviceDescA == NULL)
return -34;
if (iVMR->VBVMR_Input_GetDeviceDescW == NULL)
return -35;
return 0;
}

View File

@@ -3,6 +3,11 @@
#include "vmr.h" #include "vmr.h"
#include "util.h" #include "util.h"
/**
* @brief Removes the last part of a path
*
* @param szPath
*/
void remove_name_in_path(char *szPath) void remove_name_in_path(char *szPath)
{ {
char *p = szPath; char *p = szPath;
@@ -57,9 +62,17 @@ int replace_multiple_space_with_one(char *s, size_t len)
return j; return j;
} }
char *kind_as_string(char *s, enum kind kind, int n) /**
* @brief
*
* @param s Pointer to a character buffer
* @param kind The kind of Voicemeeter.
* @param n maximum number of characters to be written to the buffer
* @return char* The kind of Voicemeeter as a string
*/
char *kind_as_string(char *s, int kind, int n)
{ {
char *kinds[] = { static const char *kinds[] = {
"Basic", "Basic",
"Banana", "Banana",
"Potato", "Potato",

View File

@@ -8,11 +8,21 @@
#define VERSION_STR_LEN 128 #define VERSION_STR_LEN 128
#define KIND_STR_LEN 64 #define KIND_STR_LEN 64
long login(T_VBVMR_INTERFACE *vmr, int kind) /**
* @brief Logs into the API.
* Tests for valid connection for up to 2 seconds.
* If successful initializes the dirty parameters.
*
* @param vmr
* @param kind
* @return long
*/
long login(PT_VMR vmr, int kind)
{ {
int rep; int rep;
long v; long v;
log_trace("VBVMR_Login()");
rep = vmr->VBVMR_Login(); rep = vmr->VBVMR_Login();
if (rep == 1) if (rep == 1)
{ {
@@ -21,111 +31,122 @@ long login(T_VBVMR_INTERFACE *vmr, int kind)
log_info( log_info(
"Launching Voicemeeter %s GUI", "Launching Voicemeeter %s GUI",
kind_as_string(kind_s, kind, KIND_STR_LEN)); kind_as_string(kind_s, kind, KIND_STR_LEN));
}
time_t endwait;
int timeout = 2; int timeout = 2;
time_t start = time(NULL);
endwait = time(NULL) + timeout;
do do
{ {
if ((rep = version(vmr, &v)) == 0) if ((rep = version(vmr, &v)) == 0)
break;
Sleep(50);
} while (time(NULL) < endwait);
}
if (rep == 0)
{ {
version(vmr, &v);
char version_s[VERSION_STR_LEN]; char version_s[VERSION_STR_LEN];
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));
break;
}
Sleep(50);
} while (time(NULL) < start + timeout);
if (rep == 0)
{
clear_dirty(vmr); clear_dirty(vmr);
} }
return rep; return rep;
} }
long logout(T_VBVMR_INTERFACE *vmr) /**
* @brief Logs out of the API giving a short wait to allow a
* final instruction to complete.
*
* @param vmr The API interface as a struct
* @return long VBVMR_Logout return value
*/
long logout(PT_VMR vmr)
{ {
int rep; int rep;
Sleep(20); /* give time for last command */ Sleep(20); /* give time for last command */
log_trace("VBVMR_Logout()");
rep = vmr->VBVMR_Logout(); rep = vmr->VBVMR_Logout();
if (rep == 0) if (rep == 0)
log_info("Successfully logged out of the Voicemeeter API"); log_info("Successfully logged out of the Voicemeeter API");
return rep; return rep;
} }
long run_voicemeeter(T_VBVMR_INTERFACE *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);
} }
long type(T_VBVMR_INTERFACE *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);
} }
long version(T_VBVMR_INTERFACE *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);
} }
bool is_pdirty(T_VBVMR_INTERFACE *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;
} }
long get_parameter_float(T_VBVMR_INTERFACE *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(T_VBVMR_INTERFACE *vmr, char *param, unsigned short *s) long get_parameter_string(PT_VMR vmr, char *param, unsigned short *s)
{ {
log_trace("VBVMR_GetParameterStringW(%s, <unsigned short> *s)", param); log_trace("VBVMR_GetParameterStringW(%s, <unsigned short> *s)", param);
return vmr->VBVMR_GetParameterStringW(param, s); return vmr->VBVMR_GetParameterStringW(param, s);
} }
long set_parameter_float(T_VBVMR_INTERFACE *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);
} }
long set_parameter_string(T_VBVMR_INTERFACE *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);
} }
long set_parameters(T_VBVMR_INTERFACE *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);
} }
bool is_mdirty(T_VBVMR_INTERFACE *vmr) bool is_mdirty(PT_VMR vmr)
{ {
log_trace("VBVMR_MacroButton_IsDirty()");
return vmr->VBVMR_MacroButton_IsDirty() == 1; return vmr->VBVMR_MacroButton_IsDirty() == 1;
} }
long macrobutton_getstatus(T_VBVMR_INTERFACE *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);
return vmr->VBVMR_MacroButton_GetStatus(n, val, mode); return vmr->VBVMR_MacroButton_GetStatus(n, val, mode);
} }
long macrobutton_setstatus(T_VBVMR_INTERFACE *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);
return vmr->VBVMR_MacroButton_SetStatus(n, val, mode); return vmr->VBVMR_MacroButton_SetStatus(n, val, mode);
} }
void clear_dirty(T_VBVMR_INTERFACE *vmr) void clear_dirty(PT_VMR vmr)
{ {
Sleep(30); Sleep(30);
while (is_pdirty(vmr)) while (is_pdirty(vmr))

View File

@@ -2,6 +2,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <getopt.h> #include <getopt.h>
#include <string.h>
#include <ctype.h>
#include "cdll.h" #include "cdll.h"
#include "vmr.h" #include "vmr.h"
#include "log.h" #include "log.h"
@@ -9,12 +11,21 @@
#define MAX_LINE 512 #define MAX_LINE 512
/**
* @brief An enum used to define the kind of value
* a 'get' call returns.
*
*/
enum enum
{ {
FLOAT_T, FLOAT_T,
STRING_T, STRING_T,
}; };
/**
* @brief A struct holding the result of a get call.
*
*/
struct result struct result
{ {
int type; int type;
@@ -25,22 +36,24 @@ struct result
} val; } val;
}; };
static bool vflag = false;
void help(void); void help(void);
enum kind set_kind(char *kval); enum kind set_kind(char *kval);
int init_voicemeeter(T_VBVMR_INTERFACE *vmr, int kind); void interactive(PT_VMR vmr);
void interactive(T_VBVMR_INTERFACE *vmr); void parse_input(PT_VMR vmr, char *input, int len);
void parse_input(T_VBVMR_INTERFACE *vmr, char *input, int len); void parse_command(PT_VMR vmr, char *command);
void parse_command(T_VBVMR_INTERFACE *vmr, char *command); void get(PT_VMR 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,
mflag = false,
sflag = false,
cflag = false;
int opt; int opt;
char *kvalue = "";
int dvalue; int dvalue;
char *cvalue;
enum kind kind = BANANAX64; enum kind kind = BANANAX64;
if (argc == 1) if (argc == 1)
@@ -51,20 +64,34 @@ int main(int argc, char *argv[])
log_set_level(LOG_WARN); log_set_level(LOG_WARN);
while ((opt = getopt(argc, argv, "k:ihD:v")) != -1) while ((opt = getopt(argc, argv, "hk:msc:iD:v")) != -1)
{ {
switch (opt) switch (opt)
{ {
case 'i':
iflag = true;
break;
case 'k':
kvalue = optarg;
kind = set_kind(kvalue);
break;
case 'h': case 'h':
help(); help();
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
case 'k':
kind = set_kind(optarg);
if (kind == UNKNOWN)
{
log_fatal("Unknown Voicemeeter kind '%s'", optarg);
exit(EXIT_FAILURE);
}
break;
case 'm':
mflag = true;
break;
case 's':
sflag = true;
break;
case 'c':
cflag = true;
cvalue = optarg;
break;
case 'i':
iflag = true;
break;
case 'D': case 'D':
dvalue = atoi(optarg); dvalue = atoi(optarg);
if (dvalue >= LOG_TRACE && dvalue <= LOG_FATAL) if (dvalue >= LOG_TRACE && dvalue <= LOG_FATAL)
@@ -73,7 +100,7 @@ int main(int argc, char *argv[])
} }
else else
{ {
log_error( log_warn(
"-D arg out of range, expected value from 0 up to 5\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");
} }
@@ -86,15 +113,33 @@ int main(int argc, char *argv[])
} }
} }
T_VBVMR_INTERFACE iVMR; PT_VMR vmr = create_interface();
T_VBVMR_INTERFACE *vmr = &iVMR;
int rep = init_voicemeeter(vmr, kind); int rep = login(vmr, kind);
if (rep != 0) if (rep != 0)
{ {
log_fatal("Error logging into the Voicemeeter API");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (mflag)
{
log_info("MacroButtons app launched");
run_voicemeeter(vmr, MACROBUTTONS);
}
if (sflag)
{
log_info("StreamerView app launched");
run_voicemeeter(vmr, STREAMERVIEW);
}
if (cflag)
{
log_info("Profile %s loaded", cvalue);
set_parameter_string(vmr, "command.load", cvalue);
}
if (iflag) if (iflag)
{ {
puts("Interactive mode enabled. Enter 'Q' to exit."); puts("Interactive mode enabled. Enter 'Q' to exit.");
@@ -110,25 +155,33 @@ int main(int argc, char *argv[])
rep = logout(vmr); rep = logout(vmr);
if (rep == 0) if (rep == 0)
{
return EXIT_SUCCESS; return EXIT_SUCCESS;
}
else else
{
log_fatal("Error logging out of the Voicemeeter API");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
}
/** /**
* @brief prints the help dialogue * @brief prints the help message
* *
*/ */
void help() void help()
{ {
puts( puts(
"Usage: ./vmrcli.exe [-h] [-i] [-k] [-D] [-v] <api commands>\n" "Usage: ./vmrcli.exe [-h] [-i] [-k] [-D] [-v] [-c] [-m] [-s] <api commands>\n"
"Where: \n" "Where: \n"
"\th: Prints the help dialogue\n" "\th: Prints the help message\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\n"
"\tv: 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"
"\tm: Launch the MacroButtons application\n"
"\ts: Launch the StreamerView application");
} }
/** /**
@@ -162,38 +215,18 @@ enum kind set_kind(char *kval)
} }
else else
{ {
log_error("Unknown Voicemeeter kind '%s'\n", kval); return UNKNOWN;
exit(EXIT_FAILURE);
} }
} }
int init_voicemeeter(T_VBVMR_INTERFACE *vmr, int kind) /**
{ * @brief Continuously read lines from stdin.
int rep = initialize_dll_interfaces(vmr); * Break if 'Q' is entered on the interactive prompt.
if (rep < 0) * Each line is passed to parse_input()
{ *
if (rep == -100) * @param vmr The API interface as a struct
{ */
log_error("Voicemeeter is not installed"); void interactive(PT_VMR vmr)
}
else
{
log_error("Error loading Voicemeeter dll with code %d\n", rep);
}
return rep;
}
rep = login(vmr, kind);
if (rep != 0)
{
log_error("Error logging into Voicemeeter");
return rep;
}
return 0;
}
void interactive(T_VBVMR_INTERFACE *vmr)
{ {
char input[MAX_LINE]; char input[MAX_LINE];
size_t len; size_t len;
@@ -213,7 +246,15 @@ void interactive(T_VBVMR_INTERFACE *vmr)
} }
} }
void parse_input(T_VBVMR_INTERFACE *vmr, char *input, int len) /**
* @brief Walks through each line split by a space delimiter.
* Each token is passed to parse_command()
*
* @param vmr The API interface as a struct
* @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)
{ {
char *token; char *token;
@@ -226,7 +267,15 @@ void parse_input(T_VBVMR_INTERFACE *vmr, char *input, int len)
} }
} }
void parse_command(T_VBVMR_INTERFACE *vmr, char *command) /**
* @brief Execute each command according to type.
* See command type definitions in:
* https://github.com/onyx-and-iris/vmrcli?tab=readme-ov-file#api-commands
*
* @param vmr The API interface as a struct
* @param command Each token from the input line as its own command string
*/
void parse_command(PT_VMR vmr, char *command)
{ {
log_debug("Parsing %s", command); log_debug("Parsing %s", command);
@@ -279,7 +328,14 @@ void parse_command(T_VBVMR_INTERFACE *vmr, char *command)
} }
} }
void get(T_VBVMR_INTERFACE *vmr, char *command, struct result *res) /**
* @brief
*
* @param vmr The API interface as a struct
* @param command A parsed 'get' command as a string
* @param res A struct holding the result of the API call.
*/
void get(PT_VMR vmr, char *command, struct result *res)
{ {
clear_dirty(vmr); clear_dirty(vmr);
if (get_parameter_float(vmr, command, &res->val.f) != 0) if (get_parameter_float(vmr, command, &res->val.f) != 0)