#nullable enable using System; using NAudio.Midi; namespace T3.IoServices; /// /// Parallel dispatch path for replaying recorded IO events through graph-side input /// operators (MidiInput, OscInput) without going through the normal /// hardware-bound MidiConnectionManager / OscConnectionManager routes. /// Makes those ops fire identically whether their events come from a real device or /// from a recorded .data file, identified by the same device name. /// /// /// Does not reach CompatibleMidiDevice instances (the surface controllers /// driving variations / snapshots) — those filter by sender == _midiInputConnection /// and always need a real . Variation replay is out of scope for /// this bus by design. /// /// The producer side is the SimulateIoData operator; consumers subscribe in /// their constructor and unsubscribe on dispose. Real-time recording /// () only listens to the connection managers, so /// simulated events never feed back into a concurrent recording. /// /// public static class SimulatedIoBus { /// /// One replayed MIDI event. Identifies the source device by product name (the same /// string MidiInput.Device matches against) rather than by /// instance, so simulation works without the original hardware connected. /// /// Source device name as recorded. /// Reconstructed NAudio MIDI event — typically NoteEvent, /// ControlChangeEvent, PitchWheelChangeEvent, or /// ChannelAfterTouchEvent. public sealed record SimulatedMidiEvent(string DeviceProductName, MidiEvent Event); /// /// One replayed OSC event. The port matches the recorded source's port so an /// OscInput bound to that port receives the event identically to a real one. /// public sealed record SimulatedOscEvent(int Port, string Address, object Value); public static event Action? MidiEventReceived; public static event Action? OscEventReceived; public static void DispatchMidi(SimulatedMidiEvent ev) => MidiEventReceived?.Invoke(ev); public static void DispatchOsc(SimulatedOscEvent ev) => OscEventReceived?.Invoke(ev); }