238 lines
7.6 KiB
C#
238 lines
7.6 KiB
C#
using System;
|
|
using FractalVisualizer.Audio;
|
|
using FractalVisualizer.Models;
|
|
using FractalVisualizer.Rendering;
|
|
using FractalVisualizer.UI;
|
|
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
using Microsoft.Xna.Framework.Input;
|
|
|
|
namespace FractalVisualizer;
|
|
|
|
public class Game1 : Game
|
|
{
|
|
private readonly GraphicsDeviceManager _graphics;
|
|
|
|
private SpriteBatch? _spriteBatch;
|
|
private Texture2D? _pixel;
|
|
private HudBitmapFont? _hudFont;
|
|
|
|
private readonly AudioCapture _audioCapture;
|
|
private readonly AudioAnalyzer _audioAnalyzer;
|
|
private FractalRenderer? _fractalRenderer;
|
|
|
|
private KeyboardState _previousKeyboardState;
|
|
private AudioInputMode _currentInputMode;
|
|
private AudioFeatures _latestFeatures;
|
|
private bool _isPaused;
|
|
private bool _showHud = true;
|
|
private int _fractalPresetIndex;
|
|
private int _fps;
|
|
private int _frameCounter;
|
|
private TimeSpan _fpsElapsed;
|
|
private readonly (int Width, int Height)[] _windowedResolutions =
|
|
[
|
|
(1280, 720),
|
|
(1600, 900),
|
|
(1920, 1080)
|
|
];
|
|
private int _resolutionIndex = 0;
|
|
|
|
public Game1()
|
|
{
|
|
_graphics = new GraphicsDeviceManager(this);
|
|
_graphics.PreferredBackBufferWidth = 1280;
|
|
_graphics.PreferredBackBufferHeight = 720;
|
|
Content.RootDirectory = "Content";
|
|
IsMouseVisible = true;
|
|
Window.AllowUserResizing = true;
|
|
|
|
_audioCapture = new AudioCapture();
|
|
_audioAnalyzer = new AudioAnalyzer(_audioCapture, fftSize: 2048, spectrumBins: 64);
|
|
_currentInputMode = AudioInputMode.Microphone;
|
|
_latestFeatures = AudioFeatures.CreateEmpty(64);
|
|
}
|
|
|
|
protected override void Initialize()
|
|
{
|
|
_audioCapture.Start();
|
|
_audioAnalyzer.Start();
|
|
Window.Title = "Fractal Visualizer";
|
|
base.Initialize();
|
|
}
|
|
|
|
protected override void LoadContent()
|
|
{
|
|
_spriteBatch = new SpriteBatch(GraphicsDevice);
|
|
_fractalRenderer = new FractalRenderer(GraphicsDevice);
|
|
_pixel = new Texture2D(GraphicsDevice, 1, 1, false, SurfaceFormat.Color);
|
|
_pixel.SetData([Color.White]);
|
|
_hudFont = new HudBitmapFont();
|
|
}
|
|
|
|
protected override void Update(GameTime gameTime)
|
|
{
|
|
KeyboardState keyboard = Keyboard.GetState();
|
|
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
|
|
{
|
|
Exit();
|
|
return;
|
|
}
|
|
|
|
if (IsPressed(keyboard, Keys.Escape))
|
|
{
|
|
if (_graphics.IsFullScreen)
|
|
{
|
|
_graphics.ToggleFullScreen();
|
|
}
|
|
else
|
|
{
|
|
Exit();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (IsPressed(keyboard, Keys.F11))
|
|
{
|
|
ToggleFullScreen();
|
|
}
|
|
|
|
if (IsPressed(keyboard, Keys.F))
|
|
{
|
|
ToggleFullScreen();
|
|
}
|
|
|
|
if (IsPressed(keyboard, Keys.R))
|
|
{
|
|
CycleWindowResolution();
|
|
}
|
|
|
|
if (IsPressed(keyboard, Keys.Space))
|
|
{
|
|
_isPaused = !_isPaused;
|
|
}
|
|
|
|
if (IsPressed(keyboard, Keys.Tab))
|
|
{
|
|
_showHud = !_showHud;
|
|
}
|
|
|
|
if (IsPressed(keyboard, Keys.Left))
|
|
{
|
|
_fractalPresetIndex = Math.Max(0, _fractalPresetIndex - 1);
|
|
}
|
|
|
|
if (IsPressed(keyboard, Keys.Right))
|
|
{
|
|
_fractalPresetIndex = Math.Min(8, _fractalPresetIndex + 1);
|
|
}
|
|
|
|
if (IsPressed(keyboard, Keys.M))
|
|
{
|
|
_currentInputMode = _currentInputMode == AudioInputMode.Microphone
|
|
? AudioInputMode.SystemOutput
|
|
: AudioInputMode.Microphone;
|
|
_audioCapture.SwitchMode(_currentInputMode);
|
|
}
|
|
|
|
_latestFeatures = _audioAnalyzer.GetLatestFeatures();
|
|
_fpsElapsed += gameTime.ElapsedGameTime;
|
|
_frameCounter++;
|
|
if (_fpsElapsed >= TimeSpan.FromSeconds(1))
|
|
{
|
|
_fps = _frameCounter;
|
|
_frameCounter = 0;
|
|
_fpsElapsed -= TimeSpan.FromSeconds(1);
|
|
}
|
|
|
|
Window.Title = $"Fractal Visualizer | {GetPresetName(_fractalPresetIndex)} | Mode: {_currentInputMode} | L:{_latestFeatures.Level:F3} B:{_latestFeatures.Bass:F2}";
|
|
_previousKeyboardState = keyboard;
|
|
base.Update(gameTime);
|
|
}
|
|
|
|
protected override void Draw(GameTime gameTime)
|
|
{
|
|
GraphicsDevice.Clear(Color.Black);
|
|
|
|
if (_fractalRenderer is not null)
|
|
{
|
|
float renderTime = _isPaused ? _latestFeatures.TimeSeconds : (float)gameTime.TotalGameTime.TotalSeconds;
|
|
_fractalRenderer.Draw(_latestFeatures, renderTime, _fractalPresetIndex);
|
|
}
|
|
|
|
if (_showHud && _spriteBatch is not null && _hudFont is not null && _pixel is not null)
|
|
{
|
|
_spriteBatch.Begin(samplerState: SamplerState.PointClamp, blendState: BlendState.AlphaBlend);
|
|
string modeText = _currentInputMode == AudioInputMode.Microphone ? "MIC" : "SYS";
|
|
_hudFont.DrawText(_spriteBatch, _pixel, "MODE " + modeText + " M SWITCH", 12, 10, 2, Color.White);
|
|
_hudFont.DrawText(_spriteBatch, _pixel, "PRESET " + GetPresetName(_fractalPresetIndex) + " LEFT RIGHT", 12, 30, 2, Color.White);
|
|
_hudFont.DrawText(_spriteBatch, _pixel, "LEVEL " + _latestFeatures.Level.ToString("0.000"), 12, 50, 2, Color.White);
|
|
_hudFont.DrawText(_spriteBatch, _pixel, "BASS " + _latestFeatures.Bass.ToString("0.000"), 12, 70, 2, Color.White);
|
|
_hudFont.DrawText(_spriteBatch, _pixel, "MID " + _latestFeatures.Mid.ToString("0.000"), 12, 90, 2, Color.White);
|
|
_hudFont.DrawText(_spriteBatch, _pixel, "HIGH " + _latestFeatures.High.ToString("0.000"), 12, 110, 2, Color.White);
|
|
_hudFont.DrawText(_spriteBatch, _pixel, "BEAT " + _latestFeatures.Beat.ToString("0.000"), 12, 130, 2, Color.White);
|
|
_hudFont.DrawText(_spriteBatch, _pixel, "PAUSED " + (_isPaused ? "YES" : "NO"), 12, 150, 2, Color.White);
|
|
_hudFont.DrawText(_spriteBatch, _pixel, "FPS " + _fps, 12, 170, 2, Color.White);
|
|
_hudFont.DrawText(_spriteBatch, _pixel, "F OR F11 FULLSCREEN R RESIZE", 12, 190, 2, Color.White);
|
|
_spriteBatch.End();
|
|
}
|
|
|
|
base.Draw(gameTime);
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
_audioAnalyzer.Dispose();
|
|
_audioCapture.Dispose();
|
|
_fractalRenderer?.Dispose();
|
|
_pixel?.Dispose();
|
|
_spriteBatch?.Dispose();
|
|
}
|
|
|
|
base.Dispose(disposing);
|
|
}
|
|
|
|
private bool IsPressed(KeyboardState keyboardState, Keys key)
|
|
{
|
|
return keyboardState.IsKeyDown(key) && _previousKeyboardState.IsKeyUp(key);
|
|
}
|
|
|
|
private static string GetPresetName(int presetIndex)
|
|
{
|
|
return presetIndex switch
|
|
{
|
|
0 => "JULIA",
|
|
1 => "MANDELBULB",
|
|
2 => "KALEIDO",
|
|
3 => "FLAME",
|
|
4 => "PLASMA",
|
|
5 => "NEBULA",
|
|
6 => "FLAMEGRILL",
|
|
7 => "NOTES",
|
|
8 => "FIREWORKS",
|
|
_ => "JULIA"
|
|
};
|
|
}
|
|
|
|
private void ToggleFullScreen()
|
|
{
|
|
_graphics.ToggleFullScreen();
|
|
}
|
|
|
|
private void CycleWindowResolution()
|
|
{
|
|
if (_graphics.IsFullScreen)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_resolutionIndex = (_resolutionIndex + 1) % _windowedResolutions.Length;
|
|
(int width, int height) = _windowedResolutions[_resolutionIndex];
|
|
_graphics.PreferredBackBufferWidth = width;
|
|
_graphics.PreferredBackBufferHeight = height;
|
|
_graphics.ApplyChanges();
|
|
}
|
|
}
|