Jump to content

Windows 7 Peak Volume - C++ Question

Recommended Posts

My Knoweledge of c++ is extremely limited, so i thought i would release this question here as this is the c++ forum ^^.

The code below displays a GUI with a progress bar that varys depending on the volume level. Louder it is, higher the bar. Quiter it is, lower the bar.

I want to make a auto-volume control, so when the peak goes above a set level it would lower or raise it. The problem is, as far as i can tell this code only gets the volume level of the application running. I would like to get the master volume, so when the master volume is lowered then the peak would be lowered.

From my understanding atm,when the code is run it displays the peak of "B". As if i lower/raise that slider, the peak is changed. I would like to read the peak from "A". So in that example, i could see the peak is much higher then the set volume, and for it to be raised.

So i was wondering if there is someone who does understand how this works could help me change it to the desired results.



#include <GuiConstants.au3>
#include <ProgressConstants.au3>
Global Const $S_OK = 0
#interface "IMMDeviceEnumerator"
Global Const $sCLSID_MMDeviceEnumerator = "{BCDE0395-E52F-467C-8E3D-C4579291692E}"
Global Const $sIID_IMMDeviceEnumerator = "{A95664D2-9614-4F35-A746-DE8DB63617E6}"
; Definition
Global Const $tagIMMDeviceEnumerator = "EnumAudioEndpoints hresult(dword;dword;ptr*);" & _
"GetDefaultAudioEndpoint hresult(dword;dword;ptr*);" & _
"GetDevice hresult(wstr;ptr*);" & _
"RegisterEndpointNotificationCallback hresult(ptr);" & _
"UnregisterEndpointNotificationCallback hresult(ptr);"
#interface "IMMDevice"
Global Const $sIID_IMMDevice = "{D666063F-1587-4E43-81F1-B948E807363F}"
; Definition
Global Const $tagIMMDevice = "Activate hresult(clsid;dword;variant*;ptr*);" & _
"OpenPropertyStore hresult(dword;ptr*);" & _
"GetId hresult(ptr*);" & _
"GetState hresult(dword*);"
#interface "IAudioMeterInformation"
Global Const $sIID_IAudioMeterInformation = "{C02216F6-8C67-4B5B-9D00-D008E73E0064}"
; Definition
Global Const $tagIAudioMeterInformation = "GetPeakValue hresult(float*);" & _
"GetMeteringChannelCount hresult(dword*);" & _
"GetChannelsPeakValues hresult(dword;float*);" & _
"QueryHardwareSupport hresult(dword*);"

Global $oAudioMeterInformation = _AudioVolObject()
If Not IsObj($oAudioMeterInformation) Then Exit -1 ; Will happen on non-supported systems
Global $hGUI
Global $hControl = _MakePeakMeterInWindow($hGUI)
; Register function to periodically update the progress control
AdlibRegister("_LevelMeter", 45)

; Bye, bye...

Func _MakePeakMeterInWindow($hWindow)
$hWindow = GUICreate("ABC", 150, 400)
Return GUICtrlCreateProgress(20, 70, 15, 200, $PBS_VERTICAL)
Func _LevelMeter()
Local $iPeak
If $oAudioMeterInformation.GetPeakValue($iPeak) = $S_OK Then
$iCurrentRead = 100 * $iPeak
GUICtrlSetData($hControl, $iCurrentRead + 1)
GUICtrlSetData($hControl, $iCurrentRead)
Func _AudioVolObject()
; Sequences of code below are taken from the source of plugin written for AutoIt for setting master volume on Vista and above systems.
; Code was written by wraithdu in C++.
; MMDeviceEnumerator
Local $oMMDeviceEnumerator = ObjCreateInterface($sCLSID_MMDeviceEnumerator, $sIID_IMMDeviceEnumerator, $tagIMMDeviceEnumerator)
If @error Then Return SetError(1, 0, 0)
Local Const $eRender = 0
Local Const $eConsole = 0
; DefaultAudioEndpoint
Local $pDefaultDevice
$oMMDeviceEnumerator.GetDefaultAudioEndpoint($eRender, $eConsole, $pDefaultDevice)
If Not $pDefaultDevice Then Return SetError(2, 0, 0)
; Turn that pointer into object
Local $oDefaultDevice = ObjCreateInterface($pDefaultDevice, $sIID_IMMDevice, $tagIMMDevice)
; AudioMeterInformation
Local $pAudioMeterInformation
$oDefaultDevice.Activate($sIID_IAudioMeterInformation, $CLSCTX_INPROC_SERVER, 0, $pAudioMeterInformation)
If Not $pAudioMeterInformation Then Return SetError(3, 0, 0)
Return ObjCreateInterface($pAudioMeterInformation, $sIID_IAudioMeterInformation, $tagIAudioMeterInformation)

Original Post

Microsoft MSDM


Edited by IanN1990
Link to post
Share on other sites

@Wraithdu I read your reply and it did help me understand a few things. So i will amend my original post.

I wasn't sure which topic to reply to, and i guess in that sense i see what you mean by cross posting but that wasn't my goal.

Considering Posting new code on a Thread labelled "March 2012" as necroing. The original poster for that thread has not been on-line for a while and only has 5 posts. Plus the only answer available is related to c++ rather then general help / support within auto it. Which is why I felt it would be best to start fresh here. Maybe I was in the wrong.

Link to post
Share on other sites

I read your post, and i tell you what. I think you have solved this problem.

I increased the slider to 100% and I did notice the grey bar disappears. Meaning my original question becomes invalid, so i had to rethink how i would write the question to still achive the end result. I also noticed when the main-volume is turned up or down both green bars change respectively *Even in the example I now see both bars are exactly level*. So getting the App Volume or Main Volume would make no difference. I approached this whole problem the wrong way round.

Then it hit me, in the code the $peak is times 100. What if this value was timed by the master volume level ? and sure enough this gives the result I am after.

#include <_AudioEndpointVolume.au3>

Local $pDefaultDevice
local $pAudioMeterInformation
Local $oAudioMeterInformation = _AudioVolObject()

$hWindow = GUICreate("ABC", 150, 400)
$hControl = GUICtrlCreateProgress(20, 70, 15, 200, 4)

AdlibRegister("_LevelMeter", 125)

while 1

Func _LevelMeter()
Local $iPeak

$iPeak *= _GetMasterVolumeLevelScalar()
GUICtrlSetData($hControl, $iPeak)
ConsoleWrite($iPeak & @CRLF)

If $iPeak < 30 then Send("{Volume_UP}")
If $iPeak > 35 then Send("{Volume_Down}")


Func _AudioVolObject()
Local $oMMDeviceEnumerator = ObjCreateInterface("{BCDE0395-E52F-467C-8E3D-C4579291692E}", "{A95664D2-9614-4F35-A746-DE8DB63617E6}", "EnumAudioEndpoints hresult(dword;dword;ptr*);GetDefaultAudioEndpoint hresult(dword;dword;ptr*);" )
$oMMDeviceEnumerator.GetDefaultAudioEndpoint(0, 0, $pDefaultDevice)

Local $oDefaultDevice = ObjCreateInterface($pDefaultDevice, "{D666063F-1587-4E43-81F1-B948E807363F}", "Activate hresult(clsid;dword;variant*;ptr*);")
$oDefaultDevice.Activate("{C02216F6-8C67-4B5B-9D00-D008E73E0064}", 0x1, 0, $pAudioMeterInformation)

Return ObjCreateInterface($pAudioMeterInformation, "{C02216F6-8C67-4B5B-9D00-D008E73E0064}", "GetPeakValue hresult(float*);")

I have yet to really test to code, as i only came up with this idea a few minutes "and am quite excited as well, 4 days with no results and then a break though ^^" but i hope it will turn out well

Requires _AudioEndpointVolume.au3

Works on Windows 7

Edited by IanN1990
Link to post
Share on other sites

It works as long as the channel volume matches the master volume, since all this code is dealing with the master volume endpoint. Otherwise you need to be able to get the channel volume as well so you can get the proper ratio. But yeah, you're definitely on the right track.

Though I'm not sure just multiplying by the master volume level is correct. The peak value is multiplied by 100 because it is a float value between 0 and 1, and you need *100 to get a 'percentage' value from 0 to 100.

So thinking about this again... you're not really interested in the channel volume at all right? So the original code is actually what you're after... the master output peak volume.

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Create New...