A game framework written with osu! in mind.
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2// See the LICENCE file in the repository root for full licence text.
3
4using System.Linq;
5using ManagedBass;
6using ManagedBass.Fx;
7using NUnit.Framework;
8using osu.Framework.Allocation;
9using osu.Framework.Audio.Sample;
10using osu.Framework.Bindables;
11using osu.Framework.Graphics;
12using osu.Framework.Graphics.Audio;
13using osu.Framework.Graphics.Containers;
14using osu.Framework.Graphics.Shapes;
15using osu.Framework.Graphics.Sprites;
16using osu.Framework.Input.Events;
17using osuTK;
18using osuTK.Graphics;
19
20namespace osu.Framework.Tests.Visual.Audio
21{
22 public class TestSceneAudioMixer : FrameworkTestScene
23 {
24 [SetUp]
25 public void Setup() => Schedule(() =>
26 {
27 ContainerWithEffect noEffectContainer;
28 FillFlowContainer<ContainerWithEffect> effectContainers;
29
30 Child = noEffectContainer = new ContainerWithEffect("no effect", Color4.Black)
31 {
32 RelativeSizeAxes = Axes.Both,
33 Size = new Vector2(1),
34 Child = new Container
35 {
36 RelativeSizeAxes = Axes.Both,
37 Padding = new MarginPadding(20),
38 Child = effectContainers = new FillFlowContainer<ContainerWithEffect>
39 {
40 RelativeSizeAxes = Axes.Both,
41 }
42 }
43 };
44
45 for (int i = 0; i < 50; i++)
46 {
47 float centre = 150 + 50 * i;
48
49 effectContainers.Add(new ContainerWithEffect($"<{centre}Hz", Color4.Blue)
50 {
51 Size = new Vector2(100),
52 Effects =
53 {
54 new BQFParameters
55 {
56 lFilter = BQFType.LowPass,
57 fCenter = centre
58 }
59 }
60 });
61 }
62
63 AudioBox audioBox;
64 noEffectContainer.Add(audioBox = new AudioBox(noEffectContainer, effectContainers));
65
66 Add(audioBox.CreateProxy());
67 });
68
69 private class AudioBox : CompositeDrawable
70 {
71 private readonly Container<Drawable> defaultParent;
72 private readonly Container<ContainerWithEffect> effectContainers;
73
74 public AudioBox(Container<Drawable> defaultParent, Container<ContainerWithEffect> effectContainers)
75 {
76 this.defaultParent = defaultParent;
77 this.effectContainers = effectContainers;
78
79 currentContainer = defaultParent;
80
81 Origin = Anchor.Centre;
82 Size = new Vector2(50);
83
84 InternalChild = new CircularContainer
85 {
86 RelativeSizeAxes = Axes.Both,
87 Masking = true,
88 Children = new Drawable[]
89 {
90 new Box
91 {
92 RelativeSizeAxes = Axes.Both,
93 Colour = Color4.HotPink,
94 },
95 new SpriteIcon
96 {
97 Anchor = Anchor.Centre,
98 Origin = Anchor.Centre,
99 RelativeSizeAxes = Axes.Both,
100 Size = new Vector2(0.5f),
101 Icon = FontAwesome.Solid.VolumeUp,
102 }
103 }
104 };
105 }
106
107 [BackgroundDependencyLoader]
108 private void load(ISampleStore samples)
109 {
110 samples.Volume.Value = 0.5f;
111
112 DrawableSample sample;
113 AddInternal(sample = new DrawableSample(samples.Get("long.mp3")));
114
115 var channel = sample.GetChannel();
116 channel.Looping = true;
117 channel.Play();
118 }
119
120 protected override bool OnDragStart(DragStartEvent e)
121 {
122 return true;
123 }
124
125 protected override void OnDrag(DragEvent e)
126 {
127 Position += e.Delta;
128 }
129
130 private Container<Drawable> currentContainer;
131
132 protected override void Update()
133 {
134 base.Update();
135
136 Vector2 centre = ScreenSpaceDrawQuad.Centre;
137
138 Container<Drawable> targetContainer = effectContainers.FirstOrDefault(c => c.Contains(centre)) ?? defaultParent;
139 if (targetContainer == currentContainer)
140 return;
141
142 currentContainer.Remove(this);
143 targetContainer.Add(this);
144
145 Position = Parent.ToLocalSpace(centre);
146
147 currentContainer = targetContainer;
148 }
149 }
150
151 private class ContainerWithEffect : Container
152 {
153 protected override Container<Drawable> Content => content;
154
155 private readonly DrawableAudioMixer mixer;
156 private readonly Container content;
157
158 private readonly Drawable background;
159
160 public ContainerWithEffect(string name, Color4 colour)
161 {
162 Anchor = Anchor.Centre;
163 Origin = Anchor.Centre;
164
165 InternalChild = mixer = new DrawableAudioMixer
166 {
167 RelativeSizeAxes = Axes.Both,
168 Children = new[]
169 {
170 background = new Box
171 {
172 RelativeSizeAxes = Axes.Both,
173 Colour = colour,
174 Alpha = 0.2f
175 },
176 new SpriteText
177 {
178 Anchor = Anchor.TopCentre,
179 Origin = Anchor.TopCentre,
180 Text = name,
181 Font = FrameworkFont.Regular.With(size: 18)
182 },
183 content = new Container
184 {
185 RelativeSizeAxes = Axes.Both
186 }
187 }
188 };
189 }
190
191 public BindableList<IEffectParameter> Effects => mixer.Effects;
192
193 protected override void Update()
194 {
195 base.Update();
196
197 background.Alpha = content.Count > 0 ? 1 : 0.2f;
198 }
199 }
200 }
201}