// Author: Gockner, Simon // Created: 2021-04-07 // Copyright(c) 2021 SimonG. All Rights Reserved. using System.Collections.Generic; using System.Linq; using Lib.Audio.Controls; using Lib.Audio.Controls.Buttons; using Lib.Audio.Controls.Buttons.Factories; using Lib.Audio.Controls.Buttons.Interfaces; using Lib.Audio.Controls.Factories; using Lib.Audio.Controls.Interfaces; using Lib.Audio.Interfaces; 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) { Fader = faderFactory.Create(xmlChannel.Fader); Fader.PositionChanged += OnFaderPositionChanged; } if (xmlChannel.Knob != null) Knob = knobFactory.Create(); Buttons = new List(); if (xmlChannel.Buttons != null) { foreach (var button in xmlChannel.Buttons) Buttons.Add(buttonFactory.Create(button, _channelNumber)); } _processManager.ProcessStarted += OnProcessManagerProcessStarted; _processManager.ProcessExited += OnProcessManagerProcessExited; } public IFader? Fader { get; } public IKnob? Knob { get; } public List Buttons { get; } public IControllable? Controllable { get; private set; } public void MapControllable(IControllable controllable) { Controllable = controllable; ToggleButtonLed(LedState.On); if (!Controllable.IsValid) return; InitializeFader(); ToggleButtonLed(LedState.On); } private void UnMapControllable() { if (Controllable == null) return; ToggleButtonLed(LedState.Off); ToggleButtonLed(LedState.Off); } public void HandleMessage(IMidiMessage message) { if (message is NoteOnMessage noteOnMessage) { if (Fader?.NoteNumber == noteOnMessage.NoteNumber) Fader.IsTouched = true; else { IButton? button = Buttons.FirstOrDefault(b => b.NoteNumber == noteOnMessage.NoteNumber); _acknowledgeMessage = button?.HandlePressed(Controllable, (Velocity) noteOnMessage.Velocity); } } else if (message is NoteMessage noteMessage) { if (Fader?.NoteNumber == noteMessage.NoteNumber) { Fader.IsTouched = false; _acknowledgeMessage = new PitchWheelChangeMessage(0, _channelNumber, Fader.Position); } else { IButton? button = Buttons.FirstOrDefault(b => b.NoteNumber == noteMessage.NoteNumber); _acknowledgeMessage = button?.HandlePressed(Controllable, (Velocity) noteMessage.Velocity); } } else if (message is PitchWheelChangeMessage pitchWheelChangeMessage) { if (Fader != null) Fader.Position = pitchWheelChangeMessage.Pitch; } } public void SendAcknowledge() { if (_acknowledgeMessage == null) return; _midiCommunication.Send(_acknowledgeMessage); _acknowledgeMessage = null; } private void InitializeFader() { if (Fader == null || Controllable == null) return; float volume = Controllable.GetVolume(); Fader.RelativePosition = volume; _midiCommunication.Send(new PitchWheelChangeMessage(0, _channelNumber, Fader.Position)); } private void ToggleButtonLed(LedState ledState) where TButton : IButton { TButton? button = Buttons.OfType().FirstOrDefault(); IMidiMessage? selectMessage = button?.ToggleLed(ledState); if (selectMessage != null) _midiCommunication.Send(selectMessage); } private void OnFaderPositionChanged(object? sender, int position) { if (sender is not IFader fader) return; Controllable?.SetVolume(fader.RelativePosition); } private void OnProcessManagerProcessStarted(object? sender, IObservedProcess process) { if (Controllable == null) return; if (!Controllable.ExecutablePath.Equals(process.FileName)) return; Controllable = _controllableCollector.GetControllableForExecutable(Controllable.ExecutablePath); if (Controllable == null) return; InitializeFader(); ToggleButtonLed(LedState.On); } private void OnProcessManagerProcessExited(object? sender, IObservedProcess process) { if (Controllable == null) return; if (!Controllable.ExecutablePath.Equals(process.FileName)) return; Controllable.IsValid = false; ToggleButtonLed(LedState.Off); } public override string ToString() => $"Channel {_channelNumber}"; public void Dispose() { _processManager.ProcessStarted -= OnProcessManagerProcessStarted; _processManager.ProcessExited -= OnProcessManagerProcessExited; UnMapControllable(); _midiCommunication.Send(new PitchWheelChangeMessage(0, _channelNumber, 0)); foreach (IMidiMessage ledOffMessage in Buttons.Select(b => b.ToggleLed(LedState.Off))) _midiCommunication.Send(ledOffMessage); } } }