Add playback slider to instruments. (#3071)
This commit is contained in:
committed by
GitHub
parent
b2c1ab2795
commit
655316a67c
@@ -3,7 +3,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Client.GameObjects.EntitySystems;
|
using Content.Client.GameObjects.EntitySystems;
|
||||||
using Content.Shared;
|
|
||||||
using Content.Shared.GameObjects.Components.Instruments;
|
using Content.Shared.GameObjects.Components.Instruments;
|
||||||
using Content.Shared.Physics;
|
using Content.Shared.Physics;
|
||||||
using Robust.Client.Audio.Midi;
|
using Robust.Client.Audio.Midi;
|
||||||
@@ -11,13 +10,11 @@ using Robust.Shared.Audio.Midi;
|
|||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameObjects.Components.Timers;
|
using Robust.Shared.GameObjects.Components.Timers;
|
||||||
using Robust.Shared.GameObjects.Systems;
|
using Robust.Shared.GameObjects.Systems;
|
||||||
using Robust.Shared.Interfaces.Configuration;
|
|
||||||
using Robust.Shared.Interfaces.Network;
|
using Robust.Shared.Interfaces.Network;
|
||||||
using Robust.Shared.Interfaces.Timing;
|
using Robust.Shared.Interfaces.Timing;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Players;
|
using Robust.Shared.Players;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Timers;
|
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
namespace Content.Client.GameObjects.Components.Instruments
|
namespace Content.Client.GameObjects.Components.Instruments
|
||||||
@@ -162,6 +159,41 @@ namespace Content.Client.GameObjects.Components.Instruments
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public bool IsRendererAlive => _renderer != null;
|
public bool IsRendererAlive => _renderer != null;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public int PlayerTotalTick => _renderer?.PlayerTotalTick ?? 0;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public int PlayerTick
|
||||||
|
{
|
||||||
|
get => _renderer?.PlayerTick ?? 0;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!IsRendererAlive || _renderer!.Status != MidiRendererStatus.File) return;
|
||||||
|
|
||||||
|
_midiEventBuffer.Clear();
|
||||||
|
|
||||||
|
_renderer.PlayerTick = value;
|
||||||
|
var tick = _renderer.SequencerTick;
|
||||||
|
|
||||||
|
// We add a "all notes off" message.
|
||||||
|
for (byte i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
_midiEventBuffer.Add(new MidiEvent()
|
||||||
|
{
|
||||||
|
Tick = tick, Type = 176,
|
||||||
|
Control = 123, Velocity = 0, Channel = i,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we add a Reset All Controllers message.
|
||||||
|
_midiEventBuffer.Add(new MidiEvent()
|
||||||
|
{
|
||||||
|
Tick = tick, Type = 176,
|
||||||
|
Control = 121, Value = 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
@@ -390,20 +422,6 @@ namespace Content.Client.GameObjects.Components.Instruments
|
|||||||
/// <param name="midiEvent">The received midi event</param>
|
/// <param name="midiEvent">The received midi event</param>
|
||||||
private void RendererOnMidiEvent(MidiEvent midiEvent)
|
private void RendererOnMidiEvent(MidiEvent midiEvent)
|
||||||
{
|
{
|
||||||
// avoid of out-of-band, unimportant or unsupported events
|
|
||||||
switch (midiEvent.Type)
|
|
||||||
{
|
|
||||||
case 0x80: // NOTE_OFF
|
|
||||||
case 0x90: // NOTE_ON
|
|
||||||
case 0xa0: // KEY_PRESSURE
|
|
||||||
case 0xb0: // CONTROL_CHANGE
|
|
||||||
case 0xd0: // CHANNEL_PRESSURE
|
|
||||||
case 0xe0: // PITCH_BEND
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_midiEventBuffer.Add(midiEvent);
|
_midiEventBuffer.Add(midiEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,23 @@
|
|||||||
<cc:SS14Window xmlns:cc="clr-namespace:Robust.Client.UserInterface.CustomControls;assembly=Robust.Client"
|
<cc:SS14Window xmlns:cc="clr-namespace:Robust.Client.UserInterface.CustomControls;assembly=Robust.Client"
|
||||||
xmlns:uic="clr-namespace:Robust.Client.UserInterface.Controls;assembly=Robust.Client"
|
xmlns:uic="clr-namespace:Robust.Client.UserInterface.Controls;assembly=Robust.Client"
|
||||||
xmlns:ui="clr-namespace:Robust.Client.UserInterface;assembly=Robust.Client">
|
xmlns:ui="clr-namespace:Robust.Client.UserInterface;assembly=Robust.Client">
|
||||||
<uic:MarginContainer Name="Margin" SizeFlagsVertical="FillExpand" SizeFlagsHorizontal="FillExpand">
|
<uic:MarginContainer Name="Margin" SizeFlagsVertical="FillExpand" SizeFlagsHorizontal="Fill">
|
||||||
<uic:VBoxContainer SizeFlagsVertical="FillExpand" SizeFlagsHorizontal="FillExpand" SeparationOverride="5">
|
<uic:VBoxContainer SizeFlagsVertical="FillExpand" SizeFlagsHorizontal="FillExpand" SeparationOverride="5">
|
||||||
<uic:HBoxContainer SizeFlagsVertical="FillExpand" SizeFlagsHorizontal="FillExpand">
|
<uic:HBoxContainer SizeFlagsVertical="FillExpand" SizeFlagsHorizontal="FillExpand">
|
||||||
<uic:Button Name="InputButton" ToggleMode="True" Text="MIDI Input" TextAlign="Center" SizeFlagsHorizontal="FillExpand" SizeFlagsStretchRatio="1"/>
|
<uic:Button Name="InputButton" ToggleMode="True" Text="MIDI Input" TextAlign="Center" SizeFlagsHorizontal="FillExpand" SizeFlagsStretchRatio="1"/>
|
||||||
<ui:Control SizeFlagsHorizontal="FillExpand" SizeFlagsStretchRatio="2" />
|
<ui:Control SizeFlagsHorizontal="FillExpand" SizeFlagsStretchRatio="2" />
|
||||||
<uic:Button Name="FileButton" Text="Play MIDI File" TextAlign="Center" SizeFlagsHorizontal="FillExpand" SizeFlagsStretchRatio="1"/>
|
<uic:Button Name="FileButton" Text="Play MIDI File" TextAlign="Center" SizeFlagsHorizontal="FillExpand" SizeFlagsStretchRatio="1"/>
|
||||||
</uic:HBoxContainer>
|
</uic:HBoxContainer>
|
||||||
<uic:HBoxContainer SizeFlagsVertical="FillExpand" SizeFlagsHorizontal="FillExpand">
|
<uic:HBoxContainer SizeFlagsVertical="FillExpand" SizeFlagsHorizontal="Fill">
|
||||||
<uic:Button Name="LoopButton" ToggleMode="True" Text="Loop" TextAlign="Center" SizeFlagsHorizontal="FillExpand" SizeFlagsStretchRatio="1"/>
|
<uic:Button Name="LoopButton" ToggleMode="True" Text="Loop" TextAlign="Center" SizeFlagsHorizontal="FillExpand" SizeFlagsStretchRatio="1"/>
|
||||||
<ui:Control SizeFlagsHorizontal="FillExpand" SizeFlagsStretchRatio="2" />
|
<ui:Control SizeFlagsHorizontal="FillExpand" SizeFlagsStretchRatio="2" />
|
||||||
<uic:Button Name="StopButton" Text="Stop" TextAlign="Center" SizeFlagsHorizontal="FillExpand" SizeFlagsStretchRatio="1"/>
|
<uic:Button Name="StopButton" Text="Stop" TextAlign="Center" SizeFlagsHorizontal="FillExpand" SizeFlagsStretchRatio="1"/>
|
||||||
</uic:HBoxContainer>
|
</uic:HBoxContainer>
|
||||||
|
<uic:HBoxContainer SizeFlagsVertical="ShrinkEnd" SizeFlagsHorizontal="FillExpand">
|
||||||
|
<ui:Control SizeFlagsHorizontal="FillExpand" SizeFlagsStretchRatio="0.125"/>
|
||||||
|
<uic:Slider Name="PlaybackSlider" SizeFlagsHorizontal="FillExpand" />
|
||||||
|
<ui:Control SizeFlagsHorizontal="FillExpand" SizeFlagsStretchRatio="0.125"/>
|
||||||
|
</uic:HBoxContainer>
|
||||||
</uic:VBoxContainer>
|
</uic:VBoxContainer>
|
||||||
</uic:MarginContainer>
|
</uic:MarginContainer>
|
||||||
</cc:SS14Window>
|
</cc:SS14Window>
|
||||||
|
|||||||
@@ -14,11 +14,14 @@ using Robust.Client.UserInterface.Controls;
|
|||||||
using Robust.Client.UserInterface.CustomControls;
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
|
using Robust.Shared.Input;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Log;
|
using Robust.Shared.Log;
|
||||||
using Robust.Shared.Maths;
|
using Robust.Shared.Maths;
|
||||||
using Robust.Shared.Timers;
|
using Robust.Shared.Timers;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
using Range = Robust.Client.UserInterface.Controls.Range;
|
||||||
|
|
||||||
namespace Content.Client.Instruments
|
namespace Content.Client.Instruments
|
||||||
{
|
{
|
||||||
@@ -46,6 +49,7 @@ namespace Content.Client.Instruments
|
|||||||
LoopButton.Disabled = !_owner.Instrument.IsMidiOpen;
|
LoopButton.Disabled = !_owner.Instrument.IsMidiOpen;
|
||||||
LoopButton.Pressed = _owner.Instrument.LoopMidi;
|
LoopButton.Pressed = _owner.Instrument.LoopMidi;
|
||||||
StopButton.Disabled = !_owner.Instrument.IsMidiOpen;
|
StopButton.Disabled = !_owner.Instrument.IsMidiOpen;
|
||||||
|
PlaybackSlider.MouseFilter = _owner.Instrument.IsMidiOpen ? MouseFilterMode.Pass : MouseFilterMode.Ignore;
|
||||||
|
|
||||||
if (!_midiManager.IsAvailable)
|
if (!_midiManager.IsAvailable)
|
||||||
{
|
{
|
||||||
@@ -74,6 +78,8 @@ namespace Content.Client.Instruments
|
|||||||
FileButton.OnPressed += MidiFileButtonOnOnPressed;
|
FileButton.OnPressed += MidiFileButtonOnOnPressed;
|
||||||
LoopButton.OnToggled += MidiLoopButtonOnOnToggled;
|
LoopButton.OnToggled += MidiLoopButtonOnOnToggled;
|
||||||
StopButton.OnPressed += MidiStopButtonOnPressed;
|
StopButton.OnPressed += MidiStopButtonOnPressed;
|
||||||
|
PlaybackSlider.OnValueChanged += PlaybackSliderSeek;
|
||||||
|
PlaybackSlider.OnKeyBindUp += PlaybackSliderKeyUp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InstrumentOnMidiPlaybackEnded()
|
private void InstrumentOnMidiPlaybackEnded()
|
||||||
@@ -85,12 +91,15 @@ namespace Content.Client.Instruments
|
|||||||
{
|
{
|
||||||
LoopButton.Disabled = disabled;
|
LoopButton.Disabled = disabled;
|
||||||
StopButton.Disabled = disabled;
|
StopButton.Disabled = disabled;
|
||||||
|
|
||||||
|
// Whether to allow the slider to receive events..
|
||||||
|
PlaybackSlider.MouseFilter = !disabled ? MouseFilterMode.Pass : MouseFilterMode.Ignore;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void MidiFileButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
|
private async void MidiFileButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
|
||||||
{
|
{
|
||||||
var filters = new FileDialogFilters(new FileDialogFilters.Group("mid", "midi"));
|
var filters = new FileDialogFilters(new FileDialogFilters.Group("mid", "midi"));
|
||||||
var file = await _fileDialogManager.OpenFile(filters);
|
await using var file = await _fileDialogManager.OpenFile(filters);
|
||||||
|
|
||||||
// The following checks are only in place to prevent players from playing MIDI songs locally.
|
// The following checks are only in place to prevent players from playing MIDI songs locally.
|
||||||
// There are equivalents for these checks on the server.
|
// There are equivalents for these checks on the server.
|
||||||
@@ -107,7 +116,7 @@ namespace Content.Client.Instruments
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
MidiStopButtonOnPressed(null);
|
MidiStopButtonOnPressed(null);
|
||||||
var memStream = new MemoryStream((int) file.Length);
|
await using var memStream = new MemoryStream((int) file.Length);
|
||||||
// 100ms delay is due to a race condition or something idk.
|
// 100ms delay is due to a race condition or something idk.
|
||||||
// While we're waiting, load it into memory.
|
// While we're waiting, load it into memory.
|
||||||
await Task.WhenAll(Timer.Delay(100), file.CopyToAsync(memStream));
|
await Task.WhenAll(Timer.Delay(100), file.CopyToAsync(memStream));
|
||||||
@@ -165,5 +174,36 @@ namespace Content.Client.Instruments
|
|||||||
{
|
{
|
||||||
_owner.Instrument.LoopMidi = obj.Pressed;
|
_owner.Instrument.LoopMidi = obj.Pressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PlaybackSliderSeek(Range _)
|
||||||
|
{
|
||||||
|
// Do not seek while still grabbing.
|
||||||
|
if (PlaybackSlider.Grabbed) return;
|
||||||
|
|
||||||
|
_owner.Instrument.PlayerTick = (int)Math.Ceiling(PlaybackSlider.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PlaybackSliderKeyUp(GUIBoundKeyEventArgs args)
|
||||||
|
{
|
||||||
|
if (args.Function != EngineKeyFunctions.UIClick) return;
|
||||||
|
_owner.Instrument.PlayerTick = (int)Math.Ceiling(PlaybackSlider.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update(FrameEventArgs args)
|
||||||
|
{
|
||||||
|
base.Update(args);
|
||||||
|
|
||||||
|
if (!_owner.Instrument.IsMidiOpen)
|
||||||
|
{
|
||||||
|
PlaybackSlider.MaxValue = 1;
|
||||||
|
PlaybackSlider.SetValueWithoutEvent(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PlaybackSlider.Grabbed) return;
|
||||||
|
|
||||||
|
PlaybackSlider.MaxValue = _owner.Instrument.PlayerTotalTick;
|
||||||
|
PlaybackSlider.SetValueWithoutEvent(_owner.Instrument.PlayerTick);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ using System.Linq;
|
|||||||
using Content.Server.GameObjects.Components.Mobs;
|
using Content.Server.GameObjects.Components.Mobs;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Server.Utility;
|
using Content.Server.Utility;
|
||||||
using Content.Shared;
|
|
||||||
using Content.Shared.GameObjects.Components.Instruments;
|
using Content.Shared.GameObjects.Components.Instruments;
|
||||||
using Content.Shared.GameObjects.EntitySystems;
|
|
||||||
using Content.Shared.GameObjects.EntitySystems.ActionBlocker;
|
using Content.Shared.GameObjects.EntitySystems.ActionBlocker;
|
||||||
using Content.Shared.Interfaces;
|
using Content.Shared.Interfaces;
|
||||||
using Content.Shared.Interfaces.GameObjects.Components;
|
using Content.Shared.Interfaces.GameObjects.Components;
|
||||||
@@ -18,10 +16,7 @@ using Robust.Server.Player;
|
|||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameObjects.Systems;
|
using Robust.Shared.GameObjects.Systems;
|
||||||
using Robust.Shared.Interfaces.Configuration;
|
|
||||||
using Robust.Shared.Interfaces.Network;
|
using Robust.Shared.Interfaces.Network;
|
||||||
using Robust.Shared.Interfaces.Timing;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Players;
|
using Robust.Shared.Players;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
@@ -41,9 +36,6 @@ namespace Content.Server.GameObjects.Components.Instruments
|
|||||||
IUse,
|
IUse,
|
||||||
IThrown
|
IThrown
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
|
||||||
|
|
||||||
private static readonly TimeSpan OneSecAgo = TimeSpan.FromSeconds(-1);
|
|
||||||
private InstrumentSystem _instrumentSystem = default!;
|
private InstrumentSystem _instrumentSystem = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -60,9 +52,6 @@ namespace Content.Server.GameObjects.Components.Instruments
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private float _timer = 0f;
|
private float _timer = 0f;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadOnly)]
|
|
||||||
private TimeSpan _lastMeasured = TimeSpan.MinValue;
|
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private int _batchesDropped = 0;
|
private int _batchesDropped = 0;
|
||||||
|
|
||||||
@@ -213,15 +202,6 @@ namespace Content.Server.GameObjects.Components.Instruments
|
|||||||
var minTick = midiEventMsg.MidiEvent.Min(x => x.Tick);
|
var minTick = midiEventMsg.MidiEvent.Min(x => x.Tick);
|
||||||
if (_lastSequencerTick > minTick)
|
if (_lastSequencerTick > minTick)
|
||||||
{
|
{
|
||||||
var now = _gameTiming.RealTime;
|
|
||||||
var oneSecAGo = now.Add(OneSecAgo);
|
|
||||||
if (_lastMeasured < oneSecAGo)
|
|
||||||
{
|
|
||||||
_lastMeasured = now;
|
|
||||||
_laggedBatches = 0;
|
|
||||||
_batchesDropped = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_laggedBatches++;
|
_laggedBatches++;
|
||||||
|
|
||||||
if (_respectMidiLimits)
|
if (_respectMidiLimits)
|
||||||
@@ -246,15 +226,6 @@ namespace Content.Server.GameObjects.Components.Instruments
|
|||||||
if (++_midiEventCount > maxMidiEventsPerSecond
|
if (++_midiEventCount > maxMidiEventsPerSecond
|
||||||
|| midiEventMsg.MidiEvent.Length > maxMidiEventsPerBatch)
|
|| midiEventMsg.MidiEvent.Length > maxMidiEventsPerBatch)
|
||||||
{
|
{
|
||||||
var now = _gameTiming.RealTime;
|
|
||||||
var oneSecAGo = now.Add(OneSecAgo);
|
|
||||||
if (_lastMeasured < oneSecAGo)
|
|
||||||
{
|
|
||||||
_lastMeasured = now;
|
|
||||||
_laggedBatches = 0;
|
|
||||||
_batchesDropped = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_batchesDropped++;
|
_batchesDropped++;
|
||||||
|
|
||||||
send = false;
|
send = false;
|
||||||
@@ -266,7 +237,7 @@ namespace Content.Server.GameObjects.Components.Instruments
|
|||||||
}
|
}
|
||||||
|
|
||||||
var maxTick = midiEventMsg.MidiEvent.Max(x => x.Tick);
|
var maxTick = midiEventMsg.MidiEvent.Max(x => x.Tick);
|
||||||
_lastSequencerTick = Math.Max(maxTick, minTick + 1);
|
_lastSequencerTick = Math.Max(maxTick, minTick);
|
||||||
break;
|
break;
|
||||||
case InstrumentStartMidiMessage startMidi:
|
case InstrumentStartMidiMessage startMidi:
|
||||||
if (session != _instrumentPlayer)
|
if (session != _instrumentPlayer)
|
||||||
@@ -386,15 +357,14 @@ namespace Content.Server.GameObjects.Components.Instruments
|
|||||||
|
|
||||||
UserInterface?.CloseAll();
|
UserInterface?.CloseAll();
|
||||||
|
|
||||||
|
if(Handheld)
|
||||||
|
EntitySystem.Get<StandingStateSystem>().DropAllItemsInHands(mob, false);
|
||||||
|
|
||||||
if (mob != null && mob.TryGetComponent(out StunnableComponent? stun))
|
if (mob != null && mob.TryGetComponent(out StunnableComponent? stun))
|
||||||
{
|
{
|
||||||
stun.Stun(1);
|
stun.Stun(1);
|
||||||
Clean();
|
Clean();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
EntitySystem.Get<StandingStateSystem>().DropAllItemsInHands(mob, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
InstrumentPlayer = null;
|
InstrumentPlayer = null;
|
||||||
|
|
||||||
@@ -406,6 +376,8 @@ namespace Content.Server.GameObjects.Components.Instruments
|
|||||||
|
|
||||||
_timer = 0f;
|
_timer = 0f;
|
||||||
_midiEventCount = 0;
|
_midiEventCount = 0;
|
||||||
|
_laggedBatches = 0;
|
||||||
|
_batchesDropped = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user