Skip to content

Instantly share code, notes, and snippets.

@stares
Forked from anonymous1184/AppVol.ahk
Created May 25, 2023 09:26
Show Gist options
  • Save stares/85beacf7e3b49e42f505c534efd02e36 to your computer and use it in GitHub Desktop.
Save stares/85beacf7e3b49e42f505c534efd02e36 to your computer and use it in GitHub Desktop.
AppVol()

See the Volume.ahk file, contains the most up to date version of a single functions meant to control not just volume but mute.

AppVol.ahk uses a different approach, the result is almost the same. Still useful when there's a need to know the value of the volume rathen than changing it.

TODO: Clean this


; Version: 2023.01.23.1
; https://gist.github.com/b251cd8407a379d4965791585887cfce
/* ;region Example
NumpadAdd::AppVol("Spotify.exe", +5)
NumpadSub::AppVol("Spotify.exe", -5)
*/ ;endregion
AppVol(App, Volume) {
static cache := {}
Process Exist, % App
if !(pid := ErrorLevel)
return
if (cache.HasKey(App) && cache[App, "pid"] = pid) {
Volume += cache[App, "vol"]
cache[App, "vol"] := AppVol_Set(pid, Volume)
return
}
cache[App] := {}
wmi := ComObjGet("winmgmts:")
results := wmi.ExecQuery("SELECT * FROM Win32_Process WHERE Name = '" App "'")
for item in results {
currVol := AppVol_Get(item.ProcessId)
if (currVol = -1)
continue
Volume += currVol
cache[App, "pid"] := item.ProcessId
cache[App, "vol"] := AppVol_Set(item.ProcessId, Volume)
break
}
ObjRelease(wmi)
}
; TODO: Rewrite this!
; Tweaked versions of:
; https://www.autohotkey.com/boards/viewtopic.php?p=210545#p210545
AppVol_Get(Pid) {
IMMDeviceEnumerator := ComObjCreate("{BCDE0395-E52F-467C-8E3D-C4579291692E}", "{A95664D2-9614-4F35-A746-DE8DB63617E6}")
DllCall(NumGet(NumGet(IMMDeviceEnumerator+0)+4*A_PtrSize), "UPtr",IMMDeviceEnumerator, "UInt",0, "UInt",1, "UPtr*",IMMDevice:=0, "UInt")
ObjRelease(IMMDeviceEnumerator)
VarSetCapacity(GUID, 16)
DllCall("Ole32\CLSIDFromString", "Str","{77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F}", "UPtr",&GUID)
DllCall(NumGet(NumGet(IMMDevice+0)+3*A_PtrSize), "UPtr",IMMDevice, "UPtr",&GUID, "UInt",23, "UPtr",0, "UPtr*",IAudioSessionManager2:=0, "UInt")
ObjRelease(IMMDevice)
DllCall(NumGet(NumGet(IAudioSessionManager2+0)+5*A_PtrSize), "UPtr",IAudioSessionManager2, "UPtr*",IAudioSessionEnumerator:=0, "UInt")
ObjRelease(IAudioSessionManager2)
DllCall(NumGet(NumGet(IAudioSessionEnumerator+0)+3*A_PtrSize), "UPtr",IAudioSessionEnumerator, "UInt*",SessionCount:=0, "UInt")
loop % SessionCount {
DllCall(NumGet(NumGet(IAudioSessionEnumerator+0)+4*A_PtrSize), "UPtr",IAudioSessionEnumerator, "Int",A_Index-1, "UPtr*",IAudioSessionControl:=0, "UInt")
IAudioSessionControl2 := ComObjQuery(IAudioSessionControl, "{BFB7FF88-7239-4FC9-8FA2-07C950BE9C6D}")
ObjRelease(IAudioSessionControl)
DllCall(NumGet(NumGet(IAudioSessionControl2+0)+14*A_PtrSize), "UPtr",IAudioSessionControl2, "UInt*",ProcessId:=0, "UInt")
if (Pid = ProcessId) {
ISimpleAudioVolume := ComObjQuery(IAudioSessionControl2, "{87CE5498-68D6-44E5-9215-6DA47EF883D8}")
DllCall(NumGet(NumGet(ISimpleAudioVolume+0)+4*A_PtrSize), "UPtr",ISimpleAudioVolume, "Float*",MasterVolume:=0, "UInt")
ObjRelease(ISimpleAudioVolume)
}
ObjRelease(IAudioSessionControl2)
}
ObjRelease(IAudioSessionEnumerator)
if (MasterVolume ~= "[\d\.]+")
return Round(MasterVolume * 100)
return -1
}
AppVol_Set(Pid, MasterVolume) {
MasterVolume := Max(0, Min(100, MasterVolume))
IMMDeviceEnumerator := ComObjCreate("{BCDE0395-E52F-467C-8E3D-C4579291692E}", "{A95664D2-9614-4F35-A746-DE8DB63617E6}")
DllCall(NumGet(NumGet(IMMDeviceEnumerator+0)+4*A_PtrSize), "UPtr",IMMDeviceEnumerator, "UInt",0, "UInt",1, "UPtr*",IMMDevice:=0, "UInt")
ObjRelease(IMMDeviceEnumerator)
VarSetCapacity(GUID, 16)
DllCall("Ole32\CLSIDFromString", "Str","{77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F}", "UPtr",&GUID)
DllCall(NumGet(NumGet(IMMDevice+0)+3*A_PtrSize), "UPtr",IMMDevice, "UPtr",&GUID, "UInt",23, "UPtr",0, "UPtr*",IAudioSessionManager2:=0, "UInt")
ObjRelease(IMMDevice)
DllCall(NumGet(NumGet(IAudioSessionManager2+0)+5*A_PtrSize), "UPtr",IAudioSessionManager2, "UPtr*",IAudioSessionEnumerator:=0, "UInt")
ObjRelease(IAudioSessionManager2)
DllCall(NumGet(NumGet(IAudioSessionEnumerator+0)+3*A_PtrSize), "UPtr",IAudioSessionEnumerator, "UInt*",SessionCount:=0, "UInt")
loop % SessionCount {
DllCall(NumGet(NumGet(IAudioSessionEnumerator+0)+4*A_PtrSize), "UPtr",IAudioSessionEnumerator, "Int",A_Index-1, "UPtr*",IAudioSessionControl:=0, "UInt")
IAudioSessionControl2 := ComObjQuery(IAudioSessionControl, "{BFB7FF88-7239-4FC9-8FA2-07C950BE9C6D}")
ObjRelease(IAudioSessionControl)
DllCall(NumGet(NumGet(IAudioSessionControl2+0)+14*A_PtrSize), "UPtr",IAudioSessionControl2, "UInt*",ProcessId:=0, "UInt")
if (Pid = ProcessId) {
ISimpleAudioVolume := ComObjQuery(IAudioSessionControl2, "{87CE5498-68D6-44E5-9215-6DA47EF883D8}")
DllCall(NumGet(NumGet(ISimpleAudioVolume+0)+3*A_PtrSize), "UPtr",ISimpleAudioVolume, "Float",MasterVolume/100.0, "UPtr",0, "UInt")
ObjRelease(ISimpleAudioVolume)
}
ObjRelease(IAudioSessionControl2)
}
ObjRelease(IAudioSessionEnumerator)
return MasterVolume
}

#Warn
#NoEnv
SetBatchLines -1
return ; End of auto-execute
; Active Window
1::Volume() ; Toggle Mute
2::Volume(-2) ; Percent
3::Volume(+2) ; Percent
; Specific app
4::Volume("firefox.exe") ; Toggle Mute
5::Volume("firefox.exe", -2) ; Percent
6::Volume("firefox.exe", +2) ; Percent
; Specific window
7::Volume("Picture-in-Picture") ; Toggle Mute
8::Volume("Picture-in-Picture", -2) ; Percent
9::Volume("Picture-in-Picture", +2) ; Percent
Volume(Title := "", Offset := 0) {
if (!Title)
Title := "A"
else if (Title ~= "^-?\d+$")
Offset := Title, Title := "A"
else if (SubStr(Title, -3) = ".exe")
Title := "ahk_exe " Title
WinGet appName, ProcessName, % Title
IMMDeviceEnumerator := ComObjCreate("{BCDE0395-E52F-467C-8E3D-C4579291692E}", "{A95664D2-9614-4F35-A746-DE8DB63617E6}")
DllCall(NumGet(NumGet(IMMDeviceEnumerator+0) + 4 * A_PtrSize), "Ptr",IMMDeviceEnumerator, "UInt",0, "UInt",1, "Ptr*",IMMDevice:=0)
ObjRelease(IMMDeviceEnumerator)
VarSetCapacity(GUID, 16, 0)
DllCall("Ole32\CLSIDFromString", "Str","{77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F}", "Ptr",&GUID)
DllCall(NumGet(NumGet(IMMDevice+0) + 3 * A_PtrSize), "Ptr",IMMDevice, "Ptr",&GUID, "UInt",23, "Ptr",0, "Ptr*",IAudioSessionManager2:=0)
ObjRelease(IMMDevice)
DllCall(NumGet(NumGet(IAudioSessionManager2+0) + 5 * A_PtrSize), "Ptr",IAudioSessionManager2, "Ptr*",IAudioSessionEnumerator:=0)
ObjRelease(IAudioSessionManager2)
DllCall(NumGet(NumGet(IAudioSessionEnumerator+0) + 3 * A_PtrSize), "Ptr",IAudioSessionEnumerator, "UInt*",sessionCount:=0)
loop % sessionCount {
DllCall(NumGet(NumGet(IAudioSessionEnumerator+0) + 4 * A_PtrSize), "Ptr",IAudioSessionEnumerator, "Int",A_Index - 1, "Ptr*",IAudioSessionControl:=0)
IAudioSessionControl2 := ComObjQuery(IAudioSessionControl, "{BFB7FF88-7239-4FC9-8FA2-07C950BE9C6D}")
ObjRelease(IAudioSessionControl)
DllCall(NumGet(NumGet(IAudioSessionControl2+0) + 14 * A_PtrSize), "Ptr",IAudioSessionControl2, "UInt*",pid:=0)
hProc := DllCall("OpenProcess", "UInt",0x0400, "Int",false, "UInt",pid) ; PROCESS_QUERY_INFORMATION
sz := VarSetCapacity(path, 1024, 0)
DllCall("psapi\GetModuleFileNameEx", "UInt",hProc, "UInt",0, "Str",path, "UInt",sz)
DllCall("CloseHandle", hProc)
SplitPath path, filename
if (filename = appName) {
ISimpleAudioVolume := ComObjQuery(IAudioSessionControl2, "{87CE5498-68D6-44E5-9215-6DA47EF883D8}")
DllCall(NumGet(NumGet(ISimpleAudioVolume+0) + 6 * A_PtrSize), "Ptr",ISimpleAudioVolume, "Int*",muted:=0) ; Get mute
if (muted || !Offset)
DllCall(NumGet(NumGet(ISimpleAudioVolume+0) + 5 * A_PtrSize), "Ptr",ISimpleAudioVolume, "Int",!muted , "Ptr",0) ; Toggle mute
if (Offset) {
Offset := Offset / 100
DllCall(NumGet(NumGet(ISimpleAudioVolume+0) + 4 * A_PtrSize), "Ptr",ISimpleAudioVolume, "Float*",level:=0) ; Get volume
DllCall(NumGet(NumGet(ISimpleAudioVolume+0) + 3 * A_PtrSize), "Ptr",ISimpleAudioVolume, "Float",Max(0.0, Min(1.0, level + Offset)), "Ptr",0) ; Set volume
}
ObjRelease(ISimpleAudioVolume)
}
ObjRelease(IAudioSessionControl2)
}
ObjRelease(IAudioSessionEnumerator)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment