rhythmbullet/RhythmBullet/Audio/Visualizer/ReflectedHorizontalVisualizer.cs

126 lines
4.0 KiB
C#

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 PrimitiveBatch primitiveBatch;
private RectangleRenderer renderer;
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];
primitiveBatch = new PrimitiveBatch(camera2D);
renderer = new RectangleRenderer(primitiveBatch);
}
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);
for (int i = 0; i < BAR_COUNT; i++)
{
bar.X = (i * (bar.Width + spaceBetweenBars)) + bounds.X;
bar.Y = bounds.Y;
renderer.Begin(true);
bar.Height = barValue[i];
renderer.DrawRectangle(bar.X, bar.Y, bar.Width, bar.Height, color);
bar.Height = -barValue[BAR_COUNT - i - 1];
renderer.DrawRectangle(bar.X, bar.Y, bar.Width, bar.Height, color);
}
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)
{
primitiveBatch.Dispose();
}
disposed = true;
}
~HorizontalVisualizer()
{
Dispose(false);
}
}
}