#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:: If GetKeyState("ScrollLock", "T") ; Control music volume if scroll lock is on { 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:: If GetKeyState("ScrollLock", "T") ; Control music volume if scroll lock is on { 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:: If (GetKeyState("Media_Stop")) ; Mutes all output. Basically a kill switch { b0M := Round(readParam("Bus[0]" . ".Mute")) ; Speakers b1M := Round(readParam("Bus[1]" . ".Mute")) ; Headphones cM := b0M + b1M if (cM = "2") { ; Unmute the ones that were unmuted before adjustMute("Bus[0]" . ".Mute", b0Ms) ; Speakers adjustMute("Bus[1]" . ".Mute", b1Ms) ; Headphones } else { if !(b0M) ; Speakers { b0Ms := True } else { b0Ms := False } if !(b1M) ; Headphones { b1Ms := True } else { b1Ms := False } ; Mute adjustMute("Bus[0]" . ".Mute", "0") ; Speakers adjustMute("Bus[1]" . ".Mute", "0") ; Headphones } Return } cM := Round(readParam("Bus[1]" . ".Mute")) ; Toggles between the speakers and headphones being muted, normal operation if (cM) { adjustMute("Bus[0]" . ".Mute", "0") ; Speakers adjustMute("Bus[1]" . ".Mute", "1") ; Headphones } if !(cM) { adjustMute("Bus[0]" . ".Mute", "1") ; Speakers adjustMute("Bus[1]" . ".Mute", "0") ; Headphones } return !m:: ; Mute: No audio out Send {F23} 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 Send {F24} s4M := Round(readParam("Strip[4]" . ".Mute")) ; Comms OUT If (s4M) { adjustMute("Bus[3]" . ".Mute", "1") ; Comms IN adjustMute("Strip[4]" . ".Mute", "1") ; Comms OUT } else { adjustMute("Bus[3]" . ".Mute", "0") ; Comms IN adjustMute("Strip[4]" . ".Mute", "0") ; Comms OUT } Return !j:: ; Mute toggle for meetings on work laptop Send {F24} cM := Round(readParam("Bus[2]" . ".Mute")) if (cM) { adjustMute("Bus[2]" . ".Mute", "1") ; Work Laptop adjustMute("Bus[3]" . ".Mute", "0") ; Comms IN adjustMute("Strip[3]" . ".Mute", "0") ; Desktop Sleep, 650 ; Delay so that the "deafened" sound from discord can play adjustMute("Strip[4]" . ".Mute", "0") ; Comms OUT } if !(cM) { adjustMute("Bus[2]" . ".Mute", "0") ; Work Laptop adjustMute("Bus[3]" . ".Mute", "1") ; Comms IN adjustMute("Strip[4]" . ".Mute", "1") ; Comms OUT adjustMute("Strip[3]" . ".Mute", "1") ; Desktop } Return ; == 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) tVol := 12.0 else if (tVol < -60.0) tVol := -60.0 DllCall(VMR_FUNCTIONS["SetParameterFloat"], "AStr", loc, "Float", tVol, "Int") } adjustMute(loc, tM) { if (tM = 0) tM := 1 else tM := 0 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 }