Get/Set Sound volume level programmatically

Just starting out? Need help? Post your questions and find answers here.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Get/Set Sound volume level programmatically

Post by netmaestro »

On Windows, does someone know how a running program can:

- See if the volume is muted or not
- Mute/Unmute volume from software
- Adjust volume level up or down

There's got to be an API for that, I just have no idea where to look.
BERESHEIT
Joris
Addict
Addict
Posts: 890
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: Get/Set Sound volume level programmatically

Post by Joris »

I have been doing some stuff for that in GFA32 years ago.
Here a the most important declares I needed when being bussy on this.
It is really a mess to figure out how the MS-audio-mixer works I still remember.
I was using this when I was still on Win98, so I don't know what all might be changed.
If you Google for "mixerGetControlDetails" you'll get easy to the MSDN pages for more info on all these.
Another place that existed then was : http://www.borg.com/~jglatt/tech/mixer.htm (seems to be changed now).

The GFA32 style declares :

Code: Select all

'***********************************************************************************************
Declare Function mixerClose Lib "winmm.dll" Alias "mixerClose" (ByVal hmx As Long) As Long
Declare Function mixerGetControlDetails Lib "winmm.dll" Alias "mixerGetControlDetailsA" (ByVal hmxobj As Long, ByRef pmxcd As MIXERCONTROLDETAILS, ByVal fdwDetails As Long) As Long
Declare Function mixerGetDevCaps Lib "winmm.dll" Alias "mixerGetDevCapsA" (ByVal uMxId As Long, ByRef pmxcaps As MIXERCAPS, ByVal cbmxcaps As Long) As Long
Declare Function mixerGetID Lib "winmm.dll" Alias "mixerGetID" (ByVal hmxobj As Long, pumxID As Long, ByVal fdwId As Long) As Long
Declare Function mixerGetLineControls Lib "winmm.dll" Alias "mixerGetLineControlsA" (ByVal hmxobj As Long, ByRef pmxlc As MIXERLINECONTROLS, ByVal fdwControls As Long) As Long
Declare Function mixerGetLineInfo Lib "winmm.dll" Alias "mixerGetLineInfoA" (ByVal hmxobj As Long, ByRef pmxl As MIXERLINE, ByVal fdwInfo As Long) As Long
Declare Function mixerGetNumDevs Lib "winmm.dll" Alias "mixerGetNumDevs" () As Long
Declare Function mixerMessage Lib "winmm.dll" Alias "mixerMessage" (ByVal hmx As Long, ByVal uMsg As Long, ByVal dwParam1 As Long, ByVal dwParam2 As Long) As Long
Declare Function mixerOpen Lib "winmm.dll" Alias "mixerOpen" (phmx As Long, ByVal uMxId As Long, ByVal dwCallback As Long, ByVal dwInstance As Long, ByVal fdwOpen As Long) As Long
Declare Function mixerSetControlDetails Lib "winmm.dll" Alias "mixerSetControlDetails" (ByVal hmxobj As Long, ByRef pmxcd As MIXERCONTROLDETAILS, ByVal fdwDetails As Long) As Long
'***********************************************************************************************
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
Joris
Addict
Addict
Posts: 890
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: Get/Set Sound volume level programmatically

Post by Joris »

Maybe you'll need these too :
the constants an stuctures (called Type in GFA32).

Code: Select all

'***********************************************************************************************
'***********************************************************************************************
' General error return values
Global Const MMSYSERR_NOERROR = 0  '  no error
Global Const MMSYSERR_ERROR = 1  '  unspecified error
Global Const MMSYSERR_BADDEVICEID = 2  '  device ID out of range
Global Const MMSYSERR_NOTENABLED = 3  '  driver failed enable
Global Const MMSYSERR_ALLOCATED = 4  '  device already allocated
Global Const MMSYSERR_INVALHANDLE = 5  '  device handle is invalid
Global Const MMSYSERR_NODRIVER = 6  '  no device driver present
Global Const MMSYSERR_NOMEM = 7  '  memory allocation error
Global Const MMSYSERR_NOTSUPPORTED = 8  '  function isn't supported
Global Const MMSYSERR_BADERRNUM = 9  '  error value out of range
Global Const MMSYSERR_INVALFLAG = 10 '  invalid flag passed
Global Const MMSYSERR_INVALPARAM = 11 '  invalid parameter passed
Global Const MMSYSERR_HANDLEBUSY = 12 '  handle being used
'  simultaneously on another
'  thread (eg callback)
Global Const MMSYSERR_INVALIDALIAS = 13 '  "Specified alias not found in WIN.INI
Global Const MMSYSERR_LASTERROR = 13 '  last error in range
Global Const MM_MOM_POSITIONCB = &H3CA              '  Callback for MEVT_POSITIONCB
Global Const MM_MCISIGNAL = &H3CB
Global Const MM_MIM_MOREDATA = &H3CC                '  MIM_DONE w/ pending events
Global Const MM_MIXM_LINE_CHANGE = &H3D0
Global Const MM_MIXM_CONTROL_CHANGE = &H3D1
'
Global Const MIDICAPS_STREAM = &H8               '  driver supports midiStreamOut directly
'
Global Const MIXER_SHORT_NAME_CHARS = 16
Global Const MIXER_LONG_NAME_CHARS = 64
Global Const MIXERR_BASE = 1024
Global Const MIXERR_INVALLINE = (MIXERR_BASE + 0)
Global Const MIXERR_INVALCONTROL = (MIXERR_BASE + 1)
Global Const MIXERR_INVALVALUE = (MIXERR_BASE + 2)
Global Const MIXERR_LASTERROR = (MIXERR_BASE + 2)
'
Global Const MIXER_OBJECTF_HANDLE = &H80000000
Global Const MIXER_OBJECTF_MIXER = &H0
Global Const MIXER_OBJECTF_HMIXER = (&H80000000 Or &H0)
Global Const MIXER_OBJECTF_WAVEOUT = &H10000000
Global Const MIXER_OBJECTF_HWAVEOUT = (MIXER_OBJECTF_HANDLE Or MIXER_OBJECTF_WAVEOUT)
Global Const MIXER_OBJECTF_WAVEIN = &H20000000
Global Const MIXER_OBJECTF_HWAVEIN = (MIXER_OBJECTF_HANDLE Or MIXER_OBJECTF_WAVEIN)
Global Const MIXER_OBJECTF_MIDIOUT = &H30000000
Global Const MIXER_OBJECTF_HMIDIOUT = (MIXER_OBJECTF_HANDLE Or MIXER_OBJECTF_MIDIOUT)
Global Const MIXER_OBJECTF_MIDIIN = &H40000000
Global Const MIXER_OBJECTF_HMIDIIN = (MIXER_OBJECTF_HANDLE Or MIXER_OBJECTF_MIDIIN)
Global Const MIXER_OBJECTF_AUX = &H50000000
'
Global Const MIXERLINE_LINEF_ACTIVE = &H1
Global Const MIXERLINE_LINEF_DISCONNECTED = &H8000
Global Const MIXERLINE_LINEF_SOURCE = &H80000000
'
Global Const MIXERLINE_COMPONENTTYPE_DST_FIRST = &H0
Global Const MIXERLINE_COMPONENTTYPE_DST_UNDEFINED = 0
Global Const MIXERLINE_COMPONENTTYPE_DST_DIGITAL = 1
Global Const MIXERLINE_COMPONENTTYPE_DST_LINE = 2
Global Const MIXERLINE_COMPONENTTYPE_DST_MONITOR = 3
Global Const MIXERLINE_COMPONENTTYPE_DST_SPEAKERS = 4
Global Const MIXERLINE_COMPONENTTYPE_DST_HEADPHONES = 5
Global Const MIXERLINE_COMPONENTTYPE_DST_TELEPHONE = 6
Global Const MIXERLINE_COMPONENTTYPE_DST_WAVEIN = 7
Global Const MIXERLINE_COMPONENTTYPE_DST_VOICEIN = 8
Global Const MIXERLINE_COMPONENTTYPE_DST_LAST = 8
'
Global Const MIXERLINE_COMPONENTTYPE_SRC_FIRST = &H1000
Global Const MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 0)
Global Const MIXERLINE_COMPONENTTYPE_SRC_DIGITAL = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 1)
Global Const MIXERLINE_COMPONENTTYPE_SRC_LINE = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 2)
Global Const MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 3)
Global Const MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 4)
Global Const MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 5)
Global Const MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 6)
Global Const MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 7)
Global Const MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 8)
Global Const MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 9)
Global Const MIXERLINE_COMPONENTTYPE_SRC_ANALOG = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 10)
Global Const MIXERLINE_COMPONENTTYPE_SRC_LAST = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 10)
'
Global Const MIXERLINE_TARGETTYPE_UNDEFINED = 0
Global Const MIXERLINE_TARGETTYPE_WAVEOUT = 1
Global Const MIXERLINE_TARGETTYPE_WAVEIN = 2
Global Const MIXERLINE_TARGETTYPE_MIDIOUT = 3
Global Const MIXERLINE_TARGETTYPE_MIDIIN = 4
Global Const MIXERLINE_TARGETTYPE_AUX = 5
'
Global Const MIXER_GETLINEINFOF_DESTINATION = &H0
Global Const MIXER_GETLINEINFOF_SOURCE = &H1
Global Const MIXER_GETLINEINFOF_LINEID = &H2
Global Const MIXER_GETLINEINFOF_COMPONENTTYPE = &H3
Global Const MIXER_GETLINEINFOF_TARGETTYPE = &H4
Global Const MIXER_GETLINEINFOF_QUERYMASK = &HF
'
Global Const MIXERCONTROL_CONTROLF_UNIFORM = &H1
Global Const MIXERCONTROL_CONTROLF_MULTIPLE = &H2
Global Const MIXERCONTROL_CONTROLF_DISABLED = &H80000000
'
Global Const MIXERCONTROL_CT_CLASS_MASK = &HF0000000
Global Const MIXERCONTROL_CT_CLASS_CUSTOM = &H0
Global Const MIXERCONTROL_CT_CLASS_METER = &H10000000
Global Const MIXERCONTROL_CT_CLASS_SWITCH = &H20000000
Global Const MIXERCONTROL_CT_CLASS_NUMBER = &H30000000
Global Const MIXERCONTROL_CT_CLASS_SLIDER = &H40000000
Global Const MIXERCONTROL_CT_CLASS_FADER = &H50000000
Global Const MIXERCONTROL_CT_CLASS_TIME = &H60000000
Global Const MIXERCONTROL_CT_CLASS_LIST = &H70000000
Global Const MIXERCONTROL_CT_SUBCLASS_MASK = &HF000000
Global Const MIXERCONTROL_CT_SC_SWITCH_BOOLEAN = &H0
Global Const MIXERCONTROL_CT_SC_SWITCH_BUTTON = &H1000000
Global Const MIXERCONTROL_CT_SC_METER_POLLED = &H0
Global Const MIXERCONTROL_CT_SC_TIME_MICROSECS = &H0
Global Const MIXERCONTROL_CT_SC_TIME_MILLISECS = &H1000000
Global Const MIXERCONTROL_CT_SC_LIST_SINGLE = &H0
Global Const MIXERCONTROL_CT_SC_LIST_MULTIPLE = &H1000000
Global Const MIXERCONTROL_CT_UNITS_MASK = &HFF0000
Global Const MIXERCONTROL_CT_UNITS_CUSTOM = &H0
Global Const MIXERCONTROL_CT_UNITS_BOOLEAN = &H10000
Global Const MIXERCONTROL_CT_UNITS_SIGNED = &H20000
Global Const MIXERCONTROL_CT_UNITS_UNSIGNED = &H30000
Global Const MIXERCONTROL_CT_UNITS_DECIBELS = &H40000 '  in 10ths
Global Const MIXERCONTROL_CT_UNITS_PERCENT = &H50000 '  in 10ths
'
Global Const MIXERCONTROL_CONTROLTYPE_CUSTOM = 0
Global Const MIXERCONTROL_CONTROLTYPE_BOOLEANMETER = (MIXERCONTROL_CT_CLASS_METER Or 0 Or MIXERCONTROL_CT_UNITS_BOOLEAN)
Global Const MIXERCONTROL_CONTROLTYPE_SIGNEDMETER = (MIXERCONTROL_CT_CLASS_METER Or 0 Or MIXERCONTROL_CT_UNITS_SIGNED)
Global Const MIXERCONTROL_CONTROLTYPE_PEAKMETER = (MIXERCONTROL_CONTROLTYPE_SIGNEDMETER + 1)
Global Const MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER = (MIXERCONTROL_CT_CLASS_METER Or 0 Or MIXERCONTROL_CT_UNITS_UNSIGNED)
Global Const MIXERCONTROL_CONTROLTYPE_BOOLEAN = (MIXERCONTROL_CT_CLASS_SWITCH Or 0 Or MIXERCONTROL_CT_UNITS_BOOLEAN)
Global Const MIXERCONTROL_CONTROLTYPE_ONOFF = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 1)
Global Const MIXERCONTROL_CONTROLTYPE_MUTE = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 2)
Global Const MIXERCONTROL_CONTROLTYPE_MONO = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 3)
Global Const MIXERCONTROL_CONTROLTYPE_LOUDNESS = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 4)
Global Const MIXERCONTROL_CONTROLTYPE_STEREOENH = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 5)
Global Const MIXERCONTROL_CONTROLTYPE_BUTTON = (MIXERCONTROL_CT_CLASS_SWITCH Or MIXERCONTROL_CT_SC_SWITCH_BUTTON Or MIXERCONTROL_CT_UNITS_BOOLEAN)
Global Const MIXERCONTROL_CONTROLTYPE_DECIBELS = (MIXERCONTROL_CT_CLASS_NUMBER Or MIXERCONTROL_CT_UNITS_DECIBELS)
Global Const MIXERCONTROL_CONTROLTYPE_SIGNED = (MIXERCONTROL_CT_CLASS_NUMBER Or MIXERCONTROL_CT_UNITS_SIGNED)
Global Const MIXERCONTROL_CONTROLTYPE_UNSIGNED = (MIXERCONTROL_CT_CLASS_NUMBER Or MIXERCONTROL_CT_UNITS_UNSIGNED)
Global Const MIXERCONTROL_CONTROLTYPE_PERCENT = (MIXERCONTROL_CT_CLASS_NUMBER Or MIXERCONTROL_CT_UNITS_PERCENT)
Global Const MIXERCONTROL_CONTROLTYPE_SLIDER = (MIXERCONTROL_CT_CLASS_SLIDER Or MIXERCONTROL_CT_UNITS_SIGNED)
Global Const MIXERCONTROL_CONTROLTYPE_PAN = (MIXERCONTROL_CONTROLTYPE_SLIDER + 1)
Global Const MIXERCONTROL_CONTROLTYPE_QSOUNDPAN = (MIXERCONTROL_CONTROLTYPE_SLIDER + 2)
Global Const MIXERCONTROL_CONTROLTYPE_FADER = (MIXERCONTROL_CT_CLASS_FADER Or MIXERCONTROL_CT_UNITS_UNSIGNED)
Global Const MIXERCONTROL_CONTROLTYPE_VOLUME = (MIXERCONTROL_CONTROLTYPE_FADER + 1)
Global Const MIXERCONTROL_CONTROLTYPE_BASS = (MIXERCONTROL_CONTROLTYPE_FADER + 2)
Global Const MIXERCONTROL_CONTROLTYPE_TREBLE = (MIXERCONTROL_CONTROLTYPE_FADER + 3)
Global Const MIXERCONTROL_CONTROLTYPE_EQUALIZER = (MIXERCONTROL_CONTROLTYPE_FADER + 4)
Global Const MIXERCONTROL_CONTROLTYPE_SINGLESELECT = (MIXERCONTROL_CT_CLASS_LIST Or 0 Or MIXERCONTROL_CT_UNITS_BOOLEAN)
Global Const MIXERCONTROL_CONTROLTYPE_MUX = (MIXERCONTROL_CONTROLTYPE_SINGLESELECT + 1)
Global Const MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT = (MIXERCONTROL_CT_CLASS_LIST Or MIXERCONTROL_CT_SC_LIST_MULTIPLE Or MIXERCONTROL_CT_UNITS_BOOLEAN)
Global Const MIXERCONTROL_CONTROLTYPE_MIXER = (MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT + 1)
Global Const MIXERCONTROL_CONTROLTYPE_MICROTIME = (MIXERCONTROL_CT_CLASS_TIME Or 0 Or MIXERCONTROL_CT_UNITS_UNSIGNED)
Global Const MIXERCONTROL_CONTROLTYPE_MILLITIME = (MIXERCONTROL_CT_CLASS_TIME Or MIXERCONTROL_CT_SC_TIME_MILLISECS Or MIXERCONTROL_CT_UNITS_UNSIGNED)
'
Global Const MIXER_GETLINECONTROLSF_ALL = &H0
Global Const MIXER_GETLINECONTROLSF_ONEBYID = &H1
Global Const MIXER_GETLINECONTROLSF_ONEBYTYPE = &H2
Global Const MIXER_GETLINECONTROLSF_QUERYMASK = &HF
'
Global Const MIXER_GETCONTROLDETAILSF_VALUE = &H0
Global Const MIXER_GETCONTROLDETAILSF_LISTTEXT = &H1
Global Const MIXER_GETCONTROLDETAILSF_QUERYMASK = &HF
'
Global Const MIXER_SETCONTROLDETAILSF_VALUE = &H0
Global Const MIXER_SETCONTROLDETAILSF_CUSTOM = &H1
Global Const MIXER_SETCONTROLDETAILSF_QUERYMASK = &HF

Type MIXERCAPS                  'informatie van de geluidskaarten
  wMid As Int16
  wPid As Int16
  vDriverVersion As Long
  szPname As String * MAXPNAMELEN
  fdwSupport As Long
  cDestinations As Long
EndType
Type MIXERLINE                  'informatie van in-output op elke geluidskaart
  cbStruct As Long
  dwDestination As Long
  dwSource As Long
  dwLineID As Long
  fdwLine As Long
  dwUser As Long
  dwComponentType As Long       'type of audio line (digital, speaker, telephone etc.)
  cChannels As Long
  cConnections As Long
  cControls As Long
  szShortName As String * MIXER_SHORT_NAME_CHARS
  szName As String * MIXER_LONG_NAME_CHARS
  dwType As Long
  dwDeviceID As Long
  wMid  As Integer
  wPid As Integer
  vDriverVersion As Long
  szPname As String * MAXPNAMELEN
EndType
Type MIXERLINECONTROLS          'informatie van de controls op elke in-output
  cbStruct As Long       '  size in Byte of MIXERLINECONTROLS
  dwLineID As Long       '  line id (from MIXERLINE.dwLineID)
  '  MIXER_GETLINECONTROLSF_ONEBYID or
  dwControlID As Long    '  or dwControlType  MIXER_GETLINECONTROLSF_ONEBYTYPE
  cControls As Long      '  count of controls pmxctrl points to
  cbmxctrl As Long       '  size in Byte of _one_ MIXERCONTROL
  pamxctrl As Long 'MIXERCONTROL       '  pointer to first MIXERCONTROL array
EndType
Type MIXERCONTROL               'algemene opbouw van één control
  cbStruct As Long
  dwControlID As Long
  dwControlType As Long
  fdwControl As Long
  cMultipleItems As Long
  szShortName As String * MIXER_SHORT_NAME_CHARS
  szName As String * MIXER_LONG_NAME_CHARS
  lMinimum As Long
  lMaximum As Long
  reserved(10) As Long
EndType
Type MIXERCONTROLDETAILS        'specifieke elementen van de control en zijn gebruik
  cbStruct As Long       '  size in Byte of MIXERCONTROLDETAILS
  dwControlID As Long    '  control id to get/set details on
  cChannels As Long      '  number of channels in paDetails array
  cMultipleItems As Long ' hwndOwner or cMultipleItems
  cbDetails As Long      '  size of _one_ details_XX struct
  paDetails As Long      '  pointer to array of details_XX structs
EndType
Type MIXERCONTROLDETAILS_LISTTEXT
  dwParam1 As Long
  dwParam2 As Long
  szName As String * MIXER_LONG_NAME_CHARS
EndType
Type MIXERCONTROLDETAILS_BOOLEAN
  fValue As Long
EndType
Type MIXERCONTROLDETAILS_SIGNED
  lValue As Long
EndType
Type MIXERCONTROLDETAILS_UNSIGNED
  dwValue As Long
EndType
I just tested that GFA source and it still works (on XP 32) yet I don't remember what all was ment for ... getting old.
It does read out all my audio devices, which was quit a job to get it done under MS, but then furthermore ... ?
I remember I wonted to create a mixer that could handle the multiple audio-cards at once (instead of the MS-mixer which handles just one device).
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
MachineCode
Addict
Addict
Posts: 1482
Joined: Tue Feb 22, 2011 1:16 pm

Re: Get/Set Sound volume level programmatically

Post by MachineCode »

netmaestro, here's a VB snippet I found years ago which I never converted to PureBasic. Maybe it's a starting point? If you get it working, please pay back the favor by posting it here. ;)

BTW, there are other volume examples in these forums, but they're all very long and the one I used in XP doesn't work with Win 7, due to each app on Win 7 having their own volume levels. :(

Code: Select all

; Option Explicit
; Private Declare Function waveOutSetVolume Lib "Winmm" (ByVal wDeviceID
; As Integer, ByVal dwVolume As Long) As Integer
; Private Declare Function waveOutGetVolume Lib "Winmm" (ByVal wDeviceID
; As Integer, dwVolume As Long) As Integer
;
; Private Sub volume(up As Boolean)
;    Dim a, i As Long, getv As Long, setv As Long
;    Dim tmp, vol As Long
;       a = waveOutGetVolume(0, i)
;       tmp = "&h" & Right(Hex$(i), 4)
;       getv = CLng(tmp)
;       If up Then
;          setv = getv + 500
;          If setv > 65535 Then setv = 65535
;       Else
;          setv = getv - 500
;          If setv < 0 Then setv = 0
;       End If
;       tmp = Right((Hex$(vol + 65536)), 4)
;       vol = CLng("&H" & tmp & tmp)
;       a = waveOutSetVolume(0, vol)
;
; End Sub

; Full = 65535
; 3/4  = 49152
; Half = 32768
; 1/4  = 16384
; Mute = 0
Microsoft Visual Basic only lasted 7 short years: 1991 to 1998.
PureBasic: Born in 1998 and still going strong to this very day!
User avatar
luis
Addict
Addict
Posts: 3893
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: Get/Set Sound volume level programmatically

Post by luis »

I don't have any code sorry (never tried)

Background on the new way of controlling volume for your application vs system/wide:
http://blogs.msdn.com/b/larryosterman/a ... 04158.aspx
http://blogs.msdn.com/b/larryosterman/a ... vista.aspx

I have found this:

Master volume control example
http://www.codeproject.com/Articles/185 ... me-Control

A dirty way (easy) maybe through #WM_APPCOMMAND, I think it changes too the master volume but I'm not sure.
http://msdn.microsoft.com/en-us/library ... 85%29.aspx
"Have you tried turning it off and on again ?"
A little PureBasic review
MachineCode
Addict
Addict
Posts: 1482
Joined: Tue Feb 22, 2011 1:16 pm

Re: Get/Set Sound volume level programmatically

Post by MachineCode »

netmaestro wrote:- Mute/Unmute volume from software
- Adjust volume level up or down
This one line will toggle the current mute state, but don't rely on it. I did once and it didn't work on all PCs. I think I remember that it only works on PCs that have a media keyboard? Not sure. Definitely works on Win 7 with a media keyboard.

You can also use #VK_VOLUME_UP and #VK_VOLUME_DOWN with virtual keystrokes. Really simple APIs, but such hacky code.

Code: Select all

keybd_event_(#VK_VOLUME_MUTE,0,0,0) : keybd_event_(#VK_VOLUME_MUTE,0,#KEYEVENTF_KEYUP,0)
Microsoft Visual Basic only lasted 7 short years: 1991 to 1998.
PureBasic: Born in 1998 and still going strong to this very day!
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: Get/Set Sound volume level programmatically

Post by ts-soft »

For WinVista and higher:

Code: Select all

EnableExplicit

#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 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

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 
Greetings - Thomas
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Get/Set Sound volume level programmatically

Post by netmaestro »

Thanks to all for the help, it's appreciated!

A little background info for why I suddenly want this after ignoring sound volumes forever, I have a handy little app called Alarm Clock that we use here at home often. Last night my wife set it and went to bed. She had it set properly and all, but the sound was muted and she didn't notice. It occurred to me that the Alarm Clock program could check the volume settings a few seconds before it rings and if they aren't audible or very loud it could adjust them. It would also solve the problem of email notifications waking people up too as the volume could be muted and it wouldn't affect the alarm. So thanks again, this will be useful to me.
BERESHEIT
User avatar
skywalk
Addict
Addict
Posts: 4211
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Get/Set Sound volume level programmatically

Post by skywalk »

Yes, very interesting topic.
My son often complains of Spotify "checking" the master volume level and then pausing its commercials if muted. :evil:
So, a programmatic countermeasure would be cool to have.

But if on Windows 7, each app controls the sound level, how to dominate?
I imagine this calls for a global system hook?
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
jassing
Addict
Addict
Posts: 1885
Joined: Wed Feb 17, 2010 12:00 am

Re: Get/Set Sound volume level programmatically

Post by jassing »

I have always wanted a way to "check the volume" and "normalize it" -- ie: while watching hulu or netflix, have the volume drop down when it suddenly gets louder (ie: commercials on hulu or a big car crash etc)
MachineCode
Addict
Addict
Posts: 1482
Joined: Tue Feb 22, 2011 1:16 pm

Re: Get/Set Sound volume level programmatically

Post by MachineCode »

Here's the code I used on XP which muted/unmuted the volume, but doesn't work under Win 7 or even compile anymore. Just throwing it in here so maybe someone can update it, since this is an interesting thread with many snippets and tips on how to do it.

Code: Select all

;-MIXERCONTROL
Structure MIXERCONTROL
  cbStruct.l
  dwControlID.l
  dwControlType.l
  fdwControl.l
  cMultipleItems.l
  szShortName.b[#MIXER_SHORT_NAME_CHARS]
  szName.b[#MIXER_LONG_NAME_CHARS]
  lMinimum.l
  lMaximum.l
  dwMinimum.l
  dwMaximum.l
  Reserved.l[6]
  cSteps.l
  cbCustomData.l
  dwReserved.l[6]
EndStructure

;-MIXERCONTROLDETAILSUNSIGNED
Structure MIXERCONTROLDETAILSUNSIGNED
  dwValue.l
EndStructure

Procedure ZeroMemory(adr,len)
  For i=0 To len-1 : PokeB(adr+i,0) : Next
EndProcedure

Procedure GetMasterVolumeControl(mixer,*control.MIXERCONTROL)
  line.mixerline
  controls.mixerlinecontrols
  ZeroMemory(Line,SizeOf(mixerline))
  Line\cbStruct=SizeOf(mixerline)
  Line\dwComponentType=#MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
  Result=mixerGetLineInfo_(Mixer,Line,#MIXER_GETLINEINFOF_COMPONENTTYPE)
  If Result=#MMSYSERR_NOERROR
    ZeroMemory(Controls,SizeOf(mixerlinecontrols))
    Controls\cbStruct=SizeOf(mixerlinecontrols)
    Controls\dwLineID=Line\dwLineID
    Controls\cControls=1
    Controls\dwControlType=#MIXERCONTROL_CONTROLTYPE_VOLUME
    Controls\cbmxctrl=SizeOf(MIXERCONTROL)
    Controls\pamxctrl=*Control
    Result=mixerGetLineControls_(Mixer,Controls,#MIXER_GETLINECONTROLSF_ONEBYTYPE)
  EndIf
  ProcedureReturn result
EndProcedure

Procedure GetMasterMuteControl(mixer,*control.MIXERCONTROL)
  line.mixerline
  controls.mixerlinecontrols
  ZeroMemory(Line,SizeOf(mixerline))
  Line\cbStruct=SizeOf(mixerline)
  Line\dwComponentType=#MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
  Result=mixerGetLineInfo_(Mixer,Line,#MIXER_GETLINEINFOF_COMPONENTTYPE)
  If Result=#MMSYSERR_NOERROR
    ZeroMemory(Controls,SizeOf(mixerlinecontrols))
    Controls\cbStruct=SizeOf(mixerlinecontrols)
    Controls\dwLineID=Line\dwLineID
    Controls\cControls=1
    Controls\dwControlType=#MIXERCONTROL_CONTROLTYPE_MUTE
    Controls\cbmxctrl=SizeOf(MIXERCONTROL)
    Controls\pamxctrl=*Control
    Result=mixerGetLineControls_(Mixer,Controls,#MIXER_GETLINECONTROLSF_ONEBYTYPE)
  EndIf
  ProcedureReturn result
EndProcedure

Procedure SetMasterVolume(mixer,value)
  MasterVolume.MIXERCONTROL
  Details.MIXERCONTROLDETAILS
  UnsignedDetails.MIXERCONTROLDETAILSUNSIGNED
  code.l
  code=GetMasterVolumeControl(Mixer,MasterVolume)
  If code=#MMSYSERR_NOERROR
    Details\cbStruct=SizeOf(MIXERCONTROLDETAILS)
    Details\dwControlID=MasterVolume\dwControlID
    Details\cChannels=1
    Details\Item=0
    Details\cbDetails=SizeOf(MIXERCONTROLDETAILSUNSIGNED)
    Details\paDetails=@UnsignedDetails
    UnsignedDetails\dwValue=Value
    code=mixerSetControlDetails_(Mixer,Details,#MIXER_SETCONTROLDETAILSF_VALUE)
  EndIf
  ProcedureReturn code
EndProcedure

Procedure SetMasterMute(mixer,value)
  MasterVolume.MIXERCONTROL
  Details.MIXERCONTROLDETAILS
  UnsignedDetails.MIXERCONTROLDETAILSUNSIGNED
  code=GetMasterMuteControl(Mixer,MasterVolume)
  If code=#MMSYSERR_NOERROR
    Details\cbStruct=SizeOf(MIXERCONTROLDETAILS)
    Details\dwControlID=MasterVolume\dwControlID
    Details\cChannels=1
    Details\Item=0
    Details\cbDetails=SizeOf(MIXERCONTROLDETAILSUNSIGNED)
    Details\paDetails=@UnsignedDetails
    UnsignedDetails\dwValue=Value
    code=mixerSetControlDetails_(Mixer,Details,#MIXER_SETCONTROLDETAILSF_VALUE)
  EndIf
  ProcedureReturn code
EndProcedure

Procedure GetMasterVolume(mixer)
  MasterVolume.MIXERCONTROL
  Details.MIXERCONTROLDETAILS
  UnsignedDetails.MIXERCONTROLDETAILSUNSIGNED
  code=GetMasterVolumeControl(Mixer,MasterVolume)
  If code=#MMSYSERR_NOERROR
    Details\cbStruct=SizeOf(MIXERCONTROLDETAILS)
    Details\dwControlID=MasterVolume\dwControlID
    Details\cChannels=1
    Details\Item=0
    Details\cbDetails=SizeOf(MIXERCONTROLDETAILSUNSIGNED)
    Details\paDetails=@UnsignedDetails
    code=mixerGetControlDetails_(Mixer,Details,#MIXER_SETCONTROLDETAILSF_VALUE)
  EndIf
  ProcedureReturn UnsignedDetails\dwValue
EndProcedure

Procedure GetMasterMute(mixer)
  MasterVolume.MIXERCONTROL
  Details.MIXERCONTROLDETAILS
  UnsignedDetails.MIXERCONTROLDETAILSUNSIGNED
  code=GetMasterMuteControl(Mixer,MasterVolume)
  If code=#MMSYSERR_NOERROR
    Details\cbStruct=SizeOf(MIXERCONTROLDETAILS)
    Details\dwControlID=MasterVolume\dwControlID
    Details\cChannels=1
    Details\Item=0
    Details\cbDetails=SizeOf(MIXERCONTROLDETAILSUNSIGNED)
    Details\paDetails=@UnsignedDetails
    code=mixerGetControlDetails_(Mixer,Details,#MIXER_SETCONTROLDETAILSF_VALUE)
  EndIf
  ProcedureReturn UnsignedDetails\dwValue
EndProcedure

Procedure GetMasterVolumeMinimum(mixer)
  Volume.MIXERCONTROL
  GetMasterVolumeControl(mixer,Volume)
  ProcedureReturn volume\lMinimum
EndProcedure

Procedure GetMasterVolumeMaximum(mixer)
  Volume.MIXERCONTROL
  GetMasterVolumeControl(mixer,Volume)
  ProcedureReturn volume\lMaximum
EndProcedure
Microsoft Visual Basic only lasted 7 short years: 1991 to 1998.
PureBasic: Born in 1998 and still going strong to this very day!
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Get/Set Sound volume level programmatically

Post by netmaestro »

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)
BERESHEIT
Joris
Addict
Addict
Posts: 890
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: Get/Set Sound volume level programmatically

Post by Joris »

It does not work on XP (like you said someway) but I think it's not that big thing, only as newbee PBuser...

[10:13:11] Waiting for executable to start...
[10:13:11] Executable type: Windows - x86 (32bit)
[10:13:11] Executable started.
[10:13:11] [ERROR] Line: 54
[10:13:11] [ERROR] Invalid memory access. (read error at address 0)
[10:13:19] The Program was killed.

This is the error line :
hr = deviceEnumerator\GetDefaultAudioEndpoint(0, 1, @defaultDevice)
in :

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
  
  hr = deviceEnumerator\GetDefaultAudioEndpoint(0, 1, @defaultDevice)
  deviceEnumerator\Release()
  
  hr = defaultDevice\Activate(?uuidof_IAudioEndpointVolume, #CLSCTX_INPROC_SERVER, #Null, *endpointVolume);
  defaultDevice\release()
  
  ProcedureReturn *endpointvolume
EndProcedure
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: Get/Set Sound volume level programmatically

Post by ts-soft »

Joris wrote:It does not work on XP (like you said someway) but I think it's not that big thing, only as newbee PBuser...
Vista and higher have a completely new sound system, this code will never be able to run under XP!
More infos can you found in the thread from luis: http://www.purebasic.fr/english/viewtop ... 59#p403759
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Get/Set Sound volume level programmatically

Post by netmaestro »

@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.
BERESHEIT
Post Reply