Getting Values in AHK script from Voicemeeter Banana - stuck

How to use Voicemeeter Remote API and control Voicemeeter Audio Engine
Post Reply
geekgarage
Posts: 17
Joined: Fri Dec 15, 2017 10:07 pm

Getting Values in AHK script from Voicemeeter Banana - stuck

Post by geekgarage »

Been trying for better part of a week now to get AHK to read gain from A1 but i'm stuck and i hope some one here can spot the issue. No one on the AHK forum have replied to my cry for help so i hope i have better luck

The short explanation is that i'm initializing a float with -35.0
currently i've set the hotkeys Vol++ and Vol- to run a function that should read the gain value and display a message box with the value. but even tho i change the value from voicemeeter GUI and try to update it again, it's still the initialized value, it's not changing at any point

Code: Select all

;#NoTrayIcon
#Persistent
#SingleInstance force
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
#Warn  ; Recommended for catching common errors.
#MaxHotkeysPerInterval 99000000
#HotkeyInterval 99000000
#KeyHistory 0
#UseHook
ListLines Off
Process, Priority, , H
SetBatchLines, -1
SetKeyDelay, -1, -1
SetMouseDelay, -1
SetDefaultMouseSpeed, 0
SetWinDelay, -1
SetControlDelay, -1
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.


OnExit("cleanup_before_exit")
SetFormat, Float, 0.3
global volLvlB0 = -36.0
global VMR_FUNCTIONS := {}
global VMR_DLL_DRIVE := "C:"
global VMR_DLL_DIRPATH := "Program Files (x86)\VB\Voicemeeter"
global VMR_DLL_FILENAME_32 := "VoicemeeterRemote.dll"
global VMR_DLL_FILENAME_64 := "VoicemeeterRemote64.dll"
global VMR_DLL_FULL_PATH := VMR_DLL_DRIVE . "\" . VMR_DLL_DIRPATH . "\"
Sleep, 500
if (A_Is64bitOS) {
    VMR_DLL_FULL_PATH .= VMR_DLL_FILENAME_64
} else {
    VMR_DLL_FULL_PATH .= VMR_DLL_FILENAME_32
}

; == START OF EXECUTION ==
; ========================

; Load the VoicemeeterRemote DLL:
; This returns a module handle
global VMR_MODULE := DllCall("LoadLibrary", "Str", VMR_DLL_FULL_PATH, "Ptr")
if (ErrorLevel || VMR_MODULE == 0)
    die("Attempt to load VoiceMeeter Remote DLL failed.")

; Populate VMR_FUNCTIONS
add_vmr_function("Login")
add_vmr_function("Logout")
add_vmr_function("RunVoicemeeter")
add_vmr_function("SetParameterFloat")
add_vmr_function("GetParameterFloat")

; "Login" to Voicemeeter, by calling the function in the DLL named 'VBVMR_Login()'...
login_result := DllCall(VMR_FUNCTIONS["Login"], "Int")
if (ErrorLevel || login_result < 0)
    die("VoiceMeeter Remote login failed.")

; If the login returns 1, that apparently means that Voicemeeter isn't running,
; so we start it; pass 1 to run Voicemeeter, or 2 for Voicemeeter Banana:
if (login_result == 1) {
    DllCall(VMR_FUNCTIONS["RunVoicemeeter"], "Int", 2, "Int")
    if (ErrorLevel)
        die("Attempt to run VoiceMeeter failed.")
    Sleep 2000
}

spoOpen := 0


; == HOTKEYS ==
; =============

loop{
	WinGetTitle, spotifyname, ahk_class SpotifyMainWindow
	if(spotifyname != "" && spoOpen = 0){
		DllCall(VMR_FUNCTIONS["SetParameterFloat"], "AStr", "Bus[0].mode.Repeat", "Float", 1.0, "Int")
		spoOpen := 1
	} else if (spoOpen = 1 && spotifyname = ""){
		DllCall(VMR_FUNCTIONS["SetParameterFloat"], "AStr", "Bus[0].mode.Normal", "Float", 1.0, "Int")
		spoOpen := 0
	} else {
		;do nothing
	}
	Sleep, 5000
	ToolTip
}

Volume_Up::
	readVolLvl()
	;volLvlB0 += 1
	;adjustVolLvl()
return


Volume_Down::
	readVolLvl()
	;volLvlB0 -= 1
	;adjustVolLvl()
return

; == Functions ==
; ===============
;DllCall(VMR_FUNCTIONS["SetParameterFloat"], "AStr", "Strip[0].B1", "Float", 1.0, "Int")

readVolLvl(){
	statusLvlB0 = DllCall(VMR_FUNCTIONS["GetParameterFloat"], "AStr", "Bus[0].Gain", "Ptr", &volLvlB0, "Int")
	if (statusLvlB0 < 0){
		MsgBox, Error: %statusLvlB0%
	} else {
		SetFormat, Float, 0.3
		MsgBox, %volLvlB0%
	}
}

adjustVolLvl() {
	if (volLvlB0 > 12.0){
		volLvlB0 = 12.0
	} else if (volLvlB0 < -60.0) {
		volLvlB0 = -60.0
	}
	DllCall(VMR_FUNCTIONS["SetParameterFloat"], "AStr", "Bus[0].Gain", "Float", volLvlB0, "Int")
}

add_vmr_function(func_name) {
    VMR_FUNCTIONS[func_name] := DllCall("GetProcAddress", "Ptr", VMR_MODULE, "AStr", "VBVMR_" . func_name, "Ptr")
    if (ErrorLevel || VMR_FUNCTIONS[func_name] == 0)
        die("Failed to register VMR function " . func_name . ".")
}

cleanup_before_exit(exit_reason, exit_code) {
    DllCall(VMR_FUNCTIONS["Logout"], "Int")
    ; OnExit functions must return 0 to allow the app to exit.
    return 0
}

die(die_string:="UNSPECIFIED FATAL ERROR.", exit_status:=254) {
    MsgBox 16, FATAL ERROR, %die_string%
    ExitApp exit_status
}

FHex( int, pad=8 ) { ; Function by [VxE]. Formats an integer (decimals are truncated) as hex. NOT IN USE FOR NOW
; "Pad" may be the minimum number of digits that should appear on the right of the "0x".
	Static hx := "0123456789ABCDEF"
	If !( 0 < int |= 0 )
		Return !int ? "0x0" : "-" FHex( -int, pad )
	s := 1 + Floor( Ln( int ) / Ln( 16 ) )
	h := SubStr( "0x0000000000000000", 1, pad := pad < s ? s + 2 : pad < 16 ? pad + 2 : 18 )
	u := A_IsUnicode = 1
	Loop % s
		NumPut( *( &hx + ( ( int & 15 ) << u ) ), h, pad - A_Index << u, "UChar" ), int >>= 4
	Return h
}


BNK3R Boy
Posts: 2
Joined: Mon Nov 19, 2018 6:11 pm

Re: Getting Values in AHK script from Voicemeeter Banana - stuck

Post by BNK3R Boy »

I hope i can help.
;#NoTrayIcon
#Persistent
#SingleInstance force
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
#Warn ; Recommended for catching common errors.
#MaxHotkeysPerInterval 99000000
#HotkeyInterval 99000000
#KeyHistory 0
#UseHook
ListLines Off
Process, Priority, , H
SetBatchLines, -1
SetKeyDelay, -1, -1
SetMouseDelay, -1
SetDefaultMouseSpeed, 0
SetWinDelay, -1
SetControlDelay, -1
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.


OnExit("cleanup_before_exit")
SetFormat, Float, 0.3
global volLvlB0 = -36.0
global VMR_FUNCTIONS := {}
global VMR_DLL_DRIVE := "C:"
global VMR_DLL_DIRPATH := "Program Files (x86)\VB\Voicemeeter"
global VMR_DLL_FILENAME_32 := "VoicemeeterRemote.dll"
global VMR_DLL_FILENAME_64 := "VoicemeeterRemote64.dll"
global VMR_DLL_FULL_PATH := VMR_DLL_DRIVE . "\" . VMR_DLL_DIRPATH . "\"
Sleep, 500
if (A_Is64bitOS) {
VMR_DLL_FULL_PATH .= VMR_DLL_FILENAME_64
} else {
VMR_DLL_FULL_PATH .= VMR_DLL_FILENAME_32
}

; == START OF EXECUTION ==
; ========================

; Load the VoicemeeterRemote DLL:
; This returns a module handle
global VMR_MODULE := DllCall("LoadLibrary", "Str", VMR_DLL_FULL_PATH, "Ptr")
if (ErrorLevel || VMR_MODULE == 0)
die("Attempt to load VoiceMeeter Remote DLL failed.")

; Populate VMR_FUNCTIONS
add_vmr_function("Login")
add_vmr_function("Logout")
add_vmr_function("RunVoicemeeter")
add_vmr_function("SetParameterFloat")
add_vmr_function("GetParameterFloat")
add_vmr_function("IsParametersDirty")

; "Login" to Voicemeeter, by calling the function in the DLL named 'VBVMR_Login()'...
login_result := DllCall(VMR_FUNCTIONS["Login"], "Int")
if (ErrorLevel || login_result < 0)
die("VoiceMeeter Remote login failed.")

; If the login returns 1, that apparently means that Voicemeeter isn't running,
; so we start it; pass 1 to run Voicemeeter, or 2 for Voicemeeter Banana:
if (login_result == 1) {
DllCall(VMR_FUNCTIONS["RunVoicemeeter"], "Int", 2, "Int")
if (ErrorLevel)
die("Attempt to run VoiceMeeter failed.")
Sleep 2000
}

spoOpen := 0


; == HOTKEYS ==
; =============

loop{
WinGetTitle, spotifyname, ahk_class SpotifyMainWindow
if(spotifyname != "" && spoOpen = 0){
DllCall(VMR_FUNCTIONS["SetParameterFloat"], "AStr", "Bus[0].mode.Repeat", "Float", 1.0, "Int")
spoOpen := 1
} else if (spoOpen = 1 && spotifyname = ""){
DllCall(VMR_FUNCTIONS["SetParameterFloat"], "AStr", "Bus[0].mode.Normal", "Float", 1.0, "Int")
spoOpen := 0
} else {
;do nothing
}
Sleep, 5000
ToolTip
}

Volume_Up::
readVolLvl()
;volLvlB0 += 1
;adjustVolLvl()
return


Volume_Down::
readVolLvl()
;volLvlB0 -= 1
;adjustVolLvl()
return

; == Functions ==
; ===============
;DllCall(VMR_FUNCTIONS["SetParameterFloat"], "AStr", "Strip[0].B1", "Float", 1.0, "Int")

readVolLvl(){
DLLCall(VMR_FUNCTIONS["IsParametersDirty"])
statusLvlB0 = DllCall(VMR_FUNCTIONS["GetParameterFloat"], "AStr", "Bus[0].Gain", "Ptr", &volLvlB0, "Int")
if (statusLvlB0 < 0){
MsgBox, Error: %statusLvlB0%
} else {
SetFormat, Float, 0.3
MsgBox, %volLvlB0%
}
}

adjustVolLvl() {
if (volLvlB0 > 12.0){
volLvlB0 = 12.0
} else if (volLvlB0 < -60.0) {
volLvlB0 = -60.0
}
DllCall(VMR_FUNCTIONS["SetParameterFloat"], "AStr", "Bus[0].Gain", "Float", volLvlB0, "Int")
}

add_vmr_function(func_name) {
VMR_FUNCTIONS[func_name] := DllCall("GetProcAddress", "Ptr", VMR_MODULE, "AStr", "VBVMR_" . func_name, "Ptr")
if (ErrorLevel || VMR_FUNCTIONS[func_name] == 0)
die("Failed to register VMR function " . func_name . ".")
}

cleanup_before_exit(exit_reason, exit_code) {
DllCall(VMR_FUNCTIONS["Logout"], "Int")
; OnExit functions must return 0 to allow the app to exit.
return 0
}

die(die_string:="UNSPECIFIED FATAL ERROR.", exit_status:=254) {
MsgBox 16, FATAL ERROR, %die_string%
ExitApp exit_status
}

FHex( int, pad=8 ) { ; Function by [VxE]. Formats an integer (decimals are truncated) as hex. NOT IN USE FOR NOW
; "Pad" may be the minimum number of digits that should appear on the right of the "0x".
Static hx := "0123456789ABCDEF"
If !( 0 < int |= 0 )
Return !int ? "0x0" : "-" FHex( -int, pad )
s := 1 + Floor( Ln( int ) / Ln( 16 ) )
h := SubStr( "0x0000000000000000", 1, pad := pad < s ? s + 2 : pad < 16 ? pad + 2 : 18 )
u := A_IsUnicode = 1
Loop % s
NumPut( *( &hx + ( ( int & 15 ) << u ) ), h, pad - A_Index << u, "UChar" ), int >>= 4
Return h
}
The 2 red lines should solve your problem.

info out of the VoicemeeterRemote.h:
/**
@brief Check if parameters have changed.
Call this function periodically (typically every 10 or 20ms).
(this function must be called from one thread only)

@return: 0: no new paramters.
1: New parameters -> update your display.
-1: error (unexpected)
-2: no server.
*/

long __stdcall VBVMR_IsParametersDirty(void);




Don't worry your script was very helpful to understand this API.
Thanks for it too.

Code: Select all

#NoEnv 
#Warn
SendMode Input  
SetWorkingDir %A_ScriptDir%  
#persistent
ExitApp
Post Reply