Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Vista Audio Control Functions


  • Please log in to reply
178 replies to this topic
Lexikos
  • Administrators
  • 9441 posts
  • Last active:
  • Joined: 17 Oct 2006

Vista Audio Control Functions

VA provides Windows Vista and 7-compatible alternatives to some SoundSet/SoundGet subcommands, as well as some additional features that SoundSet/SoundGet do not support. See the online documentation for a list of functions.

Note: This library depends entirely upon APIs present only in Windows Vista and later. Scripts using it should NOT be run in XP compatibility mode or on any version of Windows older than Vista.

Notes for v2.1 and later:

  • Requires AutoHotkey_L (any recent build should work).
  • COM.ahk is NOT required. COM_Init() does NOT need to be called.

Notes for v2.0:

  • Requires Sean's Standard Library COM.ahk
  • COM must be initialized prior to calling any VA functions: COM_Init().

Installation: Download and extract VA.ahk into a Lib folder.

 

Download v2.3 for AutoHotkey 1.1 - v2.0 for AutoHotkey 1.0
Online Documentation
VA is public domain or similar.


Device Topology / Subunits

Subunit/component names are defined by the audio drivers, so will vary from PC to PC. Volume subunits often have the same names as shown on the Levels tab in the Properties of the sound device. Mute subunits might not have unique names; in those cases, use a numeric index instead of a name.



Seabiscuit
  • Members
  • 109 posts
  • Last active: May 08 2008 06:31 PM
  • Joined: 07 Jan 2007
Posted Image I wanted this! I had problems with some of the OSC sound controls scripts working in Vista. Mes omages! :D

Lexikos
  • Administrators
  • 9441 posts
  • Last active:
  • Joined: 17 Oct 2006
I'm glad it was of use to someone. :) I wrote it so that I could mute/unmute line in. :lol:

tuna
  • Members
  • 158 posts
  • Last active: Dec 28 2012 04:50 PM
  • Joined: 03 Oct 2007
Sounds like a great app but i still cant get it to work correctly. The thing is VA_GETVOLUME() seems to retrieve the wrong volumes when compared to what is detailed by windows mixer, so i did a test:

Windows Mixer vs VA_GETVOLUME()

0	0.000000
1	0.184100
2	0.391507
3	0.623866
4	0.878952
5	1.151728
6	1.451509
7	1.773915
8	2.112748
9	2.470650
10	2.854000
11	3.246838
12	3.671082
13	4.110560
14	4.560251
15	5.034180
16	5.531064
17	6.049241
18	6.586668
19	7.113557
20	7.679757
21	8.256726
22	8.874515
23	9.500057
24	10.129228
25	10.757594
26	11.423194
27	12.128233
28	12.827102
29	13.514300
30	14.236999
31	14.997031
32	15.796326
33	16.575456
34	17.327725
35	18.180182
36	19.003250
37	19.789590
38	20.683663
39	21.537840
40	22.426500
41	23.351034
42	24.223868
43	25.128676
44	26.066630
45	27.038945
46	28.046877
47	28.985548
48	30.064791
49	31.069872
50	32.108030
51	33.059484
52	34.163121
53	35.303077
54	36.347829
55	37.423088
56	38.529746
57	39.668718
58	40.840949
59	41.894696
60	43.131927
61	44.244104
62	45.549938
63	46.723785
64	47.927570
65	49.162057
66	50.428028
67	51.726288
68	53.057658
69	54.225826
70	55.620946
71	56.845049
72	58.306970
73	59.589685
74	60.900392
75	62.239699
76	63.608233
77	65.006629
78	66.435541
79	67.895633
80	69.387587
81	70.655721
82	72.207904
83	73.793958
84	75.142075
85	76.514664
86	78.194697
87	79.622695
88	81.076615
89	82.856196
90	84.368809
91	85.908878
92	87.476902
93	89.073389
94	90.698855
95	92.353825
96	94.038836
97	95.408841
98	97.149306
99	98.921363
100	100.000000
[Moderator's note - added code tags to shrink]
Which ends up looking like this:
Posted Image

I simply wrote the values derived from currentSound := VA_GetVolume() to a csv file as a test - what could have gone wrong? Any suggestions?

Many thanks.

Lexikos
  • Administrators
  • 9441 posts
  • Last active:
  • Joined: 17 Oct 2006

Sounds like a great app but i still cant get it to work correctly. The thing is VA_GETVOLUME() seems to retrieve the wrong volumes when compared to what is detailed by windows mixer,

The APIs I used aren't really intended for simple master volume control. They only allow volume control using decibels (which is non-linear), whereas a more appropriate interface (for master volume only) allows decibels or scalar values (between 0 and 1.)

To use scalar values, I had to find an algorithm to calculate scalar from decibels, and vice versa. Since I had tested it (on "Line Volume") and the results seemed accurate, your results surprise me.

Actually, testing it again, it does exactly what it is supposed to: VA_GetVolume("Speakers") matches up with the volume reported by Speakers Properties (Levels tab.) It is strange that Speakers in Speakers Properties and Speakers in the Volume Mixer differ like that. I guess it's because the Speakers Properties tab uses the same interface and algorithm as I do to convert decibels <-> scalar values, whereas the Volume Mixer does not.

To get to Speakers Properties, right-click the volume tray icon, click Playback Devices, and on the Playback tab, double-click Speakers.

In Vista RTM, the SetMasterVolumeLevelScalar API runs the input volume (from 0.0 to 1.0) through a volume curve to produce a more linear volume experience - it's intended for use in application volume control sliders.

IAudioEndpointVolume value and SndVol not in Sync
(He is referring to the IAudioEndpointVolume interface, which is for master volume control. I use IAudioVolumeLevel, which works for Line In, Microphone, etc.)

Lexikos
  • Administrators
  • 9441 posts
  • Last active:
  • Joined: 17 Oct 2006
I've updated the script, adding the following functions:
VA_GetMasterVolume( [ channel ] )
VA_SetMasterVolume( vol [, channel ] )
VA_GetMasterChannelCount()
VA_GetMasterMute()
VA_SetMasterMute( mute )
These use IAudioEndpointVolume, so they accurately reflect the volume levels reported by Vista's volume mixer.

tuna
  • Members
  • 158 posts
  • Last active: Dec 28 2012 04:50 PM
  • Joined: 03 Oct 2007
Thanks. However oddly enough it still doesnt seem to work too well (though the mute function seems to wrok fine - its just the get and set ones that seem to be having problems). Since you've fixed your code, its probably now something in my code:

COM_CoInitialize() 


currentSound := VA_GetMasterVolume()
; msgbox %currentSound%`n%vol% ;just for testing

wingetactivetitle, programName 
winget, progID, id, %programName% 
progPID := errorlevel

loop, 25
	emptyBar = %EmptyBar%%volBarEmpty%
exit

Display:
currentSound := VA_GetVolume("master", "")
tooltip, Volume (%currentSound%`%): %curr%

presstime = %a_mday%%a_hour%%a_min%%a_sec%
presstime += 2
settimer, splashOff, On
return

ctrl_bn_volume:
g_buttonDown(1, "")

if ctrl_bn_volume = 1
{
	VA_SetMute(1)
	currentSound := VA_GetMasterVolume()
	toolTipmessage = Unmute volume (at %currentSound%`%)
	g_tooltipControl("" , toolTipmessage)
}
	
else
{
	VA_SetMute(0)
	g_tooltipControl("", "Mute volume")
}
return

volumeUp:
currentSound := VA_GetMasterVolume()
currentSound += 1
VA_SetMasterVolume(currentSound) ; Send {Volume_Up 2}

mark = 0
curr = %emptyBar%

loop
{
	mark += 1
	if mark <= %currentSound%
		stringreplace, curr, curr, %volBarEmpty%, %volBarFull%
	else
		break
}

gosub, display
return


volumeDn:
currentSound := VA_GetMasterVolume()
currentSound -= 1
VA_SetMasterVolume(currentSound)

mark = 0
curr = %emptyBar%

loop
{
	mark += 1
	if mark <= %currentSound%
		stringreplace, curr, curr, %volBarEmpty%, %volBarFull%
	else
		break
}

gosub, display
return

Its a bit messy becuase i cut in halfway through the script. Any suggestions?

Many thanks

Lexikos
  • Administrators
  • 9441 posts
  • Last active:
  • Joined: 17 Oct 2006
Perhaps this line:
currentSound := VA_GetVolume("master", "")
On my system, there aren't any volume interfaces with "master" in the name. The master volume interface is called "Speakers". You should probably be using VA_GetMasterVolume(), anyway.

It's probably unrelated, but I guess this:
winget, progID, id, %programName%
progPID := errorlevel
is meant to be:
winget, progID, id, %programName%
winget, progPID, PID, %programName%


tuna
  • Members
  • 158 posts
  • Last active: Dec 28 2012 04:50 PM
  • Joined: 03 Oct 2007
Cheers. Yeah the PID thing was a bit left over from a deleted section. I did another test using the exact same test script with currentSound := VA_GetMasterVolume() instead of VA_GetVolume() and got a set of perfect results. I think you've fixed the problem - just probably something a bit dodgy with my script - ill check it out.

Many thanks.

tuna
  • Members
  • 158 posts
  • Last active: Dec 28 2012 04:50 PM
  • Joined: 03 Oct 2007
After a fine comb i think the suspect is

setformat, float, 0.0

when i remove it from the autoexcecute section, i seem to get a correct value with VA_GETMASTERVOLUME() (though va_getvolume() still doesnt seem to work).

...just in case anyone else is having similar problems.

Lexikos
  • Administrators
  • 9441 posts
  • Last active:
  • Joined: 17 Oct 2006

After a fine comb i think the suspect is

setformat, float, 0.0

Yes, that would do it. VA_GetMasterVolume() retrieves a floating-point value between 0.0 and 1.0. With SetFormat,Float,0.0, this value would be set to either 0 or 1 when it is stored in a variable (since DecimalPlaces is 0.) The return value is volume*100, which would be 0 or 100 (but never something in between.)

(though va_getvolume() still doesnt seem to work).

If it doesn't work at all: Specifying "master" as the component (as in your previous post) is not likely to work; "Speakers" is the name you need. (For mute it is "Master Mute", or a substring like "master".) I explained this in my original post and again in the comments of the script. If the device topology script shows "master" in the VOLUME SUBINITS list, it should work (and you should disregard what I just said.)

If the component name isn't the issue, please be more specific as to the expected and actual effects of VA_GetVolume() in your script.

If it is reporting values that don't match the volume mixer: it isn't supposed to, as previously explained.

Lexikos
  • Administrators
  • 9441 posts
  • Last active:
  • Joined: 17 Oct 2006
New feature:
Detect when sound is playing through the default output device.

Example script:
COM_CoInitialize()
if peakMeter := VA_GetDefaultAudioMeter()
{
    Loop {
        if GetKeyState("End")
            break
        ToolTip % VA_GetPeakValue(peakMeter)  ; display peak value since last call
        Sleep, 100
    }
    COM_Release(peakMeter)
} else
    MsgBox Failed to get peak meter.
COM_CoUninitialize()
(Be sure to update to the latest version of VA.ahk first.)

bmcclure
  • Members
  • 774 posts
  • Last active: Jan 04 2014 10:44 PM
  • Joined: 24 Nov 2007
Hey this works great without needing UAC access!

To clarify, this will only work in Vista, right?

I currently run this if A_OSVersion = WIN_VISTA and run SoundSet otherwise, but I just want to make sure that's necessary.

Thanks for the great functions!

Edit: Maybe I spoke too soon. I seem to be having trouble now with VA_GetMasterVolume returning a blank value. It worked at first, and oddly enough, just stopped working on subsequent script runs.

Edit 2: Now it works again. Hmm. Perhaps just some odd Vista behavior. Seems fine now though.

Lexikos
  • Administrators
  • 9441 posts
  • Last active:
  • Joined: 17 Oct 2006

To clarify, this will only work in Vista, right?

Unfortunately, that is correct.

bmcclure
  • Members
  • 774 posts
  • Last active: Jan 04 2014 10:44 PM
  • Joined: 24 Nov 2007
Here's an OS-independent function that lets you increment, set, or mute/unmute the master volume. It uses SoundGet/SoundSet or your functions, depending on OS type.
SetVol(pSetVol="") {
	If (pSetVol="") {
		curMute := (A_OSVersion = "WIN_VISTA") ? VA_GetMasterMute() : SoundGet("","Mute")
		If (curMute = "On" or curMute = "Off")
			curMute := (curMute = "On") ? 1 : 0
		pSetVol := curMute ? "u" : "m"
	}
	If (SubStr(pSetVol,1,1) = "m") {
		If (A_OSVersion = "WIN_VISTA")
			VA_SetMasterMute(1)
		Else SoundSet,% 1,,Mute
		return "Muted"
	} Else If (SubStr(pSetVol,1,1) = "u") {
		If (A_OSVersion = "WIN_VISTA")
			VA_SetMasterMute(0)
		Else SoundSet,% 0,,Mute
		return "Unmuted"
	} Else {
		curVol := Transform("Round", (A_OSVersion = "WIN_VISTA") ? VA_GetMasterVolume() : SoundGet())
		If (SubStr(pSetVol,1,1) = "+") {
			newVol := ((curVol + SubStr(pSetVol,2)) > 100) ? 100 : curVol + SubStr(pSetVol,2)
		} Else If (SubStr(pSetVol,1,1) = "-") {
			newVol := ((curVol - SubStr(pSetVol,2)) < 0) ? 0 : curVol - SubStr(pSetVol,2)
		} Else If (pSetVol <= 100 and pSetVol >= 0){
			newVol := pSetVol
		} Else Return "Error"
		If (A_OSVersion = "WIN_VISTA")
			VA_SetMasterVolume(newVol)
		Else SoundSet %newVol%
		Return newVol
	} 
}

Note: requires Titan's AHK functions and SoundGet and Transform. Otherwise it can be easily modified to use AHK's base commands

Pass nothing to toggle mute on and off - SetVol()
Pass "u" or "m" or "unmute" or "mute" to unmute or mute - SetVol("m")
Pass a +num or -num to increment the volume - SetVol("-5")
Pass a number between 1 and 100 to set the volume - SetVol(75)

Function will return either the new volume, "Muted"/"Unmuted", or "Error"