From a2893dd6c3963639b0236b183629ec5cd9dd14b9 Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto <6766154+Zumorica@users.noreply.github.com> Date: Sun, 16 Jul 2023 21:12:53 +0200 Subject: [PATCH] Instrument band support, submodule update to 138.0.0 (#17995) --- .../Instruments/InstrumentSystem.cs | 114 ++++++-- Content.Client/Instruments/UI/BandMenu.xaml | 9 + .../Instruments/UI/BandMenu.xaml.cs | 45 +++ .../Instruments/UI/ChannelsMenu.xaml | 11 + .../Instruments/UI/ChannelsMenu.xaml.cs | 66 +++++ .../UI/InstrumentBoundUserInterface.cs | 83 +++++- .../Instruments/UI/InstrumentMenu.xaml | 10 +- .../Instruments/UI/InstrumentMenu.xaml.cs | 121 +++++--- .../Instruments/InstrumentComponent.cs | 23 +- .../Instruments/InstrumentSystem.cs | 264 ++++++++++++++++-- .../Instruments/SharedInstrumentComponent.cs | 82 +++--- .../Instruments/SharedInstrumentSystem.cs | 39 +-- .../InstrumentBoundUserInterfaceMessages.cs | 19 ++ .../instruments/instruments-component.ftl | 10 +- RobustToolbox | 2 +- SpaceStation14.sln.DotSettings | 2 + 16 files changed, 722 insertions(+), 178 deletions(-) create mode 100644 Content.Client/Instruments/UI/BandMenu.xaml create mode 100644 Content.Client/Instruments/UI/BandMenu.xaml.cs create mode 100644 Content.Client/Instruments/UI/ChannelsMenu.xaml create mode 100644 Content.Client/Instruments/UI/ChannelsMenu.xaml.cs create mode 100644 Content.Shared/Instruments/UI/InstrumentBoundUserInterfaceMessages.cs diff --git a/Content.Client/Instruments/InstrumentSystem.cs b/Content.Client/Instruments/InstrumentSystem.cs index 009fa6bcc5..02e3cf0da3 100644 --- a/Content.Client/Instruments/InstrumentSystem.cs +++ b/Content.Client/Instruments/InstrumentSystem.cs @@ -52,13 +52,44 @@ public sealed class InstrumentSystem : SharedInstrumentSystem EndRenderer(uid, false, component); } + public void SetMaster(EntityUid uid, EntityUid? masterUid) + { + if (!TryComp(uid, out InstrumentComponent? instrument)) + return; + + RaiseNetworkEvent(new InstrumentSetMasterEvent(uid, masterUid)); + } + + public void SetFilteredChannel(EntityUid uid, int channel, bool value) + { + if (!TryComp(uid, out InstrumentComponent? instrument)) + return; + + if(value) + instrument.Renderer?.SendMidiEvent(RobustMidiEvent.AllNotesOff((byte)channel, 0), false); + + RaiseNetworkEvent(new InstrumentSetFilteredChannelEvent(uid, channel, value)); + } + public override void SetupRenderer(EntityUid uid, bool fromStateChange, SharedInstrumentComponent? component = null) { if (!Resolve(uid, ref component)) return; - if (component is not InstrumentComponent instrument || instrument.IsRendererAlive) + if (component is not InstrumentComponent instrument) + { return; + } + + if (instrument.IsRendererAlive) + { + if (fromStateChange) + { + UpdateRenderer(uid, instrument); + } + + return; + } instrument.SequenceDelay = 0; instrument.SequenceStartTick = 0; @@ -88,17 +119,39 @@ public sealed class InstrumentSystem : SharedInstrumentSystem return; instrument.Renderer.TrackingEntity = uid; + + instrument.Renderer.FilteredChannels.SetAll(false); + instrument.Renderer.FilteredChannels.Or(instrument.FilteredChannels); + instrument.Renderer.DisablePercussionChannel = !instrument.AllowPercussion; instrument.Renderer.DisableProgramChangeEvent = !instrument.AllowProgramChange; + for (int i = 0; i < RobustMidiEvent.MaxChannels; i++) + { + if(instrument.FilteredChannels[i]) + instrument.Renderer.SendMidiEvent(RobustMidiEvent.AllNotesOff((byte)i, 0)); + } + if (!instrument.AllowProgramChange) { instrument.Renderer.MidiBank = instrument.InstrumentBank; instrument.Renderer.MidiProgram = instrument.InstrumentProgram; } + UpdateRendererMaster(instrument); + instrument.Renderer.LoopMidi = instrument.LoopMidi; - instrument.DirtyRenderer = false; + } + + private void UpdateRendererMaster(InstrumentComponent instrument) + { + if (instrument.Renderer == null || instrument.Master == null) + return; + + if (!TryComp(instrument.Master, out InstrumentComponent? masterInstrument) || masterInstrument.Renderer == null) + return; + + instrument.Renderer.Master = masterInstrument.Renderer; } public override void EndRenderer(EntityUid uid, bool fromStateChange, SharedInstrumentComponent? component = null) @@ -121,7 +174,8 @@ public sealed class InstrumentSystem : SharedInstrumentSystem return; } - instrument.Renderer?.StopAllNotes(); + instrument.Renderer?.SystemReset(); + instrument.Renderer?.ClearAllEvents(); var renderer = instrument.Renderer; @@ -162,13 +216,14 @@ public sealed class InstrumentSystem : SharedInstrumentSystem SetupRenderer(uid, false, instrument); - if (instrument.Renderer != null && instrument.Renderer.OpenInput()) - { - instrument.Renderer.OnMidiEvent += instrument.MidiEventBuffer.Add; - return true; - } + if (instrument.Renderer == null || !instrument.Renderer.OpenInput()) + return false; + + SetMaster(uid, null); + instrument.MidiEventBuffer.Clear(); + instrument.Renderer.OnMidiEvent += instrument.MidiEventBuffer.Add; + return true; - return false; } public bool OpenMidi(EntityUid uid, ReadOnlySpan data, InstrumentComponent? instrument = null) @@ -179,12 +234,10 @@ public sealed class InstrumentSystem : SharedInstrumentSystem SetupRenderer(uid, false, instrument); if (instrument.Renderer == null || !instrument.Renderer.OpenMidi(data)) - { return false; - } + SetMaster(uid, null); instrument.MidiEventBuffer.Clear(); - instrument.Renderer.OnMidiEvent += instrument.MidiEventBuffer.Add; return true; } @@ -266,12 +319,24 @@ public sealed class InstrumentSystem : SharedInstrumentSystem instrument.SequenceDelay = Math.Max(instrument.SequenceDelay, delta); - var currentTick = renderer.SequencerTick; + SendMidiEvents(midiEv.MidiEvent, instrument); + } + + private void SendMidiEvents(IReadOnlyList midiEvents, InstrumentComponent instrument) + { + if (instrument.Renderer == null) + { + Log.Warning($"Tried to send Midi events to an instrument without a renderer."); + return; + } + + var currentTick = instrument.Renderer.SequencerTick; // ReSharper disable once ForCanBeConvertedToForeach - for (uint i = 0; i < midiEv.MidiEvent.Length; i++) + for (uint i = 0; i < midiEvents.Count; i++) { - var ev = midiEv.MidiEvent[i]; + // I am surprised this doesn't take uint... + var ev = midiEvents[(int)i]; var scheduled = ev.Tick + instrument.SequenceDelay; @@ -306,12 +371,14 @@ public sealed class InstrumentSystem : SharedInstrumentSystem return; } - foreach (var instrument in EntityManager.EntityQuery(true)) + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var instrument)) { - if (instrument.DirtyRenderer && instrument.Renderer != null) - UpdateRenderer(instrument.Owner, instrument); + // For cases where the master renderer was not created yet. + if (instrument is { Renderer.Master: null, Master: not null }) + UpdateRendererMaster(instrument); - if (!instrument.IsMidiOpen && !instrument.IsInputOpen) + if (instrument is { IsMidiOpen: false, IsInputOpen: false }) continue; var now = _gameTiming.RealTime; @@ -323,10 +390,11 @@ public sealed class InstrumentSystem : SharedInstrumentSystem instrument.SentWithinASec = 0; } - if (instrument.MidiEventBuffer.Count == 0) continue; + if (instrument.MidiEventBuffer.Count == 0) + continue; - var max = instrument.RespectMidiLimits ? - Math.Min(MaxMidiEventsPerBatch, MaxMidiEventsPerSecond - instrument.SentWithinASec) + var max = instrument.RespectMidiLimits + ? Math.Min(MaxMidiEventsPerBatch, MaxMidiEventsPerSecond - instrument.SentWithinASec) : instrument.MidiEventBuffer.Count; if (max <= 0) @@ -357,7 +425,7 @@ public sealed class InstrumentSystem : SharedInstrumentSystem if (eventCount == 0) continue; - RaiseNetworkEvent(new InstrumentMidiEventEvent(instrument.Owner, events)); + RaiseNetworkEvent(new InstrumentMidiEventEvent(uid, events)); instrument.SentWithinASec += eventCount; diff --git a/Content.Client/Instruments/UI/BandMenu.xaml b/Content.Client/Instruments/UI/BandMenu.xaml new file mode 100644 index 0000000000..620f38fa97 --- /dev/null +++ b/Content.Client/Instruments/UI/BandMenu.xaml @@ -0,0 +1,9 @@ + + + +