音階が見えるビジュアライザーです
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();
}
}