Added Math Class

Added Rainbow Line Visual
Added Delta-Timing to Visuals
Cleanup Code Structure
This commit is contained in:
Maurice Grönwoldt 2021-02-21 23:22:01 +01:00
parent 238e22caf6
commit dd06aa3e35
19 changed files with 244 additions and 34 deletions

View file

@ -22,9 +22,11 @@ set(SOURCE_FILES
src/VulcanoLE/Audio/FFT.cpp src/VulcanoLE/Audio/FFT.cpp
src/VulcanoLE/Audio/VisAudioRunner.cpp src/VulcanoLE/Audio/VisAudioRunner.cpp
src/VulcanoLE/Visual/VisPlugins.cpp src/VulcanoLE/Visual/VisPlugins.cpp
src/VulcanoLE/Colors/ColorHelper.cpp
src/VulcanoLE/Scripts/Loudness.cpp src/VulcanoLE/Scripts/Loudness.cpp
src/VulcanoLE/Scripts/Spectrum.cpp src/VulcanoLE/Scripts/Spectrum.cpp
src/VulcanoLE/Scripts/WeirdSpec.cpp src/VulcanoLE/Scripts/PoliceLike.cpp
src/VulcanoLE/Scripts/RainbowLine.cpp
) )
set(UTILS_FILES set(UTILS_FILES
src/VUtils/Logging.cpp src/VUtils/Logging.cpp
@ -32,6 +34,7 @@ set(UTILS_FILES
src/VUtils/Pool.cpp src/VUtils/Pool.cpp
src/VUtils/Environment.cpp src/VUtils/Environment.cpp
src/VUtils/StringUtils.cpp src/VUtils/StringUtils.cpp
src/VUtils/Math.cpp
) )
include_directories(${CMAKE_SOURCE_DIR}/headers/) include_directories(${CMAKE_SOURCE_DIR}/headers/)
add_executable( add_executable(

10
headers/VUtils/Math.h Normal file
View file

@ -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);
};
}

View file

@ -0,0 +1,8 @@
#pragma once
#include <VulcanoLE/Colors/Type.h>
namespace Color {
struct Generator {
static rgba rgbFromRatio(double ratio, int16_t alpha);
};
}

View file

@ -0,0 +1,10 @@
#pragma once
#include <cstdint>
typedef struct rgba_type {
int16_t r{};
int16_t g{};
int16_t b{};
int16_t a = 255;
} rgba;

View file

@ -1,18 +1,12 @@
#pragma once #pragma once
#include <VulcanoLE/API/HIDHelper.h> #include <VulcanoLE/API/HIDHelper.h>
#include <VulcanoLE/Colors/Type.h>
#define NUM_KEYS 144 #define NUM_KEYS 144
#define NUM_ROWS 6 #define NUM_ROWS 6
#define NUM_COLS 21 #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 { typedef struct subArray {
int count = 0; int count = 0;
int *index = nullptr; // will init in code! and returned int *index = nullptr; // will init in code! and returned

View file

@ -9,7 +9,7 @@ namespace VIZ {
Loudness(AudioGrabber *pGrabber, Vulcan121 *pVulcan121); Loudness(AudioGrabber *pGrabber, Vulcan121 *pVulcan121);
~Loudness() override = default; ~Loudness() override = default;
void on_setup() override; void on_setup() override;
void on_tick() override; void on_tick(float delta) override;
float lastVal = 0; float lastVal = 0;
const char *name() override; const char *name() override;
std::string m_name = "Loudness Meter"; std::string m_name = "Loudness Meter";

View file

@ -3,16 +3,16 @@
#include <VulcanoLE/Visual/VIZ.h> #include <VulcanoLE/Visual/VIZ.h>
namespace VIZ { namespace VIZ {
class WeirdSpec : public VIZ { class PoliceLike : public VIZ {
protected: protected:
int decayRate = 10; int decayRate = 10;
double lastPeak = -1; double lastPeak = -1;
double threshold = 15; double threshold = 15;
public: public:
WeirdSpec(AudioGrabber *pGrabber, Vulcan121 *pVulcan121); PoliceLike(AudioGrabber *pGrabber, Vulcan121 *pVulcan121);
~WeirdSpec() override = default; ~PoliceLike() override = default;
void on_setup() override; void on_setup() override;
void on_tick() override; void on_tick(float delta) override;
void switchOnPeak(double); void switchOnPeak(double);
int tick = 0; int tick = 0;
bool left = true; bool left = true;

View file

@ -0,0 +1,26 @@
#pragma once
#include <VulcanoLE/Visual/VIZ.h>
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;
};
}

View file

@ -8,7 +8,7 @@ namespace VIZ {
Spectrum(AudioGrabber *pGrabber, Vulcan121 *pVulcan121); Spectrum(AudioGrabber *pGrabber, Vulcan121 *pVulcan121);
~Spectrum() override = default; ~Spectrum() override = default;
void on_setup() override; void on_setup() override;
void on_tick() override; void on_tick(float delta) override;
double lastVal = 0; double lastVal = 0;
const char *name() override; const char *name() override;
std::string m_name = "Spectrum One"; std::string m_name = "Spectrum One";

View file

@ -7,7 +7,7 @@ namespace VIZ {
VIZ(AudioGrabber *pGrabber, Vulcan121 *pVulcan121) : grabber(pGrabber), keyboard(pVulcan121) {} VIZ(AudioGrabber *pGrabber, Vulcan121 *pVulcan121) : grabber(pGrabber), keyboard(pVulcan121) {}
virtual ~VIZ() = default; virtual ~VIZ() = default;
virtual void on_setup() = 0; virtual void on_setup() = 0;
virtual void on_tick() = 0; virtual void on_tick(float delta) = 0;
Vulcan121 *keyboard{}; Vulcan121 *keyboard{};
Vulcan121::DATA keyboardData = Vulcan121::DATA{}; Vulcan121::DATA keyboardData = Vulcan121::DATA{};
AudioGrabber *grabber{}; AudioGrabber *grabber{};

View file

@ -3,23 +3,26 @@
#include <vector> #include <vector>
#include <VulcanoLE/Scripts/Spectrum.h> #include <VulcanoLE/Scripts/Spectrum.h>
#define VIZSIZE 3 #define VIZSIZE 4
using micro = std::chrono::duration<double, std::micro>;
namespace VIZ { namespace VIZ {
struct VisPlugins { struct VisPlugins {
int mode = 0; int mode = 0;
void init(HIDHelper *, AudioGrabber*); void init(HIDHelper *, AudioGrabber *);
void on_startup(); void on_startup();
void on_tick(); void on_tick();
void on_shutdown(); void on_shutdown();
void setCurrentMode(int); void setCurrentMode(int);
~VisPlugins(); ~VisPlugins();
VUtils::Environment *env; VUtils::Environment *env{};
protected: protected:
VIZ *viz[VIZSIZE]{}; VIZ *viz[VIZSIZE]{};
VIZ *currentVis; VIZ *currentVis{};
Vulcan121 *keyboard; Vulcan121 *keyboard{};
AudioGrabber *grabber; AudioGrabber *grabber{};
std::chrono::time_point<std::chrono::system_clock, micro> start;
}; };
} }

View file

@ -44,7 +44,7 @@ int main(int argc, char **argv) {
runner->plugins->setCurrentMode(config.getAsInt("visual_mode", 1)); runner->plugins->setCurrentMode(config.getAsInt("visual_mode", 1));
while (shouldRun) { while (shouldRun) {
int mode; 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; std::cin >> mode;
if (std::cin.fail()) { if (std::cin.fail()) {
ERR("ERROR -- You did not enter an integer") ERR("ERROR -- You did not enter an integer")

17
src/VUtils/Math.cpp Normal file
View file

@ -0,0 +1,17 @@
#include <VUtils/Math.h>
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;
}
}

View file

@ -0,0 +1,44 @@
#include <VulcanoLE/Colors/ColorHelper.h>
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 };
}
}

View file

@ -9,7 +9,7 @@ namespace VIZ {
usleep(100000); usleep(100000);
} }
void Loudness::on_tick() { void Loudness::on_tick(float delta) {
auto data = Vulcan121::createEmptyLEDMap(); auto data = Vulcan121::createEmptyLEDMap();
float val = grabber->getLoudness(); float val = grabber->getLoudness();
val = val > 1.0f ? 1.0f : val; val = val > 1.0f ? 1.0f : val;

View file

@ -1,17 +1,17 @@
#include <VulcanoLE/Scripts/WeirdSpec.h> #include <VulcanoLE/Scripts/PoliceLike.h>
namespace VIZ { 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 }); keyboard->send_led_to({ 0, 0, 0, 0 });
grabber->requestMode = AudioGrabber::ReqMode::FFT; grabber->requestMode = AudioGrabber::ReqMode::FFT;
usleep(100000); usleep(100000);
} }
void WeirdSpec::on_tick() { void PoliceLike::on_tick(float delta) {
auto map = Vulcan121::createEmptyLEDMap(); auto map = Vulcan121::createEmptyLEDMap();
auto data = grabber->fft.getData()->leftChannel; auto data = grabber->fft.getData()->leftChannel;
auto val = 0.0; auto val = 0.0;
@ -35,7 +35,7 @@ namespace VIZ {
keyboard->send_led_map(map, true); keyboard->send_led_map(map, true);
} }
void WeirdSpec::switchOnPeak(double peak) { void PoliceLike::switchOnPeak(double peak) {
if (tick < 3) { if (tick < 3) {
return; return;
} }
@ -56,7 +56,7 @@ namespace VIZ {
} }
} }
const char *WeirdSpec::name() { const char *PoliceLike::name() {
return m_name.c_str(); return m_name.c_str();
} }
} }

View file

@ -0,0 +1,89 @@
#include <VulcanoLE/Scripts/RainbowLine.h>
#include <VulcanoLE/Colors/ColorHelper.h>
#include <VUtils/Logging.h>
#include <VUtils/Math.h>
#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;
}
}
}

View file

@ -8,7 +8,7 @@ namespace VIZ {
grabber->requestMode = AudioGrabber::ReqMode::FFT; grabber->requestMode = AudioGrabber::ReqMode::FFT;
usleep(100000); usleep(100000);
} }
void Spectrum::on_tick() { void Spectrum::on_tick(float delta) {
auto map = Vulcan121::createEmptyLEDMap(); auto map = Vulcan121::createEmptyLEDMap();
auto data = grabber->fft.getData()->leftChannel; auto data = grabber->fft.getData()->leftChannel;
// find largest bass ~43hz (44100 / FFT_SIZE) range // find largest bass ~43hz (44100 / FFT_SIZE) range

View file

@ -1,8 +1,9 @@
#include <VulcanoLE/Visual/VisPlugins.h> #include <VulcanoLE/Visual/VisPlugins.h>
#include <VulcanoLE/Scripts/Spectrum.h> #include <VulcanoLE/Scripts/Spectrum.h>
#include <VulcanoLE/Scripts/Loudness.h> #include <VulcanoLE/Scripts/Loudness.h>
#include <VulcanoLE/Scripts/WeirdSpec.h> #include <VulcanoLE/Scripts/PoliceLike.h>
#include <VUtils/Logging.h> #include <VUtils/Logging.h>
#include <VulcanoLE/Scripts/RainbowLine.h>
namespace VIZ { namespace VIZ {
void VisPlugins::init(HIDHelper *hidHelper, AudioGrabber *audioGrabber) { void VisPlugins::init(HIDHelper *hidHelper, AudioGrabber *audioGrabber) {
@ -10,7 +11,8 @@ namespace VIZ {
keyboard = new Vulcan121(hidHelper); keyboard = new Vulcan121(hidHelper);
viz[0] = new Spectrum(grabber, keyboard); viz[0] = new Spectrum(grabber, keyboard);
viz[1] = new Loudness(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]; currentVis = viz[mode];
} }
@ -20,11 +22,15 @@ namespace VIZ {
exit(1); exit(1);
} }
currentVis->on_setup(); currentVis->on_setup();
start = std::chrono::high_resolution_clock::now();
} }
void VisPlugins::on_tick() { void VisPlugins::on_tick() {
currentVis->on_tick(); auto stop = std::chrono::high_resolution_clock::now();
auto delta = std::chrono::duration_cast<micro>(stop - start).count();
currentVis->on_tick(delta);
usleep(1000); usleep(1000);
start = stop;
} }
void VisPlugins::on_shutdown() { void VisPlugins::on_shutdown() {
@ -44,7 +50,7 @@ namespace VIZ {
} }
void VisPlugins::setCurrentMode(int m) { 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) ERR("Mode Setting Failed >> Mode is not in the available range 1 - %d", VIZSIZE)
return; return;
} }