VBA code to turn volume on, up, down

Kerry Newman

New Member
Joined
Feb 23, 2018
Messages
19
Office Version
  1. 365
  2. 2019
Platform
  1. Windows
I am trying to find some code to turn my speaker volume on, up or down.
I am using the Speak function if that has any relevance...... thanks!
 
Thanks! I wanted to set both Left and Right so that I could adjust the balance. Like: APPCOMMAND_VOLUME_SET_LEFT_RIGHT.
I was so excited to find "SoundVolumeView" - they found what actually works. I used their command line version in the end.
Thanks for the feedabck and happy you found a solution.
 
Upvote 0

Excel Facts

Excel Can Read to You
Customize Quick Access Toolbar. From All Commands, add Speak Cells or Speak Cells on Enter to QAT. Select cells. Press Speak Cells.
In case anyone is looking for an answer in the future, here is a solution for muting, umuting, setting and reading the volume of the system default audio. This approach works in Windows Vista or higher w/o relying on unreliable keyboard strokes.

Workbook Demo: CoreAudio.xlsm

The code doesn't depend on any external exes or typelibs... The code is entirely based on plain vba and a few low-level VTable calls @runtime on the IMMDeviceEnumerator, IMMDevice and IAudioEndpointVolume Interfaces.


Sanaaaaaaaaaaaaaaas titre.png



1- Class Module : CAudio
VBA Code:
Option Explicit

Private Enum VOL_ACTION
    ºSetVol
    ºGetVol
    ºMute
    ºUnMute
    ºIsMuteState
End Enum

#If Win64 Then
    Private Const NULL_PTR = 0^
    Private Const PTR_SIZE = 8&
#Else
    Private Const NULL_PTR = 0&
    Private Const PTR_SIZE = 4&
#End If

Private Type GUID
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(0& To 7&) As Byte
End Type

#If VBA7 Then
    Private Declare PtrSafe Sub SetLastError Lib "Kernel32.dll" (ByVal dwErrCode As Long)
    Private Declare PtrSafe Function DispCallFunc Lib "OleAut32.dll" (ByVal pvInstance As LongPtr, ByVal offsetinVft As LongPtr, ByVal CallConv As Long, ByVal retTYP As Integer, ByVal paCNT As Long, ByRef paTypes As Integer, ByRef paValues As LongPtr, ByRef retVAR As Variant) As Long
    Private Declare PtrSafe Function IIDFromString Lib "ole32.dll" (ByVal lpsz As LongPtr, ByRef lpiid As Any) As Long
    Private Declare PtrSafe Function CoCreateInstance Lib "ole32" (ByRef rclsid As GUID, ByVal pUnkOuter As LongPtr, ByVal dwClsContext As Long, ByRef riid As GUID, ByRef ppv As LongPtr) As Long
    Private Declare PtrSafe Function CLSIDFromString Lib "ole32" (ByVal OleStringCLSID As LongPtr, ByRef cGUID As Any) As Long
#Else
    Private Enum LongPtr
        [_]
    End Enum
    Private Declare Sub SetLastError Lib "Kernel32.dll" (ByVal dwErrCode As Long)
    Private Declare Function DispCallFunc Lib "OleAut32.dll" (ByVal pvInstance As LongPtr, ByVal offsetinVft As LongPtr, ByVal CallConv As Long, ByVal retTYP As Integer, ByVal paCNT As Long, ByRef paTypes As Integer, ByRef paValues As LongPtr, ByRef retVAR As Variant) As Long
    Private Declare Function IIDFromString Lib "ole32.dll" (ByVal lpsz As LongPtr, ByRef lpiid As Any) As Long
    Private Declare Function CoCreateInstance Lib "ole32" (ByRef rclsid As GUID, ByVal pUnkOuter As LongPtr, ByVal dwClsContext As Long, ByRef riid As GUID, ByRef ppv As LongPtr) As Long
    Private Declare Function CLSIDFromString Lib "ole32" (ByVal OleStringCLSID As LongPtr, ByRef cGUID As Any) As Long
#End If


' _________________________________________PUBLIC CLASS METHODS _____________________________________

Public Sub Mute(Optional ByVal bMute As Boolean = True)
    If bMute Then
        Audio ºMute
    Else
        Audio ºUnMute
    End If
End Sub

Public Sub SeVol(ByVal VolLevel As Single)
    Audio ºSetVol, VolLevel
End Sub

Public Function GetVol() As Single
    GetVol = Audio(ºGetVol)
End Function

Public Function IsMuteState() As Boolean
    IsMuteState = Audio(ºIsMuteState)
End Function



' _________________________________________PRIVATE HELPER ROUTINES _____________________________________

Private Function Audio(eAction As VOL_ACTION, Optional VolLevel As Single = -1&) As Single

    Const CLSID_MMDeviceEnumerator = "{BCDE0395-E52F-467C-8E3D-C4579291692E}"
    Const IID_IMMDeviceEnumerator = "{A95664D2-9614-4F35-A746-DE8DB63617E6}"
    Const IID_IAudioEndpointVolume = "{5CDF2C82-841E-4546-9722-0CF74078229A}"
    Const IID_NULL = "{00000000-0000-0000-0000-000000000000}"
    Const CLSCTX_INPROC_SERVER = 1&
    Const CC_STDCALL = 4&
   
    Dim tClsID As GUID, tIID As GUID
    Dim pDeviceEnumerator As LongPtr, pdefaultDevice As LongPtr, pIAudioEndpointVolume As LongPtr
    Dim eRender As Long, eMultimedia As Long
    Dim lRet As Long
   
    If VolLevel <> -1& Then
        If VolLevel < 0& Or VolLevel > 1& Then
            MsgBox "Audio-tapered value must be in the range from 0.0 to 1.0"
            Exit Function
        End If
    End If

    lRet = CLSIDFromString(StrPtr(CLSID_MMDeviceEnumerator), tClsID)
    lRet = IIDFromString(StrPtr(IID_IMMDeviceEnumerator), tIID)

    'Create an enumerator for the audio endpoint devices
    lRet = CoCreateInstance(tClsID, NULL_PTR, CLSCTX_INPROC_SERVER, tIID, pDeviceEnumerator)
    If lRet Then MsgBox "Failed to get IMMDeviceEnumerator.": Exit Function
 
    eRender = 0&: eMultimedia = 1&
    'IMMDeviceEnumerator::GetDefaultAudioEndpoint Method.
    lRet = vtblCall(pDeviceEnumerator, 4& * PTR_SIZE, vbLong, CC_STDCALL, eRender, eMultimedia, VarPtr(pdefaultDevice))
    If lRet Then MsgBox "Failed to get IMMDevice.": Exit Function
 
    lRet = IIDFromString(StrPtr(IID_IAudioEndpointVolume), tIID)
    'IMMDevice::Activate Method.
    lRet = vtblCall(pdefaultDevice, 3& * PTR_SIZE, vbLong, CC_STDCALL, VarPtr(tIID), CLSCTX_INPROC_SERVER, 0&, VarPtr(pIAudioEndpointVolume))
    If lRet Then MsgBox "Failed to get IAudioEndpointVolume.": Exit Function

    lRet = IIDFromString(StrPtr(IID_NULL), tIID)
   
    Select Case eAction
        Case ºMute
            'IAudioEndpointVolume::SetMute Method.(True)
            lRet = vtblCall(pIAudioEndpointVolume, 14& * PTR_SIZE, vbLong, CC_STDCALL, 1&, VarPtr(tIID))
        Case ºUnMute
            'IAudioEndpointVolume::SetMute Method. (False)
            lRet = vtblCall(pIAudioEndpointVolume, 14& * PTR_SIZE, vbLong, CC_STDCALL, 0&, VarPtr(tIID))
        Case ºSetVol
            'IAudioEndpointVolume::SetMasterVolumeLevelScalar Method.
            lRet = vtblCall(pIAudioEndpointVolume, 7& * PTR_SIZE, vbLong, CC_STDCALL, CSng(VolLevel), VarPtr(tIID))
        Case ºGetVol
            'IAudioEndpointVolume::GetMasterVolumeLevelScalar Method.
            lRet = vtblCall(pIAudioEndpointVolume, 9& * PTR_SIZE, vbLong, CC_STDCALL, VarPtr(Audio))
        Case ºIsMuteState
            'IAudioEndpointVolume::GetMute Method.
            lRet = vtblCall(pIAudioEndpointVolume, 15& * PTR_SIZE, vbLong, CC_STDCALL, VarPtr(Audio))
    End Select
 
    'Release Interfaces.
    lRet = vtblCall(pIAudioEndpointVolume, 2& * PTR_SIZE, vbLong, CC_STDCALL)
    lRet = vtblCall(pdefaultDevice, 2& * PTR_SIZE, vbLong, CC_STDCALL)
    lRet = vtblCall(pDeviceEnumerator, 2& * PTR_SIZE, vbLong, CC_STDCALL)

End Function


Private Function vtblCall(ByVal InterfacePointer As LongPtr, ByVal VTableOffset As Long, ByVal FunctionReturnType As Long, ByVal CallConvention As Long, ParamArray FunctionParameters() As Variant) As Variant

    Dim vParamPtr() As LongPtr

    If InterfacePointer = 0& Or VTableOffset < 0& Then Exit Function
    If Not (FunctionReturnType And &HFFFF0000) = 0& Then Exit Function

    Dim pIndex As Long, pCount As Long
    Dim vParamType() As Integer
    Dim vRtn As Variant, vParams() As Variant

    vParams() = FunctionParameters()
    pCount = Abs(UBound(vParams) - LBound(vParams) + 1&)
    If pCount = 0& Then
        ReDim vParamPtr(0& To 0&)
        ReDim vParamType(0& To 0&)
    Else
        ReDim vParamPtr(0& To pCount - 1&)
        ReDim vParamType(0& To pCount - 1&)
        For pIndex = 0& To pCount - 1&
            vParamPtr(pIndex) = VarPtr(vParams(pIndex))
            vParamType(pIndex) = VarType(vParams(pIndex))
        Next
    End If

    pIndex = DispCallFunc(InterfacePointer, VTableOffset, CallConvention, FunctionReturnType, pCount, _
    vParamType(0&), vParamPtr(0&), vRtn)
    If pIndex = 0& Then
        vtblCall = vRtn
    Else
        SetLastError pIndex
    End If

End Function



2- Code Usage example ( UserFormm Module )
VBA Code:
Option Explicit

Private oAudio As CAudio

Private Sub UserForm_Initialize()
    Set oAudio = New CAudio
    ScrollBar1.Min = 0
    ScrollBar1.Max = 100
    ScrollBar1.value = oAudio.GetVol * 100&
    CheckBox1.value = oAudio.IsMuteState
    Label1.Caption = "Vol:  [ " & oAudio.GetVol * 100 & " ]"
End Sub

Private Sub UserForm_Terminate()
    Set oAudio = Nothing
End Sub

Private Sub CheckBox1_Change()
    oAudio.Mute CheckBox1.value
End Sub

Private Sub ScrollBar1_Change()
    oAudio.SeVol ScrollBar1.value / 100&
    Label1.Caption = "Vol:  [ " & oAudio.GetVol * 100 & " ]"
End Sub

Private Sub ScrollBar1_Scroll()
    oAudio.SeVol ScrollBar1.value / 100&
    Label1.Caption = "Vol:  [ " & oAudio.GetVol * 100 & " ]"
End Sub
 
Upvote 0
Umm... wow... where do I start?!

First of all, thank you for this. I was obviously not using the correct keywords when doing my searches. I've loaded that code into a workbook and it didn't like Private Enum LongPtr [_] End Enum. I'm guessing this is for backward compatibility with older versions of VBA? In any case, it was happier with that enumeration removed.

I got the userform working - that was (relatively, for me) - easy, and after some wrangling I managed to incorporate .SeVol, .GetVol, .Mute, .UnMute and .IsMuteState into my own code.

So thank you. I would never have come up with anything like that on my own. In fact, I don't understand most of it!

Best wishes from a very rainy West Country (of England).
 
Upvote 0
@Ruddles
I've loaded that code into a workbook and it didn't like Private Enum LongPtr [_] End Enum. I'm guessing this is for backward compatibility with older versions of VBA?
Yes, that's there for office 2007 or earlier but you can just ignore it and leave it as is as it won't compile in later versions.

Glad you got it working and thanks for the feedback.
 
Upvote 0
Thanks! I wanted to set both Left and Right so that I could adjust the balance. Like: APPCOMMAND_VOLUME_SET_LEFT_RIGHT.
I was so excited to find "SoundVolumeView" - they found what actually works. I used their command line version in the end.
Thanks, this alleviate me from installing App which I don't mind paying but after
(1) experiencing the hassle of reinstall after a PC reset which requires downloading of Apps or use a Paid Backup Tool
(2) feeling Web is becoming more important me prefer an Edge Extension.

Unfortunately, there is no Edge Extension for this and so I am using VBA while waiting.

What I need is a choice of 3 Audio Volume Setting: 60%, 70%, 80% Is it possible ?
 
Upvote 0
What I need is a choice of 3 Audio Volume Setting: 60%, 70%, 80% Is it possible ?
Have you tried uing the CAudio Class I posted in post#12 ?

Something like this should set the system volume to 60% :

oAudio.SeVol 0.6

Hope this helps.
 
Upvote 0

Forum statistics

Threads
1,223,886
Messages
6,175,196
Members
452,616
Latest member
intern444

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top