Audio: Added Stereo Support
RainbowLine: Moved FadeOut effect to Keyboard Loudness: Changed to use Stereo Keyboard: Fixed Wrong Column Mapping
This commit is contained in:
parent
9b791f0765
commit
2e266fe038
10 changed files with 105 additions and 69 deletions
17
README.md
17
README.md
|
@ -49,13 +49,18 @@ shutdown_color_red=235
|
||||||
shutdown_color_green=0
|
shutdown_color_green=0
|
||||||
shutdown_color_blue=141
|
shutdown_color_blue=141
|
||||||
shutdown_brightness=50
|
shutdown_brightness=50
|
||||||
|
rainbow_tail_factor=30
|
||||||
```
|
```
|
||||||
|
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
- Support for custom Scripts without writing C++
|
- [ ] Support for custom Scripts without writing C++
|
||||||
- VWeb Interface to control Configs without restarting
|
- [ ] LUA (sol2)
|
||||||
- Less CPU Usage
|
- [ ] Helper Functions
|
||||||
- Keyboard Mapping
|
- [ ] Keyboard Mapper
|
||||||
- Macro Support
|
- [ ] Web Interface to control Configs without restarting
|
||||||
- Execute of Script on Hotkeys
|
- [ ] VWeb Implementing
|
||||||
|
- [x] Keyboard Mapping
|
||||||
|
- [ ] Keyboard Input Event-Handler
|
||||||
|
- [ ] Macro Support
|
||||||
|
- [ ] Execute of Script on Hotkeys (LUA)
|
|
@ -35,8 +35,8 @@ public:
|
||||||
void init();
|
void init();
|
||||||
FFT fft;
|
FFT fft;
|
||||||
ReqMode requestMode = ReqMode::FFT;
|
ReqMode requestMode = ReqMode::FFT;
|
||||||
double loudness = 0.0;
|
stereoSampleFrame loudness = {0.0, 0.0};
|
||||||
float getLoudness();
|
stereoSampleFrame getLoudness();
|
||||||
bool work();
|
bool work();
|
||||||
VUtils::Environment *env = nullptr;
|
VUtils::Environment *env = nullptr;
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -39,6 +39,7 @@ public:
|
||||||
int getIndex(int row, int col);
|
int getIndex(int row, int col);
|
||||||
// PLEASE MAKE SURE YOU KNOW THE LIMITS!
|
// PLEASE MAKE SURE YOU KNOW THE LIMITS!
|
||||||
int getIndexNoCheck(int row, int col);
|
int getIndexNoCheck(int row, int col);
|
||||||
|
static void fadeOutMap(led_map* map, double factor);
|
||||||
protected:
|
protected:
|
||||||
void setupMap();
|
void setupMap();
|
||||||
// we need some mapping feature! rows and cols dont have the same amount of keys. so the struct needs
|
// we need some mapping feature! rows and cols dont have the same amount of keys. so the struct needs
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <VulcanoLE/Visual/VIZ.h>
|
#include <VulcanoLE/Visual/VIZ.h>
|
||||||
#include <VulcanoLE/Audio/AudioGrabber.h>
|
#include <VulcanoLE/Audio/AudioGrabber.h>
|
||||||
#include <VulcanoLE/Keyboards/Vulcan121.h>
|
#include <VulcanoLE/Keyboards/Vulcan121.h>
|
||||||
|
@ -10,9 +11,18 @@ namespace VIZ {
|
||||||
~Loudness() override = default;
|
~Loudness() override = default;
|
||||||
void onSetup() override;
|
void onSetup() override;
|
||||||
void onTick(float delta) override;
|
void onTick(float delta) override;
|
||||||
float lastVal = 0;
|
void setForChannel(float value, int channel);
|
||||||
|
void drawFrame(int toRow);
|
||||||
const char *name() override;
|
const char *name() override;
|
||||||
std::string m_name = "Loudness Meter";
|
std::string m_name = "Loudness Meter";
|
||||||
|
protected:
|
||||||
|
rgba colours[3] = {
|
||||||
|
{ 0, 0, 255, 80 },
|
||||||
|
{ 0, 255, 0, 80 },
|
||||||
|
{ 255, 0, 0, 40 }
|
||||||
|
};
|
||||||
|
double tailFactor = 0;
|
||||||
|
led_map *data = Vulcan121::createEmptyLEDMap();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace VIZ {
|
||||||
rgba *colours = nullptr;
|
rgba *colours = nullptr;
|
||||||
double lastValue = 0;
|
double lastValue = 0;
|
||||||
double decayValue = 0;
|
double decayValue = 0;
|
||||||
double ratios[4] = {1.3,1.2,1.3,1.4};
|
double ratios[4] = {1.3,1.3,1.3,1.2};
|
||||||
double tailFactor = 0.3;
|
double tailFactor = 0.3;
|
||||||
public:
|
public:
|
||||||
RainbowLine(AudioGrabber *pGrabber, Vulcan121 *vulcan);
|
RainbowLine(AudioGrabber *pGrabber, Vulcan121 *vulcan);
|
||||||
|
@ -18,7 +18,6 @@ namespace VIZ {
|
||||||
void onSetup() override;
|
void onSetup() override;
|
||||||
void onTick(float delta) override;
|
void onTick(float delta) override;
|
||||||
void calcNextDelta(double ratio);
|
void calcNextDelta(double ratio);
|
||||||
void updateMap(double factor);
|
|
||||||
const char *name() override;
|
const char *name() override;
|
||||||
std::string m_name = "Rainbow Line";
|
std::string m_name = "Rainbow Line";
|
||||||
led_map *data = Vulcan121::createEmptyLEDMap();
|
led_map *data = Vulcan121::createEmptyLEDMap();
|
||||||
|
|
|
@ -356,7 +356,7 @@ Key Count With LEDs: 105
|
||||||
| 18 | 3 |
|
| 18 | 3 |
|
||||||
| 19 | E |
|
| 19 | E |
|
||||||
| 20 | D |
|
| 20 | D |
|
||||||
| 27 | C |
|
| 21 | X |
|
||||||
|
|
||||||
|
|
||||||
### COL 4
|
### COL 4
|
||||||
|
@ -367,7 +367,7 @@ Key Count With LEDs: 105
|
||||||
| 24 | 4 |
|
| 24 | 4 |
|
||||||
| 25 | R |
|
| 25 | R |
|
||||||
| 26 | F |
|
| 26 | F |
|
||||||
| 32 | V |
|
| 27 | C |
|
||||||
|
|
||||||
|
|
||||||
### COL 5
|
### COL 5
|
||||||
|
@ -379,6 +379,7 @@ Key Count With LEDs: 105
|
||||||
| 30 | T |
|
| 30 | T |
|
||||||
| 31 | G |
|
| 31 | G |
|
||||||
| 36 | B |
|
| 36 | B |
|
||||||
|
| 32 | V |
|
||||||
| 37 | SPACE |
|
| 37 | SPACE |
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -134,45 +134,49 @@ void AudioGrabber::init() {
|
||||||
if (env != nullptr)
|
if (env != nullptr)
|
||||||
m_scale = env->getAsDouble("audio_scale", 1.0);
|
m_scale = env->getAsDouble("audio_scale", 1.0);
|
||||||
DBG("SET Audio Scale: %.3f", m_scale)
|
DBG("SET Audio Scale: %.3f", m_scale)
|
||||||
loudness = 0.0;
|
loudness = { 0.0, 0.0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioGrabber::calculateRMS(stereoSample *pFrame) {
|
void AudioGrabber::calculateRMS(stereoSample *pFrame) {
|
||||||
float square = 0, mean;
|
float squareL = 0, meanL;
|
||||||
|
float squareR = 0, meanR;
|
||||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
float left = pFrame[0].l;
|
squareL += std::pow(pFrame[0].l, 2);
|
||||||
square += std::pow(left, 2);
|
squareR += std::pow(pFrame[0].r, 2);
|
||||||
}
|
}
|
||||||
mean = (square / (float) (BUFFER_SIZE));
|
meanL = (squareL / (float) (BUFFER_SIZE));
|
||||||
loudness = std::sqrt(mean);
|
meanR = (squareR / (float) (BUFFER_SIZE));
|
||||||
|
loudness = { std::sqrt(meanL), std::sqrt(meanR) };
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioGrabber::calculatePEAK(stereoSample *pFrame) {
|
void AudioGrabber::calculatePEAK(stereoSample *pFrame) {
|
||||||
float max = 0;
|
stereoSampleFrame max = { 0, 0 };
|
||||||
for (int i = 0; i < BUFFER_SIZE; i++) {
|
for (int i = 0; i < BUFFER_SIZE; i++) {
|
||||||
float left = std::abs(pFrame[0].l);
|
float left = std::abs(pFrame[0].l);
|
||||||
if (left > max) {
|
float right = std::abs(pFrame[0].r);
|
||||||
max = left;
|
if (left > max.l)
|
||||||
}
|
max.l = left;
|
||||||
|
if (right > max.r)
|
||||||
|
max.r = right;
|
||||||
}
|
}
|
||||||
loudness = max;
|
loudness = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
float AudioGrabber::getLoudness() {
|
stereoSampleFrame AudioGrabber::getLoudness() {
|
||||||
std::unique_lock<std::mutex> lck(m_mtx);
|
std::unique_lock<std::mutex> lck(m_mtx);
|
||||||
return (float) loudness;
|
return loudness;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioGrabber::work() {
|
bool AudioGrabber::work() {
|
||||||
std::unique_lock<std::mutex> lck(m_mtx);
|
std::unique_lock<std::mutex> lck(m_mtx);
|
||||||
if (this->read(m_buffer, BUFFER_SIZE)) {
|
if (this->read(m_buffer, BUFFER_SIZE)) {
|
||||||
|
switch (requestMode) {
|
||||||
|
case ReqMode::FFT:
|
||||||
|
// FFT get's better results with maybe a bit scaling.. for RMS and PEAK this gets "worse"
|
||||||
for (int i = 0; i < BUFFER_SIZE; ++i) {
|
for (int i = 0; i < BUFFER_SIZE; ++i) {
|
||||||
// my system is fucking quite
|
|
||||||
m_buffer[i].l *= m_scale;
|
m_buffer[i].l *= m_scale;
|
||||||
m_buffer[i].r *= m_scale;
|
m_buffer[i].r *= m_scale;
|
||||||
}
|
}
|
||||||
switch (requestMode) {
|
|
||||||
case ReqMode::FFT:
|
|
||||||
fft.process(m_buffer);
|
fft.process(m_buffer);
|
||||||
break;
|
break;
|
||||||
case ReqMode::RMS:
|
case ReqMode::RMS:
|
||||||
|
|
|
@ -233,8 +233,8 @@ bool Vulcan121::waitForCtrlDev() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int Vulcan121::getColumnsForRow(int row) {
|
int Vulcan121::getColumnsForRow(int row) {
|
||||||
if (row > NUM_ROWS-1) {
|
if (row > NUM_ROWS - 1) {
|
||||||
WARN("Try to Access out of Bound %d max %d", row, NUM_ROWS-1)
|
WARN("Try to Access out of Bound %d max %d", row, NUM_ROWS - 1)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return keyMapRow[row]->count;
|
return keyMapRow[row]->count;
|
||||||
|
@ -242,16 +242,16 @@ int Vulcan121::getColumnsForRow(int row) {
|
||||||
|
|
||||||
|
|
||||||
int Vulcan121::getRowsForColumns(int col) {
|
int Vulcan121::getRowsForColumns(int col) {
|
||||||
if (col > NUM_COLS-1) {
|
if (col > NUM_COLS - 1) {
|
||||||
WARN("Try to Access out of Bound %d max %d", col, NUM_COLS-1)
|
WARN("Try to Access out of Bound %d max %d", col, NUM_COLS - 1)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return keyMapCol[col]->count;
|
return keyMapCol[col]->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Vulcan121::getIndex(int row, int col) {
|
int Vulcan121::getIndex(int row, int col) {
|
||||||
if (row > NUM_ROWS-1) {
|
if (row > NUM_ROWS - 1) {
|
||||||
WARN("Try to Access out of Bound %d max %d", row, NUM_ROWS-1)
|
WARN("Try to Access out of Bound %d max %d", row, NUM_ROWS - 1)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (col > keyMapRow[row]->count) {
|
if (col > keyMapRow[row]->count) {
|
||||||
|
@ -274,8 +274,8 @@ void Vulcan121::setupMap() {
|
||||||
79, 87, 100, 104, 109, 113, 119, 124, 129 };
|
79, 87, 100, 104, 109, 113, 119, 124, 129 };
|
||||||
keyMapRow[2]->count = 19;
|
keyMapRow[2]->count = 19;
|
||||||
keyMapRow[2]->index = new int[19]{ 2, 7, 13, 19, 25, 30, 34, 50, 55, 61, 67, 73, 80, 101, 105, 110, 114, 120, 125 };
|
keyMapRow[2]->index = new int[19]{ 2, 7, 13, 19, 25, 30, 34, 50, 55, 61, 67, 73, 80, 101, 105, 110, 114, 120, 125 };
|
||||||
keyMapRow[3]->count = 17;
|
keyMapRow[3]->count = 18;
|
||||||
keyMapRow[3]->index = new int[17]{ 3, 8, 14, 20, 26, 31, 35, 51, 56, 62, 68, 74, 88, 115, 121, 126, 130 };
|
keyMapRow[3]->index = new int[18]{ 3, 8, 14, 20, 26, 31, 35, 51, 56, 62, 68, 74, 96, 88, 115, 121, 126, 130 };
|
||||||
keyMapRow[4]->count = 17;
|
keyMapRow[4]->count = 17;
|
||||||
keyMapRow[4]->index = new int[17]{ 4, 9, 15, 21, 27, 32, 36, 52, 57, 63, 69, 75, 82, 106, 116, 122, 127 };
|
keyMapRow[4]->index = new int[17]{ 4, 9, 15, 21, 27, 32, 36, 52, 57, 63, 69, 75, 82, 106, 116, 122, 127 };
|
||||||
keyMapRow[5]->count = 14;
|
keyMapRow[5]->count = 14;
|
||||||
|
@ -288,11 +288,11 @@ void Vulcan121::setupMap() {
|
||||||
keyMapCol[2]->count = 6;
|
keyMapCol[2]->count = 6;
|
||||||
keyMapCol[2]->index = new int[6]{ 11, 12, 13, 14, 15, 16 };
|
keyMapCol[2]->index = new int[6]{ 11, 12, 13, 14, 15, 16 };
|
||||||
keyMapCol[3]->count = 5;
|
keyMapCol[3]->count = 5;
|
||||||
keyMapCol[3]->index = new int[5]{ 17, 18, 19, 20, 27 };
|
keyMapCol[3]->index = new int[5]{ 17, 18, 19, 20, 21 };
|
||||||
keyMapCol[4]->count = 5;
|
keyMapCol[4]->count = 5;
|
||||||
keyMapCol[4]->index = new int[5]{ 23, 24, 25, 26, 32 };
|
keyMapCol[4]->index = new int[5]{ 23, 24, 25, 26, 27 };
|
||||||
keyMapCol[5]->count = 6;
|
keyMapCol[5]->count = 7;
|
||||||
keyMapCol[5]->index = new int[6]{ 28, 29, 30, 31, 36, 37 };
|
keyMapCol[5]->index = new int[7]{ 28, 29, 30, 31, 36, 32, 37 };
|
||||||
keyMapCol[6]->count = 5;
|
keyMapCol[6]->count = 5;
|
||||||
keyMapCol[6]->index = new int[5]{ 48, 33, 34, 35, 52 };
|
keyMapCol[6]->index = new int[5]{ 48, 33, 34, 35, 52 };
|
||||||
keyMapCol[7]->count = 5;
|
keyMapCol[7]->count = 5;
|
||||||
|
@ -329,9 +329,15 @@ int Vulcan121::getIndexNoCheck(int row, int col) {
|
||||||
return keyMapRow[row]->index[col];
|
return keyMapRow[row]->index[col];
|
||||||
}
|
}
|
||||||
|
|
||||||
const keys * Vulcan121::getColumn(int col) {
|
const keys *Vulcan121::getColumn(int col) {
|
||||||
return keyMapCol[col];
|
return keyMapCol[col];
|
||||||
}
|
}
|
||||||
const keys * Vulcan121::getRow(int row) {
|
const keys *Vulcan121::getRow(int row) {
|
||||||
return keyMapRow[row];
|
return keyMapRow[row];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Vulcan121::fadeOutMap(led_map *map, double factor = 0.3) {
|
||||||
|
for (auto &i : map->key) {
|
||||||
|
i.a *= factor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,25 +10,41 @@ namespace VIZ {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Loudness::onTick(float delta) {
|
void Loudness::onTick(float delta) {
|
||||||
auto data = Vulcan121::createEmptyLEDMap();
|
Vulcan121::fadeOutMap(data, tailFactor);
|
||||||
float val = grabber->getLoudness();
|
stereoSample val = grabber->getLoudness();
|
||||||
val = val > 1.0f ? 1.0f : val;
|
val.l = val.l > 1.0f ? 1.0f : val.l;
|
||||||
double newVal = (val + lastVal) * 0.5;
|
val.r = val.r > 1.0f ? 1.0f : val.r;
|
||||||
int maxCol = newVal * keyboardData.num_cols;
|
setForChannel(val.l, 0);
|
||||||
for (int col = 0; col < maxCol; ++col) {
|
setForChannel(val.r, 1);
|
||||||
auto column = keyboard->getColumn(col);
|
keyboard->sendLedMap(data, false);
|
||||||
for (int i = 0; i < column->count; ++i) {
|
|
||||||
auto index = column->index[i];
|
|
||||||
if (col >= maxCol - 1) data[ 0 ].key[ index ] = { 255, 0, 0, 100 };
|
|
||||||
else data[ 0 ].key[ index ] = { 0, 0, 255, 80 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// delete map! ;)
|
|
||||||
lastVal = val;
|
|
||||||
keyboard->sendLedMap(data, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *Loudness::name() {
|
const char *Loudness::name() {
|
||||||
return m_name.c_str();
|
return m_name.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Loudness::setForChannel(float value, int channel) {
|
||||||
|
// because we have stereo we need to move on the rows
|
||||||
|
int offset = channel == 0 ? 1 : 3;
|
||||||
|
int until = channel == 0 ? 3 : 5;
|
||||||
|
colours[channel].a = value * 128.0;
|
||||||
|
for (int i = offset; i < until; ++i) {
|
||||||
|
auto row = keyboard->getRow(i);
|
||||||
|
int to = row->count * value;
|
||||||
|
for (int j = 0; j < to; ++j) {
|
||||||
|
auto index = row->index[j];
|
||||||
|
data[0].key[index] = colours[channel];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drawFrame(0);
|
||||||
|
drawFrame(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Loudness::drawFrame(int toRow) {
|
||||||
|
auto row = keyboard->getRow(toRow);
|
||||||
|
for (int j = 0; j < row->count; ++j) {
|
||||||
|
auto index = row->index[j];
|
||||||
|
data[0].key[index] = colours[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
#include <VUtils/Math.h>
|
#include <VUtils/Math.h>
|
||||||
|
|
||||||
#define MAX_DELTA 1212000
|
#define MAX_DELTA 1212000
|
||||||
#define MAX_PEAK 180
|
#define MAX_PEAK 170
|
||||||
|
|
||||||
namespace VIZ {
|
namespace VIZ {
|
||||||
RainbowLine::RainbowLine(AudioGrabber *pGrabber, Vulcan121 *vulcan) : VIZ(pGrabber, vulcan) {
|
RainbowLine::RainbowLine(AudioGrabber *pGrabber, Vulcan121 *vulcan) : VIZ(pGrabber, vulcan) {
|
||||||
|
@ -20,7 +20,7 @@ namespace VIZ {
|
||||||
}
|
}
|
||||||
void RainbowLine::onSetup() {
|
void RainbowLine::onSetup() {
|
||||||
currentColumn = 0;
|
currentColumn = 0;
|
||||||
updateMap(0);
|
Vulcan121::fadeOutMap(data, 0);
|
||||||
tailFactor = VUtils::Math::clamp(grabber->env->getAsDouble("rainbow_tail_factor", 0.3), 0.0, 0.9);
|
tailFactor = VUtils::Math::clamp(grabber->env->getAsDouble("rainbow_tail_factor", 0.3), 0.0, 0.9);
|
||||||
keyboard->sendToLEDs({ 0, 0, 0, 0 });
|
keyboard->sendToLEDs({ 0, 0, 0, 0 });
|
||||||
grabber->requestMode = AudioGrabber::ReqMode::FFT;
|
grabber->requestMode = AudioGrabber::ReqMode::FFT;
|
||||||
|
@ -28,7 +28,7 @@ namespace VIZ {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RainbowLine::onTick(float delta) {
|
void RainbowLine::onTick(float delta) {
|
||||||
updateMap(tailFactor);
|
Vulcan121::fadeOutMap(data, tailFactor);
|
||||||
deltaElapsed += delta;
|
deltaElapsed += delta;
|
||||||
auto fftData = grabber->fft.getData()->leftChannel;
|
auto fftData = grabber->fft.getData()->leftChannel;
|
||||||
auto val = 0.0;
|
auto val = 0.0;
|
||||||
|
@ -85,10 +85,4 @@ namespace VIZ {
|
||||||
rRatio = (VUtils::Math::easeIn(rRatio) - 1.0) * -1;
|
rRatio = (VUtils::Math::easeIn(rRatio) - 1.0) * -1;
|
||||||
deltaNeeded = rRatio * MAX_DELTA;
|
deltaNeeded = rRatio * MAX_DELTA;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RainbowLine::updateMap(double factor) {
|
|
||||||
for (int i = 0; i < keyboardData.num_keys; ++i) {
|
|
||||||
data->key[i].a *= factor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
Reference in a new issue