60 Commits

Author SHA1 Message Date
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
28945b72c5 modify example_commands to show multiple instructions per line
Add note in README about change.
2024-07-02 10:14:25 +01:00
97fc9ca9ce use strtok to walk through the input string
vflag added for extra console output (toggle, set operations)
2024-07-02 10:13:37 +01:00
12a55a52f2 Merge branch 'main' of https://github.com/onyx-and-iris/vmrcli 2024-07-01 07:35:35 +01:00
d4afbfa881 upd heading 2024-07-01 07:35:32 +01:00
ea1f05d323 remove shift one char 2024-07-01 04:43:15 +01:00
900ed23ebf Create LICENSE 2024-07-01 03:46:09 +01:00
815a19210b protect against unsafe gain changes 2024-07-01 03:40:33 +01:00
adaf3a7837 break up long line 2024-06-29 03:08:03 +01:00
1199b31e2c extra X64 kinds added to enum kind
log message updated to reflect new kinds

replace_multiple_space_with_one() now returns new line length

kind_as_string() added to util.c
2024-06-29 03:05:51 +01:00
2740c6c82d move remove_name_in_path() into util.c
add version_as_string() to util.c
2024-06-28 03:21:38 +01:00
0bda368f59 add -h flag to help dialogue
add -h flag to Use section in README

update example markdown in README
2024-06-28 03:04:14 +01:00
49604b874b ensure we don't step past the NUL terminator here. 2024-06-28 01:54:04 +01:00
161b1061c4 remove unnecessary args in log_trace calls
ensure we shift a char after copying next command from input buffer
2024-06-28 01:23:40 +01:00
3c46b3d9f3 Use VBVMR_GetParameterStringW instead of VBVMR_GetParameterStringA
update struct result definition

fixes bug with unknown parameters
2024-06-27 23:26:46 +01:00
accab93fba reword 2024-06-27 23:09:10 +01:00
947abb3c01 clear the input buffer before reading from stdin again 2024-06-27 23:07:29 +01:00
e06a26f87b add Build section to README. 2024-06-27 23:02:34 +01:00
25bf542b46 add conditional override var LOG_USE_COLOR to makefile 2024-06-27 22:57:35 +01:00
50271edd8f add log_trace message while traversing input buffer 2024-06-27 22:56:58 +01:00
41bf1322ac add Interactive Mode section to README. 2024-06-27 22:07:53 +01:00
f88fb9b994 pass len of input to replace_multiple_space_with_one()
add an input prompt to interactive mode
2024-06-27 22:06:15 +01:00
9191a38745 readd comment 2024-06-27 19:20:21 +01:00
1d71f38d39 add utility function replace_multiple_space_with_one()
use it to parse the interactive input
2024-06-27 19:18:28 +01:00
2dda32ead9 up clean target 2024-06-27 10:28:09 +01:00
f60fdb4ed2 rename iVMR to vmr in vmr.c
update get() prototype. no need to return pointer.
2024-06-27 10:06:22 +01:00
6567c2c610 write error messages using log_error 2024-06-27 08:27:49 +01:00
41afc099dc sleep after, set to 50ms 2024-06-27 03:39:52 +01:00
7db10650fb do..while, sleep before first call to version() 2024-06-27 03:31:26 +01:00
06df144374 fix log_trace messages 2024-06-27 03:23:48 +01:00
35ec276979 add login timeout
print the API version to info string
2024-06-27 02:51:27 +01:00
744f0d64df print float values to 1 dp 2024-06-27 02:00:17 +01:00
760924def8 upd README 2024-06-27 01:18:25 +01:00
7b7d4fc2c7 add log trace messages to vmr.c 2024-06-27 01:18:17 +01:00
0b6e0800ce default log level to LOG_WARN
write message to stderr if -D flag out of range
2024-06-27 01:17:59 +01:00
4488a386b8 move includes into header guards 2024-06-27 01:17:09 +01:00
9863ca6dca remove EOF check 2024-06-26 20:17:33 +01:00
cd11b26ad8 add -D flag to help() output 2024-06-26 19:31:08 +01:00
71e06ac646 fix script files example 2024-06-26 19:03:21 +01:00
050a4d9e60 add link to api documentation 2024-06-26 18:37:52 +01:00
694a4dbc65 add ./ 2024-06-26 18:34:05 +01:00
3f8ed17176 reword 2024-06-26 18:30:47 +01:00
12 changed files with 1143 additions and 907 deletions

21
LICENSE Normal file
View File

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

View File

@@ -1,4 +1,4 @@
# VMRCLI Command Line Utility # Voicemeeter Remote Command Line Utility
## `Tested against` ## `Tested against`
@@ -12,38 +12,85 @@
## `Use` ## `Use`
`./vmrcli.exe [-i] [-k] [-D] <api commands>` ```powershell
./vmrcli.exe [-h] [-i] [-k] [-D] [-v] [-p] [-m] [-s] <api commands>
```
Where: Where:
- `i`: Enable interactive mode. If set any api commands passed will be ignored. - `h`: Prints the help message.
- `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)
- `p`: Load a user configuration (given the file name or a full 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 debug 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
`./vmrcli.exe -kbasic -D2 !strip[0].mute strip[0].mute` ```powershell
./vmrcli.exe -kbasic -D2 !strip[0].mute strip[0].mute bus[0].gain-=3.8
```
Launch banana GUI, set debug 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
`vmrcli.exe -kbanana -D1 strip[0].label=podmic strip[2].label` ```powershell
./vmrcli.exe -kbanana -D1 strip[0].label=podmic strip[2].label
```
## `Interactive Mode`
Running the following command in Powershell:
```powershell
./vmrcli.exe -i
```
Will open an interactive prompt:
```powershell
Interactive mode enabled. Enter 'Q' to exit.
>>
```
API commands follow the same rules as listed above. Entering `Q` or `q` will exit the program.
## `Script files` ## `Script files`
Scripts can be loaded from text files, for example: Scripts can be loaded from text files, for example in Powershell:
```powershell ```powershell
./vbantxt-cli -D1 $(Get-Content .\example_commands.txt) ./vmrcli.exe -D1 $(Get-Content .\example_commands.txt)
``` ```
Multiple API commands can be in a single line but they should be space separated.
## `Build`
Run the included `makefile` with [GNU Make](https://www.gnu.org/software/make/).
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`
## `Official Documentation`
- [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,8 +1,5 @@
strip[0].mute strip[0].mute !strip[0].mute strip[0].mute strip[0].gain strip[0].label=podmic strip[0].label
!strip[0].mute strip[1].mute=1 strip[1].mute strip[1].limit-=8
strip[0].mute strip[2].gain-=5 strip[2].comp+=4.8
strip[1].mute=1 bus[0].label
strip[1].mute bus[1].gain-=5.8
strip[0].gain
strip[0].label=podmic
strip[0].label

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,25 +19,24 @@
/* 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
/******************************************************************************/ /******************************************************************************/
/* */ /* */
/* Login */ /* Login */
/* */ /* */
/******************************************************************************/ /******************************************************************************/
/** @name Communication Login / logout /** @name Communication Login / logout
* @{ */ * @{ */
/** /**
@brief Open Communication Pipe With Voicemeeter (typically called on software startup). @brief Open Communication Pipe With Voicemeeter (typically called on software startup).
@@ -47,15 +46,14 @@ extern "C" {
-2: unexpected login (logout was expected before). -2: unexpected login (logout was expected before).
*/ */
long __stdcall VBVMR_Login(void); long __stdcall VBVMR_Login(void);
/** /**
@brief Close Communication Pipe With Voicemeeter (typically called on software end). @brief Close Communication Pipe With Voicemeeter (typically called on software end).
@return : 0 if ok. @return : 0 if ok.
*/ */
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).
@@ -65,29 +63,18 @@ long __stdcall VBVMR_Logout(void);
-2: unknown vType number -2: unknown vType number
*/ */
long __stdcall VBVMR_RunVoicemeeter(long vType); long __stdcall VBVMR_RunVoicemeeter(long vType);
/** @} */
/** @} */ /******************************************************************************/
/* */
/* General Information */
/* */
/******************************************************************************/
/** @name General Information
* @{ */
/******************************************************************************/
/* */
/* General Information */
/* */
/******************************************************************************/
/** @name General Information
* @{ */
/** /**
@brief Get Voicemeeter Type @brief Get Voicemeeter Type
@@ -117,7 +104,7 @@ long __stdcall VBVMR_RunVoicemeeter(long vType);
-2: no server. -2: no server.
*/ */
long __stdcall VBVMR_GetVoicemeeterType(long * pType); long __stdcall VBVMR_GetVoicemeeterType(long *pType);
/** /**
@brief Get Voicemeeter Version @brief Get Voicemeeter Version
@@ -132,36 +119,18 @@ long __stdcall VBVMR_GetVoicemeeterType(long * pType);
-2: no server. -2: no server.
*/ */
long __stdcall VBVMR_GetVoicemeeterVersion(long * pVersion); long __stdcall VBVMR_GetVoicemeeterVersion(long *pVersion);
/** @} */
/** @} */ /******************************************************************************/
/* */
/* Get parameters */
/* */
/******************************************************************************/
/** @name Getting Parameters
* @{ */
/******************************************************************************/
/* */
/* Get parameters */
/* */
/******************************************************************************/
/** @name Getting Parameters
* @{ */
/** /**
@brief Check if parameters have changed. @brief Check if parameters have changed.
@@ -174,7 +143,7 @@ long __stdcall VBVMR_GetVoicemeeterVersion(long * pVersion);
-2: no server. -2: no server.
*/ */
long __stdcall VBVMR_IsParametersDirty(void); long __stdcall VBVMR_IsParametersDirty(void);
/** /**
@brief get parameter value. @brief get parameter value.
@@ -187,7 +156,7 @@ long __stdcall VBVMR_IsParametersDirty(void);
-5: structure mismatch -5: structure mismatch
*/ */
long __stdcall VBVMR_GetParameterFloat(char * szParamName, float * pValue); long __stdcall VBVMR_GetParameterFloat(char *szParamName, float *pValue);
/** /**
@brief get parameter value. @brief get parameter value.
@@ -200,27 +169,19 @@ long __stdcall VBVMR_GetParameterFloat(char * szParamName, float * pValue);
-5: structure mismatch -5: structure mismatch
*/ */
long __stdcall VBVMR_GetParameterStringA(char * szParamName, char * szString); long __stdcall VBVMR_GetParameterStringA(char *szParamName, char *szString);
long __stdcall VBVMR_GetParameterStringW(char * szParamName, unsigned short * wszString); long __stdcall VBVMR_GetParameterStringW(char *szParamName, unsigned short *wszString);
/** @} */ /** @} */
/******************************************************************************/
/* */
/* Get levels */
/* */
/******************************************************************************/
/** @name Getting RT Data
* @{ */
/******************************************************************************/
/* */
/* Get levels */
/* */
/******************************************************************************/
/** @name Getting RT Data
* @{ */
/** /**
@brief Get Current levels. @brief Get Current levels.
@@ -281,8 +242,7 @@ long __stdcall VBVMR_GetParameterStringW(char * szParamName, unsigned short * ws
-4: out of range -4: out of range
*/ */
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.
@@ -301,9 +261,7 @@ 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.
@@ -319,29 +277,18 @@ 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 */
/* */
/******************************************************************************/
/** @} */ /** @name Setting Parameters
* @{ */
/******************************************************************************/
/* */
/* Set Parameters */
/* */
/******************************************************************************/
/** @name Setting Parameters
* @{ */
/** /**
@brief Set a single float 32 bits parameters . @brief Set a single float 32 bits parameters .
@@ -359,9 +306,7 @@ long __stdcall VBVMR_SendMidiMessage(unsigned char *pMIDIBuffer, long nbByte);
-3: unknown parameter -3: unknown parameter
*/ */
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 .
@@ -379,12 +324,8 @@ 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 ).
@@ -407,29 +348,17 @@ long __stdcall VBVMR_SetParameterStringW(char * szParamName, unsigned short * ws
-4: unexpected error -4: unexpected error
*/ */
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 */
/******************************************************************************/
/** @name Device Enumeration Functions
* @{ */
/******************************************************************************/
/* DEVICES ENUMERATOR */
/******************************************************************************/
/** @name Device Enumeration Functions
* @{ */
#define VBVMR_DEVTYPE_MME 1 #define VBVMR_DEVTYPE_MME 1
#define VBVMR_DEVTYPE_WDM 3 #define VBVMR_DEVTYPE_WDM 3
@@ -441,7 +370,7 @@ long __stdcall VBVMR_SetParametersW(unsigned short * szParamScript);
@return : return number of device found. @return : return number of device found.
*/ */
long __stdcall VBVMR_Output_GetDeviceNumber(void); long __stdcall VBVMR_Output_GetDeviceNumber(void);
/** /**
@brief Return pointer on Output Device Descriptor according index @brief Return pointer on Output Device Descriptor according index
@@ -452,15 +381,15 @@ long __stdcall VBVMR_Output_GetDeviceNumber(void);
@return : 0: OK (no error). @return : 0: OK (no error).
*/ */
long __stdcall VBVMR_Output_GetDeviceDescA(long zindex, long * nType, char * szDeviceName, char * szHardwareId); long __stdcall VBVMR_Output_GetDeviceDescA(long zindex, long *nType, char *szDeviceName, char *szHardwareId);
long __stdcall VBVMR_Output_GetDeviceDescW(long zindex, long * nType, unsigned short * wszDeviceName, unsigned short * wszHardwareId); long __stdcall VBVMR_Output_GetDeviceDescW(long zindex, long *nType, unsigned short *wszDeviceName, unsigned short *wszHardwareId);
/** /**
@brief Get number of Audio Input Device available on the system @brief Get number of Audio Input Device available on the system
@return : return number of device found. @return : return number of device found.
*/ */
long __stdcall VBVMR_Input_GetDeviceNumber(void); long __stdcall VBVMR_Input_GetDeviceNumber(void);
/** /**
@brief Return pointer on Input Device Descriptor according index @brief Return pointer on Input Device Descriptor according index
@@ -471,50 +400,40 @@ long __stdcall VBVMR_Input_GetDeviceNumber(void);
@return : 0: OK (no error). @return : 0: OK (no error).
*/ */
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 */
/******************************************************************************/
/* 4x Functions to process all voicemeeter audio input and output channels */
/* */
/* VBVMR_AudioCallbackRegister :to register your audio callback(s) */
/* VBVMR_AudioCallbackStart :to start the audio stream */
/* VBVMR_AudioCallbackStop :to stop the audio stream */
/* VBVMR_AudioCallbackUnregister :to unregister / Release callback(s) */
/******************************************************************************/
/** @} */ /** @name VB-Audio Callback Functions
* @{ */
typedef struct tagVBVMR_AUDIOINFO
{
/******************************************************************************/
/* VB-AUDIO CALLBACK */
/******************************************************************************/
/* 4x Functions to process all voicemeeter audio input and output channels */
/* */
/* VBVMR_AudioCallbackRegister :to register your audio callback(s) */
/* VBVMR_AudioCallbackStart :to start the audio stream */
/* VBVMR_AudioCallbackStop :to stop the audio stream */
/* VBVMR_AudioCallbackUnregister :to unregister / Release callback(s) */
/******************************************************************************/
/** @name VB-Audio Callback Functions
* @{ */
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
{
long audiobuffer_sr; //Sampling Rate
long audiobuffer_nbs; //number of sample per frame
long audiobuffer_nbi; //number of inputs
long audiobuffer_nbo; //number of outputs
float * audiobuffer_r[128]; //nbi input 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;
typedef struct tagVBVMR_AUDIOBUFFER
{
long audiobuffer_sr; // Sampling Rate
long audiobuffer_nbs; // number of sample per frame
long audiobuffer_nbi; // number of inputs
long audiobuffer_nbo; // number of outputs
float *audiobuffer_r[128]; // nbi input 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;
/** /**
@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.
@@ -533,23 +452,21 @@ 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
// info = (VBVMR_LPT_AUDIOINFO)lpData
#define VBVMR_CBCOMMAND_ENDING 2 // command to release data
#define VBVMR_CBCOMMAND_CHANGE 3 // If change in audio stream, you will have to restart audio
#define VBVMR_CBCOMMAND_STARTING 1 //command to initialize data according SR and buffer size #define VBVMR_CBCOMMAND_BUFFER_IN 10 // input insert
//info = (VBVMR_LPT_AUDIOINFO)lpData #define VBVMR_CBCOMMAND_BUFFER_OUT 11 // bus output insert
#define VBVMR_CBCOMMAND_BUFFER_MAIN 20 // all i/o
// audiobuffer = (VBVMR_LPT_AUDIOBUFFER)lpData
// nnn = synchro = 1 if synchro with Voicemeeter
#define VBVMR_CBCOMMAND_ENDING 2 //command to release data /*
#define VBVMR_CBCOMMAND_CHANGE 3 //If change in audio stream, you will have to restart audio
#define VBVMR_CBCOMMAND_BUFFER_IN 10 //input insert
#define VBVMR_CBCOMMAND_BUFFER_OUT 11 //bus output insert
#define VBVMR_CBCOMMAND_BUFFER_MAIN 20 //all i/o
//audiobuffer = (VBVMR_LPT_AUDIOBUFFER)lpData
//nnn = synchro = 1 if synchro with Voicemeeter
/*
----------------------------------------------------- -----------------------------------------------------
AUDIO BUFFER for VBVMR_CBCOMMAND_BUFFER_IN AUDIO BUFFER for VBVMR_CBCOMMAND_BUFFER_IN
----------------------------------------------------- -----------------------------------------------------
@@ -572,9 +489,9 @@ typedef long (__stdcall *T_VBVMR_VBAUDIOCALLBACK)(void * lpUser, long nCommand,
| 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
----------------------------------------------------- -----------------------------------------------------
AUDIO BUFFER for VBVMR_CBCOMMAND_BUFFER_OUT AUDIO BUFFER for VBVMR_CBCOMMAND_BUFFER_OUT
----------------------------------------------------- -----------------------------------------------------
VOICEMEETER VOICEMEETER
| Output A1 / A2 | Virtual Output | | Output A1 / A2 | Virtual Output |
@@ -603,9 +520,9 @@ typedef long (__stdcall *T_VBVMR_VBAUDIOCALLBACK)(void * lpUser, long nCommand,
| 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
----------------------------------------------------- -----------------------------------------------------
AUDIO BUFFER for VBVMR_CBCOMMAND_BUFFER_MAIN AUDIO BUFFER for VBVMR_CBCOMMAND_BUFFER_MAIN
----------------------------------------------------- -----------------------------------------------------
VOICEMEETER VOICEMEETER
| Strip 1 | Strip 2 | Virtual Input | | Strip 1 | Strip 2 | Virtual Input |
@@ -656,7 +573,7 @@ typedef long (__stdcall *T_VBVMR_VBAUDIOCALLBACK)(void * lpUser, long nCommand,
| 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
*/ */
/** /**
@brief register your audio callback function to receive real time audio buffer @brief register your audio callback function to receive real time audio buffer
@@ -678,11 +595,11 @@ typedef long (__stdcall *T_VBVMR_VBAUDIOCALLBACK)(void * lpUser, long nCommand,
1: callback already registered (by another application). 1: callback already registered (by another application).
*/ */
long __stdcall VBVMR_AudioCallbackRegister(long mode, T_VBVMR_VBAUDIOCALLBACK pCallback, void * lpUser, char szClientName[64]); long __stdcall VBVMR_AudioCallbackRegister(long mode, T_VBVMR_VBAUDIOCALLBACK pCallback, void *lpUser, char szClientName[64]);
#define VBVMR_AUDIOCALLBACK_IN 0x00000001 //to process input insert #define VBVMR_AUDIOCALLBACK_IN 0x00000001 // to process input insert
#define VBVMR_AUDIOCALLBACK_OUT 0x00000002 //to process output bus insert #define VBVMR_AUDIOCALLBACK_OUT 0x00000002 // to process output bus insert
#define VBVMR_AUDIOCALLBACK_MAIN 0x00000004 //to receive all i/o #define VBVMR_AUDIOCALLBACK_MAIN 0x00000004 // to receive all i/o
/** /**
@brief Start / Stop Audio processing @brief Start / Stop Audio processing
@@ -693,9 +610,8 @@ long __stdcall VBVMR_AudioCallbackRegister(long mode, T_VBVMR_VBAUDIOCALLBACK pC
-2: no callback registred. -2: no callback registred.
*/ */
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
@@ -706,25 +622,18 @@ long __stdcall VBVMR_AudioCallbackStop(void);
1: callback already unregistered. 1: callback already unregistered.
*/ */
long __stdcall VBVMR_AudioCallbackUnregister(void); long __stdcall VBVMR_AudioCallbackUnregister(void);
/** @} */
/******************************************************************************/
/* */
/* Macro Buttons */
/* */
/******************************************************************************/
/** @} */ /** @name Macro Buttons functions
* @{ */
/******************************************************************************/
/* */
/* Macro Buttons */
/* */
/******************************************************************************/
/** @name Macro Buttons functions
* @{ */
/** /**
@brief Check if Macro Buttons states changed. @brief Check if Macro Buttons states changed.
@@ -737,7 +646,7 @@ long __stdcall VBVMR_AudioCallbackUnregister(void);
-2: no server. -2: no server.
*/ */
long __stdcall VBVMR_MacroButton_IsDirty(void); long __stdcall VBVMR_MacroButton_IsDirty(void);
/** /**
@brief get current status of a given button. @brief get current status of a given button.
@@ -751,7 +660,7 @@ long __stdcall VBVMR_MacroButton_IsDirty(void);
-5: structure mismatch -5: structure mismatch
*/ */
long __stdcall VBVMR_MacroButton_GetStatus(long nuLogicalButton, float * pValue, long bitmode); long __stdcall VBVMR_MacroButton_GetStatus(long nuLogicalButton, float *pValue, long bitmode);
/** /**
@brief set current button value. @brief set current button value.
@@ -765,72 +674,59 @@ long __stdcall VBVMR_MacroButton_GetStatus(long nuLogicalButton, float * pValue,
-5: structure mismatch -5: structure mismatch
*/ */
long __stdcall VBVMR_MacroButton_SetStatus(long nuLogicalButton, float fValue, long bitmode); long __stdcall VBVMR_MacroButton_SetStatus(long nuLogicalButton, float fValue, long bitmode);
#define VBVMR_MACROBUTTON_MODE_DEFAULT 0x00000000 //PUSH or RELEASE button #define VBVMR_MACROBUTTON_MODE_DEFAULT 0x00000000 // PUSH or RELEASE button
#define VBVMR_MACROBUTTON_MODE_STATEONLY 0x00000002 //change Displayed State only #define VBVMR_MACROBUTTON_MODE_STATEONLY 0x00000002 // change Displayed State only
#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 */
/******************************************************************************/
/** @} */ typedef long long(__stdcall *T_VBVMR_Login)(void);
typedef long long(__stdcall *T_VBVMR_Logout)(void);
typedef long long(__stdcall *T_VBVMR_RunVoicemeeter)(long vType);
typedef long long(__stdcall *T_VBVMR_GetVoicemeeterType)(long *pType);
typedef long long(__stdcall *T_VBVMR_GetVoicemeeterVersion)(long *pVersion);
typedef long long(__stdcall *T_VBVMR_IsParametersDirty)(void);
typedef long long(__stdcall *T_VBVMR_GetParameterFloat)(char *szParamName, float *pValue);
typedef long long(__stdcall *T_VBVMR_GetParameterStringA)(char *szParamName, char *szString);
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 long(__stdcall *T_VBVMR_SetParameterFloat)(char *szParamName, float Value);
typedef long long(__stdcall *T_VBVMR_SetParameters)(char *szParamScript);
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 long(__stdcall *T_VBVMR_Output_GetDeviceNumber)(void);
typedef long long(__stdcall *T_VBVMR_Output_GetDeviceDescA)(long zindex, long *nType, char *szDeviceName, char *szHardwareId);
typedef long long(__stdcall *T_VBVMR_Output_GetDeviceDescW)(long zindex, long *nType, unsigned short *wszDeviceName, unsigned short *wszHardwareId);
typedef long long(__stdcall *T_VBVMR_Input_GetDeviceNumber)(void);
typedef long 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 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
/******************************************************************************/ {
/* 'C' STRUCTURED INTERFACE */
/******************************************************************************/
typedef long (__stdcall *T_VBVMR_Login)(void);
typedef long (__stdcall *T_VBVMR_Logout)(void);
typedef long (__stdcall *T_VBVMR_RunVoicemeeter)(long vType);
typedef long (__stdcall *T_VBVMR_GetVoicemeeterType)(long * pType);
typedef long (__stdcall *T_VBVMR_GetVoicemeeterVersion)(long * pVersion);
typedef long (__stdcall *T_VBVMR_IsParametersDirty)(void);
typedef long (__stdcall *T_VBVMR_GetParameterFloat)(char * szParamName, float * pValue);
typedef long (__stdcall *T_VBVMR_GetParameterStringA)(char * szParamName, char * szString);
typedef long (__stdcall *T_VBVMR_GetParameterStringW)(char * szParamName, unsigned short * wszString);
typedef long (__stdcall *T_VBVMR_GetLevel)(long nType, long nuChannel, float * pValue);
typedef long (__stdcall *T_VBVMR_GetMidiMessage)(unsigned char *pMIDIBuffer, long nbByteMax);
typedef long (__stdcall *T_VBVMR_SendMidiMessage)(unsigned char *pMIDIBuffer, long nbByteMax);
typedef long (__stdcall *T_VBVMR_SetParameterFloat)(char * szParamName, float Value);
typedef long (__stdcall *T_VBVMR_SetParameters)(char * szParamScript);
typedef long (__stdcall *T_VBVMR_SetParametersW)(unsigned short * szParamScript);
typedef long (__stdcall *T_VBVMR_SetParameterStringA)(char * szParamName, char * szString);
typedef long (__stdcall *T_VBVMR_SetParameterStringW)(char * szParamName, unsigned short * wszString);
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 struct tagVBVMR_INTERFACE
{
T_VBVMR_Login VBVMR_Login; T_VBVMR_Login VBVMR_Login;
T_VBVMR_Logout VBVMR_Logout; T_VBVMR_Logout VBVMR_Logout;
T_VBVMR_RunVoicemeeter VBVMR_RunVoicemeeter; T_VBVMR_RunVoicemeeter VBVMR_RunVoicemeeter;
@@ -867,34 +763,27 @@ 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 */
/******************************************************************************/
#pragma pack(1) #pragma pack(1)
// short = 2 bytes // short = 2 bytes
// char = 1 byte // char = 1 byte
// COMPATIBILITY: defined structure cannot be changed. // COMPATIBILITY: defined structure cannot be changed.
// some field could be added at the end of the structure to keep the compatibility in the time. // some field could be added at the end of the structure to keep the compatibility in the time.
typedef struct tagVBAN_VMRT_PACKET //packedt ident: 0 typedef struct tagVBAN_VMRT_PACKET // packedt ident: 0
{ {
unsigned char voicemeeterType; // 1 = Voicemeeter, 2= Voicemeeter Banana, 3 Potato unsigned char voicemeeterType; // 1 = Voicemeeter, 2= Voicemeeter Banana, 3 Potato
unsigned char reserved; // unused unsigned char reserved; // unused
unsigned short buffersize; // main stream buffer size unsigned short buffersize; // main stream buffer size
@@ -917,9 +806,9 @@ typedef struct tagVBAN_VMRT_PACKET //packedt ident: 0
short busGaindB100[8]; // Bus Gain in dB * 100 short busGaindB100[8]; // Bus Gain in dB * 100
char stripLabelUTF8c60[8][60]; // Strip Label char stripLabelUTF8c60[8][60]; // Strip Label
char busLabelUTF8c60[8][60]; // Bus Label char busLabelUTF8c60[8][60]; // Bus Label
} T_VBAN_VMRT_PACKET, *PT_VBAN_VMRT_PACKET, *LPT_VBAN_VMRT_PACKET; } T_VBAN_VMRT_PACKET, *PT_VBAN_VMRT_PACKET, *LPT_VBAN_VMRT_PACKET;
#define expected_size_T_VBAN_VMRT_PACKET 1384 //1436 max #define expected_size_T_VBAN_VMRT_PACKET 1384 // 1436 max
#pragma pack() #pragma pack()
@@ -971,16 +860,15 @@ 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
// short = 2 bytes // short = 2 bytes
// char = 1 byte // char = 1 byte
// float = 4 bytes // float = 4 bytes
typedef struct tagVBAN_VMPARAM_STRIP typedef struct tagVBAN_VMPARAM_STRIP
{ {
long mode; long mode;
float dblevel; // x 100 float dblevel; // x 100
short Audibility; // x 100 short Audibility; // x 100
@@ -992,7 +880,7 @@ typedef struct tagVBAN_VMPARAM_STRIP
short EQgain2; // x 100 short EQgain2; // x 100
short EQgain3; // x 100 short EQgain3; // x 100
//first channel parametric EQ // first channel parametric EQ
char PEQ_eqOn[6]; // 0 or 1 char PEQ_eqOn[6]; // 0 or 1
char PEQ_eqtype[6]; // see define below char PEQ_eqtype[6]; // see define below
float PEQ_eqgain[6]; float PEQ_eqgain[6];
@@ -1036,7 +924,7 @@ typedef struct tagVBAN_VMPARAM_STRIP
short Pitch_formant_med; // x 100 short Pitch_formant_med; // x 100
short Pitch_formant_high; // x 100 short Pitch_formant_high; // x 100
} T_VBAN_VMPARAM_STRIP, *PT_VBAN_VMPARAM_STRIP, *LPT_VBAN_VMPARAM_STRIP; } T_VBAN_VMPARAM_STRIP, *PT_VBAN_VMPARAM_STRIP, *LPT_VBAN_VMPARAM_STRIP;
#define VMRT_EQTYPE_PEQ 0 #define VMRT_EQTYPE_PEQ 0
#define VMRT_EQTYPE_NOTCH 1 #define VMRT_EQTYPE_NOTCH 1
@@ -1046,12 +934,11 @@ 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)))
// 170
#define expected_size_T_VBAN_VMPARAM_STRIP (8+ (8 * sizeof(short)) + (2*6) + (3 * 6 * sizeof(float)) + ((11 + 9 + 6 + 7) * sizeof(short))) typedef struct tagVBAN_VMPARAMSTRIP_PACKET // packedt ident: 1
//170 {
typedef struct tagVBAN_VMPARAMSTRIP_PACKET //packedt ident: 1
{
unsigned char voicemeeterType; // 1 = Voicemeeter, 2= Voicemeeter Banana, 3 Potato unsigned char voicemeeterType; // 1 = Voicemeeter, 2= Voicemeeter Banana, 3 Potato
unsigned char reserved; // unused unsigned char reserved; // unused
unsigned short buffersize; // main stream buffer size unsigned short buffersize; // main stream buffer size
@@ -1059,35 +946,29 @@ typedef struct tagVBAN_VMPARAMSTRIP_PACKET //packedt ident: 1
unsigned long optionBits; // unused unsigned long optionBits; // unused
unsigned long samplerate; // main stream samplerate unsigned long samplerate; // main stream samplerate
T_VBAN_VMPARAM_STRIP Strips[8]; // all input strips T_VBAN_VMPARAM_STRIP Strips[8]; // all input strips
} T_VBAN_VMPARAMSTRIP_PACKET, *PT_VBAN_VMPARAMSTRIP_PACKET, *LPT_VBAN_VMPARAMSTRIP_PACKET; } T_VBAN_VMPARAMSTRIP_PACKET, *PT_VBAN_VMPARAMSTRIP_PACKET, *LPT_VBAN_VMPARAMSTRIP_PACKET;
#pragma pack() #pragma pack()
#define expected_size_T_VBAN_VMPARAMSTRIP_PACKET ((4 * 4) + (expected_size_T_VBAN_VMPARAM_STRIP * 8)) //1436 max #define expected_size_T_VBAN_VMPARAMSTRIP_PACKET ((4 * 4) + (expected_size_T_VBAN_VMPARAM_STRIP * 8)) // 1436 max
//1376 // 1376
/******************************************************************************/ /******************************************************************************/
/* LOCAL FUNCTIONS */ /* LOCAL FUNCTIONS */
/******************************************************************************/ /******************************************************************************/
long VBVMR_LocalInit(void);
long VBVMR_LocalEnd(void);
void * VBVMR_GetRequestVB0STREAMPTR(void);
long VBVMR_SetParametersWEx(unsigned short * szParamScript, long fCopyToClient);
long VBVMR_LoginEx(long properties);
long VBVMR_MB_PushSettings(void * lpParam);
long VBVMR_LocalInit(void);
long VBVMR_LocalEnd(void);
void *VBVMR_GetRequestVB0STREAMPTR(void);
long VBVMR_SetParametersWEx(unsigned short *szParamScript, long fCopyToClient);
long VBVMR_LoginEx(long properties);
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 @@
#include <windows.h>
#include "VoicemeeterRemote.h"
#ifndef __CDLL_H__ #ifndef __CDLL_H__
#define __CDLL_H__ #define __CDLL_H__
long initialize_dll_interfaces(T_VBVMR_INTERFACE *iVMR); #include "VoicemeeterRemote.h"
PT_VMR create_interface();
#endif /*__CDLL_H__*/ #endif /*__CDLL_H__*/

9
include/util.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef __UTIL_H__
#define __UTIL_H__
void remove_name_in_path(char *szPath);
int replace_multiple_space_with_one(char *s, size_t len);
char *kind_as_string(char *s, int kind, int n);
char *version_as_string(char *, long v, int n);
#endif /* __UTIL_H__ */

View File

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

View File

@@ -9,7 +9,12 @@ 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)
CPPFLAGS := -Iinclude -MMD -MP LOG_USE_COLOR ?= yes
ifeq ($(LOG_USE_COLOR), yes)
CPPFLAGS := -Iinclude -MMD -MP -DLOG_USE_COLOR
else
CPPFLAGS := -Iinclude -MMD -MP
endif
CFLAGS = -O -Wall -W -pedantic -ansi -std=c99 CFLAGS = -O -Wall -W -pedantic -ansi -std=c99
LDFLAGS := -Llib LDFLAGS := -Llib
LDLIBS := -lm LDLIBS := -lm
@@ -28,7 +33,6 @@ $(BIN_DIR) $(OBJ_DIR):
pwsh -Command New-Item -Path $@ -ItemType Directory pwsh -Command New-Item -Path $@ -ItemType Directory
clean: clean:
pwsh -Command Remove-Item -Recurse $(EXE) pwsh -Command Remove-Item -Recurse $(EXE), $(OBJ_DIR)
pwsh -Command Remove-Item -Recurse $(OBJ_DIR)
-include $(OBJ:.o=.d) -include $(OBJ:.o=.d)

View File

@@ -1,6 +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 "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 **/
@@ -12,19 +157,7 @@
#define KEY_WOW64_32KEY 0x0200 #define KEY_WOW64_32KEY 0x0200
#endif #endif
void remove_name_in_path(char *szPath) static bool registry_get_voicemeeter_folder(char *szDir)
{
char *p = szPath;
while (*p++)
;
while (p > szPath && *p != '\\')
p--;
if (*p == '\\')
*p = '\0';
}
bool __cdecl registry_get_voicemeeter_folder(char *szDir)
{ {
char szKey[256]; char szKey[256];
char sss[1024]; char sss[1024];
@@ -65,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;
}

103
src/util.c Normal file
View File

@@ -0,0 +1,103 @@
#include <stddef.h>
#include <stdio.h>
#include "vmr.h"
#include "util.h"
/**
* @brief Removes the last part of a path
*
* @param szPath
*/
void remove_name_in_path(char *szPath)
{
char *p = szPath;
while (*p++)
;
while (p > szPath && *p != '\\')
p--;
if (*p == '\\')
*p = '\0';
}
/**
* @brief replaces multiple newlines and tabs with single spaces
*
* @param s the string to be reduced
* @param len current length of the string
* @return int new length of the string
*/
int replace_multiple_space_with_one(char *s, size_t len)
{
int j = 0;
int count = 0;
if (len == 1 && (s[0] == ' ' || s[0] == '\t'))
{
s[0] = '\0';
return len;
}
if (len < 2)
return len;
for (int i = 0; s[i] != '\0'; i++)
{
if (s[i] == ' ' || s[i] == '\t')
{
count++;
}
if (s[i] != ' ' && s[i] != '\t')
{
if (count >= 1)
{
count = 0;
s[j++] = ' ';
}
s[j++] = s[i];
}
}
s[j] = '\0';
return j;
}
/**
* @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)
{
static const char *kinds[] = {
"Basic",
"Banana",
"Potato",
"Basic x64",
"Banana x64",
"Potato x64",
};
snprintf(s, n, kinds[kind - 1]);
return s;
}
/**
* @brief returns Voicemeeter's version as a string
*
* @param s string buffer the version will be written to
* @param v unprocessed version as a long int
* @param n maximum number of characters to be written to the buffer
* @return char*
*/
char *version_as_string(char *s, long v, int n)
{
long v1 = (v & 0xFF000000) >> 24,
v2 = (v & 0x00FF0000) >> 16,
v3 = (v & 0x0000FF00) >> 8,
v4 = (v & 0x000000FF);
snprintf(s, n, "%i.%i.%i.%i", (int)v1, (int)v2, (int)v3, (int)v4);
return s;
}

135
src/vmr.c
View File

@@ -1,117 +1,154 @@
#include <windows.h> #include <windows.h>
#include <stdio.h> #include <stdio.h>
#include <time.h>
#include "vmr.h" #include "vmr.h"
#include "log.h" #include "log.h"
#include "util.h"
long login(T_VBVMR_INTERFACE *iVMR, int kind) #define VERSION_STR_LEN 128
#define KIND_STR_LEN 64
/**
* @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;
rep = iVMR->VBVMR_Login(); log_trace("VBVMR_Login()");
Sleep(20); rep = vmr->VBVMR_Login();
if (rep == 1) if (rep == 1)
{ {
rep = run_voicemeeter(iVMR, kind); run_voicemeeter(vmr, kind);
switch (kind) char kind_s[KIND_STR_LEN];
{ log_info(
case BASIC: "Launching Voicemeeter %s GUI",
log_info("Launching Voicemeeter Basic GUI"); kind_as_string(kind_s, kind, KIND_STR_LEN));
break;
case BANANA:
log_info("Launching Voicemeeter Banana GUI");
break;
case POTATO:
log_info("Launching Voicemeeter Potato GUI");
break;
case POTATOX64:
log_info("Launching Voicemeeter Potato x64 GUI");
break;
} }
Sleep(1200); int timeout = 2;
time_t start = time(NULL);
do
{
if ((rep = version(vmr, &v)) == 0)
{
char version_s[VERSION_STR_LEN];
log_info(
"Successfully logged into the Voicemeeter API v%s",
version_as_string(version_s, v, VERSION_STR_LEN));
break;
} }
Sleep(50);
} while (time(NULL) < start + timeout);
if (rep == 0) if (rep == 0)
{ {
log_info("Successfully logged into the Voicemeeter API"); clear_dirty(vmr);
clear_dirty(iVMR);
} }
return rep; return rep;
} }
long logout(T_VBVMR_INTERFACE *iVMR) /**
* @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 */
rep = iVMR->VBVMR_Logout(); log_trace("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 *iVMR, int kind) long run_voicemeeter(PT_VMR vmr, int kind)
{ {
return iVMR->VBVMR_RunVoicemeeter((long)kind); log_trace("VBVMR_RunVoicemeeter(%d)", kind);
return vmr->VBVMR_RunVoicemeeter((long)kind);
} }
long type(T_VBVMR_INTERFACE *iVMR, long *type) long type(PT_VMR vmr, long *type)
{ {
return iVMR->VBVMR_GetVoicemeeterType(type); log_trace("VBVMR_GetVoicemeeterType(<long> *t)");
return vmr->VBVMR_GetVoicemeeterType(type);
} }
long version(T_VBVMR_INTERFACE *iVMR, long *version) long version(PT_VMR vmr, long *version)
{ {
return iVMR->VBVMR_GetVoicemeeterType(version); log_trace("VBVMR_GetVoicemeeterVersion(<long> *v)");
return vmr->VBVMR_GetVoicemeeterVersion(version);
} }
bool is_pdirty(T_VBVMR_INTERFACE *iVMR) bool is_pdirty(PT_VMR vmr)
{ {
return iVMR->VBVMR_IsParametersDirty() == 1; log_trace("VBVMR_IsParametersDirty()");
return vmr->VBVMR_IsParametersDirty() == 1;
} }
long get_parameter_float(T_VBVMR_INTERFACE *iVMR, char *param, float *f) long get_parameter_float(PT_VMR vmr, char *param, float *f)
{ {
return iVMR->VBVMR_GetParameterFloat(param, f); log_trace("VBVMR_GetParameterFloat(%s, <float> *f)", param);
return vmr->VBVMR_GetParameterFloat(param, f);
} }
long get_parameter_string(T_VBVMR_INTERFACE *iVMR, char *param, char *s) long get_parameter_string(PT_VMR vmr, char *param, unsigned short *s)
{ {
return iVMR->VBVMR_GetParameterStringA(param, s); log_trace("VBVMR_GetParameterStringW(%s, <unsigned short> *s)", param);
return vmr->VBVMR_GetParameterStringW(param, s);
} }
long set_parameter_float(T_VBVMR_INTERFACE *iVMR, char *param, float val) long set_parameter_float(PT_VMR vmr, char *param, float val)
{ {
return iVMR->VBVMR_SetParameterFloat(param, val); log_trace("VBVMR_SetParameterFloat(%s, %.1f)", param, val);
return vmr->VBVMR_SetParameterFloat(param, val);
} }
long set_parameter_string(T_VBVMR_INTERFACE *iVMR, char *param, char *s) long set_parameter_string(PT_VMR vmr, char *param, char *s)
{ {
return iVMR->VBVMR_SetParameterStringA(param, s); log_trace("VBVMR_SetParameterStringA(%s, %s)", param, s);
return vmr->VBVMR_SetParameterStringA(param, s);
} }
long set_parameters(T_VBVMR_INTERFACE *iVMR, char *command) long set_parameters(PT_VMR vmr, char *command)
{ {
return iVMR->VBVMR_SetParameters(command); log_trace("VBVMR_SetParameters(%s)", command);
return vmr->VBVMR_SetParameters(command);
} }
bool is_mdirty(T_VBVMR_INTERFACE *iVMR) bool is_mdirty(PT_VMR vmr)
{ {
return iVMR->VBVMR_MacroButton_IsDirty() == 1; log_trace("VBVMR_MacroButton_IsDirty()");
return vmr->VBVMR_MacroButton_IsDirty() == 1;
} }
long macrobutton_getstatus(T_VBVMR_INTERFACE *iVMR, long n, float *val, long mode) long macrobutton_getstatus(PT_VMR vmr, long n, float *val, long mode)
{ {
return iVMR->VBVMR_MacroButton_GetStatus(n, val, mode); log_trace("VBVMR_MacroButton_GetStatus(%ld, <float> *v, %ld)", n, mode);
return vmr->VBVMR_MacroButton_GetStatus(n, val, mode);
} }
long macrobutton_setstatus(T_VBVMR_INTERFACE *iVMR, long n, float val, long mode) long macrobutton_setstatus(PT_VMR vmr, long n, float val, long mode)
{ {
return iVMR->VBVMR_MacroButton_SetStatus(n, val, mode); log_trace("VBVMR_MacroButton_SetStatus(%ld, %d, %ld)", n, (int)val, mode);
return vmr->VBVMR_MacroButton_SetStatus(n, val, mode);
} }
void clear_dirty(T_VBVMR_INTERFACE *iVMR) void clear_dirty(PT_VMR vmr)
{ {
Sleep(30); Sleep(30);
while (is_pdirty(iVMR)) while (is_pdirty(vmr))
Sleep(1); Sleep(1);
} }

View File

@@ -2,85 +2,144 @@
#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"
#include "util.h"
#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;
union val union val
{ {
float f; float f;
char s[MAX_LINE]; wchar_t s[MAX_LINE];
} val; } val;
}; };
static bool vflag = false;
void help(void); void help(void);
int 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_command(T_VBVMR_INTERFACE *vmr, char *command); void parse_command(PT_VMR vmr, char *command);
struct result *get(T_VBVMR_INTERFACE *vmr, char *command, struct result *res); 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,
sflag = false,
pflag = false;
int opt; int opt;
char *kvalue = "";
int dvalue; int dvalue;
int kind = BANANA; char *pvalue;
enum kind kind = BANANAX64;
if (argc == 1) if (argc == 1)
{ {
help(); help();
return EXIT_SUCCESS; exit(EXIT_SUCCESS);
} }
log_set_level(LOG_INFO); log_set_level(LOG_WARN);
while ((opt = getopt(argc, argv, "k:ihD:")) != -1) while ((opt = getopt(argc, argv, "hk:msp: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 'p':
pflag = true;
pvalue = optarg;
break;
case 'i':
iflag = true;
break;
case 'D': case 'D':
if ((dvalue = atoi(optarg)) && dvalue >= LOG_TRACE && dvalue <= LOG_FATAL) dvalue = atoi(optarg);
if (dvalue >= LOG_TRACE && dvalue <= LOG_FATAL)
{ {
log_set_level(dvalue); log_set_level(dvalue);
} }
else
{
log_warn(
"-D arg out of range, expected value from 0 up to 5\n"
"Log level will default to LOG_WARN (3).\n");
}
break;
case 'v':
vflag = true;
break; break;
default: default:
abort(); abort();
} }
} }
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 (pflag)
{
log_info("Profile %s loaded", pvalue);
set_parameter_string(vmr, "command.load", pvalue);
}
if (iflag) if (iflag)
{ {
puts("Interactive mode enabled. Enter 'Q' to exit."); puts("Interactive mode enabled. Enter 'Q' to exit.");
@@ -90,35 +149,61 @@ int main(int argc, char *argv[])
{ {
for (int i = optind; i < argc; i++) for (int i = optind; i < argc; i++)
{ {
parse_command(vmr, argv[i]); parse_input(vmr, argv[i], strlen(argv[i]));
} }
} }
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 message
*
*/
void help() void help()
{ {
puts( puts(
"Usage: ./vmrcli.exe [-i] [-k] <api commands>\n" "Usage: ./vmrcli.exe [-h] [-i] [-k] [-D] [-v] [-p] [-m] [-s] <api commands>\n"
"Where: \n" "Where: \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"
"\tp: Load a user configuration (given the file name or a full path)\n"
"\tm: Launch the MacroButtons application\n"
"\ts: Launch the StreamerView application");
} }
int set_kind(char *kval) /**
* @brief Set the kind object
*
* @param kval
* @return enum kind
*/
enum kind set_kind(char *kval)
{ {
if (strcmp(kval, "basic") == 0) if (strcmp(kval, "basic") == 0)
{ {
if (sizeof(void *) == 8)
return BASICX64;
else
return BASIC; return BASIC;
} }
else if (strcmp(kval, "banana") == 0) else if (strcmp(kval, "banana") == 0)
{ {
if (sizeof(void *) == 8)
return BANANAX64;
else
return BANANA; return BANANA;
} }
else if (strcmp(kval, "potato") == 0) else if (strcmp(kval, "potato") == 0)
@@ -130,66 +215,67 @@ int set_kind(char *kval)
} }
else else
{ {
fprintf(stderr, "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
{ */
fputs("Voicemeeter is not installed", stderr); void interactive(PT_VMR vmr)
}
else
{
fprintf(stderr, "Error loading Voicemeeter dll with code %d\n", rep);
}
return rep;
}
rep = login(vmr, kind);
if (rep != 0)
{
fputs("Error logging into Voicemeeter", stderr);
return rep;
}
return 0;
}
void interactive(T_VBVMR_INTERFACE *vmr)
{ {
char input[MAX_LINE]; char input[MAX_LINE];
char *p = input; size_t len;
printf(">> ");
while (fgets(input, MAX_LINE, stdin) != NULL) while (fgets(input, MAX_LINE, stdin) != NULL)
{ {
input[strcspn(input, "\n")] = 0; input[strcspn(input, "\n")] = 0;
if (strlen(input) == 1 && (strncmp(input, "Q", 1) == 0 || strncmp(input, "q", 1) == 0)) len = strlen(input);
if (len == 1 && toupper(input[0]) == 'Q')
break; break;
while (*p) parse_input(vmr, input, len);
{
char command[MAX_LINE];
int i = 0;
while (!isspace(*p) && *p != EOF) memset(input, '\0', MAX_LINE); /* reset input buffer */
command[i++] = *p++; printf(">> ");
command[i] = '\0';
p++; /* shift to next char */
parse_command(vmr, command);
}
p = input; /* reset pointer */
} }
} }
void parse_command(T_VBVMR_INTERFACE *vmr, char *command) /**
* @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;
replace_multiple_space_with_one(input, len);
token = strtok(input, " ");
while (token != NULL)
{
parse_command(vmr, token);
token = strtok(NULL, " ");
}
}
/**
* @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);
@@ -200,8 +286,17 @@ void parse_command(T_VBVMR_INTERFACE *vmr, char *command)
get(vmr, command, &res); get(vmr, command, &res);
if (res.type == FLOAT_T) if (res.type == FLOAT_T)
{
if (res.val.f == 1 || res.val.f == 0)
{ {
set_parameter_float(vmr, command, 1 - res.val.f); set_parameter_float(vmr, command, 1 - res.val.f);
if (vflag)
{
printf("Toggling %s\n", command);
}
}
else
log_warn("%s does not appear to be a boolean parameter", command);
} }
return; return;
} }
@@ -209,6 +304,10 @@ void parse_command(T_VBVMR_INTERFACE *vmr, char *command)
if (strchr(command, '=') != NULL) /* set */ if (strchr(command, '=') != NULL) /* set */
{ {
set_parameters(vmr, command); set_parameters(vmr, command);
if (vflag)
{
printf("Setting %s\n", command);
}
} }
else /* get */ else /* get */
{ {
@@ -218,19 +317,25 @@ void parse_command(T_VBVMR_INTERFACE *vmr, char *command)
switch (res.type) switch (res.type)
{ {
case FLOAT_T: case FLOAT_T:
printf("%.2f\n", res.val.f); printf("%s: %.1f\n", command, res.val.f);
break; break;
case STRING_T: case STRING_T:
puts(res.val.s); printf("%s: %ls\n", command, res.val.s);
break; break;
default: default:
fputs("Unknown result...", stderr);
break; break;
} }
} }
} }
struct result *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)
@@ -239,9 +344,7 @@ struct result *get(T_VBVMR_INTERFACE *vmr, char *command, struct result *res)
if (get_parameter_string(vmr, command, res->val.s) != 0) if (get_parameter_string(vmr, command, res->val.s) != 0)
{ {
res->val.s[0] = 0; res->val.s[0] = 0;
fputs("Unknown parameter", stderr); log_error("Unknown parameter '%s'", command);
} }
} }
return res;
} }