Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audio mixers #5554

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions Robust.Client/Audio/AudioSystem.Mixers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using Robust.Client.Audio.Mixers;
using Robust.Shared.Audio.Components;
using Robust.Shared.Audio.Mixers;
using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;

namespace Robust.Client.Audio;

public sealed partial class AudioSystem
{
[Dependency] private readonly IAudioMixersManager _audioMixersManager = default!;

protected override void InitializeMixers()
{
base.InitializeMixers();

SubscribeLocalEvent<AudioMixerComponent, ComponentAdd>(OnMixerAdd);
}

public override Entity<AudioMixerComponent> CreateMixer(Entity<AudioMixerComponent>? outMixer)
{
var mixerEntity = base.CreateMixer(outMixer);
if (outMixer is { } outMixerValue)
{
mixerEntity.Comp.Mixer.SetOut(outMixerValue.Comp.Mixer);
}
return mixerEntity;
}

public override void SetMixerGain(Entity<AudioMixerComponent> mixer, float gain)
{
base.SetMixerGain(mixer, gain);
if (mixer.Comp.Mixer.GainCVar is { } cvar)
{
CfgManager.SetCVar(cvar, gain);
}
else
{
mixer.Comp.Mixer.SelfGain = gain;
}
}

public override void SetMixerGainCVar(Entity<AudioMixerComponent> mixer, string? name)
{
base.SetMixerGainCVar(mixer, name);
_audioMixersManager.SetMixerGainCVar(mixer.Comp.Mixer, name);
}

protected override Entity<AudioMixerComponent> SpawnMixerForPrototype(ProtoId<AudioMixerPrototype> mixerProtoId)
{
var mixer = base.SpawnMixerForPrototype(mixerProtoId);
mixer.Comp.Mixer = _audioMixersManager.GetMixer(mixerProtoId) ?? mixer.Comp.Mixer;
return mixer;
}

private void OnMixerAdd(Entity<AudioMixerComponent> mixer, ref ComponentAdd args)
{
mixer.Comp.Mixer = _audioMixersManager.CreateMixer();
}

protected override void OnMixerShutdown(Entity<AudioMixerComponent> mixer, ref ComponentShutdown args)
{
base.OnMixerShutdown(mixer, ref args);
DisposeMixer(mixer.Comp.Mixer);
}

protected override void OnHandleState(Entity<AudioMixerComponent> mixer, ref ComponentHandleState args)
{
base.OnHandleState(mixer, ref args);

if (mixer.Comp.ProtoId is { } protoId
&& protoId != mixer.Comp.Mixer.ProtoId
&& _audioMixersManager.GetMixer(protoId) is { } newMixer)
{
DisposeMixer(mixer.Comp.Mixer);
mixer.Comp.Mixer = newMixer;
}
SetMixerGainCVar(mixer, mixer.Comp.GainCVar);
if (mixer.Comp.ProtoId is null)
{
Entity<AudioMixerComponent>? outMixer = mixer.Comp.OutEntity is { } outMixerOwner
&& TryComp<AudioMixerComponent>(outMixerOwner, out var outMixerComponent)
? new Entity<AudioMixerComponent>(outMixerOwner, outMixerComponent) : null;
SetMixerOut(mixer, outMixer);
}
}

private void DisposeMixer(IAudioMixer mixer)
{
// We don't want to dispose mixers from prototypes cos they are supposed to be re-used.
if (mixer.ProtoId is { })
return;
mixer.Dispose();
}
}
21 changes: 20 additions & 1 deletion Robust.Client/Audio/AudioSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using Robust.Client.Audio.Sources;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
Expand Down Expand Up @@ -134,6 +135,15 @@ private void OnAudioState(EntityUid uid, AudioComponent component, ref AfterAuto
component.Source.SetAuxiliary(null);
}

if (TryComp<AudioMixerComponent>(component.Mixer, out var mixerComp))
{
component.Source.SetMixer(mixerComp.Mixer);
}
else
{
ApplyAudioParamsMixer((uid, component), component.Params);
}

switch (component.State)
{
case AudioState.Playing:
Expand Down Expand Up @@ -219,12 +229,20 @@ private void SetupSource(Entity<AudioComponent> entity, AudioResource audioResou
}
else
{
component.Source = newSource;
component.Source = new MixableAudioSource(newSource);
}
}

// Need to set all initial data for first frame.
ApplyAudioParams(component.Params, component);
if (TryComp<AudioMixerComponent>(component.Mixer, out var mixerComp))
{
component.Source.SetMixer(mixerComp.Mixer);
}
else
{
ApplyAudioParamsMixer(entity, component.Params);
}
component.Source.Global = component.Global;

// Don't play until first frame so occlusion etc. are correct.
Expand All @@ -245,6 +263,7 @@ private void OnAudioShutdown(EntityUid uid, AudioComponent component, ComponentS
{
// Breaks with prediction?
component.Source.Dispose();
ClearMixer((uid, component));

RemoveAudioLimit(component.FileName);
}
Expand Down
6 changes: 6 additions & 0 deletions Robust.Client/Audio/Midi/IMidiManager.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using NFluidsynth;
using Robust.Shared.Audio.Midi;
using Robust.Shared.Audio.Mixers;

namespace Robust.Client.Audio.Midi;

Expand All @@ -21,6 +22,11 @@ public interface IMidiManager
/// </summary>
float Gain { get; set; }

/// <summary>
/// Audio mixer to play with.
/// </summary>
IAudioMixer? Mixer { get; set; }

/// <summary>
/// This method tries to return a midi renderer ready to be used.
/// You only need to set the <see cref="IMidiRenderer.MidiProgram"/> afterwards.
Expand Down
5 changes: 5 additions & 0 deletions Robust.Client/Audio/Midi/IMidiRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public interface IMidiRenderer : IDisposable
/// </summary>
internal IBufferedAudioSource Source { get; }

/// <summary>
/// Mixable audio source reference to apply mixing.
/// </summary>
internal IMixableAudioSource MixableSource { get; }

/// <summary>
/// Whether this renderer has been disposed or not.
/// </summary>
Expand Down
35 changes: 23 additions & 12 deletions Robust.Client/Audio/Midi/MidiManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Robust.Shared;
using Robust.Shared.Asynchronous;
using Robust.Shared.Audio.Midi;
using Robust.Shared.Audio.Mixers;
using Robust.Shared.Collections;
using Robust.Shared.Configuration;
using Robust.Shared.ContentPack;
Expand Down Expand Up @@ -81,6 +82,7 @@ public bool IsAvailable
private Thread? _midiThread;
private ISawmill _midiSawmill = default!;
private float _gain = 0f;
private IAudioMixer? _audioMixer;
private bool _volumeDirty = true;

// Not reliable until Fluidsynth is initialized!
Expand All @@ -95,7 +97,21 @@ public float Gain
if (MathHelper.CloseToPercent(_gain, clamped))
return;

_cfgMan.SetCVar(CVars.MidiVolume, clamped);
_gain = value;
_volumeDirty = true;
}
}

[ViewVariables(VVAccess.ReadWrite)]
public IAudioMixer? Mixer
{
get => _audioMixer;
set
{
if (_audioMixer == value)
return;

_audioMixer = value;
_volumeDirty = true;
}
}
Expand Down Expand Up @@ -145,12 +161,6 @@ private void InitializeFluidsynth()
{
if (FluidsynthInitialized || _failedInitialize) return;

_cfgMan.OnValueChanged(CVars.MidiVolume, value =>
{
_gain = value;
_volumeDirty = true;
}, true);

_midiSawmill = _logger.GetSawmill("midi");
#if DEBUG
_midiSawmill.Level = LogLevel.Debug;
Expand Down Expand Up @@ -396,7 +406,8 @@ private void UpdateRenderer(IMidiRenderer renderer, MapCoordinates listener)

if (_volumeDirty)
{
renderer.Source.Gain = Gain;
renderer.MixableSource.Gain = Gain;
renderer.MixableSource.SetMixer(_audioMixer);
}

if (!renderer.Mono)
Expand Down Expand Up @@ -429,14 +440,14 @@ private void UpdateRenderer(IMidiRenderer renderer, MapCoordinates listener)
// If it's on a different map then just mute it, not pause.
if (mapPos.MapId == MapId.Nullspace || mapPos.MapId != listener.MapId)
{
renderer.Source.Gain = 0f;
renderer.MixableSource.Gain = 0f;
return;
}

// Was previously muted maybe so try unmuting it?
if (renderer.Source.Gain == 0f)
if (renderer.MixableSource.Gain == 0f)
{
renderer.Source.Gain = Gain;
renderer.MixableSource.Gain = Gain;
}

var worldPos = mapPos.Position;
Expand All @@ -448,7 +459,7 @@ private void UpdateRenderer(IMidiRenderer renderer, MapCoordinates listener)
if (distance > renderer.Source.MaxDistance)
{
// Still keeps the source playing, just with no volume.
renderer.Source.Gain = 0f;
renderer.MixableSource.Gain = 0f;
return;
}

Expand Down
4 changes: 4 additions & 0 deletions Robust.Client/Audio/Midi/MidiRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.Collections;
using JetBrains.Annotations;
using NFluidsynth;

using Robust.Client.Audio.Sources;
using Robust.Client.Graphics;
using Robust.Shared.Asynchronous;
using Robust.Shared.Audio;
Expand Down Expand Up @@ -56,6 +58,7 @@ internal sealed class MidiRenderer : IMidiRenderer
private IMidiRenderer? _master;
public MidiRendererState RendererState => _rendererState;
public IBufferedAudioSource Source { get; set; }
public IMixableAudioSource MixableSource { get; set; }
IBufferedAudioSource IMidiRenderer.Source => Source;

[ViewVariables]
Expand Down Expand Up @@ -263,6 +266,7 @@ internal MidiRenderer(Settings settings, SoundFontLoader soundFontLoader, bool m
_midiSawmill = midiSawmill;

Source = clydeAudio.CreateBufferedAudioSource(Buffers, true) ?? DummyBufferedAudioSource.Instance;
MixableSource = new MixableAudioSource(Source);
Source.SampleRate = SampleRate;
_settings = settings;
_soundFontLoader = soundFontLoader;
Expand Down
Loading
Loading