refactoring to comply with c# conventions

This commit is contained in:
2018-11-20 18:56:41 -06:00
parent efbaad9c1b
commit 3347316182
37 changed files with 115 additions and 115 deletions

View File

@@ -0,0 +1,127 @@
using Microsoft.Xna.Framework.Media;
using NAudio.Dsp;
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RhythmBullet.Audio
{
internal class MusicController : IDisposable
{
public readonly MusicList musicList;
WaveOutEvent outputDevice;
TransparentSampleProvider transparentSampleProvider;
AudioFileReader audioInput;
Random random;
float volume;
private float Volume
{
get
{
return volume;
}
set
{
if (outputDevice != null)
{
outputDevice.Volume = value;
}
volume = value;
}
}
private int PlayingIndex
{
get
{
return musicList.List.IndexOf(audioInput.FileName);
}
set
{
if (value < 0) value = musicList.List.Count -1;
if (value >= musicList.List.Count) value = 0;
LoadMusic(musicList.List[value]);
}
}
public MusicController()
{
musicList = new MusicList();
musicList.SearchCompleteEvent += MusicListRefreshListener;
random = new Random();
}
public MusicController(MusicList musicList)
{
random = new Random();
this.musicList = musicList;
this.musicList.SearchCompleteEvent += MusicListRefreshListener;
}
private void LoadMusic(string path)
{
outputDevice?.Dispose();
audioInput?.Dispose();
audioInput = new AudioFileReader(path);
transparentSampleProvider = new TransparentSampleProvider(audioInput);
outputDevice = new WaveOutEvent();
outputDevice.Volume = Volume;
outputDevice.Init(transparentSampleProvider);
}
public void Skip()
{
PlayingIndex++;
}
public void Previous()
{
PlayingIndex--;
}
public void Shuffle()
{
PlayingIndex = random.Next(0, musicList.List.Count);
}
public void Play()
{
outputDevice.Play();
}
public void Pause()
{
outputDevice.Pause();
}
public void Stop()
{
outputDevice.Stop();
}
public TimeSpan Position()
{
return audioInput.CurrentTime;
}
public void Dispose()
{
audioInput?.Dispose();
outputDevice?.Dispose();
musicList.SearchCompleteEvent -= MusicListRefreshListener;
}
public void MusicListRefreshListener(MusicList musicList)
{
}
}
}

View File

@@ -0,0 +1,121 @@
using Microsoft.Xna.Framework.Media;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace RhythmBullet.Audio
{
internal delegate void SearchListener(MusicList musicList);
internal class MusicList
{
public event SearchListener SearchCompleteEvent;
private volatile bool work;
private List<string> list = new List<string>();
public List<string> List
{
get
{
if (!thread.IsAlive)
{
lock (list)
{
return list;
}
}
else
{
return null;
}
}
}
public string path;
private Thread thread;
public bool Searched
{
get
{
return (thread != null && !thread.IsAlive);
}
}
internal MusicList()
{
}
public void StartSearch()
{
if (thread == null || !thread.IsAlive)
{
work = true;
thread = new Thread(Search);
thread.IsBackground = true;
thread.Name = "Music Search Thread";
Debug.WriteLine("Starting music file search with path: " + path, GetType().Name);
thread.Start();
}
else
{
StopSearch();
StartSearch();
}
}
public void StopSearch()
{
work = false;
thread.Join();
}
private void Search()
{
lock (list)
{
list.Clear();
list.AddRange(recursiveMusicSearch(path));
}
OnSearchComplete();
Debug.WriteLine("Completed search. Found " + list.Count + " valid file(s).", GetType().Name);
}
private List<string> recursiveMusicSearch(string path)
{
List<string> musicFiles = new List<string>();
string[] folders = Directory.GetDirectories(path);
string[] files = Directory.GetFiles(path);
for (int folderID = 0; folderID < folders.Length && work; folderID++)
{
musicFiles.AddRange(recursiveMusicSearch(folders[folderID]));
}
for (int fileID = 0; fileID < files.Length && work; fileID++)
{
string extensionType = Path.GetExtension(files[fileID]).ToUpper().Substring(1);
SupportedFormats format;
bool supported = Enum.TryParse<SupportedFormats>(extensionType, out format);
if (supported)
{
musicFiles.Add(files[fileID]);
Debug.WriteLine("Music file found: " + files[fileID], GetType().Name);
}
else
{
Debug.WriteLine("Unsupported file format: " + Path.GetFileName(files[fileID]), GetType().Name);
}
}
return musicFiles;
}
private void OnSearchComplete()
{
SearchCompleteEvent?.Invoke(this);
}
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RhythmBullet.Audio
{
public enum SupportedFormats
{
WAV, MP3
}
}

View File

@@ -0,0 +1,92 @@
using Microsoft.Xna.Framework;
using NAudio.Dsp;
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RhythmBullet.Audio
{
public class TransparentSampleProvider : ISampleProvider
{
private const int FFT_SIZE = 2048;
private readonly int m;
private ISampleProvider source;
private Complex[] fftBuffer;
private volatile bool updatedSpectrum;
private readonly float[] currentSpectrum;
private int channelCount;
public bool performFFT;
public TransparentSampleProvider(ISampleProvider sampleProvider)
{
m = (int)Math.Log(FFT_SIZE);
source = sampleProvider;
channelCount = sampleProvider.WaveFormat.Channels;
fftBuffer = new Complex[FFT_SIZE];
currentSpectrum = new float[FFT_SIZE];
}
public WaveFormat WaveFormat
{
get
{
return source.WaveFormat;
}
}
public float[] GetCurrentSpectrum()
{
if (updatedSpectrum)
{
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)
{
int sampleCount = source.Read(buffer, offset, count);
if (performFFT)
{
int fftOffset = 0;
for (int s = 0; s < sampleCount; s += channelCount)
{
if (s >= FFT_SIZE)
{
lock (fftBuffer)
{
FastFourierTransform.FFT(true, m, fftBuffer);
}
updatedSpectrum = true;
fftOffset -= FFT_SIZE;
}
float greatestVal = 0;
for (int c = 0; c < channelCount; c++)
{
greatestVal = MathHelper.Max(buffer[s + offset + c], greatestVal);
}
fftBuffer[s + fftOffset].X = (float)(buffer[s + offset] * FastFourierTransform.HammingWindow(s, FFT_SIZE));
fftBuffer[s + fftOffset].Y = 0;
}
}
return sampleCount;
}
}
}

View File

@@ -0,0 +1,109 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RhythmBullet.UI.Modular;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RhythmBullet.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();
}
}
}