音階が見えるビジュアライザー

音階が見えるビジュアライザーです
<iframe width="312" height="176" src="http://ext.nicovideo.jp/thumb/sm22450052" scrolling="no" style="border:solid 1px #CCC;" frameborder="0"><a href="http://www.nicovideo.jp/watch/sm22450052">【ニコニコ動画】音階が見えるビジュアライザーを作ってみた[Siv3D]</a></iframe>

```ruby:Main.cpp
//はむくん ビジュアライザー 試作
# include <Siv3D.hpp>

class SoundPlayer
{
private:

	GUI m_gui;

	Sound m_sound;

	const Font m_font;

	const Vec2 m_centerPos;

	static const double m_freq[];

	static const bool m_isWhite[];

	static const String m_name[];

	bool m_isRecording;
public:

	SoundPlayer()
		: m_gui{ GUISkin::Default({ 0, 0, 0 }) }, m_font(10), m_centerPos(320, 190), m_isRecording(false)
	{
		m_gui.addButton(L"PlayButton", { L"Play" });

		m_gui.addButton(L"PauseButton", { L"Pause" });

		m_gui.addButton(L"OpenButton", { L"Open" });

		m_gui.addButton(L"UseMic", { L"Mic" });

		m_gui.addNewLine();

		m_gui.addSlider(L"Slider", { 0.0, 1.0, 0.0, 500 });

		m_gui.setPos((Window::Width() - m_gui.rect.w) / 2, 380);

		
	}

	void update()
	{
		m_gui.button(L"PlayButton").setEnabled(m_sound && !m_sound.isPlaying);

		m_gui.button(L"PauseButton").setEnabled(m_sound.isPlaying);

		m_gui.button(L"UseMic").setEnabled(!m_isRecording );

		m_gui.slider(L"Slider").setEnabled(!m_isRecording);

		if (m_gui.button(L"PlayButton").pushed)
		{
			m_sound.play();

			m_isRecording = false;

			Recorder::Stop();
		}
		else if (m_gui.button(L"PauseButton").pushed)
		{
			m_sound.pause();

			m_isRecording = false;

			Recorder::Stop();
		}
		else if (m_gui.button(L"OpenButton").pushed)
		{
			m_sound.pause();

			m_isRecording = false;

			Recorder::Stop();

			m_sound = Dialog::OpenSound();
		}

		if (m_gui.slider(L"Slider").hasChanged)
		{
			m_sound.setPosSec(m_sound.lengthSec*m_gui.slider(L"Slider").value);
		}

		m_gui.slider(L"Slider").setValue(m_sound.posSec / m_sound.lengthSec);

		if (m_gui.button(L"UseMic").pushed)
		{
			if (!Recorder::Start()){

			}
			else
			{
				m_isRecording = true;

				m_sound.pause();
			}
		}

	}

	void drawVisualizer() 
	{
		
		if (m_isRecording)
		{
			Waving::FFT(Recorder::GetWave(), Recorder::GetPos());
		}
		else
		{
			if (m_sound.isPlaying)Waving::FFT(m_sound);
		}
		

		const float* p = Waving::FFTBuffer();

		for (int i = 0; i < 12; ++i)
		{
			const double startRad = getRad((m_freq[i] + m_freq[i + 1]) / 2.0) + 0.01;

			const double angle = getRad((m_freq[i + 1] + m_freq[i + 2]) / 2.0) - startRad;

			const Vec2 pos = getPosFromRad( getRad(m_freq[i])) * (160.0) + m_centerPos;

			if (m_isWhite[i])
			{ 
				Circle(m_centerPos, 180).drawPie(startRad, angle, Color(50));
			}
			else
			{
				Circle(m_centerPos, 180).drawPie(startRad, angle, Color(20));
			}

			m_font.drawCenter(m_name[i], pos,Color(70));
		}

		for (int i = 0; i<1760; ++i)
		{
			const double di = i;

			const double radian = getRad(di);

			const double radius = 0.0;

			const double radiusOuter = 180.0;

			const double width = Min(radiusOuter * ((radian)- getRad(di-1)), 50.0);

			const double size = Pow(p[i], 0.6f) * 800 * Log(di)/Log(10.0);

			const double strength = Pow(size , 2.0) * Log( di ) / 1000000.0;

			const Vec2 pos = getPosFromRad(radian) * (radius + size / 2.0) + m_centerPos;

			RectF(width, size).setCenter(pos).rotate(radian).draw(HSV(240 - Log( di ) * 100,1.0,strength));
		}


		
		if (m_isRecording && Recorder::IsEnd()) // 録音が終了
		{
			Recorder::Restart();
		}
		
		
	}

	double getRad(double freq) 
	{
		return 2 * Pi * Log(freq) / Log(2.0) + 2.42;
	}

	Vec2 getPosFromRad(double rad)
	{
		return Vec2(Sin(rad), -Cos(rad));
	}
};

const double SoundPlayer::m_freq[] = {
	440.000000,
	466.163762,
	493.883301,
	523.251131,
	554.365262,
	587.329536,
	622.253967,
	659.255114,
	698.456463,
	739.988845,
	783.990872,
	830.609395,
	880.000000,
	932.328
};

const bool SoundPlayer::m_isWhite[] = {
	false, true, true, false, true, false, true, false, true, true, false, true
};

const String SoundPlayer::m_name[] = {
	L"D", L"D#", L"E", L"F", L"F#", L"G", L"G#", L"A", L"A#", L"B", L"C", L"C#"
};

void Main()
{
	SoundPlayer soundPlayer;

	Graphics::Set2DBlendState(BlendState::Additive());
		
	while (System::Update())
	{
		soundPlayer.update();

		soundPlayer.drawVisualizer();		
	}
}
```