Siv3D で音楽プレイヤーを作る

# 概要
完成形はこれです。Open でダイアログから音楽ファイルを選び、Play で再生、Pause で一時停止、シークバーを動かして再生位置を変更します。
![https://lh6.googleusercontent.com/-cqhFHZ5kNx0/VHkWYj5aNsI/AAAAAAAADiI/SSH4EIZYhbo/s800/soundplayer.gif](https://lh6.googleusercontent.com/-cqhFHZ5kNx0/VHkWYj5aNsI/AAAAAAAADiI/SSH4EIZYhbo/s800/soundplayer.gif)

# 実装 [1/4]
SoundPlayer クラスを作ります。
GUI をデフォルトの GUIStyle で初期化します。

```cpp
# include <Siv3D.hpp>

class SoundPlayer
{
private:

	GUI m_gui;

public:

	SoundPlayer()
		: m_gui(GUIStyle::Default)
	{

	}

	void update()
	{

	}
};

void Main()
{
	SoundPlayer soundPlayer;

	while (System::Update())
	{
		soundPlayer.update();
	}
}
```

# 実装 [2/4]
GUI に以下のアイテムを追加します。

* Play ボタン
* Pause ボタン
* Open ボタン
* [0.0, 1.0] を調節する幅 500px のスライダー

そのあと、GUI を画面下の中央に移動させます。

```cpp
# include <Siv3D.hpp>

class SoundPlayer
{
private:

	GUI m_gui;

public:

	SoundPlayer()
		: m_gui(GUIStyle::Default)
	{
		m_gui.add(L"PlayButton", GUIButton::Create(L"Play"));

		m_gui.add(L"PauseButton", GUIButton::Create(L"Pause"));

		m_gui.addln(L"OpenButton", GUIButton::Create(L"Open"));

		m_gui.add(L"Slider", GUISlider::Create(0.0, 1.0, 0.0, 500));

		m_gui.setPos((Window::Width() - m_gui.getRect().w) / 2, 360);
	}

	void update()
	{

	}
};

void Main()
{
	SoundPlayer soundPlayer;

	while (System::Update())
	{
		soundPlayer.update();
	}
}
```

# 実装 [3/4]
GUI::button(name).pushed で、指定したボタンが押されたかを取得できます。
それぞれのボタンを押したときの処理を加えます。

```cpp
# include <Siv3D.hpp>

class SoundPlayer
{
private:

	GUI m_gui;

	Sound m_sound;

public:

	SoundPlayer()
		: m_gui(GUIStyle::Default)
	{
		m_gui.add(L"PlayButton", GUIButton::Create(L"Play"));

		m_gui.add(L"PauseButton", GUIButton::Create(L"Pause"));

		m_gui.addln(L"OpenButton", GUIButton::Create(L"Open"));

		m_gui.add(L"Slider", GUISlider::Create(0.0, 1.0, 0.0, 500));

		m_gui.setPos((Window::Width() - m_gui.getRect().w) / 2, 360);
	}

	void update()
	{
		if (m_gui.button(L"PlayButton").pushed)
		{
			m_sound.play();
		}
		else if (m_gui.button(L"PauseButton").pushed)
		{
			m_sound.pause();
		}
		else if (m_gui.button(L"OpenButton").pushed)
		{
			m_sound.pause();

			m_sound = Dialog::OpenSound();
		}
	}
};

void Main()
{
	SoundPlayer soundPlayer;

	while (System::Update())
	{
		soundPlayer.update();
	}
}
```

# 実装 [4/4]
GUI::button(name).enabled プロパティを変更すると、ボタンのアクティブ / 非アクティブを切り替えられます。
サウンドがロードされていないか再生中である時には Play ボタンを非アクティブに、
サウンドが再生されていないときは Pause ボタンを非アクティブにします。

スライダーがユーザによって操作されたとき GUI::slider(name).hasChanged が true を返します。
スライダーの位置に応じてサウンドの再生位置を変更します。

また、サウンドの再生位置に応じてスライダーを GUI::slider(name).setValue() で動かします。

```cpp
# include <Siv3D.hpp>

class SoundPlayer
{
private:

	GUI m_gui;

	Sound m_sound;

public:

	SoundPlayer()
		: m_gui(GUIStyle::Default)
	{
		m_gui.add(L"PlayButton", GUIButton::Create(L"Play"));

		m_gui.add(L"PauseButton", GUIButton::Create(L"Pause"));

		m_gui.addln(L"OpenButton", GUIButton::Create(L"Open"));

		m_gui.add(L"Slider", GUISlider::Create(0.0, 1.0, 0.0, 500));

		m_gui.setPos((Window::Width() - m_gui.getRect().w) / 2, 360);
	}

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

		m_gui.button(L"PauseButton").enabled = m_sound.isPlaying();

		if (m_gui.button(L"PlayButton").pushed)
		{
			m_sound.play();
		}
		else if (m_gui.button(L"PauseButton").pushed)
		{
			m_sound.pause();
		}
		else if (m_gui.button(L"OpenButton").pushed)
		{
			m_sound.pause();

			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.streamPosSec() / m_sound.lengthSec());
	}
};

void Main()
{
	SoundPlayer soundPlayer;

	while (System::Update())
	{
		soundPlayer.update();
	}
}
```

# 完成
リファレンスの <a href="https://github.com/Siv3D/Reference-JP/wiki/%E3%82%AA%E3%83%BC%E3%83%87%E3%82%A3%E3%82%AA%E3%82%B9%E3%83%9A%E3%82%AF%E3%83%88%E3%83%A9%E3%83%A0" target="_blank">サンプル | オーディオスペクトラム</a> を参考に簡単なオーディオビジュアライザを加えました。これで完成です！

このソースコードはパブリックドメインです。

```cpp
// Siv3D March 2016
# include <Siv3D.hpp>

class SoundPlayer
{
private:

	GUI m_gui;

	Sound m_sound;

public:

	SoundPlayer()
		: m_gui(GUIStyle::Default)
	{
		m_gui.add(L"PlayButton", GUIButton::Create(L"Play"));

		m_gui.add(L"PauseButton", GUIButton::Create(L"Pause"));

		m_gui.addln(L"OpenButton", GUIButton::Create(L"Open"));

		m_gui.add(L"Slider", GUISlider::Create(0.0, 1.0, 0.0, 500));

		m_gui.setPos((Window::Width() - m_gui.getRect().w) / 2, 360);
	}

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

		m_gui.button(L"PauseButton").enabled = m_sound.isPlaying();

		if (m_gui.button(L"PlayButton").pushed)
		{
			m_sound.play();
		}
		else if (m_gui.button(L"PauseButton").pushed)
		{
			m_sound.pause();
		}
		else if (m_gui.button(L"OpenButton").pushed)
		{
			m_sound.pause();

			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.streamPosSec() / m_sound.lengthSec());
	}

	void drawVisualizer() const
	{
		if (!m_sound.isPlaying())
		{
			return;
		}

		const auto fft = FFT::Analyze(m_sound);

		for (int i = 0; i < 640; ++i)
		{
			const double size = Pow(fft.buffer[i], 0.6f) * 500;

			RectF(i, 200 + size, 1, -size * 2).draw(HSV(240 - i));
		}
	}
};

void Main()
{
	Graphics::SetBackground(Color(70, 80, 170));

	SoundPlayer soundPlayer;

	while (System::Update())
	{
		soundPlayer.update();

		soundPlayer.drawVisualizer();
	}
}
```

# 拡張
このプログラムを拡張するヒントです。

## オーディオビジュアライザー
オリジナルのエフェクトのオーディオビジュアライザーを作ってみましょう
## ループ再生
GUIToggleSwitch と Sound::setLoop(loop) を使ってループの有無を切り替えます
## サウンドの情報
Dialog::GetOpenSound() でファイルパスを取得したあとに Audio::GetProperty(path) で音楽ファイルのメタデータ（タイトル、ビットレート等）を取得できます
## 再生時間の表示
公式リファレンスの「サウンドの再生」チュートリアルが参考になります

# Siv3D について
Siv3D は C++ で楽しく簡単にゲームやメディアアートを作れるライブラリです。Kinect や Leap Motion, カメラやマイクといった多くのデバイスに対応し、複雑なインタラクションを短いコードで書くことができます。2008 年から開発を始め、2012 年に α 版を公開、2013 年 9 月には IPA 未踏事業に採択 、2014 年 9 月に CEDEC に出展、2016 年 8 月に最新版 Siv3D August 2016 をリリースしました。

Siv3D 公式ページ http://play-siv3d.hateblo.jp/