2020-04-24 22:22:48 -05:00
#NoEnv
#SingleInstance force
#MaxHotkeysPerInterval 99000000
#HotkeyInterval 99000000
#KeyHistory 0
#UseHook
ListLines Off
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetTitleMatchMode RegEx
StringCaseSense Off
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
OnExit ( "cleanup_before_exit" )
SetFormat , Float , 0.3
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
}
; == HOTKEYS ==
; =============
Volume_Up::
2020-04-29 20:39:18 -05:00
If GetKeyState ( "ScrollLock" , "T" ) ; Control music volume if scroll lock is on
2020-04-24 22:22:48 -05:00
{
cLvl := readParam ( "Strip[2]" . ".Gain" )
if ( cLvl != "" )
{
cLvl += 2
adjustVolLvl ( "Strip[2]" . ".Gain" , cLvl )
}
Return
}
b0M := Round ( readParam ( "Bus[0]" . ".Mute" ))
b1M := Round ( readParam ( "Bus[1]" . ".Mute" ))
if ! ( b0M )
{
cLvl := readParam ( "Bus[0]" . ".Gain" )
if ( cLvl != "" )
{
cLvl += 2
adjustVolLvl ( "Bus[0]" . ".Gain" , cLvl )
}
}
if ! ( b1M )
{
cLvl := readParam ( "Bus[1]" . ".Gain" )
if ( cLvl != "" )
{
cLvl += 2
adjustVolLvl ( "Bus[1]" . ".Gain" , cLvl )
}
}
return
Volume_Down::
2020-04-29 20:39:18 -05:00
If GetKeyState ( "ScrollLock" , "T" ) ; Control music volume if scroll lock is on
2020-04-24 22:22:48 -05:00
{
cLvl := readParam ( "Strip[2]" . ".Gain" )
if ( cLvl != "" )
{
cLvl -= 2
adjustVolLvl ( "Strip[2]" . ".Gain" , cLvl )
}
Return
}
b0M := Round ( readParam ( "Bus[0]" . ".Mute" ))
b1M := Round ( readParam ( "Bus[1]" . ".Mute" ))
if ! ( b0M )
{
cLvl := readParam ( "Bus[0]" . ".Gain" )
if ( cLvl != "" )
{
cLvl -= 2
adjustVolLvl ( "Bus[0]" . ".Gain" , cLvl )
}
}
if ! ( b1M )
{
cLvl := readParam ( "Bus[1]" . ".Gain" )
if ( cLvl != "" )
{
cLvl -= 2
adjustVolLvl ( "Bus[1]" . ".Gain" , cLvl )
}
}
return
Volume_Mute::
2020-04-29 20:39:18 -05:00
If ( GetKeyState ( "Media_Stop" )) ; Mutes all output, and Comms as well for good measure. Basically a kill switch
2020-04-24 22:22:48 -05:00
{
2020-04-25 02:04:59 -05:00
b0M := Round ( readParam ( "Bus[0]" . ".Mute" )) ; Speakers
b1M := Round ( readParam ( "Bus[1]" . ".Mute" )) ; Headphones
2020-04-29 20:39:18 -05:00
cM := b0M + b1M
2020-04-24 22:22:48 -05:00
2020-04-29 20:39:18 -05:00
if ( cM = "2" )
2020-04-25 02:04:59 -05:00
{ ; Unmute the ones that were unmuted before
adjustMute ( "Bus[0]" . ".Mute" , b0Ms ) ; Speakers
adjustMute ( "Bus[1]" . ".Mute" , b1Ms ) ; Headphones
2020-04-24 22:22:48 -05:00
} else {
2020-04-25 02:04:59 -05:00
if ! ( b0M ) ; Speakers
2020-04-24 22:22:48 -05:00
{
b0Ms := True
} else {
b0Ms := False
}
2020-04-25 02:04:59 -05:00
if ! ( b1M ) ; Headphones
2020-04-24 22:22:48 -05:00
{
b1Ms := True
} else {
b1Ms := False
}
2020-04-25 02:04:59 -05:00
; Mute
adjustMute ( "Bus[0]" . ".Mute" , "0" ) ; Speakers
adjustMute ( "Bus[1]" . ".Mute" , "0" ) ; Headphones
2020-04-24 22:22:48 -05:00
}
Return
}
2020-04-25 02:04:59 -05:00
cM := Round ( readParam ( "Bus[0]" . ".Mute" )) ; Toggles between the speakers and headphones being muted, normal operation
2020-04-24 22:22:48 -05:00
if ( cM )
{
2020-04-25 02:04:59 -05:00
adjustMute ( "Bus[0]" . ".Mute" , "1" ) ; Speakers
adjustMute ( "Bus[1]" . ".Mute" , "0" ) ; Headphones
2020-04-24 22:22:48 -05:00
}
if ! ( cM )
{
2020-04-25 02:04:59 -05:00
adjustMute ( "Bus[0]" . ".Mute" , "0" ) ; Speakers
adjustMute ( "Bus[1]" . ".Mute" , "1" ) ; Headphones
2020-04-24 22:22:48 -05:00
}
return
2020-04-25 02:04:59 -05:00
!m:: ; Mute: No audio out
2020-04-29 20:39:18 -05:00
Send { F23 }
2020-04-25 02:04:59 -05:00
b3M := Round ( readParam ( "Bus[3]" . ".Mute" )) ; Comms IN
if ! ( b3M )
{
adjustMute ( "Bus[3]" . ".Mute" , "0" )
} else {
adjustMute ( "Bus[3]" . ".Mute" , "1" )
}
Return
!n:: ; Deafen: No audio in or out
2020-04-29 20:39:18 -05:00
Send { F24 }
2020-04-25 02:04:59 -05:00
s4M := Round ( readParam ( "Strip[4]" . ".Mute" )) ; Comms OUT
If ( s4M )
{
2020-04-29 20:39:18 -05:00
adjustMute ( "Bus[3]" . ".Mute" , "1" ) ; Comms IN
adjustMute ( "Strip[4]" . ".Mute" , "1" ) ; Comms OUT
2020-04-25 02:04:59 -05:00
} else {
2020-04-29 20:39:18 -05:00
adjustMute ( "Bus[3]" . ".Mute" , "0" ) ; Comms IN
adjustMute ( "Strip[4]" . ".Mute" , "0" ) ; Comms OUT
2020-04-25 02:04:59 -05:00
}
2020-04-29 20:39:18 -05:00
Return
!j:: ; Mute toggle for skype meeting on work laptop
2020-04-25 02:04:59 -05:00
Send { F24 }
2020-04-29 20:39:18 -05:00
cM := Round ( readParam ( "Bus[2]" . ".Mute" ))
if ( cM )
{
adjustMute ( "Bus[2]" . ".Mute" , "1" ) ; Work Laptop
}
if ! ( cM )
{
adjustMute ( "Bus[2]" . ".Mute" , "0" ) ; Work Laptop
}
2020-04-25 02:04:59 -05:00
Return
2020-04-24 22:22:48 -05:00
; == Functions ==
; ===============
readParam ( loc ){
Loop
{
pDirty := DLLCall ( VMR_FUNCTIONS [ "IsParametersDirty" ]) ;Check if parameters have changed.
if ( pDirty == 0 ) ;0 = no new paramters.
break
else if ( pDirty < 0 ) ;-1 = error, -2 = no server
return ""
else ;1 = New parameters -> update your display. (this only applies if YOU have a display, couldn't find any code to update VM display which can get off sometimes)
if A_Index > 200
return ""
sleep , 20
}
tParamVal := 0.0
NumPut ( 0.0 , tParamVal , 0 , "Float" )
statusLvl := DllCall ( VMR_FUNCTIONS [ "GetParameterFloat" ], "AStr" , loc , "Ptr" , & tParamVal , "Int" )
tParamVal := NumGet ( tParamVal , 0 , "Float" )
if ( statusLvl < 0 )
return ""
else
return tParamVal
}
adjustVolLvl ( loc , tVol ) {
if ( tVol > 12.0 )
2020-04-29 20:39:18 -05:00
tVol := 12.0
2020-04-24 22:22:48 -05:00
else if ( tVol < - 60.0 )
2020-04-29 20:39:18 -05:00
tVol := - 60.0
2020-04-24 22:22:48 -05:00
DllCall ( VMR_FUNCTIONS [ "SetParameterFloat" ], "AStr" , loc , "Float" , tVol , "Int" )
}
adjustMute ( loc , tM ) {
if ( tM = 0 )
2020-04-29 20:39:18 -05:00
tM := 1
2020-04-24 22:22:48 -05:00
else
2020-04-29 20:39:18 -05:00
tM := 0
2020-04-24 22:22:48 -05:00
DllCall ( VMR_FUNCTIONS [ "SetParameterFloat" ], "AStr" , loc , "Float" , tM , "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
}