Skip to content

Commit

Permalink
Merge pull request #6310 from smoogipoo/audio-effects-rework
Browse files Browse the repository at this point in the history
Replace audio effect `BindableList` by Add/Remove methods
  • Loading branch information
bdach committed Jun 17, 2024
2 parents 9979a9c + 878914f commit 98617ab
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 319 deletions.
106 changes: 0 additions & 106 deletions osu.Framework.Tests/Audio/BassAudioMixerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System;
using System.Threading;
using ManagedBass;
using ManagedBass.Fx;
using ManagedBass.Mix;
using NUnit.Framework;
using osu.Framework.Audio.Mixing.Bass;
Expand Down Expand Up @@ -226,95 +225,6 @@ static WeakReference<SampleChannel> runTest(SampleBass sample)
}
}

[Test]
public void TestAddEffect()
{
bass.Mixer.Effects.Add(new BQFParameters());
assertEffectParameters();

bass.Mixer.Effects.AddRange(new[]
{
new BQFParameters(),
new BQFParameters(),
new BQFParameters()
});
assertEffectParameters();
}

[Test]
public void TestRemoveEffect()
{
bass.Mixer.Effects.Add(new BQFParameters());
assertEffectParameters();

bass.Mixer.Effects.RemoveAt(0);
assertEffectParameters();

bass.Mixer.Effects.AddRange(new[]
{
new BQFParameters(),
new BQFParameters(),
new BQFParameters()
});
assertEffectParameters();

bass.Mixer.Effects.RemoveAt(1);
assertEffectParameters();

bass.Mixer.Effects.RemoveAt(1);
assertEffectParameters();
}

[Test]
public void TestMoveEffect()
{
bass.Mixer.Effects.AddRange(new[]
{
new BQFParameters(),
new BQFParameters(),
new BQFParameters()
});
assertEffectParameters();

bass.Mixer.Effects.Move(0, 1);
assertEffectParameters();

bass.Mixer.Effects.Move(2, 0);
assertEffectParameters();
}

[Test]
public void TestReplaceEffect()
{
bass.Mixer.Effects.AddRange(new[]
{
new BQFParameters(),
new BQFParameters(),
new BQFParameters()
});
assertEffectParameters();

bass.Mixer.Effects[1] = new BQFParameters();
assertEffectParameters();
}

[Test]
public void TestInsertEffect()
{
bass.Mixer.Effects.AddRange(new[]
{
new BQFParameters(),
new BQFParameters()
});
assertEffectParameters();

bass.Mixer.Effects.Insert(1, new BQFParameters());
assertEffectParameters();

bass.Mixer.Effects.Insert(3, new BQFParameters());
assertEffectParameters();
}

[Test]
public void TestChannelDoesNotPlayIfReachedEndAndSeekedBackwards()
{
Expand Down Expand Up @@ -356,22 +266,6 @@ public void TestChannelDoesNotPlayIfReachedEndAndMovedMixers()
Assert.That(secondMixer.ChannelIsActive(track), Is.Not.EqualTo(PlaybackState.Playing));
}

private void assertEffectParameters()
{
bass.Update();

Assert.That(bass.Mixer.ActiveEffects.Count, Is.EqualTo(bass.Mixer.Effects.Count));

Assert.Multiple(() =>
{
for (int i = 0; i < bass.Mixer.ActiveEffects.Count; i++)
{
Assert.That(bass.Mixer.ActiveEffects[i].Effect, Is.EqualTo(bass.Mixer.Effects[i]));
Assert.That(bass.Mixer.ActiveEffects[i].Priority, Is.EqualTo(-i));
}
});
}

private int getHandle() => ((IBassAudioChannel)track).Handle;
}
}
150 changes: 66 additions & 84 deletions osu.Framework.Tests/Visual/Audio/TestSceneAudioMixer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
using System.Linq;
using ManagedBass;
using ManagedBass.Fx;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Audio;
using osu.Framework.Graphics.Containers;
Expand All @@ -21,64 +19,88 @@ namespace osu.Framework.Tests.Visual.Audio
{
public partial class TestSceneAudioMixer : FrameworkTestScene
{
[SetUp]
public void Setup() => Schedule(() =>
{
ContainerWithEffect noEffectContainer;
FillFlowContainer<ContainerWithEffect> effectContainers;
private readonly DragHandle dragHandle;
private readonly AudioPlayingDrawable audioDrawable;
private readonly ContainerWithEffect noEffectContainer;
private readonly FillFlowContainer<ContainerWithEffect> effectContainers;

Child = noEffectContainer = new ContainerWithEffect("no effect", Color4.Black)
public TestSceneAudioMixer()
{
AddRange(new Drawable[]
{
RelativeSizeAxes = Axes.Both,
Size = new Vector2(1),
Child = new Container
noEffectContainer = new ContainerWithEffect("no effect", Color4.Black, null)
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(20),
Child = effectContainers = new FillFlowContainer<ContainerWithEffect>
Size = new Vector2(1),
Children = new Drawable[]
{
RelativeSizeAxes = Axes.Both,
effectContainers = new FillFlowContainer<ContainerWithEffect>
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding(20)
},
audioDrawable = new AudioPlayingDrawable { Origin = Anchor.Centre }
}
},
dragHandle = new DragHandle
{
Origin = Anchor.Centre,
Position = new Vector2(50)
}
};
});

for (int i = 0; i < 50; i++)
{
float centre = 150 + 50 * i;

effectContainers.Add(new ContainerWithEffect($"<{centre}Hz", Color4.Blue)
effectContainers.Add(new ContainerWithEffect($"<{centre}Hz", Color4.Blue, new BQFParameters
{
lFilter = BQFType.LowPass,
fCenter = centre
})
{
Size = new Vector2(100),
Effects =
{
new BQFParameters
{
lFilter = BQFType.LowPass,
fCenter = centre
}
}
});
}
}

AudioBox audioBox;
noEffectContainer.Add(audioBox = new AudioBox(noEffectContainer, effectContainers));
protected override void Update()
{
base.Update();

Add(audioBox.CreateProxy());
});
Vector2 pos = dragHandle.ScreenSpaceDrawQuad.Centre;
Container container = effectContainers.SingleOrDefault(c => c.ScreenSpaceDrawQuad.Contains(pos)) ?? noEffectContainer;

private partial class AudioBox : CompositeDrawable
{
private readonly Container<Drawable> defaultParent;
private readonly Container<ContainerWithEffect> effectContainers;
if (audioDrawable.Parent != container)
{
audioDrawable.Parent!.RemoveInternal(audioDrawable, false);
container.Add(audioDrawable);
}
}

public AudioBox(Container<Drawable> defaultParent, Container<ContainerWithEffect> effectContainers)
private partial class AudioPlayingDrawable : CompositeDrawable
{
[BackgroundDependencyLoader]
private void load(ISampleStore samples)
{
this.defaultParent = defaultParent;
this.effectContainers = effectContainers;
DrawableSample sample;

AddInternal(new AudioContainer
{
Volume = { Value = 0.5f },
Child = sample = new DrawableSample(samples.Get("long.mp3"))
});

currentContainer = defaultParent;
var channel = sample.GetChannel();
channel.Looping = true;
channel.Play();
}
}

Origin = Anchor.Centre;
private partial class DragHandle : CompositeDrawable
{
public DragHandle()
{
Size = new Vector2(50);

InternalChild = new CircularContainer
Expand All @@ -104,64 +126,24 @@ public AudioBox(Container<Drawable> defaultParent, Container<ContainerWithEffect
};
}

[BackgroundDependencyLoader]
private void load(ISampleStore samples)
{
samples.Volume.Value = 0.5f;

DrawableSample sample;
AddInternal(sample = new DrawableSample(samples.Get("long.mp3")));

var channel = sample.GetChannel();
channel.Looping = true;
channel.Play();
}

protected override bool OnDragStart(DragStartEvent e)
{
return true;
}
protected override bool OnDragStart(DragStartEvent e) => true;

protected override void OnDrag(DragEvent e)
{
Position += e.Delta;
}

private Container<Drawable> currentContainer;

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

Vector2 centre = ScreenSpaceDrawQuad.Centre;

Container<Drawable> targetContainer = effectContainers.FirstOrDefault(c => c.Contains(centre)) ?? defaultParent;
if (targetContainer == currentContainer)
return;

currentContainer.Remove(this, false);
targetContainer.Add(this);

Position = Parent!.ToLocalSpace(centre);

currentContainer = targetContainer;
}
protected override void OnDrag(DragEvent e) => Position = e.MousePosition;
}

private partial class ContainerWithEffect : Container
{
protected override Container<Drawable> Content => content;

private readonly DrawableAudioMixer mixer;
private readonly Container content;

private readonly Drawable background;

public ContainerWithEffect(string name, Color4 colour)
public ContainerWithEffect(string name, Color4 colour, IEffectParameter? effect)
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;

DrawableAudioMixer mixer;
InternalChild = mixer = new DrawableAudioMixer
{
RelativeSizeAxes = Axes.Both,
Expand All @@ -186,14 +168,14 @@ public ContainerWithEffect(string name, Color4 colour)
}
}
};
}

public BindableList<IEffectParameter> Effects => mixer.Effects;
if (effect != null)
mixer.AddEffect(effect);
}

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

background.Alpha = content.Count > 0 ? 1 : 0.2f;
}
}
Expand Down
9 changes: 6 additions & 3 deletions osu.Framework/Audio/Mixing/AudioMixer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.

using ManagedBass;
using osu.Framework.Bindables;
using osu.Framework.Extensions.ObjectExtensions;

namespace osu.Framework.Audio.Mixing
Expand All @@ -28,8 +27,6 @@ protected AudioMixer(AudioMixer? fallbackMixer, string identifier)
Identifier = identifier;
}

public abstract BindableList<IEffectParameter> Effects { get; }

public void Add(IAudioChannel channel)
{
channel.EnqueueAction(() =>
Expand All @@ -48,6 +45,12 @@ public void Add(IAudioChannel channel)

public void Remove(IAudioChannel channel) => Remove(channel, true);

public abstract void AddEffect(IEffectParameter effect, int priority = 0);

public abstract void RemoveEffect(IEffectParameter effect);

public abstract void UpdateEffect(IEffectParameter effect);

/// <summary>
/// Removes an <see cref="IAudioChannel"/> from the mix.
/// </summary>
Expand Down
Loading

0 comments on commit 98617ab

Please sign in to comment.