diff --git a/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs b/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs index 039290ccd5..59b77de12d 100644 --- a/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs +++ b/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs @@ -2,15 +2,17 @@ using System; using System.Collections.Generic; using Content.Shared.GameObjects.Components.Instruments; using JetBrains.Annotations; +using NFluidsynth; using Robust.Shared.GameObjects; using Robust.Client.Audio.Midi; -using Robust.Shared.Audio.Midi; using Robust.Shared.Interfaces.Network; using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Robust.Shared.Players; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; +using Logger = Robust.Shared.Log.Logger; +using MidiEvent = Robust.Shared.Audio.Midi.MidiEvent; using Timer = Robust.Shared.Timers.Timer; @@ -19,7 +21,7 @@ namespace Content.Client.GameObjects.Components.Instruments [RegisterComponent] public class InstrumentComponent : SharedInstrumentComponent { - public const float TimeBetweenNetMessages = 1f; + public const float TimeBetweenNetMessages = 0.5f; /// /// Called when a midi song stops playing. @@ -35,16 +37,16 @@ namespace Content.Client.GameObjects.Components.Instruments private IMidiRenderer _renderer; private byte _instrumentProgram = 1; + /// + /// A queue of MidiEvents to be sent to the server. + /// [ViewVariables] - private readonly Queue> _midiQueue = new Queue<(MidiEvent, double)>(); + private readonly Queue _midiQueue = new Queue(); [ViewVariables] private float _timer = 0f; - /// - /// A queue of MidiEvents to be sent to the server. - /// - private Queue _eventQueue = new Queue(); + private TimeSpan? _lastEvent = null; /// /// Whether a midi song will loop or not. @@ -140,11 +142,6 @@ namespace Content.Client.GameObjects.Components.Instruments { base.HandleNetworkMessage(message, channel, session); - if (_renderer == null) - { - return; - } - switch (message) { case InstrumentMidiEventMessage midiEventMessage: @@ -152,22 +149,27 @@ namespace Content.Client.GameObjects.Components.Instruments if (!IsRendererAlive || IsInputOpen || IsMidiOpen) break; for (var i = 0; i < midiEventMessage.MidiEvent.Length; i++) { - //_midiQueue.Enqueue((midiEventMessage.MidiEvent[i], (i == 0 ? 0 : 0) + _gameTiming.CurTime.TotalSeconds - midiEventMessage.Timestamp[i])); + var ev = midiEventMessage.MidiEvent[i]; + var delta = i != 0 ? ev.Timestamp.Subtract(midiEventMessage.MidiEvent[i-1].Timestamp) : _lastEvent.HasValue ? ev.Timestamp.Subtract(_lastEvent.Value) : TimeSpan.Zero; + ev.Timestamp = _gameTiming.CurTime + delta + TimeSpan.FromSeconds(TimeBetweenNetMessages*1.25); + _midiQueue.Enqueue(ev); + _lastEvent = ev.Timestamp; - var j = i; - Timer.Spawn((int) ((TimeBetweenNetMessages)*1.5f + _gameTiming.CurTime.TotalSeconds - midiEventMessage.Timestamp[i])*1000, - () => _renderer.SendMidiEvent(midiEventMessage.MidiEvent[j])); + //var j = i; + //Timer.Spawn((int) ((TimeBetweenNetMessages)*1.5f)*1000, + // () => _renderer.SendMidiEvent(midiEventMessage.MidiEvent[j])); } break; case InstrumentStopMidiMessage _: - _renderer.StopAllNotes(); + _renderer?.StopAllNotes(); if (IsInputOpen) CloseInput(); if (IsMidiOpen) CloseMidi(); break; case InstrumentStartMidiMessage _: SetupRenderer(); + Logger.Info("INITIALIZED MIDI RENDERER. I HOPE."); break; } } @@ -196,6 +198,7 @@ namespace Content.Client.GameObjects.Components.Instruments } EndRenderer(); + SendNetworkMessage(new InstrumentStopMidiMessage()); return true; } @@ -223,6 +226,7 @@ namespace Content.Client.GameObjects.Components.Instruments } EndRenderer(); + SendNetworkMessage(new InstrumentStopMidiMessage()); return true; } @@ -232,7 +236,8 @@ namespace Content.Client.GameObjects.Components.Instruments /// The received midi event private void RendererOnMidiEvent(MidiEvent midiEvent) { - _midiQueue.Enqueue((midiEvent, _gameTiming.CurTime.TotalSeconds)); + midiEvent.Timestamp = _gameTiming.CurTime; + _midiQueue.Enqueue(midiEvent); } public override void Update(float delta) @@ -243,7 +248,7 @@ namespace Content.Client.GameObjects.Components.Instruments if (!IsMidiOpen && !IsInputOpen) { - //UpdatePlaying(delta); + UpdatePlaying(delta); return; } @@ -254,25 +259,19 @@ namespace Content.Client.GameObjects.Components.Instruments private void UpdatePlaying(float delta) { if(_renderer == null || _midiQueue.Count == 0) return; - var (midiEvent, timestamp) = _midiQueue.Dequeue(); + var midiEvent = _midiQueue.Dequeue(); _renderer.SendMidiEvent(midiEvent); - _timer = _midiQueue.Count != 0 ? (float) (_midiQueue.Peek().Item2) : 0; + _timer = _midiQueue.Count != 0 ? (float) (midiEvent.Timestamp.Subtract(_gameTiming.CurTime).TotalSeconds) : 0; // ???? TODO: fix this } private void SendAllMidiMessages() { var count = _midiQueue.Count; - var events = new MidiEvent[count]; - var timestamps = new double[count]; + if (count == 0) return; + var events = _midiQueue.ToArray(); + _midiQueue.Clear(); - for (var i = 0; i < count; i++) - { - var (midiEvent, timestamp) = _midiQueue.Dequeue(); - events[i] = midiEvent; - timestamps[i] = timestamp; - } - - SendNetworkMessage(new InstrumentMidiEventMessage(events, timestamps)); + SendNetworkMessage(new InstrumentMidiEventMessage(events)); } } } diff --git a/Content.Shared/GameObjects/EntitySystems/SharedInstrumentSystem.cs b/Content.Client/GameObjects/EntitySystems/InstrumentSystem.cs similarity index 60% rename from Content.Shared/GameObjects/EntitySystems/SharedInstrumentSystem.cs rename to Content.Client/GameObjects/EntitySystems/InstrumentSystem.cs index 577d1542bd..6303475c30 100644 --- a/Content.Shared/GameObjects/EntitySystems/SharedInstrumentSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/InstrumentSystem.cs @@ -1,15 +1,15 @@ -using Content.Shared.GameObjects.Components.Instruments; +using Content.Client.GameObjects.Components.Instruments; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -namespace Content.Shared.GameObjects.EntitySystems +namespace Content.Client.GameObjects.EntitySystems { public class InstrumentSystem : EntitySystem { public override void Initialize() { base.Initialize(); - EntityQuery = new TypeEntityQuery(typeof(SharedInstrumentComponent)); + EntityQuery = new TypeEntityQuery(typeof(InstrumentComponent)); } public override void Update(float frameTime) @@ -18,7 +18,7 @@ namespace Content.Shared.GameObjects.EntitySystems foreach (var entity in RelevantEntities) { - entity.GetComponent().Update(frameTime); + entity.GetComponent().Update(frameTime); } } } diff --git a/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs b/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs index e7c01d61a8..32768d10ae 100644 --- a/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs +++ b/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs @@ -1,5 +1,6 @@ using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects.Components.Instruments; +using NFluidsynth; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.Interfaces.GameObjects; @@ -18,7 +19,7 @@ namespace Content.Server.GameObjects.Components.Instruments public class InstrumentComponent : SharedInstrumentComponent, IDropped, IHandSelected, IHandDeselected, IActivate, IUse, IThrown { - public const int MidiEventsPerSecond = 10; + public const int MaxMidiEventsPerSecond = 20; /// /// The client channel currently playing the instrument, or null if there's none. @@ -26,8 +27,13 @@ namespace Content.Server.GameObjects.Components.Instruments private ICommonSession _instrumentPlayer; private bool _handheld; + [ViewVariables] + private bool _playing = false; + private float _timer = 0f; - private int _midiEventCount = 1; + + [ViewVariables] + private int _midiEventCount = 0; [ViewVariables] private BoundUserInterface _userInterface; @@ -60,19 +66,25 @@ namespace Content.Server.GameObjects.Components.Instruments switch (message) { case InstrumentMidiEventMessage midiEventMsg: - SendNetworkMessage(midiEventMsg); + if (!_playing) + return; + if(++_midiEventCount <= MaxMidiEventsPerSecond) + SendNetworkMessage(new InstrumentMidiEventMessage(midiEventMsg.MidiEvent)); break; case InstrumentStartMidiMessage startMidi: - SendNetworkMessage(startMidi); + _playing = true; + SendNetworkMessage(new InstrumentStartMidiMessage()); break; case InstrumentStopMidiMessage stopMidi: - SendNetworkMessage(stopMidi); + _playing = false; + SendNetworkMessage(new InstrumentStopMidiMessage()); break; } } public void Dropped(DroppedEventArgs eventArgs) { + _playing = false; SendNetworkMessage(new InstrumentStopMidiMessage()); _instrumentPlayer = null; _userInterface.CloseAll(); @@ -80,6 +92,7 @@ namespace Content.Server.GameObjects.Components.Instruments public void Thrown(ThrownEventArgs eventArgs) { + _playing = false; SendNetworkMessage(new InstrumentStopMidiMessage()); _instrumentPlayer = null; _userInterface.CloseAll(); @@ -96,6 +109,7 @@ namespace Content.Server.GameObjects.Components.Instruments public void HandDeselected(HandDeselectedEventArgs eventArgs) { + _playing = false; SendNetworkMessage(new InstrumentStopMidiMessage()); _userInterface.CloseAll(); } @@ -128,6 +142,7 @@ namespace Content.Server.GameObjects.Components.Instruments { _instrumentPlayer = null; SendNetworkMessage(new InstrumentStopMidiMessage()); + _playing = false; } } @@ -139,6 +154,11 @@ namespace Content.Server.GameObjects.Components.Instruments public override void Update(float delta) { base.Update(delta); + + _timer += delta; + if (_timer < 1) return; + _timer = 0f; + _midiEventCount = 0; } } } diff --git a/Content.Server/GameObjects/EntitySystems/InstrumentSystem.cs b/Content.Server/GameObjects/EntitySystems/InstrumentSystem.cs new file mode 100644 index 0000000000..a64f1fec01 --- /dev/null +++ b/Content.Server/GameObjects/EntitySystems/InstrumentSystem.cs @@ -0,0 +1,25 @@ +using Content.Server.GameObjects.Components.Instruments; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; + +namespace Content.Server.GameObjects.EntitySystems +{ + public class InstrumentSystem : EntitySystem + { + public override void Initialize() + { + base.Initialize(); + EntityQuery = new TypeEntityQuery(typeof(InstrumentComponent)); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + foreach (var entity in RelevantEntities) + { + entity.GetComponent().Update(frameTime); + } + } + } +} diff --git a/Content.Shared/GameObjects/Components/Instruments/SharedInstrumentComponent.cs b/Content.Shared/GameObjects/Components/Instruments/SharedInstrumentComponent.cs index 96d3ab9fc4..385a5a9b48 100644 --- a/Content.Shared/GameObjects/Components/Instruments/SharedInstrumentComponent.cs +++ b/Content.Shared/GameObjects/Components/Instruments/SharedInstrumentComponent.cs @@ -30,6 +30,7 @@ namespace Content.Shared.GameObjects.Components.Instruments [Serializable, NetSerializable] public class InstrumentStartMidiMessage : ComponentMessage { + } /// @@ -39,12 +40,10 @@ namespace Content.Shared.GameObjects.Components.Instruments public class InstrumentMidiEventMessage : ComponentMessage { public MidiEvent[] MidiEvent; - public double[] Timestamp; - public InstrumentMidiEventMessage(MidiEvent[] midiEvent, double[] timestamp) + public InstrumentMidiEventMessage(MidiEvent[] midiEvent) { MidiEvent = midiEvent; - Timestamp = timestamp; } }