It is currently September 21st, 2021, 4:55 pm

First skin question

Help with creating, editing & fixing problems with skins
User avatar
RainMaster
Posts: 2
Joined: July 25th, 2021, 11:53 pm

First skin question

Post by RainMaster »

Hi! I started making my first skin the other day because I wanted an easy single-click method for muting/unmuting my microphone. So far I have everything working like a charm by using SoundVolumeViewer to mute and unmute the mic, however I want the state the mic was in on reboot/shutdown to be remembered by the skin. It seems the way to do this is either by using SoundVolumeViewer to get the current state of the mic when the skin starts up, or perhaps PowerShell even, and set the image accordingly. I'm not quite sure how to actually go about this though.

Here's what I have currently so you can see what I'm talking about:

Code: Select all

[Rainmeter]
Update=10000

[Metadata]
Name=MicToggle
Author=
Information=Toggles microphone between muted/unmuted
Version=1.0b
License=Creative Commons Attribution - Non - Commercial - Share Alike 3.0

[Variables]
MicOn=#@#Images\Microphone-on.png
MicOff=#@#Images\Microphone-off.png

[MeterMicButton]
Meter=Image
ImageName=#MicOn#
AlwaysOnTop=-2
LeftMouseUpAction=[!SetOption MeterMicButton ImageName #MicOff#][!SetVariable MicOn #MicOff#][!SetVariable MicOff #MicOn#][!UpdateMeter MeterMicButton][!Redraw][!CommandMeasure MeasureRun "Run"]
DynamicVariables=1

[MeasureRun]
Measure=Plugin
Plugin=RunCommand
Program=C:\Users\User\Desktop\Utility\SoundVolumeView\SoundVolumeView.exe
Parameter=/Switch "Realtek High Definition Audio\Device\Microphone Array\Capture"
State=Hide
Any help is greatly appreciated. Since I'm still learning I don't quite know how to pass the output of a program to Rainmeter and set the image accordingly, or if I can/need to define multiple Measures to process the output. I got this far mostly by looking at examples and working backwards from there. (My name is what I hope to become, not what I am :D ).
User avatar
Yincognito
Rainmeter Sage
Posts: 4052
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: First skin question

Post by Yincognito »

RainMaster wrote: July 26th, 2021, 12:20 am Hi! I started making my first skin the other day because I wanted an easy single-click method for muting/unmuting my microphone. So far I have everything working like a charm by using SoundVolumeViewer to mute and unmute the mic, however I want the state the mic was in on reboot/shutdown to be remembered by the skin. It seems the way to do this is either by using SoundVolumeViewer to get the current state of the mic when the skin starts up, or perhaps PowerShell even, and set the image accordingly. I'm not quite sure how to actually go about this though.
[...]
Any help is greatly appreciated. Since I'm still learning I don't quite know how to pass the output of a program to Rainmeter and set the image accordingly, or if I can/need to define multiple Measures to process the output. I got this far mostly by looking at examples and working backwards from there. (My name is what I hope to become, not what I am :D ).
There you go - this works for me, a bit slow, but it does. Didn't test it after a restart and I can't guarantee it will work flawlessly since there are a lot of things that happen at restart and the order in which they do or how busy is the PC at that time could have an impact on functionality, but hopefully it will work well:
MicToggle_1.0.3.rmskin

Code: Select all

[Variables]
MicOn=#@#Images\Microphone-on.png
MicOff=#@#Images\Microphone-off.png

[Rainmeter]
Update=1000
DynamicWindowSize=1
AccurateText=1
OnRefreshAction=[!CommandMeasure MeasureGetMicMute "Run"]

[Metadata]
Name=MicToggle
Author=
Information=Toggles microphone between muted/unmuted
Version=1.0b
License=Creative Commons Attribution - Non - Commercial - Share Alike 3.0

---Measures---

[MeasureSetMicMute]
Measure=Plugin
Plugin=RunCommand
Parameter=#@#Addons\SoundVolumeView.exe /Switch "Realtek High Definition Audio\Device\Microphone\Capture"
State=Hide
OutputType=ANSI
Timeout=10000
FinishAction=[!CommandMeasure MeasureGetMicMute "Run"]

[MeasureGetMicMute]
Measure=Plugin
Plugin=RunCommand
Parameter=#@#Addons\SoundVolumeView.exe /stab "" | #@#Addons\GetNir.exe "Muted" "Command-LineFriendlyID='Realtek High Definition Audio\Device\Microphone\Capture'"
State=Hide
OutputType=ANSI
Timeout=10000
RegExpSubstitute=1
Substitute="^Yes$":"#MicOff#","^No$":"#MicOn#"
FinishAction=[!SetOption MeterMicButton ImageName "[MeasureGetMicMute]"][!UpdateMeter MeterMicButton][!Redraw]
DynamicVariables=1

---Meters---

[MeterMicButton]
Meter=Image
ImageName=#MicOn#
LeftMouseUpAction=[!CommandMeasure MeasureSetMicMute "Run"]
DynamicVariables=1
I shuffled some things in your original code, corrected a single thing, and added some things for proper distribution of the skin, if it'll be the case. So:
- AlwaysOnTop=-2 is not a valid option, and it's not a valid option there, therefore I removed it
- shortened the skin update to 1 second since it doesn't harm anything in this case if you let it that way
- removed setting the variables since I had another idea, see below
- made 2 RunCommand measures, one to get and one to set the mic mute status (the latter is your original one for the most part)
- since setting some variables in itself means nothing when it comes to the success of a command (e.g. the command could fail or be delayed so the variable could yield an inaccurate value), I thought it was better to actually get the mic mute status somewhat similarly with how you set it (reference here towards the middle of the page, section "Get sound level information from command line"), especially since this was also needed to get that status after a restart, thus the "get" measure
- the "get" measure will not only run at skin refresh, but also after the "set" measure (through its FinishAction), to make sure the status was set properly
- I manipulated the string result of the "get" measure through some simple regular expression Substitute, so it can be used to set the image name in the meter as well
- I added the SoundVolumeView and GetNir tools into an appropriate folder in the @Resources folder of your skin, so that it will work even if you think of distributing such a skin (e.g. the other users might not have these tools installed, or they might not be located where you installed or copied them in the case of your system)

Notes:
- remembering the value of a variable after a skin refresh could have been much easier with the help of !WriteKeyValue bang, which writes variable values to the desired file (e.g. [!WriteKeyValue Variables MicOn #MicOff#][!WriteKeyValue Variables MicOff #MicOn#] or something along those lines), but then, if you somehow unloaded the skin before setting the mic mute status to a different value, the remembered value would be incorrect since it would be based on the last value it has while the skin was still active
- the key to getting the mic mute status was to use another NirSoft tool to pass the output of the SoundVolumeView (which is to the exit status of the program) to STDOUT with the help of GetNir, because RunCommand also gets its value from STDOUT after running its program + parameters
- the Program option can be omitted from a RunCommand measure in most cases by putting everything into the Parameter option (one exception from this is PowerShell, by the way)

Other than that, that's a very good attempt for your first skin after such a brief adaptation period - very few mistakes, well done! :thumbup: If you continue this way, you'll be on route to become what you hope to be... 8-)

P.S. Getting this done using PowerShell would have been a bit trickier, if possible that is.
You do not have the required permissions to view the files attached to this post.
User avatar
RainMaster
Posts: 2
Joined: July 25th, 2021, 11:53 pm

Re: First skin question

Post by RainMaster »

Wow, this is awesome, thank you! I really appreciate all the explanations, it actually helped me to understand how it all works. Now the only thing I can't figure out after tinkering for a bit is why when I load the skin, it shows up for a second and then disappears completely. It seems like this should be working, so I'm kind of at a loss. I basically just installed the .rmskin, letting rainmeter back up my old one just in case, and substituted your mic images for my custom ones with the same file names. It's almost as if the skin is disabling itself, because I can't even click on it after its gone or find any trace of it until I make rainmeter refresh it. Any ideas?

EDIT: I figured it out! For some odd reason GetNir refuses to play nicely with my microphone with the "Command-Line Friendly ID" part. For some reason on my system doing this:

Code: Select all

SoundVolumeView.exe /stab "" | GetNir "Muted" "Command-Line Friendly ID='Realtek High Definition Audio\Device\Microphone Array\Capture'"
Returns the muted state of every audio device on the system. That's why it kept disappearing I suppose, though I'm still not sure why GetNir behaves this way. Changing it to this makes it work:

Code: Select all

GetNir.exe "Muted" "Name='Microphone Array'"


Idk if this has something to do with my system config or what. I like keeping my laptops built-in mic muted when I'm not using it, because I'm a bit paranoid lol. I also had some trouble getting it to change the muted state too, took me longer than I'd like to admit to realize the Measure that toggles the muted state said ...Device\Microphone... instead of ...Device\Microphone Array...

Never would have got this working without your help. Much thanks! I went ahead and included the changed skin just in case anyone else finds it useful.
You do not have the required permissions to view the files attached to this post.
User avatar
Yincognito
Rainmeter Sage
Posts: 4052
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: First skin question

Post by Yincognito »

RainMaster wrote: July 26th, 2021, 6:25 am Wow, this is awesome, thank you! I really appreciate all the explanations, it actually helped me to understand how it all works. Now the only thing I can't figure out after tinkering for a bit is why when I load the skin, it shows up for a second and then disappears completely. It seems like this should be working, so I'm kind of at a loss. I basically just installed the .rmskin, letting rainmeter back up my old one just in case, and substituted your mic images for my custom ones with the same file names. It's almost as if the skin is disabling itself, because I can't even click on it after its gone or find any trace of it until I make rainmeter refresh it. Any ideas?

EDIT: I figured it out! For some odd reason GetNir refuses to play nicely with my microphone with the "Command-Line Friendly ID" part. For some reason on my system doing this:

Code: Select all

SoundVolumeView.exe /stab "" | GetNir "Muted" "Command-Line Friendly ID='Realtek High Definition Audio\Device\Microphone Array\Capture'"
Returns the muted state of every audio device on the system. That's why it kept disappearing I suppose, though I'm still not sure why GetNir behaves this way. Changing it to this makes it work:

Code: Select all

GetNir.exe "Muted" "Name='Microphone Array'"


Idk if this has something to do with my system config or what. I like keeping my laptops built-in mic muted when I'm not using it, because I'm a bit paranoid lol. I also had some trouble getting it to change the muted state too, took me longer than I'd like to admit to realize the Measure that toggles the muted state said ...Device\Microphone... instead of ...Device\Microphone Array...

Never would have got this working without your help. Much thanks! I went ahead and included the changed skin just in case anyone else finds it useful.
Glad you got it working. :great:

I forgot to mention in my previous reply that you should change the friendly IDs that I used to your own ones (this was done so I could test if it works as well, naturally), but eventually you figured it out - my bad, I was focused on the things I explained and although at first I knew I had to mention this, it somehow dissapeared from my mind while writing.

Yeah, I noticed using the "get" command was somewhat "shaky" at first too, in fact the same command didn't produce any outcome for the first 4 or 5 attempts in CMD.EXE in my case. It eventually started to work on a consistent basis, but it took a while to do so. I have no idea why that happened, but maybe your issue was related to that, and I wouldn't be surprised if you would be able to properly use those friendly IDs now as well. :confused:

P.S. The skin didn't "dissapear", actually. What happend was that due to the issue you experienced, the image name wasn't valid (since it was based on only the Yes or No outputs of the command). Since the image was the only meter in the skin, no image meant no visible part of the skin. You should either take into account some "default value" for the image name option in the meter (either in the meter or through variables, or by accounting for other than Yes or No values in the "get" measure's Substitute), or add another "static" meter (could be a dummy one, if you want) to protect against a potentially invalid or missing image name.