From 1fb7d3e7239ef5c973f295281ef9cff2613e9345 Mon Sep 17 00:00:00 2001 From: Hannah Giovanna Dawson Date: Tue, 5 Aug 2025 22:35:48 +0100 Subject: [PATCH] Minimum MIDI note volume (#6127) --- Robust.Client/Audio/Midi/IMidiRenderer.cs | 2 ++ Robust.Client/Audio/Midi/MidiRenderer.cs | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Robust.Client/Audio/Midi/IMidiRenderer.cs b/Robust.Client/Audio/Midi/IMidiRenderer.cs index b52aeb44a..3c8c51c97 100644 --- a/Robust.Client/Audio/Midi/IMidiRenderer.cs +++ b/Robust.Client/Audio/Midi/IMidiRenderer.cs @@ -213,4 +213,6 @@ public interface IMidiRenderer : IDisposable /// Actually disposes of this renderer. Do NOT use outside the MIDI thread. /// internal void InternalDispose(); + + byte MinVolume { get; set; } } diff --git a/Robust.Client/Audio/Midi/MidiRenderer.cs b/Robust.Client/Audio/Midi/MidiRenderer.cs index 190066b60..a2072bbb4 100644 --- a/Robust.Client/Audio/Midi/MidiRenderer.cs +++ b/Robust.Client/Audio/Midi/MidiRenderer.cs @@ -214,6 +214,11 @@ internal sealed partial class MidiRenderer : IMidiRenderer [ViewVariables] public BitArray FilteredChannels { get; } = new(RobustMidiEvent.MaxChannels); + [ViewVariables] + public byte MinVolume { get => _minVolume; set => _minVolume = value; } + + private byte _minVolume; + [ViewVariables(VVAccess.ReadWrite)] public byte? VelocityOverride { get; set; } = null; @@ -591,7 +596,10 @@ internal sealed partial class MidiRenderer : IMidiRenderer if (FilteredChannels[midiEvent.Channel]) break; - velocity = VelocityOverride ?? midiEvent.Velocity; + if (MinVolume > 0) + velocity = (byte)Math.Floor(MathHelper.Lerp(MinVolume, 127, (float)velocity / 127)); + + velocity = VelocityOverride ?? velocity; _rendererState.NoteVelocities.AsSpan[midiEvent.Channel].AsSpan[midiEvent.Key] = velocity; _synth.NoteOn(midiEvent.Channel, midiEvent.Key, velocity);