sl23 wrote: ↑May 3rd, 2022, 12:10 pmHmm... Interesting, very interesting!
CodeCode wrote: ↑May 3rd, 2022, 1:38 pmHmm. Far be it from me to not take interest in a new way to manage environmental mic volume with RM.
This has been a really confusing topic to read through.
I am still doing it though.
Ok, not taking no for an answer paid off eventually. This is the best that can be done to keep the AudioDeviceCmdlets memory leak under control (as in, slowing down the leak as much as possible) AND still feel like you're doing real-time adjustments on the audio input / output volumes and mute states. Apart from the code, the idea is basically a trick: why even trying to get or set the audio data every couple of milliseconds to simulate real time in the first place ... when you can only
make it look like it does?
In a nutshell, what the code does is get all the potentially needed audio data in one attempt, once every
#SlowUpdate# milliseconds (the higher, the slower the memory leak), taking care to also set all the potentially needed data if
#Changed# is
1 before that but in the same attempt, then pass the newline delimited list to individual String measures in order to distribute it separately, as independent corresponding variables. Those independent variables can be modified in realtime via scroll (by the corresponding Step variables) on volumes or click (to toggle) on mute states, at which point
#Changed# will be temporarily set to
1 to trigger inserting the set data code in the PowershellRM measure when the time comes, but the change or query to or from the actual audio devices will happen only once every
#SlowUpdate# milliseconds, irrespective of how many clicks and scrolls one does to change the variables - after all, nobody stays with the Control Panel windows opened to see if the changes happen right away or after one, two, three or whatever seconds.
Initially, when no mouse actions happen, and right after getting or setting the actual data, the
#Changed# variable will be set (or reset) to
0, to make sure we don't pointlessly override volumes and mute states and everything goes with the flow. The
[SetAudio] measure and variable will insert the code for setting the audio data based on the
#Changed# variable's value - I had to do it this way because apparently PowershellRM doesn't like or supports Rainmeter's nested syntax or measure syntax, so this extra measure will, if necessary, convert
#Changed# value to the code needed to set the data, then pass it to an identically named plain variable that can be used with PowershellRM. If the
#Changed# value says that no change or set data is needed, the code to set it will be the empty string, essentially allowing to only get the said data.
The code (you can tweak FastUpdate, SlowUpdate, OutputStep and InputStep to your liking, of course)...
[SkinFolder]\@Resources\DeviceVolume.ps1:
Code: Select all
Import-Module -Name "$($RmAPI.VariableStr('@'))Addons\AudioDeviceCmdlets"
function Get-OutputVolume
{
return Get-AudioDevice -PlaybackVolume
}
function Get-InputVolume
{
return Get-AudioDevice -RecordingVolume
}
function Get-OutputMute
{
if (Get-AudioDevice -PlaybackMute) {return 1} else {return 0}
}
function Get-InputMute
{
if (Get-AudioDevice -RecordingMute) {return 1} else {return 0}
}
function Set-OutputVolume
{
[CmdletBinding()]param([Parameter(Mandatory)][float]$Volume)
Set-AudioDevice -PlaybackVolume $Volume
}
function Set-InputVolume
{
[CmdletBinding()]param([Parameter(Mandatory)][float]$Volume)
Set-AudioDevice -RecordingVolume $Volume
}
function Set-OutputMute
{
[CmdletBinding()]param([Parameter(Mandatory)][byte]$State)
switch($State)
{
0 {Set-AudioDevice -PlaybackMute $false}
1 {Set-AudioDevice -PlaybackMute $true}
}
}
function Set-InputMute
{
[CmdletBinding()]param([Parameter(Mandatory)][byte]$State)
switch($State)
{
0 {Set-AudioDevice -RecordingMute $false}
1 {Set-AudioDevice -RecordingMute $true}
}
}
[SkinFolder]\AudioManager.ini:
Code: Select all
[Variables]
FastUpdate=25
SlowUpdate=2000
OutputVolume=0
InputVolume=0
OutputMute=0
InputMute=0
OutputStep=1
InputStep=1
Changed=0
[Rainmeter]
Update=25
DynamicWindowSize=1
AccurateText=1
[Metadata]
Name=AudioManager
Author=Yincognito & Other Credited Authors
; Credit for the AudioDeviceCmdlets .dll module to frgnca - https://github.com/frgnca/AudioDeviceCmdlets
; Credit for the initial Powershell code to death.crafter - https://forum.rainmeter.net/viewtopic.php?f=5&t=38135#p195694
; Credit for the supplemental Powershell code to jsmorley - https://forum.rainmeter.net/viewtopic.php?t=38135&start=30#p195744
; Other adjustments and improvements to keep the AudioDeviceCmdlets memory leak under control by Yincognito
---Measures---
[DeviceVolume]
Measure=Plugin
Plugin=PowershellRM
ScriptFile=#@#DeviceVolume.ps1
UpdateDivider=-1
DynamicVariables=1
[SetAudio]
Measure=String
String=#Changed#
RegExpSubstitute=1
Substitute="^0$":"","^1$":"Set-OutputVolume -Volume #OutputVolume#; Set-InputVolume -Volume #InputVolume#; Set-OutputMute -State #OutputMute#; Set-InputMute -State #InputMute#;"
UpdateDivider=(#SlowUpdate#/#FastUpdate#)
OnUpdateAction=[!SetVariable #CURRENTSECTION# [#CURRENTSECTION#]]
DynamicVariables=1
[GetAudio]
Measure=Plugin
Plugin=PowershellRM
Parent=DeviceVolume
Line=#SetAudio#$(Get-OutputVolume), $(Get-InputVolume), $(Get-OutputMute), $(Get-InputMute), "" -join "`n"
UpdateDivider=(#SlowUpdate#/#FastUpdate#)
DynamicVariables=1
[OutputVolume]
Measure=String
String=[GetAudio]
RegExpSubstitute=1
Substitute="(?siU)^.*(\N*\R)(\N*\R)(\N*\R)(\N*\R).*$":"\1","^\\\d+$":"","^(\d+).*$":"\1","^\\\d+$":""
UpdateDivider=(#SlowUpdate#/#FastUpdate#)
OnUpdateAction=[!SetVariable #CURRENTSECTION# [#CURRENTSECTION#]][!SetVariable Changed 0]
DynamicVariables=1
[InputVolume]
Measure=String
String=[GetAudio]
RegExpSubstitute=1
Substitute="(?siU)^.*(\N*\R)(\N*\R)(\N*\R)(\N*\R).*$":"\2","^\\\d+$":"","^(\d+).*$":"\1","^\\\d+$":""
UpdateDivider=(#SlowUpdate#/#FastUpdate#)
OnUpdateAction=[!SetVariable #CURRENTSECTION# [#CURRENTSECTION#]][!SetVariable Changed 0]
DynamicVariables=1
[OutputMute]
Measure=String
String=[GetAudio]
RegExpSubstitute=1
Substitute="(?siU)^.*(\N*\R)(\N*\R)(\N*\R)(\N*\R).*$":"\3","^\\\d+$":"","^(\d+).*$":"\1","^\\\d+$":""
UpdateDivider=(#SlowUpdate#/#FastUpdate#)
OnUpdateAction=[!SetVariable #CURRENTSECTION# [#CURRENTSECTION#]][!SetVariable Changed 0]
DynamicVariables=1
[InputMute]
Measure=String
String=[GetAudio]
RegExpSubstitute=1
Substitute="(?siU)^.*(\N*\R)(\N*\R)(\N*\R)(\N*\R).*$":"\4","^\\\d+$":"","^(\d+).*$":"\1","^\\\d+$":""
UpdateDivider=(#SlowUpdate#/#FastUpdate#)
OnUpdateAction=[!SetVariable #CURRENTSECTION# [#CURRENTSECTION#]][!SetVariable Changed 0]
DynamicVariables=1
---Meters---
[OutputVolumeText]
Meter=String
Y=5R
SolidColor=47,47,47,255
FontColor=255,255,255,255
FontFace=Consolas
FontSize=16
AntiAlias=1
Text=Output Volume: #OutputVolume#
MouseScrollUpAction=[!SetVariable OutputVolume (Clamp(#OutputVolume#+#OutputStep#,0,100))][!SetVariable Changed 1][!Update]
MouseScrollDownAction=[!SetVariable OutputVolume (Clamp(#OutputVolume#-#OutputStep#,0,100))][!SetVariable Changed 1][!Update]
DynamicVariables=1
[OutputMuteText]
Meter=String
Y=5R
SolidColor=47,47,47,255
FontColor=255,255,255,255
FontFace=Consolas
FontSize=16
AntiAlias=1
Text=Output Mute: #OutputMute#
LeftMouseUpAction=[!SetVariable OutputMute (1-#OutputMute#)][!SetVariable Changed 1][!Update]
DynamicVariables=1
[InputVolumeText]
Meter=String
Y=5R
SolidColor=47,47,47,255
FontColor=255,255,255,255
FontFace=Consolas
FontSize=16
AntiAlias=1
Text=Input Volume: #InputVolume#
MouseScrollUpAction=[!SetVariable InputVolume (Clamp(#InputVolume#+#InputStep#,0,100))][!SetVariable Changed 1][!Update]
MouseScrollDownAction=[!SetVariable InputVolume (Clamp(#InputVolume#-#InputStep#,0,100))][!SetVariable Changed 1][!Update]
DynamicVariables=1
[InputMuteText]
Meter=String
Y=5R
SolidColor=47,47,47,255
FontColor=255,255,255,255
FontFace=Consolas
FontSize=16
AntiAlias=1
Text=Input Mute: #InputMute#
LeftMouseUpAction=[!SetVariable InputMute (1-#InputMute#)][!SetVariable Changed 1][!Update]
DynamicVariables=1
The packed skin for the lazy ones:
AudioManager_1.0.0.rmskin
A screenshot for the curious ones (yeah, not too pretty, but functional):
AudioManager.jpg
And that's about it. Questions, complaints, awards, talks about the weather welcomed. Just not to many requests to change it, cause just like the above skin, I like to do things one time and for good, if possible...
P.S. Didn't bother to create additional String measures to add the percentage sign to the volume percentages or convert the 0 and 1 mute states to "unmute" or "mute" strings, since anyone can do that. If you do, however, take care to not affect the values passed to the
OutputVolume,
InputVolume,
OutputMute and
InputMute variables from the identically named measures, cause they need to be plain values (0 to 100 and float type for volumes, 0 or 1 and byte type for the mute states).
You do not have the required permissions to view the files attached to this post.