From c3f1c344c25066919fd164b5ddf10ab81cf0e518 Mon Sep 17 00:00:00 2001 From: Lauchmelder23 Date: Thu, 30 Dec 2021 23:41:01 +0100 Subject: [PATCH] its kinda working i guess --- src/Application.cpp | 54 +++++---------------- src/Application.hpp | 6 +-- src/CMakeLists.txt | 1 + src/Spectrogram.cpp | 114 ++++++++++++++++++++++++++++++++++++++++++++ src/Spectrogram.hpp | 21 ++++++++ src/Topology.hpp | 4 +- 6 files changed, 152 insertions(+), 48 deletions(-) create mode 100644 src/Spectrogram.cpp create mode 100644 src/Spectrogram.hpp diff --git a/src/Application.cpp b/src/Application.cpp index d277c57..4927f18 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -32,8 +32,7 @@ void Application::Quit() if (window != nullptr) { - delete file; - delete topology; + delete spectrogram; manager.Clear(); @@ -148,44 +147,15 @@ void Application::Init(int width, int height, const std::string& title) data.camera = &camera; data.aspectRatio = (float)width / (float)height; - topology = new ScrollingPlot( - manager, - glm::vec2(15.0f, 15.0f), - glm::uvec2(500, 500), - glm::vec2(-1.0f, 1.0f), - 0.001f, - // [](float t, float y) - // { - // return cos(t) + 0.5f * cos(2.0f * t) + 0.1f * sin(1.3f * t) + 0.3f * cos(3.5f * t) + 2.0f * (y * y) - 2.0f; - // } - [](float t, float y) - { - // Weierstraß - float z = 0.0f; - for(unsigned k = 1; k < 100; k++) - { - unsigned int twoK = std::pow(2, k); - z += twoK * sin(twoK * t) * cos(twoK * y) / std::pow(3, k); - } - - return z; - } + spectrogram = new Spectrogram( + manager, + glm::vec2(5.0f, 5.0f), + glm::uvec2(200, 2000), + AudioFile("res/payday.wav") ); colormap = 3; - topology->SetColormap(colormaps[colormap]); - - file = new AudioFile("res/payday.wav"); - SDL_AudioSpec specs = file->GetAudioSpec(); - std::cout << "Channels: " << (int)specs.channels << std::endl; - std::cout << "Format: " << std::bitset<16>{specs.format} << std::endl; - std::cout << "Samples: " << specs.samples << std::endl; - std::cout << "Frequency: " << specs.freq << std::endl; - file->Normalize(); - - std::cout << "First 50 samples: " << std::endl; - for(auto it = file->begin(); it != file->begin() + 50; it++) - std::cout << *it << std::endl; + spectrogram->SetColormap(colormaps[colormap]); // glEnable(GL_CULL_FACE); glEnable(GL_MULTISAMPLE); @@ -205,10 +175,10 @@ void Application::Launch() camera.SetPosition(pitch, yaw, distance); - topology->SetHeightMapping(enableHeightMap); - topology->SetColorMapping(enableColorMap); + spectrogram->SetHeightMapping(enableHeightMap); + spectrogram->SetColorMapping(enableColorMap); if(enableScroll) - topology->StepForward(3); + spectrogram->Update(); if(orthogonal) camera.SetOrthogonal(-width / 2.0f * data.aspectRatio, width / 2.0f * data.aspectRatio, -width / 2.0, width / 2.0f, -1.0f, 100.0f); @@ -218,7 +188,7 @@ void Application::Launch() glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - camera.Draw(*topology); + camera.Draw(*spectrogram); ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); @@ -256,7 +226,7 @@ void Application::Launch() ImGui::Checkbox("Scrolling", &enableScroll); ImGui::ListBox("Colormap", &colormap, colormapNames.data(), colormapNames.size()); - topology->SetColormap(colormaps[colormap]); + spectrogram->SetColormap(colormaps[colormap]); } ImGui::End(); diff --git a/src/Application.hpp b/src/Application.hpp index 9d9e8d6..c26e632 100644 --- a/src/Application.hpp +++ b/src/Application.hpp @@ -4,8 +4,7 @@ #include #include "Util.hpp" #include "OrbitingCamera.hpp" -#include "ScrollingPlot.hpp" -#include "AudioFile.hpp" +#include "Spectrogram.hpp" struct GLFWwindow; @@ -59,6 +58,5 @@ private: bool enableScroll = false; int colormap = 0; - ScrollingPlot* topology; - AudioFile* file; + Spectrogram* spectrogram; }; \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1399934..cd78da7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,6 +6,7 @@ add_executable(visualizer "Colormaps.cpp" "ScrollingPlot.cpp" "AudioFile.cpp" + "Spectrogram.cpp" ) target_sources(visualizer PUBLIC diff --git a/src/Spectrogram.cpp b/src/Spectrogram.cpp new file mode 100644 index 0000000..1d1caf5 --- /dev/null +++ b/src/Spectrogram.cpp @@ -0,0 +1,114 @@ +#include "Spectrogram.hpp" + +#include + +#define POW_OF_TWO(x) ((x) && !((x) & ((x) - 1))) + +std::vector> radix2dit( + const std::vector samples, + size_t offset, + size_t N, + size_t s +); + +Spectrogram::Spectrogram( + lol::ObjectManager& manager, + const glm::vec2& size, + const glm::uvec2& subdivision, + const AudioFile& audio +) : + Topology(manager, size, subdivision), audio(audio) +{ + this->audio.Normalize(); + + range = glm::vec2(0.0f, 0.0005f); + MakeTexture(); +} + +void Spectrogram::Update() +{ + // Load samples + unsigned int sampleNumber = audio.GetAudioSpec().freq / 60; + std::vector samples(audio.begin() + currentStrip * sampleNumber, audio.begin() + (currentStrip + 1) * sampleNumber); + size_t N = samples.size(); + + // Zeropad the signal + while(!POW_OF_TWO(N)) + { + samples.push_back(0.0f); + N++; + } + + N = samples.size() << 3; + samples.insert(samples.end(), N - samples.size(), 0.0f); + + // Perform Fourier transformation on the next samples + std::vector> spectrum = radix2dit(samples, 0, N, 1); + float freqRes = (float)audio.GetAudioSpec().freq / (float)N; + float nyquistLimit = (float)audio.GetAudioSpec().freq / 2.0f; + + std::vector> output; + float freq = 50.0f; + float maxFreq = nyquistLimit; + + for (int k = freq / freqRes; freq < nyquistLimit && freq < maxFreq; k++) // ??? wtf is going on here? + { + output.push_back(std::make_pair(freq, 2.0f * std::abs(spectrum[k]) / (float)N)); + + freq += freqRes; + } + + float* pixels = GetTopology(); + glm::uvec2 dims = image.GetDimensions(); + + glm::vec2 arrayDomain(0.0f, N); + glm::vec2 imageDomain(0.0f, dims.y); + + unsigned int imageStrip = currentStrip % dims.x; + for(unsigned int y = 0; y < dims.y; y++) + { + std::complex sample = output[Map(imageDomain, arrayDomain, y)].second; + float magnitude = std::abs(sample); + + pixels[y * dims.x + imageStrip] = magnitude; + } + + MakeTexture(); + + currentStrip++; + offset += 1.0f / (float)dims.x; +} + +std::vector> radix2dit( + const std::vector samples, + size_t offset, + size_t N, + size_t s +) +{ + std::vector> output(N); + + if(N == 1) + { + output[0] = samples[offset]; + } + else + { + size_t halfN = N >> 1; + std::vector> first = radix2dit(samples, offset, halfN, 2 * s); + std::vector> second = radix2dit(samples, offset + s, halfN, 2 * s); + + float coeff = -M_PI / (float)halfN; + + for (int k = 0; k < halfN; k++) + { + std::complex p = first[k]; + std::complex q = std::exp(coeff * (float)k) * second[k]; + + output[k] = p + q; + output[halfN + k] = p - q; + } + } + + return output; +} \ No newline at end of file diff --git a/src/Spectrogram.hpp b/src/Spectrogram.hpp new file mode 100644 index 0000000..7cfa685 --- /dev/null +++ b/src/Spectrogram.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "Topology.hpp" +#include "AudioFile.hpp" + +class Spectrogram : public Topology +{ +public: + Spectrogram( + lol::ObjectManager& manager, + const glm::vec2& size, + const glm::uvec2& subdivision, + const AudioFile& audio + ); + + void Update(); + +private: + AudioFile audio; + unsigned int currentStrip = 0; +}; \ No newline at end of file diff --git a/src/Topology.hpp b/src/Topology.hpp index 30223f3..52fc81b 100644 --- a/src/Topology.hpp +++ b/src/Topology.hpp @@ -16,7 +16,7 @@ public: void PreRender(const lol::CameraBase& camera) override; - inline void SetHeightMapping(bool enable) { heightFactor = enable ? 2.0f : 0.0f; } + inline void SetHeightMapping(bool enable) { heightFactor = enable ? 200.0f : 0.0f; } inline void SetColorMapping(bool enable) { renderColor = enable; } inline virtual void Scroll(bool enable) { scroll = enable; } @@ -41,7 +41,7 @@ protected: float offset = 0.0f; private: - float heightFactor = 2.0f; + float heightFactor = 200.0f; bool renderColor = true; bool scroll = false; }; \ No newline at end of file