diff --git a/Lib.Audio/Channel.cs b/Lib.Audio/Channel.cs index 3fd3ead..60bb5b8 100644 --- a/Lib.Audio/Channel.cs +++ b/Lib.Audio/Channel.cs @@ -14,22 +14,31 @@ using Lib.Driver.Xml; using Lib.Midi.Interfaces; using Lib.Midi.Messages; using Lib.Midi.Messages.Interfaces; +using Lib.ProcessManaging.Interfaces; namespace Lib.Audio { public class Channel : IChannel { + private readonly IControllableCollector _controllableCollector; private readonly IMidiCommunication _midiCommunication; + private readonly IProcessManager _processManager; + private readonly int _channelNumber; + private IMidiMessage? _acknowledgeMessage; public Channel(XmlChannel xmlChannel, + IControllableCollector controllableCollector, IMidiCommunication midiCommunication, + IProcessManager processManager, IFaderFactory faderFactory, IKnobFactory knobFactory, IButtonFactory buttonFactory) { + _controllableCollector = controllableCollector; _midiCommunication = midiCommunication; + _processManager = processManager; _channelNumber = xmlChannel.ChannelNumber; if (xmlChannel.Fader != null) @@ -47,6 +56,9 @@ namespace Lib.Audio foreach (var button in xmlChannel.Buttons) Buttons.Add(buttonFactory.Create(button, _channelNumber)); } + + _processManager.ProcessStarted += OnProcessManagerProcessStarted; + _processManager.ProcessExited += OnProcessManagerProcessExited; } public IFader? Fader { get; } @@ -137,11 +149,36 @@ namespace Lib.Audio Controllable?.SetVolume(fader.RelativePosition); } + + private void OnProcessManagerProcessStarted(object? sender, IObservedProcess process) + { + if (Controllable?.Process == null) + return; + + if (!Controllable.Process.IsSameExecutable(process)) + return; + + Controllable = _controllableCollector.GetControllableForProcess(process); + } + + private void OnProcessManagerProcessExited(object? sender, IObservedProcess process) + { + if (Controllable?.Process == null) + return; + + if (!Controllable.Process.IsSameExecutable(process)) + return; + + Controllable.IsValid = false; //TODO: Toggle Record button led + } public override string ToString() => $"Channel {_channelNumber}"; public void Dispose() { + _processManager.ProcessStarted -= OnProcessManagerProcessStarted; + _processManager.ProcessExited -= OnProcessManagerProcessExited; + UnMapControllable(); _midiCommunication.Send(new PitchWheelChangeMessage(0, _channelNumber, 0)); } diff --git a/Lib.Audio/Controllable.cs b/Lib.Audio/Controllable.cs index e948e27..7ceeb04 100644 --- a/Lib.Audio/Controllable.cs +++ b/Lib.Audio/Controllable.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using Lib.Audio.Interfaces; +using Lib.ProcessManaging.Interfaces; using NAudio.CoreAudioApi; namespace Lib.Audio @@ -13,12 +14,15 @@ namespace Lib.Audio { private readonly List _audioSessionControls; - public Controllable(List audioSessionControls, string name) + public Controllable(List audioSessionControls, IObservedProcess? process, string name) { _audioSessionControls = audioSessionControls; + Process = process; Name = name; } + public bool IsValid { get; set; } = true; + public IObservedProcess? Process { get; } public string Name { get; } public string? IconPath => _audioSessionControls.FirstOrDefault(c => !string.IsNullOrEmpty(c.IconPath))?.IconPath; diff --git a/Lib.Audio/ControllableCollector.cs b/Lib.Audio/ControllableCollector.cs index fa18670..45c8a21 100644 --- a/Lib.Audio/ControllableCollector.cs +++ b/Lib.Audio/ControllableCollector.cs @@ -4,10 +4,10 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using Lib.Audio.Factories; using Lib.Audio.Interfaces; +using Lib.ProcessManaging.Interfaces; using NAudio.CoreAudioApi; using NAudio.CoreAudioApi.Interfaces; @@ -15,11 +15,20 @@ namespace Lib.Audio { public class ControllableCollector : IControllableCollector { + private readonly IProcessManager _processManager; private readonly IControllableFactory _controllableFactory; - public ControllableCollector(IControllableFactory controllableFactory) => _controllableFactory = controllableFactory; + public ControllableCollector(IProcessManager processManager, IControllableFactory controllableFactory) + { + _processManager = processManager; + _controllableFactory = controllableFactory; + } public List Controllables => CreateControllables(); + + public IControllable? GetControllableForProcess(IObservedProcess process) => + Controllables.FirstOrDefault(c => c.Process != null && c.Process.IsSameExecutable(process)); + private List CreateControllables() { MMDeviceEnumerator deviceEnumerator = new(); @@ -54,7 +63,7 @@ namespace Lib.Audio { List idSessions = sessionsById[id]; - (Process? process, AudioSessionControl? audioSessionControl) = FindProcess(idSessions); + (IObservedProcess? process, AudioSessionControl? audioSessionControl) = FindProcess(idSessions); if (audioSessionControl == null || process == default && !idSessions.Any(s => s.IsSystemSoundsSession)) continue; @@ -62,25 +71,23 @@ namespace Lib.Audio if (idSessions.Any(s => s.IsSystemSoundsSession)) name = "System Sounds"; else if (process != null) - name = process.ProcessName; + name = process.Name; else name = id; - controllables.Add(_controllableFactory.Create(idSessions, name)); + controllables.Add(_controllableFactory.Create(idSessions, process, name)); } return controllables; } - private (Process? process, AudioSessionControl? session) FindProcess(List sessions) + private (IObservedProcess? process, AudioSessionControl? session) FindProcess(List sessions) { - try - { - foreach (var session in sessions) - return (Process.GetProcessById((int) session.GetProcessID), session); - } - catch (ArgumentException) + foreach (var session in sessions) { + IObservedProcess? process = _processManager.GetProcessById((int) session.GetProcessID); + if (process != null) + return (process, session); } return (null, null); diff --git a/Lib.Audio/Device.cs b/Lib.Audio/Device.cs index f0ae440..f288ea5 100644 --- a/Lib.Audio/Device.cs +++ b/Lib.Audio/Device.cs @@ -20,13 +20,13 @@ namespace Lib.Audio private readonly IMidiCommunication _midiCommunication; private readonly IChannelFactory _channelFactory; - public Device(IDriver driver, IMidiCommunicationFactory midiCommunicationFactory, IChannelFactory channelFactory) + public Device(IDriver driver, IControllableCollector controllableCollector, IMidiCommunicationFactory midiCommunicationFactory, IChannelFactory channelFactory) { _driver = driver; _midiCommunication = midiCommunicationFactory.Create(driver); _channelFactory = channelFactory; - Channels = InitializeChannels(); + Channels = InitializeChannels(controllableCollector); _midiCommunication.MessageReceived += OnMidiCommunicationMessageReceived; _midiCommunication.ErrorReceived += OnMidiCommunicationErrorReceived; @@ -36,8 +36,8 @@ namespace Lib.Audio public List Channels { get; } public void StartCommunication(bool useMidiView) => _midiCommunication.Open(useMidiView); - private List InitializeChannels() => _driver.Channels == null ? new List() - : _driver.Channels.Select(c => _channelFactory.Create(c, _midiCommunication)).ToList(); + private List InitializeChannels(IControllableCollector controllableCollector) => _driver.Channels == null ? new List() + : _driver.Channels.Select(c => _channelFactory.Create(c, controllableCollector, _midiCommunication)).ToList(); private void OnMidiCommunicationMessageReceived(object? sender, IMidiMessage message) { diff --git a/Lib.Audio/Factories/IChannelFactory.cs b/Lib.Audio/Factories/IChannelFactory.cs index bd5c7f1..62c5a09 100644 --- a/Lib.Audio/Factories/IChannelFactory.cs +++ b/Lib.Audio/Factories/IChannelFactory.cs @@ -10,6 +10,7 @@ namespace Lib.Audio.Factories { public interface IChannelFactory { - IChannel Create(XmlChannel xmlChannel, IMidiCommunication midiCommunication); + IChannel Create(XmlChannel xmlChannel, IControllableCollector controllableCollector, + IMidiCommunication midiCommunication); } } \ No newline at end of file diff --git a/Lib.Audio/Factories/IControllableFactory.cs b/Lib.Audio/Factories/IControllableFactory.cs index 4d805d0..36ff770 100644 --- a/Lib.Audio/Factories/IControllableFactory.cs +++ b/Lib.Audio/Factories/IControllableFactory.cs @@ -4,13 +4,14 @@ using System.Collections.Generic; using Lib.Audio.Interfaces; +using Lib.ProcessManaging.Interfaces; using NAudio.CoreAudioApi; namespace Lib.Audio.Factories { public interface IControllableFactory { - IControllable Create(List audioSessionControls, string name); + IControllable Create(List audioSessionControls, IObservedProcess? process, string name); IMasterControllable Create(AudioEndpointVolume audioEndpointVolume, string name); } } \ No newline at end of file diff --git a/Lib.Audio/Factories/IDeviceFactory.cs b/Lib.Audio/Factories/IDeviceFactory.cs index c653d44..e322cb8 100644 --- a/Lib.Audio/Factories/IDeviceFactory.cs +++ b/Lib.Audio/Factories/IDeviceFactory.cs @@ -9,6 +9,6 @@ namespace Lib.Audio.Factories { public interface IDeviceFactory { - IDevice Create(IDriver driver); + IDevice Create(IDriver driver, IControllableCollector controllableCollector); } } \ No newline at end of file diff --git a/Lib.Audio/Interfaces/IControllable.cs b/Lib.Audio/Interfaces/IControllable.cs index 86d4ff8..421f8fc 100644 --- a/Lib.Audio/Interfaces/IControllable.cs +++ b/Lib.Audio/Interfaces/IControllable.cs @@ -2,10 +2,15 @@ // Created: 2021-04-07 // Copyright(c) 2021 SimonG. All Rights Reserved. +using Lib.ProcessManaging.Interfaces; + namespace Lib.Audio.Interfaces { public interface IControllable { + bool IsValid { get; set; } + IObservedProcess? Process { get; } + string Name { get; } string? IconPath { get; } diff --git a/Lib.Audio/Interfaces/IControllableCollector.cs b/Lib.Audio/Interfaces/IControllableCollector.cs index 9a1f5f7..91782e8 100644 --- a/Lib.Audio/Interfaces/IControllableCollector.cs +++ b/Lib.Audio/Interfaces/IControllableCollector.cs @@ -3,11 +3,14 @@ // Copyright(c) 2021 SimonG. All Rights Reserved. using System.Collections.Generic; +using Lib.ProcessManaging.Interfaces; namespace Lib.Audio.Interfaces { public interface IControllableCollector { List Controllables { get; } + + IControllable? GetControllableForProcess(IObservedProcess process); } } \ No newline at end of file diff --git a/Lib.Audio/Lib.Audio.csproj b/Lib.Audio/Lib.Audio.csproj index 011ec4b..2d61cf1 100644 --- a/Lib.Audio/Lib.Audio.csproj +++ b/Lib.Audio/Lib.Audio.csproj @@ -13,6 +13,7 @@ + diff --git a/Lib.Audio/MasterControllable.cs b/Lib.Audio/MasterControllable.cs index f8ec36f..aa7f34b 100644 --- a/Lib.Audio/MasterControllable.cs +++ b/Lib.Audio/MasterControllable.cs @@ -3,6 +3,7 @@ // Copyright(c) 2021 SimonG. All Rights Reserved. using Lib.Audio.Interfaces; +using Lib.ProcessManaging.Interfaces; using NAudio.CoreAudioApi; namespace Lib.Audio @@ -19,6 +20,8 @@ namespace Lib.Audio _controllableCollector = controllableCollector; } + public bool IsValid { get; set; } + public IObservedProcess? Process { get; } public string Name { get; } public string? IconPath => null; diff --git a/Mystify/MainModel.cs b/Mystify/MainModel.cs index cc9f63c..ea48c1f 100644 --- a/Mystify/MainModel.cs +++ b/Mystify/MainModel.cs @@ -40,8 +40,8 @@ namespace Mystify if (driver == null) throw new Exception("Driver could not be loaded."); - _device = _deviceFactory.Create(driver); _controllableCollector = _controllableCollectorFactory.Create(); + _device = _deviceFactory.Create(driver, _controllableCollector); _device.StartCommunication(UseMidiView); }