using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using RecrownedAthenaeum.Camera; using RecrownedAthenaeum.Render; using RecrownedAthenaeum.UI.Modular; using System; namespace RhythmBullet.Audio.Visualizer { internal class HorizontalVisualizer : UIModule, IDisposable { bool disposed; private RectangleRenderer rectangleRenderer; private const int BAR_COUNT = 70; private const int SMOOTH_RANGE = 3; private readonly int binsPerBar; private readonly int spaceBetweenBars; private Rectangle bar; private TransparentSampleProvider tsp; private int[] barValue; internal HorizontalVisualizer(TransparentSampleProvider transparentSampleProvider, GraphicsDevice graphicsDevice, Camera2D camera2D) { tsp = transparentSampleProvider; bar.Width = (int)(graphicsDevice.Viewport.Width / 70f); spaceBetweenBars = (int)(0.25f * bar.Width); bar.Width -= spaceBetweenBars; binsPerBar = tsp.GetCurrentSpectrum().Length / BAR_COUNT; barValue = new int[BAR_COUNT]; rectangleRenderer = new RectangleRenderer(); } public override void Update(GameTime gameTime) { if (disposed) throw new ObjectDisposedException(this.Name); UpdateBars((float)gameTime.ElapsedGameTime.TotalSeconds); AverageBars(); base.Update(gameTime); } public override void Draw(SpriteBatch batch) { if (disposed) throw new ObjectDisposedException(this.Name); rectangleRenderer.Begin(true); for (int i = 0; i < BAR_COUNT; i++) { bar.X = (i * (bar.Width + spaceBetweenBars)) + bounds.X; bar.Y = bounds.Y; bar.Height = barValue[i]; rectangleRenderer.Draw(bar.X, bar.Y, bar.Width, bar.Height, color); bar.Height = -barValue[BAR_COUNT - i - 1]; rectangleRenderer.Draw(bar.X, bar.Y, bar.Width, bar.Height, color); } rectangleRenderer.End(); base.Draw(batch); } private void UpdateBars(float delta) { const float ALPHA = 0.5f; float[] spectrum = tsp.GetCurrentSpectrum(); for (int barID = 0; barID < BAR_COUNT; barID++) { int targetBarHeight = 0; for (int bin = barID * binsPerBar; bin < (barID + 1) * (binsPerBar); bin++) { targetBarHeight += (int)spectrum[bin]; } targetBarHeight /= binsPerBar; int distance = targetBarHeight - barValue[barID]; distance *= (int)Math.Round((1.0f - Math.Pow(1 - ALPHA, delta / 0.02f))); barValue[barID] += distance; } } private void AverageBars() { for (int barID = 0; barID < BAR_COUNT; barID++) { int terms = 0; for (int pos = 0; pos < SMOOTH_RANGE; pos++) { if (barID + pos < BAR_COUNT) { barValue[barID] += barValue[barID + pos]; terms++; } if (barID - pos > 0) { barValue[barID] += barValue[barID - pos]; terms++; } } barValue[barID] /= terms; } } public void Dispose() { if (disposed) throw new ObjectDisposedException(this.Name); Dispose(true); } public virtual void Dispose(bool disposing) { if (disposing && !disposed) { rectangleRenderer.Dispose(); } disposed = true; } ~HorizontalVisualizer() { Dispose(false); } } }