This commit is contained in:
Maurice Grönwoldt 2025-11-01 22:08:48 +01:00
commit bbd208aacf
Signed by: versustunez
GPG key ID: 3DBA8C59A63DEE3A
6 changed files with 238 additions and 224 deletions

View file

@ -33,6 +33,12 @@ cmake -DCMAKE_BUILD_TYPE=Debug ..
make -DCMAKE_BUILD_TYPE=Release .. make -DCMAKE_BUILD_TYPE=Release ..
``` ```
## UDEV
```udev
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="1e7d", ATTRS{idProduct}=="307a", MODE="660", GROUP="wheel"
ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="1e7d", ATTRS{idProduct}=="3098", MODE="660", GROUP="wheel"
```
## RUN ## RUN
`./anyVulcanoLE` `./anyVulcanoLE`

View file

@ -2,30 +2,33 @@
#include <algorithm> #include <algorithm>
#include <string> #include <string>
#include <vector>
namespace VUtils { namespace VUtils {
class StringUtils { class StringUtils {
public: public:
static void leftTrim(std::string &s); static void leftTrim(std::string &s);
static void rightTrim(std::string &s); static void rightTrim(std::string &s);
static void trim(std::string &s); static void trim(std::string &s);
static std::string leftTrimCopy(std::string s); static std::string leftTrimCopy(std::string s);
static std::string rightTrimCopy(std::string s); static std::string rightTrimCopy(std::string s);
static std::string trimCopy(std::string s); static std::string trimCopy(std::string s);
static std::vector<std::string> split(const std::string &s, const std::string &delimiter); static std::vector<std::string> split(const std::string &s,
const std::string &delimiter);
static std::string urlDecode(const std::string &url); static std::string urlDecode(const std::string &url);
static std::string urlEncode(const std::string &url); static std::string urlEncode(const std::string &url);
static std::string join(const std::vector<std::string>& vector, const std::string& delimiter); static std::string join(const std::vector<std::string> &vector,
const std::string &delimiter);
static bool hasNullByte(int size, const char string[1024]); static bool hasNullByte(int size, const char string[1024]);
}; };
}// namespace VUtils } // namespace VUtils

View file

@ -2,105 +2,108 @@
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#include <vector>
namespace VUtils { namespace VUtils {
void StringUtils::leftTrim(std::string &s) { void StringUtils::leftTrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), s.erase(s.begin(),
std::not1(std::ptr_fun<int, int>(std::isspace)))); std::find_if(s.begin(), s.end(),
std::not1(std::ptr_fun<int, int>(std::isspace))));
}
void StringUtils::rightTrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(),
std::not1(std::ptr_fun<int, int>(std::isspace)))
.base(),
s.end());
}
void StringUtils::trim(std::string &s) {
leftTrim(s);
rightTrim(s);
}
std::string StringUtils::leftTrimCopy(std::string s) {
leftTrim(s);
return s;
}
std::string StringUtils::rightTrimCopy(std::string s) {
rightTrim(s);
return s;
}
std::string StringUtils::trimCopy(std::string s) {
trim(s);
return s;
}
std::vector<std::string> StringUtils::split(const std::string &s,
const std::string &delimiter) {
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
std::string token;
std::vector<std::string> res;
while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) {
token = s.substr(pos_start, pos_end - pos_start);
pos_start = pos_end + delim_len;
res.push_back(token);
}
res.push_back(s.substr(pos_start));
return res;
}
std::string StringUtils::urlDecode(const std::string &val) {
std::string ret;
char ch;
int i, ii;
for (i = 0; i < val.length(); i++) {
if (int(val[i]) == 37) {
sscanf(val.substr(i + 1, 2).c_str(), "%x", &ii);
ch = static_cast<char>(ii);
ret += ch;
i = i + 2;
} else {
ret += val[i];
} }
}
return (ret);
}
void StringUtils::rightTrim(std::string &s) { std::string StringUtils::urlEncode(const std::string &value) {
s.erase(std::find_if(s.rbegin(), s.rend(), std::ostringstream escaped;
std::not1(std::ptr_fun<int, int>(std::isspace))) escaped.fill('0');
.base(), escaped << std::hex;
s.end());
for (char c : value) {
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
escaped << c;
continue;
} }
escaped << std::uppercase;
escaped << '%' << std::setw(2) << int((unsigned char)c);
escaped << std::nouppercase;
}
void StringUtils::trim(std::string &s) { return escaped.str();
leftTrim(s); }
rightTrim(s); std::string StringUtils::join(const std::vector<std::string> &vector,
const std::string &delimiter) {
std::stringstream string;
for (int i = 0; i < vector.size(); ++i) {
if (i != 0)
string << delimiter;
string << vector[i];
}
return string.str();
}
bool StringUtils::hasNullByte(int size, const char *string) {
for (int i = 0; i < size; ++i) {
if (string[i] == '\0') {
return true;
} }
}
std::string StringUtils::leftTrimCopy(std::string s) { return false;
leftTrim(s); }
return s; } // namespace VUtils
}
std::string StringUtils::rightTrimCopy(std::string s) {
rightTrim(s);
return s;
}
std::string StringUtils::trimCopy(std::string s) {
trim(s);
return s;
}
std::vector<std::string> StringUtils::split(const std::string &s, const std::string &delimiter) {
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
std::string token;
std::vector<std::string> res;
while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) {
token = s.substr(pos_start, pos_end - pos_start);
pos_start = pos_end + delim_len;
res.push_back(token);
}
res.push_back(s.substr(pos_start));
return res;
}
std::string StringUtils::urlDecode(const std::string &val) {
std::string ret;
char ch;
int i, ii;
for (i = 0; i < val.length(); i++) {
if (int(val[ i ]) == 37) {
sscanf(val.substr(i + 1, 2).c_str(), "%x", &ii);
ch = static_cast<char>(ii);
ret += ch;
i = i + 2;
} else {
ret += val[ i ];
}
}
return (ret);
}
std::string StringUtils::urlEncode(const std::string &value) {
std::ostringstream escaped;
escaped.fill('0');
escaped << std::hex;
for (char c : value) {
if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
escaped << c;
continue;
}
escaped << std::uppercase;
escaped << '%' << std::setw(2) << int((unsigned char) c);
escaped << std::nouppercase;
}
return escaped.str();
}
std::string StringUtils::join(const std::vector<std::string> &vector, const std::string &delimiter) {
std::stringstream string;
for (int i = 0; i < vector.size(); ++i) {
if (i != 0)
string << delimiter;
string << vector[ i ];
}
return string.str();
}
bool StringUtils::hasNullByte(int size, const char *string) {
for (int i = 0; i < size; ++i) {
if (string[ i ] == '\0') {
return true;
}
}
return false;
}
}// namespace VUtils

View file

@ -1,105 +1,104 @@
#include <cmath>
#include <VulcanoLE/Audio/AudioGrabber.h>
#include <VUtils/Logging.h>
#include <VulcanoLE/Audio/JackClient.h>
#include "VUtils/Math.h" #include "VUtils/Math.h"
#include <VUtils/Logging.h>
#include <VulcanoLE/Audio/AudioGrabber.h>
#include <VulcanoLE/Audio/JackClient.h>
#include <cmath>
#include <iostream>
AudioGrabber::AudioGrabber() = default; AudioGrabber::AudioGrabber() = default;
AudioGrabber::~AudioGrabber() = default; AudioGrabber::~AudioGrabber() = default;
bool AudioGrabber::read(stereoSample *buffer, uint32_t bufferSize) { bool AudioGrabber::read(stereoSample *buffer, uint32_t bufferSize) {
auto &client = JackClient::get(); auto &client = JackClient::get();
if (!client.isData()) if (!client.isData())
return false; return false;
availableData = client.getFrames(); availableData = client.getFrames();
client.fillSamples(buffer, availableData); client.fillSamples(buffer, availableData);
return true; return true;
} }
AudioGrabber *AudioGrabber::createAudioGrabber() { AudioGrabber *AudioGrabber::createAudioGrabber() {
JackClient::get().start(); JackClient::get().start();
auto *grabber = new AudioGrabber(); auto *grabber = new AudioGrabber();
JackClient::get().grabber = grabber; JackClient::get().grabber = grabber;
return grabber; return grabber;
} }
void AudioGrabber::init() { void AudioGrabber::init() {
m_buffer = static_cast<stereoSample *>(calloc(BUFFER_SIZE, sizeof(stereoSample))); m_buffer =
if (env != nullptr) static_cast<stereoSample *>(calloc(BUFFER_SIZE, sizeof(stereoSample)));
m_scale = env->getAsDouble("audio_scale", 1.0); if (env != nullptr)
m_filter.scale = 1.0; m_scale = env->getAsDouble("audio_scale", 1.0);
DBG("SET Audio Scale: %.3f", m_scale) m_filter.scale = 1.0;
loudness = { 0.0, 0.0 }; DBG("SET Audio Scale: %.3f", m_scale)
loudness = {0.0, 0.0};
} }
void AudioGrabber::calculateRMS(stereoSample *pFrame) { void AudioGrabber::calculateRMS(stereoSample *pFrame) {
double squareL = 0, meanL; double squareL = 0, meanL;
double squareR = 0, meanR; double squareR = 0, meanR;
for (int i = 0; i < availableData; i++) { for (int i = 0; i < availableData; i++) {
squareL += std::pow(pFrame[i].l * m_scale, 2); squareL += std::pow(pFrame[i].l * m_scale, 2);
squareR += std::pow(pFrame[i].r * m_scale, 2); squareR += std::pow(pFrame[i].r * m_scale, 2);
} }
meanL = (squareL / (float) (availableData)); meanL = (squareL / (float)(availableData));
meanR = (squareR / (float) (availableData)); meanR = (squareR / (float)(availableData));
loudness = { (float) std::sqrt(meanL), (float) std::sqrt(meanR) }; loudness = {(float)std::sqrt(meanL), (float)std::sqrt(meanR)};
} }
void AudioGrabber::calculatePEAK(stereoSample *pFrame) { void AudioGrabber::calculatePEAK(stereoSample *pFrame) {
stereoSampleFrame max = { 0, 0 }; stereoSampleFrame max = {0, 0};
for (int i = 0; i < availableData; i++) { for (int i = 0; i < availableData; i++) {
auto left = (float) std::abs(pFrame[i].l * m_scale); auto left = (float)std::abs(pFrame[i].l * m_scale);
auto right = (float) std::abs(pFrame[i].r * m_scale); auto right = (float)std::abs(pFrame[i].r * m_scale);
if (left > max.l) if (left > max.l)
max.l = left; max.l = left;
if (right > max.r) if (right > max.r)
max.r = right; max.r = right;
} }
loudness = max; loudness = max;
} }
stereoSampleFrame AudioGrabber::getLoudness() { stereoSampleFrame AudioGrabber::getLoudness() {
std::unique_lock<std::mutex> lck(m_mtx); std::unique_lock<std::mutex> lck(m_mtx);
return 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) { switch (requestMode) {
case ReqMode::FFT: case ReqMode::FFT:
fft.process(m_buffer, m_scale); fft.process(m_buffer, m_scale);
break; break;
case ReqMode::RMS: case ReqMode::RMS:
calculateRMS(m_buffer); calculateRMS(m_buffer);
break; break;
case ReqMode::PEAK: case ReqMode::PEAK:
calculatePEAK(m_buffer); calculatePEAK(m_buffer);
break; break;
case ReqMode::FILTER: case ReqMode::FILTER:
loudness = m_filter.work(m_buffer, availableData); loudness = m_filter.work(m_buffer, availableData);
break; break;
default: { default: {
calculateRMS(m_buffer); calculateRMS(m_buffer);
calculatePEAK(m_buffer); calculatePEAK(m_buffer);
fft.process(m_buffer, m_scale); fft.process(m_buffer, m_scale);
}
}
return true;
} else {
return false;
} }
}
return true;
} else {
return false;
}
} }
Audio::FilterHelper &AudioGrabber::getFilter() { Audio::FilterHelper &AudioGrabber::getFilter() { return m_filter; }
return m_filter;
}
double AudioGrabber::getBass() { double AudioGrabber::getBass() {
auto fftData = fft.getData(); auto fftData = fft.getData();
auto val = 0.0; auto val = 0.0;
for (int i = 1; i < 4; ++i) { for (int i = 1; i < 4; ++i) {
auto avg = (fftData->leftChannel[i] + fftData->rightChannel[i]) / 2.0; auto avg = (fftData->leftChannel[i] + fftData->rightChannel[i]) / 2.0;
if (avg > val) if (avg > val)
val = avg; val = avg;
} }
return VUtils::Math::clamp(val, 1, 255); return VUtils::Math::clamp(val, 1, 255);
} }

View file

@ -49,6 +49,8 @@ bool FFT::prepareInput(stereoSample *buffer, uint32_t sampleSize, double scale)
for (size_t i = 0; i < sampleSize; ++i) { for (size_t i = 0; i < sampleSize; ++i) {
m_fftwInputLeft[i][0] = VUtils::Math::clamp(buffer[i].r * scale, -1, 1) * hannWindow[i]; m_fftwInputLeft[i][0] = VUtils::Math::clamp(buffer[i].r * scale, -1, 1) * hannWindow[i];
m_fftwInputRight[i][0] = VUtils::Math::clamp(buffer[i].r * scale, -1, 1) * hannWindow[i]; m_fftwInputRight[i][0] = VUtils::Math::clamp(buffer[i].r * scale, -1, 1) * hannWindow[i];
m_fftwInputLeft[i][1] = 0;
m_fftwInputRight[i][1] = 0;
if (is_silent && (m_fftwInputLeft[i][0] != 0 || m_fftwInputRight[i][0] != 0)) is_silent = false; if (is_silent && (m_fftwInputLeft[i][0] != 0 || m_fftwInputRight[i][0] != 0)) is_silent = false;
} }
return is_silent; return is_silent;

View file

@ -1,41 +1,42 @@
#include <VulcanoLE/Scripts/TheUknown.h>
#include <VUtils/SimplexNoise.h> #include <VUtils/SimplexNoise.h>
#include <VulcanoLE/Scripts/TheUknown.h>
#include <algorithm>
namespace VIZ { namespace VIZ {
TheUnknown::TheUnknown(AudioGrabber *pGrabber, Vulcan121 *vulcan) : VIZ(pGrabber, vulcan) { TheUnknown::TheUnknown(AudioGrabber *pGrabber, Vulcan121 *vulcan)
m_random.setDist(0, 128); : VIZ(pGrabber, vulcan) {
for (int i = 0; i < NUM_KEYS; i++) { m_random.setDist(0, 128);
m_keyHeightMap[i] = std::abs(SimplexNoise::noise(i + 1.0f)) * 0.1; for (int i = 0; i < NUM_KEYS; i++) {
m_keyOffset[i] = m_random.getFast(); m_keyHeightMap[i] = std::abs(SimplexNoise::noise(i + 1.0f)) * 0.1;
} m_keyOffset[i] = m_random.getFast();
m_random.setDist(0.005, 0.01); }
} m_random.setDist(0.005, 0.01);
void TheUnknown::onSetup() {
keyboard->sendToLEDs({ 0, 0, 0, 0 });
Vulcan121::setColor(map, { 202, 35, 13, 255 });
grabber->requestMode = AudioGrabber::ReqMode::PEAK;
}
void TheUnknown::onTick(float delta) {
auto loudness = grabber->getLoudness();
auto factor = (((loudness.r + loudness.l) / 2.0) * 0.9) + 0.05;
for (size_t i = 0; i < keyboardData.num_keys; i++) {
auto &color = map.key[i];
auto noise = SimplexNoise::noise(m_keyOffset[i]) * factor;
noise = std::abs(noise) + 0.02;
auto newAlpha = std::clamp((noise + m_keyHeightMap[i]) * 255, 0.0, 255.0);
color.a = (color.a + newAlpha) / 2;
auto offset = std::sin(m_angle) * m_random.getFast();
m_keyOffset[i] += (delta * (1.5 * factor)) + offset;
m_angle += 0.0005;
if (m_keyOffset[i] > 20000000)
m_keyOffset[i] = 0.0;
if (m_angle > 1.0)
m_angle -= 1;
}
keyboard->sendLedMap(map);
}
const char *TheUnknown::name() {
return "TheUnknown";
}
} }
void TheUnknown::onSetup() {
keyboard->sendToLEDs({0, 0, 0, 0});
Vulcan121::setColor(map, {202, 35, 13, 255});
grabber->requestMode = AudioGrabber::ReqMode::PEAK;
}
void TheUnknown::onTick(float delta) {
auto loudness = grabber->getLoudness();
auto factor = (((loudness.r + loudness.l) / 2.0) * 0.9) + 0.05;
for (size_t i = 0; i < keyboardData.num_keys; i++) {
auto &color = map.key[i];
auto noise = SimplexNoise::noise(m_keyOffset[i]) * factor;
noise = std::abs(noise) + 0.02;
auto newAlpha = std::clamp((noise + m_keyHeightMap[i]) * 255, 0.0, 255.0);
color.a = (color.a + newAlpha) / 2;
auto offset = std::sin(m_angle) * m_random.getFast();
m_keyOffset[i] += (delta * (1.5 * factor)) + offset;
m_angle += 0.0005;
if (m_keyOffset[i] > 20000000)
m_keyOffset[i] = 0.0;
if (m_angle > 1.0)
m_angle -= 1;
}
keyboard->sendLedMap(map);
}
const char *TheUnknown::name() { return "TheUnknown"; }
} // namespace VIZ