From dd06aa3e35ee83bf50bc3b314a18be29b3afecb9 Mon Sep 17 00:00:00 2001 From: versustunez Date: Sun, 21 Feb 2021 23:22:01 +0100 Subject: [PATCH] Added Math Class Added Rainbow Line Visual Added Delta-Timing to Visuals Cleanup Code Structure --- CMakeLists.txt | 5 +- headers/VUtils/Math.h | 10 +++ headers/VulcanoLE/Colors/ColorHelper.h | 8 ++ headers/VulcanoLE/Colors/Type.h | 10 +++ headers/VulcanoLE/Keyboards/Vulcan121.h | 8 +- headers/VulcanoLE/Scripts/Loudness.h | 2 +- .../Scripts/{WeirdSpec.h => PoliceLike.h} | 8 +- headers/VulcanoLE/Scripts/RainbowLine.h | 26 ++++++ headers/VulcanoLE/Scripts/Spectrum.h | 2 +- headers/VulcanoLE/Visual/VIZ.h | 2 +- headers/VulcanoLE/Visual/VisPlugins.h | 15 ++-- main.cpp | 2 +- src/VUtils/Math.cpp | 17 ++++ src/VulcanoLE/Colors/ColorHelper.cpp | 44 +++++++++ src/VulcanoLE/Scripts/Loudness.cpp | 2 +- .../Scripts/{WeirdSpec.cpp => PoliceLike.cpp} | 12 +-- src/VulcanoLE/Scripts/RainbowLine.cpp | 89 +++++++++++++++++++ src/VulcanoLE/Scripts/Spectrum.cpp | 2 +- src/VulcanoLE/Visual/VisPlugins.cpp | 14 ++- 19 files changed, 244 insertions(+), 34 deletions(-) create mode 100644 headers/VUtils/Math.h create mode 100644 headers/VulcanoLE/Colors/ColorHelper.h create mode 100644 headers/VulcanoLE/Colors/Type.h rename headers/VulcanoLE/Scripts/{WeirdSpec.h => PoliceLike.h} (72%) create mode 100644 headers/VulcanoLE/Scripts/RainbowLine.h create mode 100644 src/VUtils/Math.cpp create mode 100644 src/VulcanoLE/Colors/ColorHelper.cpp rename src/VulcanoLE/Scripts/{WeirdSpec.cpp => PoliceLike.cpp} (81%) create mode 100644 src/VulcanoLE/Scripts/RainbowLine.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 00c1f2e..4fdbf33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,9 +22,11 @@ set(SOURCE_FILES src/VulcanoLE/Audio/FFT.cpp src/VulcanoLE/Audio/VisAudioRunner.cpp src/VulcanoLE/Visual/VisPlugins.cpp + src/VulcanoLE/Colors/ColorHelper.cpp src/VulcanoLE/Scripts/Loudness.cpp src/VulcanoLE/Scripts/Spectrum.cpp - src/VulcanoLE/Scripts/WeirdSpec.cpp + src/VulcanoLE/Scripts/PoliceLike.cpp + src/VulcanoLE/Scripts/RainbowLine.cpp ) set(UTILS_FILES src/VUtils/Logging.cpp @@ -32,6 +34,7 @@ set(UTILS_FILES src/VUtils/Pool.cpp src/VUtils/Environment.cpp src/VUtils/StringUtils.cpp + src/VUtils/Math.cpp ) include_directories(${CMAKE_SOURCE_DIR}/headers/) add_executable( diff --git a/headers/VUtils/Math.h b/headers/VUtils/Math.h new file mode 100644 index 0000000..652216b --- /dev/null +++ b/headers/VUtils/Math.h @@ -0,0 +1,10 @@ +#pragma once + +namespace VUtils { + struct Math { + static double clamp (double value, double min, double max); + static double lerp(double a, double b, double f); + static double bezierBlend(double t); + static double easeIn(double ratio); + }; +} \ No newline at end of file diff --git a/headers/VulcanoLE/Colors/ColorHelper.h b/headers/VulcanoLE/Colors/ColorHelper.h new file mode 100644 index 0000000..08277aa --- /dev/null +++ b/headers/VulcanoLE/Colors/ColorHelper.h @@ -0,0 +1,8 @@ +#pragma once +#include + +namespace Color { + struct Generator { + static rgba rgbFromRatio(double ratio, int16_t alpha); + }; +} \ No newline at end of file diff --git a/headers/VulcanoLE/Colors/Type.h b/headers/VulcanoLE/Colors/Type.h new file mode 100644 index 0000000..9f688c6 --- /dev/null +++ b/headers/VulcanoLE/Colors/Type.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +typedef struct rgba_type { + int16_t r{}; + int16_t g{}; + int16_t b{}; + int16_t a = 255; +} rgba; \ No newline at end of file diff --git a/headers/VulcanoLE/Keyboards/Vulcan121.h b/headers/VulcanoLE/Keyboards/Vulcan121.h index 465c447..4391287 100644 --- a/headers/VulcanoLE/Keyboards/Vulcan121.h +++ b/headers/VulcanoLE/Keyboards/Vulcan121.h @@ -1,18 +1,12 @@ #pragma once #include +#include #define NUM_KEYS 144 #define NUM_ROWS 6 #define NUM_COLS 21 -typedef struct rgba_type { - int16_t r{}; - int16_t g{}; - int16_t b{}; - int16_t a = 255; -} rgba; - typedef struct subArray { int count = 0; int *index = nullptr; // will init in code! and returned diff --git a/headers/VulcanoLE/Scripts/Loudness.h b/headers/VulcanoLE/Scripts/Loudness.h index 8afa26d..778feda 100644 --- a/headers/VulcanoLE/Scripts/Loudness.h +++ b/headers/VulcanoLE/Scripts/Loudness.h @@ -9,7 +9,7 @@ namespace VIZ { Loudness(AudioGrabber *pGrabber, Vulcan121 *pVulcan121); ~Loudness() override = default; void on_setup() override; - void on_tick() override; + void on_tick(float delta) override; float lastVal = 0; const char *name() override; std::string m_name = "Loudness Meter"; diff --git a/headers/VulcanoLE/Scripts/WeirdSpec.h b/headers/VulcanoLE/Scripts/PoliceLike.h similarity index 72% rename from headers/VulcanoLE/Scripts/WeirdSpec.h rename to headers/VulcanoLE/Scripts/PoliceLike.h index 70735eb..e268323 100644 --- a/headers/VulcanoLE/Scripts/WeirdSpec.h +++ b/headers/VulcanoLE/Scripts/PoliceLike.h @@ -3,16 +3,16 @@ #include namespace VIZ { - class WeirdSpec : public VIZ { + class PoliceLike : public VIZ { protected: int decayRate = 10; double lastPeak = -1; double threshold = 15; public: - WeirdSpec(AudioGrabber *pGrabber, Vulcan121 *pVulcan121); - ~WeirdSpec() override = default; + PoliceLike(AudioGrabber *pGrabber, Vulcan121 *pVulcan121); + ~PoliceLike() override = default; void on_setup() override; - void on_tick() override; + void on_tick(float delta) override; void switchOnPeak(double); int tick = 0; bool left = true; diff --git a/headers/VulcanoLE/Scripts/RainbowLine.h b/headers/VulcanoLE/Scripts/RainbowLine.h new file mode 100644 index 0000000..ba6726c --- /dev/null +++ b/headers/VulcanoLE/Scripts/RainbowLine.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +namespace VIZ { + class RainbowLine : public VIZ { + int currentColumn = 0; + double deltaNeeded = 100000.0; + double deltaElapsed = 0; + rgba *colours = nullptr; + double lastValue = 0; + double decayValue = 0; + double ratios[4] = {1.3,1.2,1.3,1.4}; + public: + RainbowLine(AudioGrabber *pGrabber, Vulcan121 *vulcan); + ~RainbowLine() override; + void on_setup() override; + void on_tick(float delta) override; + void calcNextDelta(double ratio); + void updateMap(double factor); + const char *name() override; + std::string m_name = "Rainbow Line"; + led_map *data = Vulcan121::createEmptyLEDMap(); + bool firstUnder = true; + }; +} \ No newline at end of file diff --git a/headers/VulcanoLE/Scripts/Spectrum.h b/headers/VulcanoLE/Scripts/Spectrum.h index 1dc252c..0d5d426 100644 --- a/headers/VulcanoLE/Scripts/Spectrum.h +++ b/headers/VulcanoLE/Scripts/Spectrum.h @@ -8,7 +8,7 @@ namespace VIZ { Spectrum(AudioGrabber *pGrabber, Vulcan121 *pVulcan121); ~Spectrum() override = default; void on_setup() override; - void on_tick() override; + void on_tick(float delta) override; double lastVal = 0; const char *name() override; std::string m_name = "Spectrum One"; diff --git a/headers/VulcanoLE/Visual/VIZ.h b/headers/VulcanoLE/Visual/VIZ.h index 2dcbe13..a1bc089 100644 --- a/headers/VulcanoLE/Visual/VIZ.h +++ b/headers/VulcanoLE/Visual/VIZ.h @@ -7,7 +7,7 @@ namespace VIZ { VIZ(AudioGrabber *pGrabber, Vulcan121 *pVulcan121) : grabber(pGrabber), keyboard(pVulcan121) {} virtual ~VIZ() = default; virtual void on_setup() = 0; - virtual void on_tick() = 0; + virtual void on_tick(float delta) = 0; Vulcan121 *keyboard{}; Vulcan121::DATA keyboardData = Vulcan121::DATA{}; AudioGrabber *grabber{}; diff --git a/headers/VulcanoLE/Visual/VisPlugins.h b/headers/VulcanoLE/Visual/VisPlugins.h index 53a0419..4673307 100644 --- a/headers/VulcanoLE/Visual/VisPlugins.h +++ b/headers/VulcanoLE/Visual/VisPlugins.h @@ -3,23 +3,26 @@ #include #include -#define VIZSIZE 3 +#define VIZSIZE 4 + +using micro = std::chrono::duration; namespace VIZ { struct VisPlugins { int mode = 0; - void init(HIDHelper *, AudioGrabber*); + void init(HIDHelper *, AudioGrabber *); void on_startup(); void on_tick(); void on_shutdown(); void setCurrentMode(int); ~VisPlugins(); - VUtils::Environment *env; + VUtils::Environment *env{}; protected: VIZ *viz[VIZSIZE]{}; - VIZ *currentVis; - Vulcan121 *keyboard; - AudioGrabber *grabber; + VIZ *currentVis{}; + Vulcan121 *keyboard{}; + AudioGrabber *grabber{}; + std::chrono::time_point start; }; } diff --git a/main.cpp b/main.cpp index a91e300..7eeb760 100644 --- a/main.cpp +++ b/main.cpp @@ -44,7 +44,7 @@ int main(int argc, char **argv) { runner->plugins->setCurrentMode(config.getAsInt("visual_mode", 1)); while (shouldRun) { int mode; - LOGWN("Enter Visual Mode: %d-%d < 0 = EXIT:\t", 0, 1) + LOGWN("Enter Visual Mode: %d-%d < 0 = EXIT:\t", 1, VIZSIZE) std::cin >> mode; if (std::cin.fail()) { ERR("ERROR -- You did not enter an integer") diff --git a/src/VUtils/Math.cpp b/src/VUtils/Math.cpp new file mode 100644 index 0000000..b507d10 --- /dev/null +++ b/src/VUtils/Math.cpp @@ -0,0 +1,17 @@ +#include + +namespace VUtils { + double Math::clamp(double value, double min, double max) { + return value > max ? max : value < min ? min : value; + } + + double Math::lerp(double a, double b, double f) { + return (a + (b - a) * f); + } + double Math::bezierBlend(double t) { + return t * t * (3.0 - 2.0 * t); + } + double Math::easeIn(double ratio) { + return ratio * ratio * ratio; + } +} \ No newline at end of file diff --git a/src/VulcanoLE/Colors/ColorHelper.cpp b/src/VulcanoLE/Colors/ColorHelper.cpp new file mode 100644 index 0000000..17dc6a5 --- /dev/null +++ b/src/VulcanoLE/Colors/ColorHelper.cpp @@ -0,0 +1,44 @@ +#include + +namespace Color { + rgba Generator::rgbFromRatio(double ratio, int16_t alpha = 255) { + int normalized = int(ratio * 256 * 6); + int x = normalized % 256; + + int16_t red = 0, green = 0, blue = 0; + switch (normalized / 256) { + case 0: + red = 255; + green = x; + blue = 0; + break; + case 1: + red = 255 - x; + green = 255; + blue = 0; + break; + case 2: + red = 0; + green = 255; + blue = x; + break; + case 3: + red = 0; + green = 255 - x; + blue = 255; + break; + case 4: + red = x; + green = 0; + blue = 255; + break; + case 5: + red = 255; + green = 0; + blue = 255 - x; + break; + } + + return { red, green, blue, alpha }; + } +} \ No newline at end of file diff --git a/src/VulcanoLE/Scripts/Loudness.cpp b/src/VulcanoLE/Scripts/Loudness.cpp index 68468f8..b3b595b 100644 --- a/src/VulcanoLE/Scripts/Loudness.cpp +++ b/src/VulcanoLE/Scripts/Loudness.cpp @@ -9,7 +9,7 @@ namespace VIZ { usleep(100000); } - void Loudness::on_tick() { + void Loudness::on_tick(float delta) { auto data = Vulcan121::createEmptyLEDMap(); float val = grabber->getLoudness(); val = val > 1.0f ? 1.0f : val; diff --git a/src/VulcanoLE/Scripts/WeirdSpec.cpp b/src/VulcanoLE/Scripts/PoliceLike.cpp similarity index 81% rename from src/VulcanoLE/Scripts/WeirdSpec.cpp rename to src/VulcanoLE/Scripts/PoliceLike.cpp index 23a43f6..80eee17 100644 --- a/src/VulcanoLE/Scripts/WeirdSpec.cpp +++ b/src/VulcanoLE/Scripts/PoliceLike.cpp @@ -1,17 +1,17 @@ -#include +#include namespace VIZ { - WeirdSpec::WeirdSpec(AudioGrabber *pGrabber, Vulcan121 *pVulcan121) : VIZ(pGrabber, pVulcan121) { + PoliceLike::PoliceLike(AudioGrabber *pGrabber, Vulcan121 *pVulcan121) : VIZ(pGrabber, pVulcan121) { } - void WeirdSpec::on_setup() { + void PoliceLike::on_setup() { keyboard->send_led_to({ 0, 0, 0, 0 }); grabber->requestMode = AudioGrabber::ReqMode::FFT; usleep(100000); } - void WeirdSpec::on_tick() { + void PoliceLike::on_tick(float delta) { auto map = Vulcan121::createEmptyLEDMap(); auto data = grabber->fft.getData()->leftChannel; auto val = 0.0; @@ -35,7 +35,7 @@ namespace VIZ { keyboard->send_led_map(map, true); } - void WeirdSpec::switchOnPeak(double peak) { + void PoliceLike::switchOnPeak(double peak) { if (tick < 3) { return; } @@ -56,7 +56,7 @@ namespace VIZ { } } - const char *WeirdSpec::name() { + const char *PoliceLike::name() { return m_name.c_str(); } } \ No newline at end of file diff --git a/src/VulcanoLE/Scripts/RainbowLine.cpp b/src/VulcanoLE/Scripts/RainbowLine.cpp new file mode 100644 index 0000000..ebdb23f --- /dev/null +++ b/src/VulcanoLE/Scripts/RainbowLine.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include + +#define MAX_DELTA 1212000 +#define MAX_PEAK 180 + +namespace VIZ { + RainbowLine::RainbowLine(AudioGrabber *pGrabber, Vulcan121 *vulcan) : VIZ(pGrabber, vulcan) { + colours = new rgba[keyboardData.num_cols]; + for (int i = 0; i < keyboardData.num_cols; ++i) { + double ratio = (double) i / keyboardData.num_cols; + colours[i] = Color::Generator::rgbFromRatio(ratio, 255); + } + } + RainbowLine::~RainbowLine() { + delete[] colours; + delete data; + } + void RainbowLine::on_setup() { + currentColumn = 0; + updateMap(0); + keyboard->send_led_to({ 0, 0, 0, 0 }); + grabber->requestMode = AudioGrabber::ReqMode::FFT; + usleep(100000); + } + + void RainbowLine::on_tick(float delta) { + updateMap(0.3); + deltaElapsed += delta; + auto fftData = grabber->fft.getData()->leftChannel; + auto val = 0.0; + for (int i = 1; i < 4; ++i) { + auto avg = fftData[i] * ratios[i]; + if (avg > val) + val = avg; + } + val = VUtils::Math::clamp(val, 0, 255); + auto avg = (lastValue + val) * 0.5; + if (avg > MAX_PEAK || avg > decayValue) { + calcNextDelta(val < MAX_PEAK && firstUnder ? 160 : val); + firstUnder = val > MAX_PEAK; + decayValue = val; + } + if (val > MAX_PEAK) { + firstUnder = true; + } + if (avg < 10) { + deltaNeeded = 1000000000; + } + if (deltaElapsed >= deltaNeeded) { + deltaElapsed = 0; + currentColumn++; + if (currentColumn >= keyboardData.num_cols) { + currentColumn = 0; + } + } + + if (decayValue >= 0) + decayValue -= 10; + colours[currentColumn].a = val; + auto column = keyboard->getColumn(currentColumn); + for (int i = 0; i < column->count; ++i) { + auto index = column->index[i]; + data[0].key[index] = colours[currentColumn]; + } + lastValue = avg; + // we clean up the map self later! :) + keyboard->send_led_map(data, false); + } + + const char *RainbowLine::name() { + return m_name.c_str(); + } + + void RainbowLine::calcNextDelta(double ratio) { + double rRatio = ratio / MAX_PEAK; + rRatio = VUtils::Math::clamp(rRatio, 0.05, 1.0); + rRatio = (VUtils::Math::easeIn(rRatio) - 1.0) * -1; + deltaNeeded = rRatio * MAX_DELTA; + } + + void RainbowLine::updateMap(double factor) { + for (int i = 0; i < keyboardData.num_keys; ++i) { + data->key[i].a *= factor; + } + } +} \ No newline at end of file diff --git a/src/VulcanoLE/Scripts/Spectrum.cpp b/src/VulcanoLE/Scripts/Spectrum.cpp index 542eca3..c1bdae5 100644 --- a/src/VulcanoLE/Scripts/Spectrum.cpp +++ b/src/VulcanoLE/Scripts/Spectrum.cpp @@ -8,7 +8,7 @@ namespace VIZ { grabber->requestMode = AudioGrabber::ReqMode::FFT; usleep(100000); } - void Spectrum::on_tick() { + void Spectrum::on_tick(float delta) { auto map = Vulcan121::createEmptyLEDMap(); auto data = grabber->fft.getData()->leftChannel; // find largest bass ~43hz (44100 / FFT_SIZE) range diff --git a/src/VulcanoLE/Visual/VisPlugins.cpp b/src/VulcanoLE/Visual/VisPlugins.cpp index a2ff997..d969fd0 100644 --- a/src/VulcanoLE/Visual/VisPlugins.cpp +++ b/src/VulcanoLE/Visual/VisPlugins.cpp @@ -1,8 +1,9 @@ #include #include #include -#include +#include #include +#include namespace VIZ { void VisPlugins::init(HIDHelper *hidHelper, AudioGrabber *audioGrabber) { @@ -10,7 +11,8 @@ namespace VIZ { keyboard = new Vulcan121(hidHelper); viz[0] = new Spectrum(grabber, keyboard); viz[1] = new Loudness(grabber, keyboard); - viz[2] = new WeirdSpec(grabber, keyboard); + viz[2] = new PoliceLike(grabber, keyboard); + viz[3] = new RainbowLine(grabber, keyboard); currentVis = viz[mode]; } @@ -20,11 +22,15 @@ namespace VIZ { exit(1); } currentVis->on_setup(); + start = std::chrono::high_resolution_clock::now(); } void VisPlugins::on_tick() { - currentVis->on_tick(); + auto stop = std::chrono::high_resolution_clock::now(); + auto delta = std::chrono::duration_cast(stop - start).count(); + currentVis->on_tick(delta); usleep(1000); + start = stop; } void VisPlugins::on_shutdown() { @@ -44,7 +50,7 @@ namespace VIZ { } void VisPlugins::setCurrentMode(int m) { - if (m == 0 || m > VIZSIZE) { + if (m < 1 || m > VIZSIZE) { ERR("Mode Setting Failed >> Mode is not in the available range 1 - %d", VIZSIZE) return; }