LB Booster
« Get and set master sound level »

Welcome Guest. Please Login or Register.
Apr 1st, 2018, 03:57am



ATTENTION MEMBERS: Conforums will be closing it doors and discontinuing its service on April 15, 2018.
We apologize Conforums does not have any export functions to migrate data.
Ad-Free has been deactivated. Outstanding Ad-Free credits will be reimbursed to respective payment methods.

Thank you Conforums members.
Speed up Liberty BASIC programs by up to ten times!
Compile Liberty BASIC programs to compact, standalone executables!
Overcome many of Liberty BASIC's bugs and limitations!
LB Booster Resources
LB Booster documentation
LB Booster Home Page
LB Booster technical Wiki
Just BASIC forum
BBC BASIC Home Page
Liberty BASIC forum (the original)

« Previous Topic | Next Topic »
Pages: 1  Notify Send Topic Print
 thread  Author  Topic: Get and set master sound level  (Read 450 times)
RobM
Junior Member
ImageImage


member is offline

Avatar




PM


Posts: 91
xx Re: Get and set master sound level
« Reply #8 on: Oct 12th, 2016, 5:56pm »

Speaking for myself I would have to say I don't know if I would use it for anything other than this current idea. Knowing in the back of my mind that COM objects weren't possible with LB I never looked into what was possible in using them.

Offhand, do you have a general list of things that could be accomplished.
User IP Logged

Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 1348
xx Re: Get and set master sound level
« Reply #9 on: Oct 13th, 2016, 7:29pm »

on Oct 12th, 2016, 5:56pm, RobM wrote:
Speaking for myself I would have to say I don't know if I would use it for anything other than this current idea.

OK, fair enough. There's a huge range of COM-based Windows API functions - pretty much any API introduced in the last ten years or so is probably a COM interface - but if it's not something you've ever wanted up to now, you probably never will.

Here's a direct, but not heavily commented, translation of the C++ code; it works in both LB 4 and LBB. It should be compatible with Windows Vista onwards:

Code:
    ' Translated to Liberty BASIC by Richard Russell from the code here, 13-Oct-2016:
    ' http://www.codeproject.com/Tips/233484/Change-Master-Volume-in-Visual-Cplusplus

    result = ChangeVolume(0.5, 1)
    end
    
function ChangeVolume(nVolume, bScalar)
    open "ole32.dll" for dll as #ole32
    open "oleaut32.dll" for dll as #oleaut32
    calldll #ole32, "CoInitialize", 0 as long, r as void

    IID.MMDeviceEnumerator$ = UUID$("{A95664D2-9614-4F35-A746-DE8DB63617E6}")
    CLSID.MMDeviceEnumerator$ = UUID$("{BCDE0395-E52F-467C-8E3D-C4579291692E}")
    IID.IAudioEndpointVolume$ = UUID$("{5CDF2C82-841E-4546-9722-0CF74078229A}")
    CLSCTX.INPROC.SERVER = 1
    eRender = 0
    eConsole = 0
    Release = 2
    Activate = 3
    GetDefaultAudioEndpoint = 4
    SetMasterVolumeLevel = 6
    SetMasterVolumeLevelScalar = 7
    GetMasterVolumeLevel = 8
    GetMasterVolumeLevelScalar = 9
        
    struct IMM, deviceEnumerator as ulong
    calldll #ole32, "CoCreateInstance", CLSID.MMDeviceEnumerator$ as ptr, _
        0 as long, CLSCTX.INPROC.SERVER as long, IID.MMDeviceEnumerator$ as ptr, _
        IMM as struct, hr as long

    ' hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);    
    struct default, Device as ulong
    struct parms, dataFlow as long, role as long, ppDevice as ptr 
    parms.dataFlow.struct = eRender
    parms.role.struct = eConsole
    parms.ppDevice.struct = default.struct
    hr = CallMethod(IMM.deviceEnumerator.struct, GetDefaultAudioEndpoint, parms.struct)
    default.struct = parms.ppDevice.struct
    
    ' hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume), 
    '      CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
    struct Iaudio, endpointVolume as ulong
    struct parms, iid as ptr, dwClsCtx as long, _
        pActivationParams as ulong, ppInterface as ptr
    parms.iid.struct = IID.IAudioEndpointVolume$
    parms.dwClsCtx.struct = CLSCTX.INPROC.SERVER
    parms.ppInterface.struct = Iaudio.struct
    hr = CallMethod(default.Device.struct, Activate, parms.struct)
    Iaudio.struct = parms.ppInterface.struct
    
    ' defaultDevice->Release();
    hr = CallMethod(default.Device.struct, Release, "")
    default.Device.struct = 0

    ' endpointVolume->GetMasterVolumeLevel(¤tVolume);
    struct Volume, float as long 
    struct parms, pfLevel as ptr
    parms.pfLevel.struct = Volume.struct
    hr = CallMethod(Iaudio.endpointVolume.struct, GetMasterVolumeLevel, parms.struct)
    Volume.struct = parms.pfLevel.struct
    
    ' Convert float to double:
    struct current, Volume as double
    float = Volume.float.struct
    calldll #oleaut32, "VarR8FromR4", float as long, current as struct, r as void
    print "Current volume (dB) = "; current.Volume.struct
    
    ' hr = endpointVolume->GetMasterVolumeLevelScalar(¤tVolume);
    hr = CallMethod(Iaudio.endpointVolume.struct, GetMasterVolumeLevelScalar, parms.struct)
    Volume.struct = parms.pfLevel.struct
    
    ' Convert float to double:
    float = Volume.float.struct
    calldll #oleaut32, "VarR8FromR4", float as long, current as struct, r as void
    print "Current volume (scalar) = "; current.Volume.struct
    
    ' Set new volume:
    struct parms, fLevel as ptr, EventContext as long
    calldll #oleaut32, "VarR4FromR8", nVolume as double, parms as struct, r as void
    if bScalar = 0 then
        hr = CallMethod(Iaudio.endpointVolume.struct, SetMasterVolumeLevel, parms.struct)
    else
        hr = CallMethod(Iaudio.endpointVolume.struct, SetMasterVolumeLevelScalar, parms.struct)    
    end if

    ' endpointVolume->Release();
    hr = CallMethod(Iaudio.endpointVolume.struct, Release, "")
    Iaudio.endpointVolume.struct = 0

    calldll #ole32, "CoUninitialize", r as void
    close #oleaut32
    close #ole32
end function       
    
function UUID$(iid$)
    l = len(iid$) + 1
    wide$ = space$(2 * l) + chr$(0)
    calldll #kernel32, "MultiByteToWideChar", 0 as long, 0 as long, _
                 iid$ as ptr, -1 as long, wide$ as ptr, l as long, r as long
    UUID$ = space$(16) + chr$(0)
    calldll #ole32, "CLSIDFromString", wide$ as ptr, UUID$ as ptr, r as long
end function

function CallMethod(object, method, parm$)
    code$ = chr$(139)+"D$"+chr$(4)+chr$(139)+"T$"+chr$(8)+chr$(139)+"L$" _
    + chr$(16)+"VW"+chr$(139)+"t$"+chr$(20)+chr$(43)+chr$(225)+chr$(139) _
    + chr$(252)+chr$(243)+chr$(164)+chr$(80)+chr$(139)+chr$(0)+chr$(255) _
    + chr$(20)+chr$(144)+chr$(95)+chr$(94)+chr$(194)+chr$(16)+chr$(0)
    p$ = parm$
    n = len(p$)
    calldll #user32, "CallWindowProcA", code$ as ptr, object as long,_
        method as long, p$ as ptr, n as long, CallMethod as long
end function  

It's really annoying that structs are global in LB, since it means I can't make this a library function that can safely be called from any program.

Richard.
« Last Edit: Oct 13th, 2016, 8:28pm by Richard Russell » User IP Logged

RobM
Junior Member
ImageImage


member is offline

Avatar




PM


Posts: 91
xx Re: Get and set master sound level
« Reply #10 on: Oct 13th, 2016, 10:59pm »

Thanks Richard!

I think I will add one more parameter to the function to specify whether it should check the sound level or change it. Looks like that should be easy enough.
User IP Logged

RobM
Junior Member
ImageImage


member is offline

Avatar




PM


Posts: 91
xx Re: Get and set master sound level
« Reply #11 on: Oct 14th, 2016, 03:15am »

I ended up splitting it into a function & a sub and removed some (but not all) unneeded code. As is, this code will lower your volume 6 seconds after it sees it over 10.

My loops here are pretty ugly coding but this is just a quick demo :)

Thanks again Richard.

Code:
    DesiredVolume=10'volume as a percentage from 0 to 100, as Windows shows it in the master volume control
    ResetTime=.1'time in minutes to wait after volume has been increased
[loop1]
    scan
    calldll #kernel32, "Sleep", 10 as long, re as void
    CurrentVolume=GetVolume()
    if CurrentVolume > DesiredVolume then
      StartTime=GetTickCount()
      goto [loop2]
    end if
    goto [loop1]

[loop2]
    scan
    calldll #kernel32, "Sleep", 10 as long, re as void
    CurrentTime=GetTickCount()
    if CurrentTime-StartTime > ResetTime*60*1000 then
      call SetVolume DesiredVolume,1
      goto [loop1]
    end if
    goto [loop2]

function GetVolume()
    open "ole32.dll" for dll as #ole32
    open "oleaut32.dll" for dll as #oleaut32
    calldll #ole32, "CoInitialize", 0 as long, r as void

    IID.MMDeviceEnumerator$ = UUID$("{A95664D2-9614-4F35-A746-DE8DB63617E6}")
    CLSID.MMDeviceEnumerator$ = UUID$("{BCDE0395-E52F-467C-8E3D-C4579291692E}")
    IID.IAudioEndpointVolume$ = UUID$("{5CDF2C82-841E-4546-9722-0CF74078229A}")
    CLSCTX.INPROC.SERVER = 1
    eRender = 0
    eConsole = 0
    Release = 2
    Activate = 3
    GetDefaultAudioEndpoint = 4
    GetMasterVolumeLevel = 8
    GetMasterVolumeLevelScalar = 9

    struct IMM, deviceEnumerator as ulong
    calldll #ole32, "CoCreateInstance", CLSID.MMDeviceEnumerator$ as ptr, _
        0 as long, CLSCTX.INPROC.SERVER as long, IID.MMDeviceEnumerator$ as ptr, _
        IMM as struct, hr as long

    ' hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
    struct default, Device as ulong
    struct parms, dataFlow as long, role as long, ppDevice as ptr
    parms.dataFlow.struct = eRender
    parms.role.struct = eConsole
    parms.ppDevice.struct = default.struct
    hr = CallMethod(IMM.deviceEnumerator.struct, GetDefaultAudioEndpoint, parms.struct)
    default.struct = parms.ppDevice.struct

    ' hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume),
    '      CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
    struct Iaudio, endpointVolume as ulong
    struct parms, iid as ptr, dwClsCtx as long, _
        pActivationParams as ulong, ppInterface as ptr
    parms.iid.struct = IID.IAudioEndpointVolume$
    parms.dwClsCtx.struct = CLSCTX.INPROC.SERVER
    parms.ppInterface.struct = Iaudio.struct
    hr = CallMethod(default.Device.struct, Activate, parms.struct)
    Iaudio.struct = parms.ppInterface.struct

    ' defaultDevice->Release();
    hr = CallMethod(default.Device.struct, Release, "")
    default.Device.struct = 0

    ' endpointVolume->GetMasterVolumeLevel(¤tVolume);
    struct Volume, float as long
    struct parms, pfLevel as ptr
    parms.pfLevel.struct = Volume.struct
    hr = CallMethod(Iaudio.endpointVolume.struct, GetMasterVolumeLevel, parms.struct)
    Volume.struct = parms.pfLevel.struct

    ' Convert float to double:
    struct current, Volume as double
    float = Volume.float.struct
    calldll #oleaut32, "VarR8FromR4", float as long, current as struct, r as void

    ' hr = endpointVolume->GetMasterVolumeLevelScalar(¤tVolume);
    hr = CallMethod(Iaudio.endpointVolume.struct, GetMasterVolumeLevelScalar, parms.struct)
    Volume.struct = parms.pfLevel.struct

    ' Convert float to double:
    float = Volume.float.struct
    calldll #oleaut32, "VarR8FromR4", float as long, current as struct, r as void
    GetVolume=int(current.Volume.struct*100+1)

    ' endpointVolume->Release();
    hr = CallMethod(Iaudio.endpointVolume.struct, Release, "")
    Iaudio.endpointVolume.struct = 0

    calldll #ole32, "CoUninitialize", r as void
    close #oleaut32
    close #ole32
end function

sub SetVolume nVolume, bScalar
    nVolume=nVolume/100
    open "ole32.dll" for dll as #ole32
    open "oleaut32.dll" for dll as #oleaut32
    calldll #ole32, "CoInitialize", 0 as long, r as void

    IID.MMDeviceEnumerator$ = UUID$("{A95664D2-9614-4F35-A746-DE8DB63617E6}")
    CLSID.MMDeviceEnumerator$ = UUID$("{BCDE0395-E52F-467C-8E3D-C4579291692E}")
    IID.IAudioEndpointVolume$ = UUID$("{5CDF2C82-841E-4546-9722-0CF74078229A}")
    CLSCTX.INPROC.SERVER = 1
    eRender = 0
    eConsole = 0
    Release = 2
    Activate = 3
    GetDefaultAudioEndpoint = 4
    SetMasterVolumeLevelScalar = 7

    struct IMM, deviceEnumerator as ulong
    calldll #ole32, "CoCreateInstance", CLSID.MMDeviceEnumerator$ as ptr, _
        0 as long, CLSCTX.INPROC.SERVER as long, IID.MMDeviceEnumerator$ as ptr, _
        IMM as struct, hr as long

    ' hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice);
    struct default, Device as ulong
    struct parms, dataFlow as long, role as long, ppDevice as ptr
    parms.dataFlow.struct = eRender
    parms.role.struct = eConsole
    parms.ppDevice.struct = default.struct
    hr = CallMethod(IMM.deviceEnumerator.struct, GetDefaultAudioEndpoint, parms.struct)
    default.struct = parms.ppDevice.struct

    ' hr = defaultDevice->Activate(__uuidof(IAudioEndpointVolume),
    '      CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
    struct Iaudio, endpointVolume as ulong
    struct parms, iid as ptr, dwClsCtx as long, _
        pActivationParams as ulong, ppInterface as ptr
    parms.iid.struct = IID.IAudioEndpointVolume$
    parms.dwClsCtx.struct = CLSCTX.INPROC.SERVER
    parms.ppInterface.struct = Iaudio.struct
    hr = CallMethod(default.Device.struct, Activate, parms.struct)
    Iaudio.struct = parms.ppInterface.struct

    ' defaultDevice->Release();
    hr = CallMethod(default.Device.struct, Release, "")
    default.Device.struct = 0

    ' Set new volume:
    struct Volume, float as long
    struct parms, fLevel as ptr, EventContext as long
    calldll #oleaut32, "VarR4FromR8", nVolume as double, parms as struct, r as void
    hr = CallMethod(Iaudio.endpointVolume.struct, SetMasterVolumeLevelScalar, parms.struct)

    ' endpointVolume->Release();
    hr = CallMethod(Iaudio.endpointVolume.struct, Release, "")
    Iaudio.endpointVolume.struct = 0

    calldll #ole32, "CoUninitialize", r as void
    close #oleaut32
    close #ole32
end sub

function UUID$(iid$)
    l = len(iid$) + 1
    wide$ = space$(2 * l) + chr$(0)
    calldll #kernel32, "MultiByteToWideChar", 0 as long, 0 as long, _
                 iid$ as ptr, -1 as long, wide$ as ptr, l as long, r as long
    UUID$ = space$(16) + chr$(0)
    calldll #ole32, "CLSIDFromString", wide$ as ptr, UUID$ as ptr, r as long
end function

function CallMethod(object, method, parm$)
    code$ = chr$(139)+"D$"+chr$(4)+chr$(139)+"T$"+chr$(8)+chr$(139)+"L$" _
    + chr$(16)+"VW"+chr$(139)+"t$"+chr$(20)+chr$(43)+chr$(225)+chr$(139) _
    + chr$(252)+chr$(243)+chr$(164)+chr$(80)+chr$(139)+chr$(0)+chr$(255) _
    + chr$(20)+chr$(144)+chr$(95)+chr$(94)+chr$(194)+chr$(16)+chr$(0)
    p$ = parm$
    n = len(p$)
    calldll #user32, "CallWindowProcA", code$ as ptr, object as long,_
        method as long, p$ as ptr, n as long, CallMethod as long
end function

function GetTickCount()
    calldll #kernel32, "GetTickCount",_
        GetTickCount as ulong
end function 
« Last Edit: Oct 14th, 2016, 03:16am by RobM » User IP Logged

RobM
Junior Member
ImageImage


member is offline

Avatar




PM


Posts: 91
xx Re: Get and set master sound level
« Reply #12 on: Oct 14th, 2016, 06:12am »

The two loops in the code above can be replaced with this this. Makes it easier to insert into a program with a single loop ;)

Code:
[loop]
    scan
    calldll #kernel32, "Sleep", 10 as long, re as void
    CurrentTime=GetTickCount()
    CurrentVolume=GetVolume()
    if CurrentVolume>DesiredVolume and CountDownStarted=0 then
      StartTime=GetTickCount()
      CountDownStarted=1
    end if

    if CurrentTime-StartTime > ResetTime*60*1000 then
      call SetVolume DesiredVolume, 1
      CountDownStarted=0
    end if
    goto [loop]
 
« Last Edit: Oct 14th, 2016, 06:13am by RobM » User IP Logged

Pages: 1  Notify Send Topic Print
« Previous Topic | Next Topic »

| |

This forum powered for FREE by Conforums ©
Terms of Service | Privacy Policy | Conforums Support | Parental Controls