diff --git a/.gitmodules b/.gitmodules index af54c18..6d36113 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "vendor/lol"] path = vendor/lol url = git@github.com:Lauchmelder23/lol.git +[submodule "vendor/sdl"] + path = vendor/sdl + url = git@github.com:libsdl-org/SDL.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 2bbf282..093cf12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,14 @@ if(NOT GLFW3_FOUND) set(GLFW3_LIBRARIES glfw) endif() +find_package(SDL2) +if(NOT SDL2_FOUND) + message(STATUS "Could not find SDL binaries on system, building from source instead") + add_subdirectory("vendor/sdl") + + set(SDL2_INCLUDE_DIRS sdl_static) + set(SDL2_LIBRARIES sdl_static) +endif() # Include sub-projects. add_subdirectory ("vendor/lol") diff --git a/res/payday.wav b/res/payday.wav new file mode 100644 index 0000000..70829e2 Binary files /dev/null and b/res/payday.wav differ diff --git a/src/Application.cpp b/src/Application.cpp index 79578cf..d277c57 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -1,14 +1,17 @@ #include "Application.hpp" #include +#include #include #include #include #include +#include #include "imgui.h" #include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_opengl3.h" + #include "Colormaps.hpp" #ifdef NDEBUG @@ -29,6 +32,7 @@ void Application::Quit() if (window != nullptr) { + delete file; delete topology; manager.Clear(); @@ -37,6 +41,7 @@ void Application::Quit() window = nullptr; } + SDL_Quit(); glfwTerminate(); } @@ -44,7 +49,10 @@ void Application::Init(int width, int height, const std::string& title) { // Initialize GLFW if (window == nullptr) + { glfwInit(); + SDL_Init(SDL_INIT_AUDIO); + } int windowWidth = width, windowHeight = height; GLFWmonitor* monitor = NULL; @@ -62,6 +70,9 @@ void Application::Init(int width, int height, const std::string& title) windowHeight = mode->height; #endif + glfwWindowHint(GLFW_SAMPLES, 4); + glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE); + // Create GLFW window window = glfwCreateWindow(windowWidth, windowHeight, title.c_str(), monitor, NULL); if (window == nullptr) @@ -164,16 +175,32 @@ void Application::Init(int width, int height, const std::string& title) colormap = 3; topology->SetColormap(colormaps[colormap]); - glfwWindowHint(GLFW_SAMPLES, 4); + 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; // glEnable(GL_CULL_FACE); glEnable(GL_MULTISAMPLE); + + frameTimerStart = std::chrono::system_clock::now(); } void Application::Launch() { while (!glfwWindowShouldClose(window)) { + unsigned int frametime = std::chrono::duration_cast(std::chrono::system_clock::now() - frameTimerStart).count(); + frameTimerStart = std::chrono::system_clock::now(); + float fps = 1000.0f / frametime; + glfwPollEvents(); camera.SetPosition(pitch, yaw, distance); @@ -199,6 +226,8 @@ void Application::Launch() ImGui::Begin("Debug"); + ImGui::Text("FPS: %f", fps); + if (ImGui::CollapsingHeader("Camera")) { ImGui::SliderFloat("Yaw", &yaw, 0.0f, 360.0f); diff --git a/src/Application.hpp b/src/Application.hpp index dbee10a..9d9e8d6 100644 --- a/src/Application.hpp +++ b/src/Application.hpp @@ -1,9 +1,11 @@ #pragma once #include +#include +#include "Util.hpp" #include "OrbitingCamera.hpp" #include "ScrollingPlot.hpp" -#include "Util.hpp" +#include "AudioFile.hpp" struct GLFWwindow; @@ -44,6 +46,7 @@ private: GLFWwindow* window = nullptr; WindowData data; lol::ObjectManager manager; + std::chrono::system_clock::time_point frameTimerStart; OrbitingCamera camera; float pitch, yaw, distance; @@ -57,4 +60,5 @@ private: int colormap = 0; ScrollingPlot* topology; + AudioFile* file; }; \ No newline at end of file diff --git a/src/AudioFile.cpp b/src/AudioFile.cpp new file mode 100644 index 0000000..d265760 --- /dev/null +++ b/src/AudioFile.cpp @@ -0,0 +1,45 @@ +#include "AudioFile.hpp" + +#include + +AudioFile::AudioFile(const std::string& path) +{ + // Load the file from disk + uint8_t* tempBuf = nullptr; + if(SDL_LoadWAV(path.c_str(), &spec, &tempBuf, &length) == NULL) + { + std::cerr << "Failed to load audio file \"" << path << "\": " << SDL_GetError() << std::endl; + return; + } + + // Copy raw audio buffer over into vector + // Perform conversion to float if necessary + unsigned int sampleSize = SDL_AUDIO_BITSIZE(spec.format); + bool isFloat = SDL_AUDIO_ISFLOAT(spec.format); + for(uint8_t* ptr = tempBuf; ptr < tempBuf + length; ptr += sampleSize) + { + if(isFloat) + buffer.push_back(*((float*)ptr)); + else + buffer.push_back((float)*ptr); + } + + // Free the audio buffer + SDL_FreeWAV(tempBuf); +} + +AudioFile::~AudioFile() +{ + +} + +void AudioFile::Normalize() +{ + float largestVal = 0.0f; + for(const float& sample : buffer) + largestVal = std::max(largestVal, std::abs(sample)); + + float normFactor = 1.0f / largestVal; + for(float& sample : buffer) + sample *= normFactor; +} \ No newline at end of file diff --git a/src/AudioFile.hpp b/src/AudioFile.hpp new file mode 100644 index 0000000..5a6ab88 --- /dev/null +++ b/src/AudioFile.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +#include + +class AudioFile +{ +public: + AudioFile(const std::string& path); + ~AudioFile(); + + inline std::vector::const_iterator begin() const { return buffer.begin(); } + inline std::vector::const_iterator end() const { return buffer.end(); } + + inline const SDL_AudioSpec& GetAudioSpec() { return spec; } + inline uint32_t GetLength() { return length; } + + void Normalize(); + +private: + SDL_AudioSpec spec; + uint32_t length; + std::vector buffer; +}; \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 069edf6..1399934 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,9 +1,11 @@ add_executable(visualizer - "main.cpp" "Application.cpp" + "main.cpp" + "Application.cpp" "OrbitingCamera.cpp" "Topology.cpp" "Colormaps.cpp" "ScrollingPlot.cpp" + "AudioFile.cpp" ) target_sources(visualizer PUBLIC @@ -18,11 +20,17 @@ target_sources(visualizer PUBLIC target_include_directories(visualizer PRIVATE ${GLFW3_INCLUDE_DIRS} + ${SDL2_INCLUDE_DIRS} ${VENDOR_DIR}/imgui lol ) target_link_libraries(visualizer PRIVATE ${GLFW3_LIBRARIES} + ${SDL2_LIBRARIES} lol +) + +add_custom_command(TARGET visualizer POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/res $/res ) \ No newline at end of file diff --git a/vendor/sdl b/vendor/sdl new file mode 160000 index 0000000..2363ddc --- /dev/null +++ b/vendor/sdl @@ -0,0 +1 @@ +Subproject commit 2363ddc330efa939d2d43a6c809794970f401120