すこし新しい方です
Main.cpp
//はむくん ビジュアライザー 試作
# include <Siv3D.hpp>
void createGrad(Image& image)
{
const Vec2 center = Vec2(image.width, image.height) / 2;
const double maxLength = center.x;
Color col;
for (int y = 0; y < image.height; ++y)
{
for (int x = 0; x < image.width; ++x)
{
const Vec2 pos(x, y);
const double length = (center - pos).length();
const double value = length / maxLength;
col = ColorF(1.0 - Pow(value, 2.0));
image[y][x] = col;
}
}
}
class SoundPlayer
{
private:
GUI m_guiBasic;
GUI m_guiSettings;
Sound m_sound;
Texture m_gradTexture;
Texture m_backTexture;
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;
bool m_isShowingSetting;
int m_hideSettingCount;
public:
SoundPlayer()
: m_guiBasic{ GUISkin::Default({ 0, 0, 0 }) }, m_guiSettings(m_guiBasic.skin),
m_font(10), m_centerPos(320, 190), m_isRecording(false), m_isShowingSetting(false)
{
Image image(10, 10);
createGrad(image);
m_gradTexture = Texture(image);
m_guiBasic.addSlider(L"Slider", { 0.0, 1.0, 0.0, 500 });
m_guiBasic.addNewLine();
m_guiBasic.addButton(L"PlayButton", { L"再生" });
m_guiBasic.addButton(L"PauseButton", { L"停止" });
m_guiBasic.addButton(L"OpenButton", { L"ファイルを開く" });
m_guiBasic.addButton(L"UseMic", { L"マイク" });
m_guiBasic.setPos((Window::Width() - m_guiBasic.rect.w) / 2, 380);
m_guiSettings.addText(L"setting",{ L"設定" });
m_guiSettings.addNewLine();
m_guiSettings.addButton(L"OpenPicture", { L"背景画像" });
m_guiSettings.addNewLine();
m_guiSettings.addText({ L"画像明るさ" });
m_guiSettings.addNewLine();
m_guiSettings.addSlider(L"Brightness", { 0.0, 1.0});
m_guiSettings.addNewLine();
m_guiSettings.addToggleSwitch(L"scale", { true });
m_guiSettings.addText(L"音階表", { L"音階表" });
m_guiSettings.addNewLine();
m_guiSettings.addToggleSwitch(L"CircleOfFifth", { false });
m_guiSettings.addText(L"godoken", { L"五度圏" });
m_guiSettings.addNewLine();
m_guiSettings.addText({ L"光強度" });
m_guiSettings.addNewLine();
m_guiSettings.addSlider(L"LightStrength", { 0.0, 1.0, 0.5 });
m_guiSettings.addNewLine();
m_guiSettings.addText({ L"色合い" });
m_guiSettings.addNewLine();
m_guiSettings.addSlider(L"HSVStart", { 0.0, 1.0 , 0.0});
m_hideSettingCount = 0;
}
void update()
{
m_guiBasic.button(L"PlayButton").setEnabled(m_sound && !m_sound.isPlaying);
m_guiBasic.button(L"PauseButton").setEnabled(m_sound.isPlaying);
m_guiBasic.button(L"UseMic").setEnabled(!m_isRecording );
m_guiBasic.slider(L"Slider").setEnabled(!m_isRecording);
if (m_guiBasic.button(L"PlayButton").pushed)
{
m_sound.play();
m_isRecording = false;
Recorder::Stop();
}
else if (m_guiBasic.button(L"PauseButton").pushed)
{
m_sound.pause();
m_isRecording = false;
Recorder::Stop();
}
else if (m_guiBasic.button(L"OpenButton").pushed)
{
m_sound.pause();
m_isRecording = false;
Recorder::Stop();
m_sound = Dialog::OpenSound();
}
if (m_guiBasic.slider(L"Slider").hasChanged)
{
m_sound.setPosSec(m_sound.lengthSec*m_guiBasic.slider(L"Slider").value);
}
m_guiBasic.slider(L"Slider").setValue(m_sound.posSec / m_sound.lengthSec);
if (m_guiBasic.button(L"UseMic").pushed)
{
if (!Recorder::Start()){
}
else
{
m_isRecording = true;
m_sound.pause();
}
}
if (m_guiSettings.button(L"OpenPicture").pushed)
{
m_backTexture = Dialog::OpenTexture();
}
//設定のGUIを隠したりする処理
const Rect guiRect = m_guiSettings.rect;
const Point nowPos(guiRect.pos);
const Point showPos(0, 0);
const Point remainPos(10, 0);
const Point hidePos(remainPos - Point(guiRect.size.x, 0));
const double mass = 0.9;
if (m_isShowingSetting)
{
if (!guiRect.mouseOver)
{
++m_hideSettingCount;
}
else
{
m_hideSettingCount = 0;
}
if (m_hideSettingCount > 60)
{
m_isShowingSetting = false;
}
}
else
{
if (Rect(0,0,remainPos.x, guiRect.size.y).mouseOver)
{
m_isShowingSetting = true;
}
}
if (m_isShowingSetting)
{
m_guiSettings.setPos(((nowPos - showPos) * mass + showPos).asPoint());
}
else
{
m_guiSettings.setPos(((nowPos - hidePos) * mass + hidePos).asPoint());
}
}
void drawVisualizer()
{
if (m_backTexture)
{
Vec2 size;
const double windowRatio = double(Window::Size().x) / double(Window::Size().y);
const double texRatio = double(m_backTexture.width) / double(m_backTexture.height);
if (windowRatio > texRatio)
{
size = Vec2(Window::Size().x, double(Window::Size().x) / texRatio);
}
else
{
size = Vec2(double(Window::Size().y) * texRatio, Window::Size().y);
}
RectF(size)(m_backTexture).drawAt(Window::Size() / 2,ColorF(m_guiSettings.slider(L"Brightness").value));
}
if (m_guiSettings.toggleSwitch(L"scale").isRight)
{
drawBackGround();
}
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<1760; ++i)
{
const double di = i;
const double radian = getRad(di);
const double radius = 0.0;
const double radiusOuter = 180.0;
const double radianWidth = Max((radian)-getRad(di - 1),0.0);
const double width = Clamp(radiusOuter * (radianWidth), 0.0,50.0);
const double size = Pow(p[i], 0.6f) * 800 * Log(di)/Log(10.0);
const double sliderStrength = Pow(10.0,m_guiSettings.slider(L"LightStrength").value * 2.0);
const double strength = sliderStrength * Pow(size , 2.0) * Log( di ) / 10000000.0;
const Vec2 pos = getPosFromRad(radian) * (radius + size / 2.0) + m_centerPos;
const double hsvStart = m_guiSettings.slider(L"HSVStart").value * 255;
const Color col = HSV(240 - Log(di) * 100 + hsvStart, 1.0, strength);
const Color colPie = HSV(240 - Log(di) * 100, 1.0, strength);
RectF(width, size).setCenter(pos).rotate(radian)(m_gradTexture).draw(col);//{ Palette::Black, Palette::Black, col, col });
//Circle(m_centerPos, size).drawPie(radian - (radianWidth) / 2.0, radianWidth, colPie);
const Vec2 posOuter = getPosFromRad(radian) * (radiusOuter) + m_centerPos;
RectF(width * 2, width * 2).setCenter(posOuter).rotate(radian)(m_gradTexture).draw(col);//{ Palette::Black, Palette::Black, col, col });
}
if (m_isRecording && Recorder::IsEnd()) // 録音が終了
{
Recorder::Restart();
}
Rect(Window::Size())(m_gradTexture).draw(ColorF(0.0, 0.3, 0.3));
}
void drawBackGround()
{
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 < 5; ++i)
{
Circle(m_centerPos, 170 + i * 3).drawFrame(1.0, 0.0, Color(70));
}
}
double getRad(double freq)
{
if (!m_guiSettings.toggleSwitch(L"CircleOfFifth").isRight)
{
return 2.0 * Pi * Log(freq) / Log(2.0) + 2.4;
}
else
{
return getRadCircleOfFifth(freq);
}
}
double getRadCircleOfFifth(double freq)
{
const double startRad = -0.7;
const double rad = 2.0 * Pi * Log(freq) / Log(2.0) + startRad;
const double baseRad = 2.0 * Pi * Log((m_freq[0] + m_freq[1]) / 2.0) / Log(2.0) + startRad;
if (int((rad - baseRad) / (2.0 * Pi / 12.0) + 100) % 2 == 0)
{
return rad;
}
else
{
return rad + Pi;
}
}
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::Set2DSamplerState(SamplerState::Clamp());
Graphics::Set2DBlendState(BlendState::Additive());
Graphics::SetBackground({ 0, 0, 0 });
Window::SetTitle(L"はむビジュアライザー");
while (System::Update())
{
soundPlayer.update();
soundPlayer.drawVisualizer();
}
}