A game framework written with osu! in mind.
at master 130 lines 5.0 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 System; 5using ManagedBass; 6using ManagedBass.Mix; 7using osu.Framework.Audio; 8using osu.Framework.Graphics.Containers; 9using osu.Framework.Graphics.Shapes; 10using osu.Framework.Graphics.Sprites; 11using osuTK; 12using osuTK.Graphics; 13 14namespace osu.Framework.Graphics.Visualisation.Audio 15{ 16 public class AudioChannelDisplay : CompositeDrawable 17 { 18 private const int sample_window = 30; 19 private const int peak_hold_time = 3000; 20 21 public readonly int ChannelHandle; 22 23 private readonly Drawable volBarL; 24 private readonly Drawable volBarR; 25 private readonly SpriteText peakText; 26 private readonly SpriteText maxPeakText; 27 28 private float maxPeak = float.MinValue; 29 private double lastMaxPeakTime; 30 31 public AudioChannelDisplay(int channelHandle) 32 { 33 ChannelHandle = channelHandle; 34 35 RelativeSizeAxes = Axes.Y; 36 AutoSizeAxes = Axes.X; 37 38 InternalChild = new GridContainer 39 { 40 RelativeSizeAxes = Axes.Y, 41 AutoSizeAxes = Axes.X, 42 ColumnDimensions = new[] 43 { 44 new Dimension(GridSizeMode.AutoSize) 45 }, 46 RowDimensions = new[] 47 { 48 new Dimension(), 49 new Dimension(GridSizeMode.AutoSize) 50 }, 51 Content = new[] 52 { 53 new Drawable[] 54 { 55 new FillFlowContainer 56 { 57 RelativeSizeAxes = Axes.Y, 58 AutoSizeAxes = Axes.X, 59 Direction = FillDirection.Horizontal, 60 Spacing = new Vector2(5), 61 Children = new[] 62 { 63 volBarL = new Box 64 { 65 Anchor = Anchor.BottomLeft, 66 Origin = Anchor.BottomLeft, 67 RelativeSizeAxes = Axes.Y, 68 Width = 30, 69 Colour = Color4.YellowGreen 70 }, 71 volBarR = new Box 72 { 73 Anchor = Anchor.BottomLeft, 74 Origin = Anchor.BottomLeft, 75 RelativeSizeAxes = Axes.Y, 76 Width = 30, 77 Colour = Color4.YellowGreen 78 } 79 } 80 } 81 }, 82 new Drawable[] 83 { 84 new FillFlowContainer 85 { 86 AutoSizeAxes = Axes.Y, 87 RelativeSizeAxes = Axes.X, 88 Direction = FillDirection.Vertical, 89 Children = new Drawable[] 90 { 91 peakText = new SpriteText { Text = "N/A", Font = FrameworkFont.Condensed.With(size: 14f) }, 92 maxPeakText = new SpriteText { Text = "N/A", Font = FrameworkFont.Condensed.With(size: 14f) }, 93 } 94 } 95 } 96 } 97 }; 98 } 99 100 protected override void Update() 101 { 102 base.Update(); 103 104 float[] levels = new float[2]; 105 BassMix.ChannelGetLevel(ChannelHandle, levels, 1 / 1000f * sample_window, LevelRetrievalFlags.Stereo); 106 107 var curPeakL = levels[0]; 108 var curPeakR = levels[1]; 109 var curPeak = (curPeakL + curPeakR) / 2f; 110 111 if (curPeak > maxPeak || Clock.CurrentTime - lastMaxPeakTime > peak_hold_time) 112 { 113 lastMaxPeakTime = Clock.CurrentTime; 114 maxPeak = float.MinValue; 115 } 116 117 maxPeak = Math.Max(maxPeak, curPeak); 118 119 volBarL.ResizeHeightTo(curPeakL, sample_window * 4); 120 volBarR.ResizeHeightTo(curPeakR, sample_window * 4); 121 122 var peakDisplay = curPeak == 0 ? "-∞ " : $"{BassUtils.LevelToDb(curPeak):F}"; 123 var maxPeakDisplay = maxPeak == 0 ? "-∞ " : $"{BassUtils.LevelToDb(maxPeak):F}"; 124 peakText.Text = $"curr: {peakDisplay}dB"; 125 maxPeakText.Text = $"peak: {maxPeakDisplay}dB"; 126 peakText.Colour = BassUtils.LevelToDb(curPeak) > 0 ? Colour4.Red : Colour4.White; 127 maxPeakText.Colour = BassUtils.LevelToDb(maxPeak) > 0 ? Colour4.Red : Colour4.White; 128 } 129 } 130}