ho0ber / NK2Tray

Windows Application Volume Control via MIDI
Microsoft Public License
167 stars 26 forks source link

🚀 Refactor and react to external volume changes #67

Closed jpwilliams closed 4 years ago

jpwilliams commented 4 years ago

This will be a draft until more testing can be done and the refactor is seen as beneficial.


The main aim of this PR is to have the volume/mute indicators on the MIDI controller react to outside input. For example, if I change the volume manually in the Windows Volume Mixer, the indicators on my controller should show the new volume that has been set.

This PR achieves that (with less code than before!) but it became apparent that a refactor of the way we handle audio devices and Windows Mixer entries would be a good move.


Main changes


What was the point of a refactor?

The #1 target was to remove the constant refreshing and duplication of MixerSession instances which would create many internal MMDevice instances. This was causing a small memory leak, but the main drawback was that it was confusing to work with after a good year-or-so of small edits and tweaks.

The AudioDeviceWatcher uses events to keep an up-to-date list of both audio devices and Windows Mixer entries with no need for manual refreshing. This means that not only are we no longer spawning MMDevice instances where we don't need to, but also that the absolute latest state is always available for viewing in places like the pop-up. This means it's lightning fast, simpler, and has no memory leaks! In fact, AudioDeviceWatcher even keeps track of the current default audio device, meaning we could add an option that always controls your default!

There was also a lot of code that traversed the various "types" of MixerSession: Master, Application, SystemSounds, and Focus. For this, we've created a new Assignment class which provides a consistent interface that things like Fader can use to reliably get/set volumes/mutes (etc) without having to worry about the source.

On top of this, our Assignment instances register to events from the AudioDeviceWatcher and can feed external volume/mute/etc changes back to faders, meaning we can now keep the MIDI controller up-to-date with whatever state the machine is in without having to constantly check!


Is everything working?

I'll add a list here to work through and will include anything else that pops up. Currently, a couple of things haven't been added in:


Building and testing

Because of the nature of Visual Studio, it may be necessary to clean your solution before you try using this branch.

  1. Check out branch
  2. Build -> Clean Solution
  3. Delete bin and obj folders inside NK2Tray folder
  4. Go!