untested visualizer complete.

This commit is contained in:
Harrison Deng 2018-11-19 21:07:23 -06:00
parent 02d814b4f7
commit 57e76be95d
6 changed files with 143 additions and 21 deletions

View File

@ -51,6 +51,7 @@
<Compile Include="Zer01HD\Audio\MusicList.cs" />
<Compile Include="Zer01HD\Audio\SupportedFormats.cs" />
<Compile Include="Zer01HD\Audio\TransparentSampleProvider.cs" />
<Compile Include="Zer01HD\Audio\Visualizer\HorizontalVisualizer.cs" />
<Compile Include="Zer01HD\Screens\MainMenu\MainPage.cs" />
<Compile Include="Zer01HD\Screens\Transitions\FadeAwayTransition.cs" />
<Compile Include="Zer01HD\Utilities\Camera\Camera2D.cs" />
@ -151,9 +152,7 @@
<None Include="app.manifest" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Folder Include="Zer01HD\Audio\Visualizer\" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\MonoGame\v3.0\MonoGame.Content.Builder.targets" />
<Import Project="..\packages\BulletSharp.0.11.1\build\net40-client\BulletSharp.targets" Condition="Exists('..\packages\BulletSharp.0.11.1\build\net40-client\BulletSharp.targets')" />

View File

@ -9,7 +9,7 @@ using System.Threading.Tasks;
namespace RhythmBullet.Zer01HD.Audio
{
internal class MusicController
internal class MusicController : IDisposable
{
MusicList musicList;
WaveOutEvent outputDevice;
@ -105,5 +105,10 @@ namespace RhythmBullet.Zer01HD.Audio
return audioInput.CurrentTime;
}
public void Dispose()
{
audioInput?.Dispose();
outputDevice?.Dispose();
}
}
}

View File

@ -12,10 +12,11 @@ namespace RhythmBullet.Zer01HD.Audio
public class TransparentSampleProvider : ISampleProvider
{
private const int FFT_SIZE = 2048;
private readonly int m;
private readonly int m;
private ISampleProvider source;
private Complex[] fftBuffer;
private float[] spectrum;
private volatile bool updatedSpectrum;
private readonly float[] currentSpectrum;
private int channelCount;
public bool performFFT;
@ -27,7 +28,7 @@ namespace RhythmBullet.Zer01HD.Audio
source = sampleProvider;
channelCount = sampleProvider.WaveFormat.Channels;
fftBuffer = new Complex[FFT_SIZE];
spectrum = new float[FFT_SIZE];
currentSpectrum = new float[FFT_SIZE];
}
public WaveFormat WaveFormat
@ -38,12 +39,20 @@ namespace RhythmBullet.Zer01HD.Audio
}
}
public float GetSpectrumBin(int bin)
public float[] GetCurrentSpectrum()
{
lock (spectrum)
if (updatedSpectrum)
{
return spectrum[bin];
lock (fftBuffer)
{
for (int binID = 0; binID < currentSpectrum.Length; binID++)
{
currentSpectrum[binID] = fftBuffer[binID].X;
}
}
}
return currentSpectrum;
}
public int Read(float[] buffer, int offset, int count)
@ -57,14 +66,11 @@ namespace RhythmBullet.Zer01HD.Audio
{
if (s >= FFT_SIZE)
{
FastFourierTransform.FFT(true, m, fftBuffer);
lock (spectrum)
lock (fftBuffer)
{
for (int binID = 0; binID < spectrum.Length; binID++)
{
spectrum[binID] = fftBuffer[binID].X;
}
FastFourierTransform.FFT(true, m, fftBuffer);
}
updatedSpectrum = true;
fftOffset -= FFT_SIZE;
}
float greatestVal = 0;

View File

@ -0,0 +1,109 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RhythmBullet.Zer01HD.UI.Modular;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RhythmBullet.Zer01HD.Audio.Visualizer
{
internal class HorizontalVisualizer : UIModule, IDisposable
{
GraphicsDevice graphicsDevice;
Texture2D barTexture;
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)
{
this.graphicsDevice = graphicsDevice;
tsp = transparentSampleProvider;
bar.Width = (int)(graphicsDevice.Viewport.Width / 70f);
spaceBetweenBars = (int)(0.25f * bar.Width);
bar.Width -= spaceBetweenBars;
barTexture = new Texture2D(graphicsDevice, 1, 1);
barTexture.SetData(new[] { Color.White });
binsPerBar = tsp.GetCurrentSpectrum().Length / BAR_COUNT;
barValue = new int[BAR_COUNT];
}
public override void Update(GameTime gameTime)
{
UpdateBars((float)gameTime.ElapsedGameTime.TotalSeconds);
AverageBars();
base.Update(gameTime);
}
public override void Draw(SpriteBatch batch)
{
for (int i = 0; i < BAR_COUNT; i++)
{
bar.X = (i * (bar.Width + spaceBetweenBars)) + Bounds.X;
bar.Y = Bounds.Y;
bar.Height = barValue[i];
batch.Draw(barTexture, bar, Color);
bar.Height = -barValue[BAR_COUNT - i - 1];
batch.Draw(barTexture, bar, 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()
{
barTexture.Dispose();
}
}
}

View File

@ -32,11 +32,14 @@ namespace RhythmBullet.Zer01HD.Utilities.Camera
Matrix.CreateTranslation(new Vector3(bounds.Width * 0.5f, bounds.Height * 0.5f, 0f));
}
public void LinearInterpolationToPosition(float alpha, Vector2 targetPosition)
public void LinearInterpolationToPosition(float alpha, Vector2 targetPosition, float delta)
{
if (alpha < 0 && alpha > 1f) throw new ArgumentException("Alpha can't be greater than 1f, or less than 0.");
Position.X = MathHelper.Lerp(Position.X, targetPosition.X, alpha);
Position.Y = MathHelper.Lerp(Position.Y, targetPosition.Y, alpha);
if (alpha <= 0 && alpha > 1f) throw new ArgumentException("Alpha can't be greater than 1f, less than or equal to 0.");
Vector2 distance = targetPosition - Position;
distance *= (float)(1.0f - Math.Pow(1 - alpha, delta / 0.02f));
Position += distance;
}
}
}

View File

@ -45,7 +45,7 @@ namespace RhythmBullet.Zer01HD.UI.Book
Rectangle targetBounds = targetPage.Bounds;
position.X = targetBounds.X + (targetBounds.Width * 0.5f);
position.Y = targetBounds.Y + (targetBounds.Height * 0.5f);
camera.LinearInterpolationToPosition(0.4f, position);
camera.LinearInterpolationToPosition(0.4f, position, (float)gameTime.ElapsedGameTime.TotalSeconds);
if (camera.Position == position)
{
targetPage = null;