Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Vista Audio Control Functions


  • Please log in to reply
182 replies to this topic
maximo3491
  • Members
  • 92 posts
  • Last active: Dec 01 2010 12:43 AM
  • Joined: 10 Feb 2007
I'm trying to get the active levels of my microphone, however, there seems to be something wrong with VA_IAudioMeterInformation_GetPeakValue(audioMeter, peakValue) as it always returns null

Here is my code

#SingleInstance, Force
MeterLength = 30
COM_Init()

device := VA_GetDevice("Microphone Array")
audioMeter := VA_GetAudioMeter(device)

VA_IAudioMeterInformation_GetMeteringChannelCount(audioMeter, channelCount)

; "The peak value for each channel is recorded over one device
;  period and made available during the subsequent device period."
VA_GetDevicePeriod("playback", devicePeriod)

Loop
{
    ; Get the peak value across all channels.
    VA_IAudioMeterInformation_GetPeakValue(audioMeter, peakValue)    
	meter := MakeMeter(peakValue, MeterLength)
	
    ; Get the peak values of all channels.
    VarSetCapacity(peakValues, channelCount*4)
    VA_IAudioMeterInformation_GetChannelsPeakValues(audioMeter, channelCount, &peakValues)
	Loop %channelCount%
        meter .= "`n" MakeMeter(NumGet(peakValues, A_Index*4-4, "float"), MeterLength)

    ToolTip, %meter%
    Sleep, %devicePeriod%
}

MakeMeter(fraction, size)
{
    global MeterLength
	Loop % fraction*size
        meter .= "|"
    Loop % (1-fraction)*size
        meter .= "."
    meter .= "  " fraction
    return meter
}

I have the right device selected as VA_GetDeviceName returns the name of my recording microphone.

Any ideas?

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
VA_GetAudioMeter expects a device_desc, the same as VA_GetDevice's first parameter. When you pass it a pointer value, it is misinterpreted as a numeric index. In retrospect, a pointer value is extremely unlikely to ever be in the range of a valid index, so VA_GetDevice (which is used internally by functions such as VA_GetAudioMeter) could simply return the value it is given as-is. However, in this case you have no need for the device pointer anyway.

Instead pass the device name directly to VA_GetAudioMeter, or pass "capture" to use your default recording device.

Also, the "playback" in VA_GetDevicePeriod("playback",...) should be changed to whatever device_desc is passed to VA_GetAudioMeter.


Edit: I've updated VA.zip so that VA_GetDevice(device_pointer) will return device_pointer. I also fixed a "pointer leak" in VA_GetAudioMeter.

maximo3491
  • Members
  • 92 posts
  • Last active: Dec 01 2010 12:43 AM
  • Joined: 10 Feb 2007
Ahh, that works perfectly. Thank you :D

maximo3491
  • Members
  • 92 posts
  • Last active: Dec 01 2010 12:43 AM
  • Joined: 10 Feb 2007
Sorry for the double post, but I noticed something odd. The levels are only displayed if another program starts up the capture drivers. For example, if I load up Audacity and hit record, or open up recording devices (which has a meter next to ever device) only then does this script show the meters.

If I close out all programs that, upon exit, disable the record drivers, the meters for this script go back down to 0.

I'm no expert at calling the proper drivers so how exactly do I load up my main capture device driver?

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

The peak meter only reports meaningful values when something is actually capturing audio. I'm not sure how it is done, and haven't spent the necessary time to find out as I don't have a need to detect sound input.
Source: Microphone Peak Value - Vista Audio (Lexikos)

Sorry.

maximo3491
  • Members
  • 92 posts
  • Last active: Dec 01 2010 12:43 AM
  • Joined: 10 Feb 2007
Ahh gotcha Lexikos, didn't really read that. Thanks for the script nontheless. Works like a charm for output devices. I'll try to find a way to load the input device and will post my solution when (and if) I find it.

rokky
  • Members
  • 2 posts
  • Last active: Mar 13 2010 08:05 AM
  • Joined: 13 Mar 2010
Hi,
First of all thanks for the script, it makes the move to windows 7 seem a bit less painful. :p

I'm having a small problem though. I use hotkeys to control the volume on line in coming from my ps3. It works great except for when I lower the volume down to 0 and then press twice on the volume down key. The sound level goes up to 89 and it'll get ear shatteringly loud. The same thing doesn't happen if I try to increase the volume over 100, not that it'd matter much if it did. :>

Here's my code, hope you can help me.

COM_Init()

+Volume_Mute::
VA_SetMute(!VA_GetMute(4),4)
return

+Volume_Up::VA_SetVolume(VA_GetVolume(4) + 1, 4)

+Volume_Down::VA_SetVolume(VA_GetVolume(4) - 1, 4)


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
Thanks for the bug report. I've fixed a divide-by-zero error in VA_SetVolume which seemed to be the cause. Please download and try again.

rokky
  • Members
  • 2 posts
  • Last active: Mar 13 2010 08:05 AM
  • Joined: 13 Mar 2010
Seems to work flawlessly now. Thanks for the quick response!

duveit
  • Members
  • 9 posts
  • Last active: Jul 19 2011 02:31 PM
  • Joined: 08 Dec 2009
Is it possible with application specific sound control in windows 7 with this script?

Lets say if you only want to mute the sound in a specific program, but let others stay the same volume.

undin
  • Members
  • 6 posts
  • Last active: Jun 22 2010 04:31 AM
  • Joined: 10 Jun 2010

Sorry, I'm pretty new to this stuff so I don't really understand much.

With that said, I think I've solved it.

I used this line

F11::VA_SetMasterMute(!VA_GetMasterMute("capture"), "capture")

This appears to just toggle mute the default input device, exactly what I need! If there's some way I can get it to mute just the mic instead of the default input device, that would be better. But really, this is just splitting hairs and I'm just overjoyed to actually have it working!

Much thanks!

i've used your finding as base for the following
COM_Init()




startup=1
while startup=1
{
mutestatus := VA_GetMasterMute("microphone")
if (mutestatus = 0)
{
menu, tray, icon, ON.ico,,1
}

else
{
menu, tray, icon, OFF.ico,,1
}
startup=0
}
return




YOURHOTKEY::
mutestatus := VA_GetMasterMute("microphone")
if (mutestatus = 1)
{
VA_SetMasterMute(0, "microphone")
menu, tray, icon, ON.ico,,1
CoordMode, ToolTip, Screen
Tooltip, ON, 0, 0
}

else
{
VA_SetMasterMute(1, "microphone")
menu, tray, icon, OFF.ico,,1
CoordMode, ToolTip, Screen
Tooltip, OFF, 0, 0
}

SetTimer, RemoveToolTip, 1500
Return




RemoveToolTip:
  SetTimer, RemoveToolTip, Off
  ToolTip
return
in addition to just toggling it always show the current mute status in the traybar with custom icons (even when just started)
and it shows the status as a tooltip when you toggle (handy at fullscreen games)





it would be nice if someone could help me with my own audio problem:
i need to find a way to change the windows 7 speaker setup (2.0 speakers, 5.1 speakers, etc) with a hotkey
but i have found nothing about how one could do it for hours

my old thread in the help forum:
<!-- m -->http://www.autohotke...topic59091.html<!-- m -->

Ivan68
  • Members
  • 13 posts
  • Last active: Dec 22 2010 05:59 PM
  • Joined: 15 Jun 2010

I'm trying to get the active levels of my microphone, however, there seems to be something wrong with VA_IAudioMeterInformation_GetPeakValue(audioMeter, peakValue) as it always returns null

Here is my code

#SingleInstance, Force
MeterLength = 30
COM_Init()

device := VA_GetDevice("Microphone Array")
audioMeter := VA_GetAudioMeter(device)

VA_IAudioMeterInformation_GetMeteringChannelCount(audioMeter, channelCount)

; "The peak value for each channel is recorded over one device
;  period and made available during the subsequent device period."
VA_GetDevicePeriod("playback", devicePeriod)

Loop
{
    ; Get the peak value across all channels.
    VA_IAudioMeterInformation_GetPeakValue(audioMeter, peakValue)    
	meter := MakeMeter(peakValue, MeterLength)
	
    ; Get the peak values of all channels.
    VarSetCapacity(peakValues, channelCount*4)
    VA_IAudioMeterInformation_GetChannelsPeakValues(audioMeter, channelCount, &peakValues)
	Loop %channelCount%
        meter .= "`n" MakeMeter(NumGet(peakValues, A_Index*4-4, "float"), MeterLength)

    ToolTip, %meter%
    Sleep, %devicePeriod%
}

MakeMeter(fraction, size)
{
    global MeterLength
	Loop % fraction*size
        meter .= "|"
    Loop % (1-fraction)*size
        meter .= "."
    meter .= "  " fraction
    return meter
}

I have the right device selected as VA_GetDeviceName returns the name of my recording microphone.

Any ideas?


I would like to do something like that. So, what is the final code? How can I get microphone peak levels? TY

EDIT: I found the problem. "capure" device must be opened, in some way. If I run the code with "Recording Devices" window opened from volume icon, it works correctly. So, ho can I "open" the device?

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
From the device pointer (IMMDevice Interface), you need to create and initialize an audio client (IAudioClient Interface). It can be tricky to call the interface functions correctly, so I've written a complete example:
COM_Init()
; Get the device which we'll be monitoring.
device := VA_GetDevice("capture")

; Get IAudioClient interface.
VA_IMMDevice_Activate(device, IID_IAudioClient:="{1CB9AD4C-DBFA-4c32-B178-C2F568A703B2}", 7, 0, audioClient)
; Get mixer format to pass to Initialize.
VA_IAudioClient_GetMixFormat(audioClient, format)
; Initialize audio client to ensure peak meter is active.
VA_IAudioClient_Initialize(audioClient, 0, 0, 0, 0, format, 0)

; Get IAudioMeterInformation interface.
audioMeter := VA_GetAudioMeter(device)
; No longer needed, so free it:
COM_Release(device)

MeterLength = 30

; "The peak value for each channel is recorded over one device
;  period and made available during the subsequent device period."
VA_GetDevicePeriod("capture", devicePeriod)

Loop
{
    VA_IAudioMeterInformation_GetPeakValue(audioMeter, peakValue)    
    
    meter =
    ; Make the meter.
    Loop % peakValue*MeterLength
        meter .= "|"
    Loop % (1-peakValue)*MeterLength
        meter .= "."
    meter .= "  " peakValue

    ToolTip, %meter%
    Sleep, %devicePeriod%
}

/* To clean up:
COM_Release(audioMeter)
COM_Release(audioClient)
*/

;
; IAudioClient
;
VA_IAudioClient_Initialize(this, ShareMode, StreamFlags, BufferDuration, Periodicity, Format, AudioSessionGuid) {
    return DllCall(NumGet(NumGet(this+0)+12), "uint", this, "int", ShareMode, "uint", StreamFlags, "int64", BufferDuration, "int64", Periodicity, "uint", Format, "uint", SubStr(AudioSessionGuid,1,1)="{" ? COM_GUID4String(AudioSessionGuid,AudioSessionGuid) : AudioSessionGuid)
}
VA_IAudioClient_GetBufferSize(this, ByRef NumBufferFrames) {
    return DllCall(NumGet(NumGet(this+0)+16), "uint", this, "uint*", NumBufferFrames)
}
VA_IAudioClient_GetStreamLatency(this, ByRef Latency) {
    return DllCall(NumGet(NumGet(this+0)+20), "uint", this, "int64*", Latency)
}
VA_IAudioClient_GetCurrentPadding(this, ByRef NumPaddingFrames) {
    return DllCall(NumGet(NumGet(this+0)+24), "uint", this, "uint*", NumPaddingFrames)
}
VA_IAudioClient_IsFormatSupported(this, ShareMode, Format, ByRef ClosestMatch) {
    return DllCall(NumGet(NumGet(this+0)+28), "uint", this, "int", ShareMode, "uint", Format, "uint*", ClosestMatch)
}
VA_IAudioClient_GetMixFormat(this, ByRef Format) {
    return DllCall(NumGet(NumGet(this+0)+32), "uint", this, "uint*", Format)
}
VA_IAudioClient_GetDevicePeriod(this, ByRef DefaultDevicePeriod, ByRef MinimumDevicePeriod) {
    return DllCall(NumGet(NumGet(this+0)+36), "uint", this, "int64*", DefaultDevicePeriod, "int64*", MinimumDevicePeriod)
}
VA_IAudioClient_Start(this) {
    return DllCall(NumGet(NumGet(this+0)+40), "uint", this)
}
VA_IAudioClient_Stop(this) {
    return DllCall(NumGet(NumGet(this+0)+44), "uint", this)
}
VA_IAudioClient_Reset(this) {
    return DllCall(NumGet(NumGet(this+0)+48), "uint", this)
}
VA_IAudioClient_SetEventHandle(this, eventHandle) {
    return DllCall(NumGet(NumGet(this+0)+52), "uint", this, "uint", eventHandle)
}
VA_IAudioClient_GetService(this, iid, ByRef Service) {
    return DllCall(NumGet(NumGet(this+0)+56), "uint", this, "uint", COM_GUID4String(iid,iid), "uint*", Service)
}
I had attempted this previously but had overlooked IAudioClient::GetMixFormat, which is needed to get the stream format to pass to IAudioClient::Initialize.

element
  • Members
  • 24 posts
  • Last active: Oct 20 2011 09:15 AM
  • Joined: 02 Apr 2010
Can this library be used to set app-specific volume levels visible in the Win7 audio mixer? My mp3/TV/video players produce uneven audio levels. When a particular player starts, I'd like to set the relevant application volume to, say, 50% of current master volume. I can do this manually in the mixer and it works. However, every now and then I may inadvertently hit an app-specific volume hotkey, and the app will reset its volume level to 100%. Then I have to adjust the level manually again. I want to automate this.

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

Can this library be used to set app-specific volume levels visible in the Win7 audio mixer?

No.

After spending several hours researching it, wrapping various COM interfaces and experimenting I'm able to enumerate audio sessions and determine which app owns them, but not control their volume. Basically, I got to the same point as this guy before realising it was impossible.

According to Larry Osterman
"There is no publicly documented mechanism for doing what you're trying to do."

Source: Controlling the volume of other applications - Stack Overflow