From f55aaf040c320eb2a91c7f57c623f03a1ae0fab0 Mon Sep 17 00:00:00 2001 From: Vibe Nuage Agent Date: Fri, 4 Sep 2026 18:44:25 +0000 Subject: [PATCH 1/2] Fix CI tests and extract math utilities - Enable BUILD_TESTING=ON and ENABLE_COVERAGE=ON in main.yml CI build job - Extract pure functions (BlackmanWindow, LinearToDecibels, SmoothingOverTime) to new src/math_utils.h header - Update main.cpp and main.h to use math_utils.h instead of inline definitions - Update test file to use math_utils.h instead of copied function code - Add math_utils.h to CMakeLists.txt MATRIX_HEADERS This makes the test suite actually run in CI and tests the real implementation rather than copied code. Co-authored-by: MarcelRaschke --- .github/workflows/main.yml | 6 ++- CMakeLists.txt | 1 + src/main.cpp | 31 +-------------- src/main.h | 10 +---- src/math_utils.h | 62 +++++++++++++++++++++++++++++ tests/test_visualization_matrix.cpp | 46 +-------------------- 6 files changed, 72 insertions(+), 84 deletions(-) create mode 100644 src/math_utils.h diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index df8db92..fac6e69 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -173,7 +173,11 @@ jobs: - name: Configure CMake run: | mkdir -p build && cd build - cmake -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} .. + cmake -G Ninja \ + -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \ + -DBUILD_TESTING=ON \ + -DENABLE_COVERAGE=ON \ + .. - name: Build project run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 965d76b..1a61734 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,7 @@ set(MATRIX_SOURCES set(MATRIX_HEADERS src/main.h + src/math_utils.h src/tracyprofiler.h src/stb_image.h ${kissfft_SOURCE_DIR}/kiss_fft.h diff --git a/src/main.cpp b/src/main.cpp index 294dc0b..0038f86 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,7 @@ */ #include "main.h" +#include "math_utils.h" #include @@ -19,7 +20,6 @@ #include #include -#include #include #define SMOOTHING_TIME_CONSTANT (0.5f) // default 0.8 @@ -673,35 +673,6 @@ GLuint CVisualizationMatrix::CreateTexture(const std::string& file, GLint intern return texture; } -float CVisualizationMatrix::BlackmanWindow(float in, size_t i, size_t length) -{ - constexpr double alpha = 0.16; - constexpr double a0 = 0.5 * (1.0 - alpha); - constexpr double a1 = 0.5; - constexpr double a2 = 0.5 * alpha; - - const float x = static_cast(i) / static_cast(length); - return in * static_cast(a0 - a1 * std::cos(2.0 * M_PI * x) + a2 * std::cos(4.0 * M_PI * x)); -} - -void CVisualizationMatrix::SmoothingOverTime(std::vector& outputBuffer, const std::vector& lastOutputBuffer, - kiss_fft_cpx* inputBuffer, size_t length, float smoothingTimeConstant, unsigned int fftSize) -{ - for (size_t i = 0; i < length; i++) - { - const kiss_fft_cpx c = inputBuffer[i]; - const float magnitude = std::sqrt(c.r * c.r + c.i * c.i) / static_cast(fftSize); - outputBuffer[i] = smoothingTimeConstant * lastOutputBuffer[i] + (1.0f - smoothingTimeConstant) * magnitude; - } -} - -float CVisualizationMatrix::LinearToDecibels(float linear) -{ - if (!linear) - return -1000.0f; - return 20.0f * std::log10(linear); -} - int CVisualizationMatrix::DetermineBitsPrecision() { m_state.fbwidth = 32; diff --git a/src/main.h b/src/main.h index 11ab420..7f3428a 100644 --- a/src/main.h +++ b/src/main.h @@ -14,6 +14,7 @@ #include #include +#include "math_utils.h" #include #include @@ -56,18 +57,9 @@ class ATTRIBUTE_HIDDEN CVisualizationMatrix GLuint CreateTexture(GLint format, unsigned int w, unsigned int h, const GLvoid* data); GLuint CreateTexture(const GLvoid* data, GLint format, unsigned int w, unsigned int h, GLint internalFormat, GLint scaling, GLint repeat); GLuint CreateTexture(const std::string& file, GLint internalFormat, GLint scaling, GLint repeat); - float BlackmanWindow(float in, size_t i, size_t length); - void SmoothingOverTime(std::vector& outputBuffer, const std::vector& lastOutputBuffer, - kiss_fft_cpx* inputBuffer, size_t length, float smoothingTimeConstant, unsigned int fftSize); - float LinearToDecibels(float linear); int DetermineBitsPrecision(); bool UpdateAlbumart(); void GatherDefines(); - - // FFT configuration - static constexpr size_t AUDIO_BUFFER = 1024; - static constexpr size_t NUM_BANDS = AUDIO_BUFFER / 2; - // Audio processing kiss_fft_cfg m_kissCfg; std::vector m_audioData; diff --git a/src/math_utils.h b/src/math_utils.h new file mode 100644 index 0000000..81a4a59 --- /dev/null +++ b/src/math_utils.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2005-2021 Team Kodi + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSE.md for more information. + */ + +#pragma once + +#include +#include + +// FFT configuration constants +static constexpr size_t AUDIO_BUFFER = 1024; +static constexpr size_t NUM_BANDS = AUDIO_BUFFER / 2; + +struct kiss_fft_cpx +{ + float r; + float i; +}; + +/** + * Apply Blackman window function to a sample. + * The Blackman window reduces spectral leakage in FFT analysis. + */ +inline float BlackmanWindow(float in, size_t i, size_t length) +{ + constexpr double alpha = 0.16; + constexpr double a0 = 0.5 * (1.0 - alpha); + constexpr double a1 = 0.5; + constexpr double a2 = 0.5 * alpha; + + const float x = static_cast(i) / static_cast(length); + return in * static_cast(a0 - a1 * std::cos(2.0 * M_PI * x) + a2 * std::cos(4.0 * M_PI * x)); +} + +/** + * Convert linear amplitude to decibels. + * Returns -1000 dB for zero input (effectively negative infinity). + */ +inline float LinearToDecibels(float linear) +{ + if (!linear) + return -1000.0f; + return 20.0f * std::log10(linear); +} + +/** + * Apply exponential smoothing to magnitude values over time. + * This smooths the FFT output to reduce flickering in the visualization. + */ +inline void SmoothingOverTime(std::vector& outputBuffer, const std::vector& lastOutputBuffer, + kiss_fft_cpx* inputBuffer, size_t length, float smoothingTimeConstant, unsigned int fftSize) +{ + for (size_t i = 0; i < length; i++) + { + const kiss_fft_cpx c = inputBuffer[i]; + const float magnitude = std::sqrt(c.r * c.r + c.i * c.i) / static_cast(fftSize); + outputBuffer[i] = smoothingTimeConstant * lastOutputBuffer[i] + (1.0f - smoothingTimeConstant) * magnitude; + } +} diff --git a/tests/test_visualization_matrix.cpp b/tests/test_visualization_matrix.cpp index f9bbd33..147f946 100644 --- a/tests/test_visualization_matrix.cpp +++ b/tests/test_visualization_matrix.cpp @@ -9,50 +9,8 @@ #include #include -// Include the functions to test from main.cpp -// We need to extract the pure functions that don't depend on OpenGL/Kodi - -// --- Copied from main.cpp for testing --- - -#define AUDIO_BUFFER (1024) -#define NUM_BANDS (AUDIO_BUFFER / 2) - -struct kiss_fft_cpx -{ - float r; - float i; -}; - -// BlackmanWindow function (copied from main.cpp) -float BlackmanWindow(float in, size_t i, size_t length) -{ - double alpha = 0.16; - double a0 = 0.5 * (1.0 - alpha); - double a1 = 0.5; - double a2 = 0.5 * alpha; - - float x = (float)i / (float)length; - return in * (a0 - a1 * cos(2.0 * M_PI * x) + a2 * cos(4.0 * M_PI * x)); -} - -// LinearToDecibels function (copied from main.cpp) -float LinearToDecibels(float linear) -{ - if (!linear) - return -1000; - return 20 * log10f(linear); -} - -// SmoothingOverTime function (copied from main.cpp) -void SmoothingOverTime(float* outputBuffer, float* lastOutputBuffer, kiss_fft_cpx* inputBuffer, size_t length, float smoothingTimeConstant, unsigned int fftSize) -{ - for (size_t i = 0; i < length; i++) - { - kiss_fft_cpx c = inputBuffer[i]; - float magnitude = sqrt(c.r * c.r + c.i * c.i) / (float)fftSize; - outputBuffer[i] = smoothingTimeConstant * lastOutputBuffer[i] + (1.0 - smoothingTimeConstant) * magnitude; - } -} +// Include the actual math utilities +#include "../src/math_utils.h" // --- Tests --- From b3b341ce00b0ba10178aafd148c35207c3ab045b Mon Sep 17 00:00:00 2001 From: Vibe Nuage Agent Date: Thu, 17 Sep 2026 20:44:45 +0000 Subject: [PATCH 2/2] Fix SmoothingOverTime call signature in tests The extracted math_utils.h declares SmoothingOverTime taking std::vector& references (matching main.cpp usage), but the tests still called it with float* pointers via .data(), which does not compile. Pass the vectors directly instead. Co-authored-by: MarcelRaschke --- tests/test_visualization_matrix.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_visualization_matrix.cpp b/tests/test_visualization_matrix.cpp index 147f946..52131e2 100644 --- a/tests/test_visualization_matrix.cpp +++ b/tests/test_visualization_matrix.cpp @@ -110,7 +110,7 @@ TEST_F(VisualizationMatrixTest, SmoothingOverTime_ZeroInput) inputBuffer[i].i = 0.0f; } - SmoothingOverTime(outputBuffer.data(), lastOutputBuffer.data(), inputBuffer.data(), NUM_BANDS, 0.5f, AUDIO_BUFFER); + SmoothingOverTime(outputBuffer, lastOutputBuffer, inputBuffer.data(), NUM_BANDS, 0.5f, AUDIO_BUFFER); for (size_t i = 0; i < NUM_BANDS; i++) { @@ -132,7 +132,7 @@ TEST_F(VisualizationMatrixTest, SmoothingOverTime_NonZeroInput) inputBuffer[i].i = 0.0f; } - SmoothingOverTime(outputBuffer.data(), lastOutputBuffer.data(), inputBuffer.data(), NUM_BANDS, 0.0f, AUDIO_BUFFER); + SmoothingOverTime(outputBuffer, lastOutputBuffer, inputBuffer.data(), NUM_BANDS, 0.0f, AUDIO_BUFFER); for (size_t i = 0; i < NUM_BANDS; i++) { @@ -156,7 +156,7 @@ TEST_F(VisualizationMatrixTest, SmoothingOverTime_FullSmoothing) } // With smoothingTimeConstant = 1.0, output should be: 1.0 * lastOutputBuffer[i] + 0 * magnitude = lastOutputBuffer[i] - SmoothingOverTime(outputBuffer.data(), lastOutputBuffer.data(), inputBuffer.data(), NUM_BANDS, 1.0f, AUDIO_BUFFER); + SmoothingOverTime(outputBuffer, lastOutputBuffer, inputBuffer.data(), NUM_BANDS, 1.0f, AUDIO_BUFFER); for (size_t i = 0; i < NUM_BANDS; i++) {