A game framework written with osu! in mind.
at master 265 lines 9.1 kB view raw
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 NUnit.Framework; 5using osu.Framework.Allocation; 6using osu.Framework.Audio; 7using osu.Framework.Audio.Track; 8using osu.Framework.Bindables; 9using osu.Framework.Graphics; 10using osu.Framework.Graphics.Audio; 11using osu.Framework.Graphics.Containers; 12using osu.Framework.Graphics.Shapes; 13using osu.Framework.Graphics.Sprites; 14using osu.Framework.Graphics.UserInterface; 15using osu.Framework.Input.Events; 16using osuTK; 17using osuTK.Graphics; 18 19namespace osu.Framework.Tests.Visual.Drawables 20{ 21 public class TestSceneWaveform : FrameworkTestScene 22 { 23 private BasicButton button; 24 private Track track; 25 private Waveform waveform; 26 private Container<Drawable> waveformContainer; 27 private readonly Bindable<float> zoom = new BindableFloat(1) { MinValue = 0.1f, MaxValue = 20 }; 28 29 [BackgroundDependencyLoader] 30 private void load(Game game, AudioManager audio) 31 { 32 var store = audio.GetTrackStore(game.Resources); 33 34 const string track_name = "Tracks/sample-track.mp3"; 35 36 track = store.Get(track_name); 37 waveform = new Waveform(store.GetStream(track_name)); 38 39 const float track_width = 1366; // required because RelativeSizeAxes.X doesn't seem to work with horizontal scroll 40 41 Child = new FillFlowContainer 42 { 43 RelativeSizeAxes = Axes.Both, 44 Direction = FillDirection.Vertical, 45 Children = new Drawable[] 46 { 47 new FillFlowContainer 48 { 49 AutoSizeAxes = Axes.Y, 50 RelativeSizeAxes = Axes.X, 51 Spacing = new Vector2(10), 52 Children = new Drawable[] 53 { 54 button = new BasicButton 55 { 56 Text = "Start", 57 Size = new Vector2(100, 50), 58 BackgroundColour = Color4.DarkSlateGray, 59 Anchor = Anchor.CentreLeft, 60 Origin = Anchor.CentreLeft, 61 Action = startStop 62 }, 63 new SpriteText 64 { 65 Text = "Zoom Level:", 66 Origin = Anchor.CentreLeft, 67 Anchor = Anchor.CentreLeft, 68 }, 69 new BasicSliderBar<float> 70 { 71 Anchor = Anchor.CentreLeft, 72 Origin = Anchor.CentreLeft, 73 Size = new Vector2(200, 40), 74 Current = zoom 75 }, 76 }, 77 }, 78 new BasicScrollContainer(Direction.Horizontal) 79 { 80 RelativeSizeAxes = Axes.Both, 81 Child = waveformContainer = new FillFlowContainer 82 { 83 RelativeSizeAxes = Axes.Y, 84 Width = track_width, 85 Direction = FillDirection.Vertical, 86 Spacing = new Vector2(0, 10) 87 } 88 } 89 } 90 }; 91 92 zoom.ValueChanged += e => waveformContainer.Width = track_width * e.NewValue; 93 } 94 95 [TestCase(1f)] 96 [TestCase(1f / 2)] 97 [TestCase(1f / 4)] 98 [TestCase(1f / 8)] 99 [TestCase(1f / 16)] 100 [TestCase(0)] 101 public void TestResolution(float resolution) 102 { 103 TestWaveform graph = null; 104 105 AddStep("create waveform", () => waveformContainer.Child = graph = new TestWaveform(track, resolution) { Waveform = waveform }); 106 AddUntilStep("wait for load", () => graph.Regenerated); 107 } 108 109 [Test] 110 public void TestNullWaveform() 111 { 112 TestWaveform graph = null; 113 114 AddStep("create waveform", () => waveformContainer.Child = graph = new TestWaveform(track, 1) { Waveform = new Waveform(null) }); 115 AddUntilStep("wait for load", () => graph.Regenerated); 116 } 117 118 [Test] 119 public void TestWaveformAlpha() 120 { 121 TestWaveform graph = null; 122 123 AddStep("create waveform", () => waveformContainer.Child = graph = new TestWaveform(track, 1) 124 { 125 Waveform = waveform, 126 Alpha = 0.5f, 127 }); 128 129 AddUntilStep("wait for load", () => graph.Regenerated); 130 } 131 132 private void startStop() 133 { 134 if (track.IsRunning) 135 { 136 track.Stop(); 137 button.Text = "Start"; 138 } 139 else 140 { 141 track.Start(); 142 button.Text = "Stop"; 143 } 144 } 145 146 protected override void Dispose(bool isDisposing) 147 { 148 base.Dispose(isDisposing); 149 track?.Stop(); 150 } 151 152 private class TestWaveform : CompositeDrawable 153 { 154 private readonly Track track; 155 private readonly TestWaveformGraph graph; 156 private readonly Drawable marker; 157 158 public TestWaveform(Track track, float resolution) 159 { 160 this.track = track; 161 162 RelativeSizeAxes = Axes.X; 163 Height = 100; 164 165 InternalChildren = new[] 166 { 167 graph = new TestWaveformGraph 168 { 169 RelativeSizeAxes = Axes.Both, 170 Resolution = resolution, 171 BaseColour = new Color4(232, 78, 6, 255), 172 LowColour = new Color4(255, 232, 100, 255), 173 MidColour = new Color4(255, 153, 19, 255), 174 HighColour = new Color4(255, 46, 7, 255), 175 }, 176 new Container 177 { 178 Anchor = Anchor.Centre, 179 Origin = Anchor.Centre, 180 AutoSizeAxes = Axes.Both, 181 Children = new Drawable[] 182 { 183 new Box 184 { 185 RelativeSizeAxes = Axes.Both, 186 Colour = Color4.Black, 187 Alpha = 0.75f 188 }, 189 new SpriteText 190 { 191 Anchor = Anchor.Centre, 192 Origin = Anchor.Centre, 193 Padding = new MarginPadding(4), 194 Text = $"Resolution: {resolution:0.00}" 195 } 196 } 197 }, 198 marker = new Box 199 { 200 RelativeSizeAxes = Axes.Y, 201 RelativePositionAxes = Axes.X, 202 Width = 2, 203 Colour = Color4.Blue 204 }, 205 }; 206 } 207 208 public bool Regenerated => graph.Regenerated; 209 210 public Waveform Waveform 211 { 212 set => graph.Waveform = value; 213 } 214 215 protected override void Update() 216 { 217 base.Update(); 218 219 if (track.IsLoaded) 220 marker.X = (float)(track.CurrentTime / track.Length); 221 } 222 223 private bool mouseDown; 224 225 protected override bool OnMouseDown(MouseDownEvent e) 226 { 227 mouseDown = true; 228 seekTo(ToLocalSpace(e.ScreenSpaceMousePosition).X); 229 return true; 230 } 231 232 protected override void OnMouseUp(MouseUpEvent e) 233 { 234 mouseDown = false; 235 } 236 237 protected override bool OnMouseMove(MouseMoveEvent e) 238 { 239 if (mouseDown) 240 { 241 seekTo(ToLocalSpace(e.ScreenSpaceMousePosition).X); 242 return true; 243 } 244 245 return false; 246 } 247 248 private void seekTo(float x) 249 { 250 track.Seek(x / DrawWidth * track.Length); 251 } 252 } 253 254 private class TestWaveformGraph : WaveformGraph 255 { 256 public bool Regenerated { get; private set; } 257 258 protected override void OnWaveformRegenerated(Waveform waveform) 259 { 260 base.OnWaveformRegenerated(waveform); 261 Regenerated = true; 262 } 263 } 264 } 265}