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 osu.Framework.Allocation;
6using osu.Framework.Audio;
7using osu.Framework.Audio.Sample;
8using osu.Framework.Extensions.IEnumerableExtensions;
9using osu.Framework.Graphics;
10using osu.Framework.Graphics.Audio;
11using osu.Framework.Graphics.Containers;
12using osu.Framework.Graphics.Shapes;
13using osu.Framework.Input.Events;
14using osuTK;
15using osuTK.Graphics;
16
17namespace osu.Framework.Tests.Visual.Audio
18{
19 public class TestSceneSamples : FrameworkTestScene
20 {
21 private readonly AudioContainer samples;
22 private readonly TrackingLine tracking;
23
24 private const int beats = 8;
25 private const int notes = 16;
26
27 public TestSceneSamples()
28 {
29 Children = new Drawable[]
30 {
31 new Container
32 {
33 Anchor = Anchor.Centre,
34 Origin = Anchor.Centre,
35 RelativeSizeAxes = Axes.Both,
36 Size = new Vector2(0.95f),
37 FillMode = FillMode.Fit,
38 Children = new Drawable[]
39 {
40 new Box
41 {
42 Colour = Color4.Blue,
43 RelativeSizeAxes = Axes.Both,
44 },
45 new Grid(beats - 1, notes),
46 samples = new AudioContainer
47 {
48 RelativeSizeAxes = Axes.Both,
49 RelativeChildSize = new Vector2(beats - 1, notes),
50 Children = new Drawable[]
51 {
52 new DraggableSample(0, 0),
53 new DraggableSample(1, 2),
54 new DraggableSample(2, 4),
55 new DraggableSample(3, 5),
56 new DraggableSample(4, 8),
57 new DraggableSample(5, 11),
58 new DraggableSample(6, 14),
59 new DraggableSample(7, 16),
60 tracking = new TrackingLine()
61 }
62 },
63 }
64 },
65 };
66
67 AddStep("reduce volume", () => samples.VolumeTo(samples.Volume.Value - 0.5f, 1000, Easing.OutQuint));
68 AddStep("increase volume", () => samples.VolumeTo(samples.Volume.Value + 0.5f, 1000, Easing.OutQuint));
69
70 AddStep("reduce frequency", () => samples.FrequencyTo(samples.Frequency.Value - 0.1f, 1000, Easing.OutQuint));
71 AddStep("increase frequency", () => samples.FrequencyTo(samples.Frequency.Value + 0.1f, 1000, Easing.OutQuint));
72
73 AddStep("left balance", () => samples.BalanceTo(samples.Balance.Value - 1, 1000, Easing.OutQuint));
74 AddStep("right balance", () => samples.BalanceTo(samples.Balance.Value + 1, 1000, Easing.OutQuint));
75 }
76
77 protected override void Update()
78 {
79 base.Update();
80
81 if (tracking.X > beats)
82 {
83 tracking.X = 0;
84 samples.OfType<DraggableSample>().ForEach(s => s.Reset());
85 }
86 else
87 {
88 tracking.X += (float)Clock.ElapsedFrameTime / 500;
89 samples.OfType<DraggableSample>().Where(s => !s.Played && s.X <= tracking.X).ForEach(s => s.Play());
90 }
91 }
92
93 private class TrackingLine : CompositeDrawable
94 {
95 public TrackingLine()
96 {
97 RelativePositionAxes = Axes.Both;
98 RelativeSizeAxes = Axes.Y;
99 Size = new Vector2(4, notes);
100 Colour = Color4.SkyBlue;
101
102 Blending = BlendingParameters.Additive;
103
104 InternalChildren = new Drawable[]
105 {
106 new Box
107 {
108 Colour = Color4.White,
109 RelativeSizeAxes = Axes.Both,
110 },
111 };
112 }
113 }
114
115 public class Grid : CompositeDrawable
116 {
117 public Grid(int beats, int notes)
118 {
119 RelativeSizeAxes = Axes.Both;
120
121 for (int i = 0; i <= beats; i++)
122 {
123 AddInternal(new Box
124 {
125 RelativePositionAxes = Axes.Both,
126 RelativeSizeAxes = Axes.Y,
127 Width = 1,
128 Colour = Color4.White,
129 X = (float)i / beats
130 });
131 }
132
133 for (int i = 0; i <= notes; i++)
134 {
135 AddInternal(new Box
136 {
137 RelativePositionAxes = Axes.Both,
138 RelativeSizeAxes = Axes.X,
139 Height = 1,
140 Colour = Color4.White,
141 Y = (float)i / notes
142 });
143 }
144 }
145 }
146
147 private class DraggableSample : CompositeDrawable
148 {
149 public DraggableSample(int beat, int pitch)
150 {
151 RelativePositionAxes = Axes.Both;
152
153 Position = new Vector2(beat, pitch);
154 Size = new Vector2(16);
155
156 Origin = Anchor.Centre;
157
158 InternalChildren = new Drawable[]
159 {
160 circle = new Circle
161 {
162 Colour = Color4.Yellow,
163 RelativeSizeAxes = Axes.Both,
164 Anchor = Anchor.Centre,
165 Origin = Anchor.Centre,
166 },
167 };
168 }
169
170 public bool Played { get; private set; }
171
172 [BackgroundDependencyLoader]
173 private void load(ISampleStore samples)
174 {
175 AddInternal(sample = new DrawableSample(samples.Get("long.mp3")));
176 }
177
178 private DrawableSample sample;
179
180 private readonly Circle circle;
181
182 protected override bool OnDragStart(DragStartEvent e) => true;
183
184 protected override void OnDrag(DragEvent e)
185 {
186 Y = (int)(e.MousePosition.Y / (Parent.DrawHeight / notes));
187 }
188
189 public void Reset()
190 {
191 Played = false;
192 }
193
194 public void Play()
195 {
196 Played = true;
197 circle.ScaleTo(1.8f).ScaleTo(1, 600, Easing.OutQuint);
198
199 var channel = sample.GetChannel();
200 channel.Frequency.Value = 1 + Y / notes;
201 channel.Play();
202 }
203 }
204 }
205}