Page 2 of 3

Re: Get/Set Sound volume level programmatically

Posted: Sat Feb 09, 2013 6:11 pm
by luis
netmaestro wrote:... and my wife is very impressed.
:)

Thanks for sharing the result. Any idea if this works for a limited account too ? After all it's changing a system wide setting.

Re: Get/Set Sound volume level programmatically

Posted: Sat Feb 09, 2013 7:09 pm
by netmaestro
You raise a good point, one I confess I didn't think of :oops: I logged out of my admin account and logged in as guest. I was unable to change any files, though I could read them and I wasn't allowed to change the system time. However, I was allowed to mute the speakers. I did that and then ran the QuickAlarm program. When the alarm time came it successfully turned on the speakers and turned them up, so I'm going to assume that user privilege level isn't going to affect it. Thanks for the heads up!

Re: Get/Set Sound volume level programmatically

Posted: Sat Feb 09, 2013 9:10 pm
by luis
That's good to know thank you :wink:

Re: Get/Set Sound volume level programmatically

Posted: Sun Feb 10, 2013 12:29 pm
by Joris
netmaestro wrote:@Joris: Thanks, I'll encase the new sound stuff in a CompilerIf block for the windows version to prevent crashes and include a note in the About box saying that for XP and earlier it won't force the sound.
That would be nice.

Quest: Speaker Output VU Meter - Who know how?

Posted: Thu Jul 18, 2013 7:40 pm
by minimy
Very good topic!
Someone knows how to get the values ​​of the speaker output.
volume changes in the sound as a vumeter.
I saw a topic, very good indeed, that of metergadget, but only talk about the mic input and output nothing about.
sourceforge is an example in the Core Audio API, but is in C.
You can use coreaudioapi.dll with PureBasic?
I think that's the way you and I see you know a lot about.
Can anyone help?

Re: Get/Set Sound volume level programmatically

Posted: Tue May 06, 2014 1:31 am
by DarkRookie
Saw this and thought I could use it. Tried code in DEMO 5.21, but it is not working.
Get the following error
Image

Is this a limitation of the demo version?

Re: Get/Set Sound volume level programmatically

Posted: Tue May 06, 2014 2:27 am
by TI-994A
DarkRookie wrote:Is this a limitation of the demo version?
Hi DarkRookie. Yes, it is. The demo version does not support constants, interfaces or structures, and there're no predefined API functions.

Re: Get/Set Sound volume level programmatically

Posted: Sun May 05, 2024 2:42 am
by BarryG
I'm getting an occasional crash ("Access violation") with this procedure on the "hr=defaultDevice\[...]" line:

Code: Select all

Procedure GetEndPointVolume(*endpointvolume)
  Protected deviceEnumerator.IMMDeviceEnumerator
  Protected hr,defaultDevice.IMMDevice
  CoInitialize_(#Null)
  hr=CoCreateInstance_(?uuidof_MMDeviceEnumerator,#Null,#CLSCTX_INPROC_SERVER,?uuidof_IMMDeviceEnumerator,@deviceEnumerator)
  hr=deviceEnumerator\GetDefaultAudioEndpoint(0,1,@defaultDevice)
  deviceEnumerator\release()
  hr=defaultDevice\Activate(?uuidof_IAudioEndpointVolume,#CLSCTX_INPROC_SERVER,#Null,*endpointVolume) ; <<< CRASH!
  defaultDevice\release()
  ProcedureReturn *endpointvolume
EndProcedure
Is the variable "hr" meant to be of ".i" type maybe? The crash doesn't happen all the time so I can't test if ".i" will make a difference. Windows 11 Pro.

Re: Get/Set Sound volume level programmatically

Posted: Sun May 05, 2024 4:38 am
by idle
maybe you should check the return value hr to see if it got the defaultDevice interface

Code: Select all

Procedure GetEndPointVolume(*endpointvolume)
  Protected deviceEnumerator.IMMDeviceEnumerator
  Protected hr, defaultDevice.IMMDevice
  
  CoInitialize_(#Null)
 
  hr = CoCreateInstance_(?uuidof_MMDeviceEnumerator, #Null, #CLSCTX_INPROC_SERVER, ?uuidof_IMMDeviceEnumerator,@deviceEnumerator);#CLSCTX_ALL
  If hr = 0
    hr = deviceEnumerator\GetDefaultAudioEndpoint(0, 1, @defaultDevice)
    deviceEnumerator\Release()
    If hr = 0 
      hr = defaultDevice\Activate(?uuidof_IAudioEndpointVolume, #CLSCTX_INPROC_SERVER, #Null, *endpointVolume);
      defaultDevice\release()
    EndIf 
  EndIf   
  ProcedureReturn *endpointvolume
EndProcedure

Re: Get/Set Sound volume level programmatically

Posted: Sun May 05, 2024 6:25 am
by BarryG
Thanks, Idle! My Win 11 laptop does have some sound issues so I will use your error-checking version and see how it goes.

Re: Get/Set Sound volume level programmatically

Posted: Tue Jun 11, 2024 2:58 pm
by pthien
netmaestro wrote: Sat Feb 09, 2013 8:10 am All replies are much appreciated. The code from ts-soft works well but misses a couple of procedures, namely MediaGetMute() and MediaSetMute(), which if were included would make it perfect for my needs. I really don't need to support XP and earlier anyway and it would be a fair amount of work to put an include together that would serve both XP and Vista+ equally well. So I added the needed procs to ts-soft's code and now I have a complete working solution, which I have implemented in my alarm clock and now it's "mute-proof" and my wife is very impressed.

This is my SoundControls.pbi, most of it by ts-soft:

Code: Select all

#CLSCTX_INPROC_SERVER  = $01
#CLSCTX_INPROC_HANDLER = $02
#CLSCTX_LOCAL_SERVER   = $04
#CLSCTX_REMOTE_SERVER  = $10

#CLSCTX_ALL    = #CLSCTX_INPROC_SERVER|#CLSCTX_INPROC_HANDLER|#CLSCTX_LOCAL_SERVER|#CLSCTX_REMOTE_SERVER
#CLSCTX_INPROC = #CLSCTX_INPROC_SERVER|#CLSCTX_INPROC_HANDLER
#CLSCTX_SERVER = #CLSCTX_INPROC_SERVER|#CLSCTX_LOCAL_SERVER|#CLSCTX_REMOTE_SERVER

Interface IMMDeviceEnumerator Extends IUnknown
  EnumAudioEndpoints(dataFlow, dwStateMask, *ppDevices)
  GetDefaultAudioEndpoint(dataFlow, role, ppEndpoint)
  GetDevice(pwstrId, ppDevice)
  RegisterEndpointNotificationCallback(pClient)
  UnregisterEndpointNotificationCallback(pClient)
EndInterface

Interface IAudioEndpointVolume Extends IUnknown
  RegisterControlChangeNotify( *pNotify)
  UnregisterControlChangeNotify( *pNotify)
  GetChannelCount( *pnChannelCount)
  SetMasterVolumeLevel( fLevelDB.f)
  SetMasterVolumeLevelScalar( fLevel.f,pguidEventContext)
  GetMasterVolumeLevel(*pfLevelDB)
  GetMasterVolumeLevelScalar(*pfLevel)
  SetChannelVolumeLevel(nChannel,fLevelDB.f,pguidEventContext)
  SetChannelVolumeLevelScalar( nChannel,fLevel.f,pguidEventContext)
  GetChannelVolumeLevel( nChannel,*pfLevelDB.f)
  GetChannelVolumeLevelScalar( nChannel,*pfLevel.f)
  SetMute( bMute, pguidEventContext)
  GetMute( *pbMute)
  GetVolumeStepInfo( *pnStep, *pnStepCount)
  VolumeStepUp( pguidEventContext)
  VolumeStepDown( pguidEventContext)
  QueryHardwareSupport( *pdwHardwareSupportMask)
  GetVolumeRange( *pflVolumeMindB, *pflVolumeMaxdB, *pflVolumeIncrementdB)
EndInterface

Interface IMMDevice Extends IUnknown
  Activate(iid, dwClsCtx, pActivationParams, ppInterface);
  OpenPropertyStore( stgmAccess, ppProperties);
  GetId(ppstrId);
  GetState(pdwState);
EndInterface

Procedure GetEndPointVolume(*endpointvolume)
  Protected deviceEnumerator.IMMDeviceEnumerator
  Protected hr, defaultDevice.IMMDevice
  
  CoInitialize_(#Null)
  
  hr = CoCreateInstance_(?uuidof_MMDeviceEnumerator, #Null, #CLSCTX_INPROC_SERVER, ?uuidof_IMMDeviceEnumerator,@deviceEnumerator);#CLSCTX_ALL
  
  hr = deviceEnumerator\GetDefaultAudioEndpoint(0, 1, @defaultDevice)
  deviceEnumerator\Release()
  
  hr = defaultDevice\Activate(?uuidof_IAudioEndpointVolume, #CLSCTX_INPROC_SERVER, #Null, *endpointVolume);
  defaultDevice\release()
  
  ProcedureReturn *endpointvolume
EndProcedure

Procedure FreeEndPointVolume(*endpointvolume.IAudioEndpointVolume) 
  *endpointvolume\release()
  CoUninitialize_()
EndProcedure

Procedure MediaGetVolume()
  Protected Volume.IAudioEndpointVolume
  Protected volf.f
  
  GetEndPointVolume(@Volume)
  Volume\GetMasterVolumeLevelScalar(@volf)
  volf = Round(volf * 100, #PB_Round_Nearest)
  FreeEndPointVolume(Volume)
  ProcedureReturn Int(volf)
EndProcedure

Procedure MediaGetMute()
  Protected Volume.IAudioEndpointVolume
  Protected mute.i
  GetEndPointVolume(@Volume)
  Volume\GetMute(@mute)
  FreeEndPointVolume(Volume)
  ProcedureReturn mute
EndProcedure

Procedure MediaSetVolume(vol)
  Protected Volume.IAudioEndpointVolume
  Protected volf.f
  If vol < 0 : vol = 0 : EndIf
  If vol > 100 : vol = 100 : EndIf
  GetEndPointVolume(@Volume)
  volf = vol / 100
  Volume\SetMasterVolumeLevelScalar(volf, #Null)
  FreeEndPointVolume(Volume)
EndProcedure

Procedure MediaSetMute(value)
  Protected Volume.IAudioEndpointVolume
  Protected mute.i=1
  GetEndPointVolume(@Volume)
  Volume\SetMute(value, #Null)
  FreeEndPointVolume(Volume)
EndProcedure

DataSection
  uuidof_IAudioEndpointVolume:
  Data.l $5CDF2C82
  Data.w $841E,$4546
  Data.b $97,$22,$0C,$F7,$40,$78,$22,$9A
  
  uuidof_MMDeviceEnumerator:
  Data.l $BCDE0395
  Data.w $E52F,$467C
  Data.b $8E,$3D,$C4,$57,$92,$91,$69,$2E
  
  uuidof_IMMDeviceEnumerator:
  Data.l $A95664D2
  Data.w $9614
  Data.w $4F35
  Data.b $A7,$46,$DE,$8D,$B6,$36,$17,$E6
  
EndDataSection 

; Test prog: Set volume to 10% and mute the speakers, this should play loudly anyway...
If MediaGetMute()
  MediaSetMute(0)
EndIf
MediaSetVolume(100)
Beep_(2500,500)
This code only seems to actually set mute, if I've already done so using the mute key on my keyboard. That is, if I reboot and use the MediaSetMute(1) function, the audio is not muted. If, OTOH, I mute and then unmute the audio via my keyboard, THEN the MediaSetMute(1) seems to work fine.

Any ideas?

Re: Get/Set Sound volume level programmatically

Posted: Sat Feb 22, 2025 8:43 am
by BarryG
The code here (in this topic) no longer compiles with PureBasic 6.20 -> https://www.purebasic.fr/english/viewto ... 65#p403765

It's by ts-soft. If you're here, can you maybe fix it, please? The error -> "Line 30: Native types can't be used with pointers."

Re: Get/Set Sound volume level programmatically

Posted: Sat Feb 22, 2025 9:12 am
by Fred
Just remove the type and it should work

Re: Get/Set Sound volume level programmatically

Posted: Sat Feb 22, 2025 1:56 pm
by BarryG
Oh, I see. I did that and it works! Thanks, Fred. :) I originally didn't know what that error message meant.

Old lines:

Code: Select all

GetChannelVolumeLevel(nChannel,*pfLevelDB.f)
GetChannelVolumeLevelScalar(nChannel,*pfLevel.f)
New lines:

Code: Select all

GetChannelVolumeLevel(nChannel,*pfLevelDB)
GetChannelVolumeLevelScalar(nChannel,*pfLevel)

Re: Get/Set Sound volume level programmatically

Posted: Sun May 11, 2025 1:24 am
by BarryG
Just a heads-up: if your PC does not have a sound card, or if it's disabled in Device Manager, then the below crash will occur. Took me forever to work out this problem - who would've guessed that some PCs run without audio! :( So now I just need a reliable way to detect if a sound card is present or enabled so I can prevent this crash occurring. Anyone know?

Code: Select all

Procedure MediaGetVolume()
  Protected Volume.IAudioEndpointVolume
  Protected volf.f
  GetEndPointVolume(@Volume)
  Volume\GetMasterVolumeLevelScalar(@volf) ; Invalid access 0x3221225477 due to no sound card.
  volf=Round(volf*100,#PB_Round_Nearest)
  FreeEndPointVolume(Volume)
  ProcedureReturn Int(volf)
EndProcedure