Initial Commit

This commit is contained in:
Maurice Grönwoldt 2021-02-20 18:13:51 +01:00
commit c13016275b
41 changed files with 3596 additions and 0 deletions

View file

@ -0,0 +1,30 @@
#pragma once
#include <string>
#include <unordered_map>
namespace VUtils {
class Environment {
public:
Environment();
explicit Environment(const char *filename);
void setFile(const char *filename);
void setPrefix(std::string prefix);
void loadFile();
std::string& getEnv(const std::string& name, std::string def);
bool hasEnv(const std::string& name);
int getAsInt(const std::string& name, int def);
double getAsDouble(const std::string& name, double def);
bool getAsBool(const std::string& name);
bool saveFile();
void set(const char* name, const char *value);
void setNumber(const char* name, double value);
protected:
std::unordered_map<std::string, std::string> m_env;
std::string m_prefix = "VENV_";
std::string m_filename;
};
}

View file

@ -0,0 +1,24 @@
#pragma once
#include <string>
namespace VUtils {
class FileHandler {
public:
static bool fileExists(const std::string& fileName);
static bool isDirectory(const std::string& fileName);
static std::string readFile(const std::string& fileName);
static bool writeFile(const std::string& fileName, const std::string& content);
static int getFileID(const std::string& fileName);
static void closeFD(int fd);
static std::string getExtension(const std::string& fileName);
static long getFileSize(int fd);
static std::string getFileName(const std::basic_string<char>& name);
static bool createDirectoryIfNotExist(const std::basic_string<char>& fileName);
static char * getHomeDirectory();
static std::string getFromHomeDir(const std::basic_string<char>& path);
};
}

36
headers/VUtils/Logging.h Normal file
View file

@ -0,0 +1,36 @@
#pragma once
#include <string>
#include <VUtils/FileHandler.h>
#ifdef DEBUG
#define DEBUGLOG(message, mod) { Logging::debugMod(message, mod); }
#define DBG(...) { Logging::debug(true,__FILE__, __FUNCTION__, __VA_ARGS__); }
#define DBGWN(...) { Logging::debug(false,__FILE__, __FUNCTION__, __VA_ARGS__); }
#else
#define DEBUGLOG(message, mod)
#define DBG(...)
#define DBGWN(...)
#endif
#define ERR(...) { Logging::error(true,__FILE__, __FUNCTION__, __VA_ARGS__); }
#define ERRWN(...) { Logging::error(false,__FILE__, __FUNCTION__, __VA_ARGS__); }
#define LOG(...) { Logging::log(true,__FILE__, __FUNCTION__, __VA_ARGS__ ); }
#define LOGWN(...) { Logging::log(false,__FILE__, __FUNCTION__, __VA_ARGS__ ); }
#define WARN(...) { Logging::warn(true, __FILE__, __FUNCTION__, __VA_ARGS__ ); }
#define WARNWN(...) { Logging::warn(false, __FILE__, __FUNCTION__, __VA_ARGS__ ); }
class Logging {
public:
enum class PrintType {
ERROR = 0,
LOG = 1,
WARN = 2,
DBG = 3
};
static void debug(bool newLine, const char *file, const char *func, ...) noexcept;
static void log(bool newLine,const char *file, const char *func, ...) noexcept;
static void warn(bool newLine,const char *file, const char *func, ...) noexcept;
static void error(bool newLine,const char *file, const char *func, ...) noexcept;
static std::string format(bool newLine,PrintType type, const char *log, const char *file, const char *func);
static std::string getPrefix(PrintType type, const char *module);
};

26
headers/VUtils/Pool.h Normal file
View file

@ -0,0 +1,26 @@
#pragma once
#include <functional>
#include <thread>
namespace VUtils {
struct PoolWorker {
virtual void run() = 0;
};
class Pool {
public:
explicit Pool(const char *name);
~Pool();
void setThreadCount(int count);
void create(PoolWorker& worker);
void joinFirstThread();
protected:
bool m_isCreated = false;
int m_count = 1;
const char *m_name = "Pool";
PoolWorker *m_worker{};
std::thread *m_threads{};
void execute();
};
}

View file

@ -0,0 +1,90 @@
#pragma once
#include <utility>
#include <atomic>
#include <queue>
#include <condition_variable>
#include <optional>
#include <cassert>
namespace VUtils {
template<typename T, typename S>
struct SafeMap {
explicit SafeMap(size_t maxSize = -1UL) : m_maxSize(maxSize), m_end(false) {};
bool add(const T &t, S &x);
bool add(T &&t, S &&x);
void remove(T t);
void clear();
bool has(T t);
S &get(T t);
int size();
private:
std::unordered_map <T, S> m_map{};
std::mutex m_mtx{};
std::condition_variable m_cvFull{};
const size_t m_maxSize{};
std::atomic<bool> m_end{};
};
template<typename T, typename S>
bool SafeMap<T, S>::add(const T &t, S &x) {
std::unique_lock<std::mutex> lck(m_mtx);
while (m_map.size() == m_maxSize && !m_end) {
return false;
}
assert(!m_end);
m_map.emplace(t, std::move(x));
return true;
}
template<typename T, typename S>
bool SafeMap<T, S>::add(T &&t, S &&x) {
std::unique_lock<std::mutex> lck(m_mtx);
while (m_map.size() == m_maxSize && !m_end)
return false;
assert(!m_end);
m_map.push(std::move(t));
return true;
}
template<typename T, typename S>
void SafeMap<T, S>::clear() {
std::unique_lock <std::mutex> lck(m_mtx);
std::unordered_map <T, S> empty;
std::swap(m_map, empty);
m_cvFull.notify_all();
}
template<typename T, typename S>
void SafeMap<T, S>::remove(T t) {
std::unique_lock <std::mutex> lck(m_mtx);
if (m_map.empty() || m_end) return;
if (m_map.contains(t)) {
m_map.erase(t);
}
m_cvFull.notify_one();
}
template<typename T, typename S>
int SafeMap<T, S>::size() {
return m_map.size();
}
template<typename T, typename S>
bool SafeMap<T, S>::has(T t) {
std::unique_lock <std::mutex> lck(m_mtx);
return m_map.contains(t);
}
template<typename T, typename S>
S &SafeMap<T, S>::get(T t) {
std::unique_lock <std::mutex> lck(m_mtx);
return m_map[t];
}
}

View file

@ -0,0 +1,109 @@
#pragma once
#include <utility>
#include <atomic>
#include <queue>
#include <condition_variable>
#include <optional>
#include <cassert>
namespace VUtils {
template<typename T>
struct SafeQueue {
explicit SafeQueue(size_t maxSize = -1UL) : m_maxSize(maxSize), m_end(false) {};
void push(const T &t);
void push(T &&t);
void close();
void clear();
std::optional<T> pop();
std::optional<T> waitAndPop();
bool isClosed();
int size();
private:
std::queue<T> m_que;
std::mutex m_mtx;
std::condition_variable m_cvEmpty, m_cvFull;
const size_t m_maxSize;
std::atomic<bool> m_end;
};
template<typename T>
void SafeQueue<T>::push(const T &t) {
std::unique_lock<std::mutex> lck(m_mtx);
while (m_que.size() == m_maxSize && !m_end) {
// we dont wait! we return false because queue is full...
m_cvFull.wait(lck);
}
assert(!m_end);
m_que.push(std::move(t));
m_cvEmpty.notify_one();
}
template<typename T>
void SafeQueue<T>::push(T &&t) {
std::unique_lock<std::mutex> lck(m_mtx);
while (m_que.size() == m_maxSize && !m_end)
m_cvFull.wait(lck);
assert(!m_end);
m_que.push(std::move(t));
m_cvEmpty.notify_one();
}
template<typename T>
void SafeQueue<T>::close() {
m_end = true;
std::lock_guard<std::mutex> lck(m_mtx);
m_cvEmpty.notify_all();
m_cvFull.notify_all();
}
template<typename T>
std::optional<T> SafeQueue<T>::pop() {
std::unique_lock<std::mutex> lck(m_mtx);
if (m_que.empty() || m_end) return {};
T t = std::move(m_que.front());
m_que.pop();
m_cvFull.notify_one();
return t;
}
template<typename T>
std::optional<T> SafeQueue<T>::waitAndPop() {
std::unique_lock<std::mutex> lck(m_mtx);
while (m_que.empty() && !m_end)
m_cvEmpty.wait(lck);
if (m_que.empty() || m_end) return {};
T t = std::move(m_que.front());
m_que.pop();
m_cvFull.notify_one();
return t;
}
template<typename T>
void SafeQueue<T>::clear() {
std::unique_lock<std::mutex> lck(m_mtx);
std::queue<T> empty;
std::swap(m_que, empty);
m_cvEmpty.notify_all();
m_cvFull.notify_all();
}
template<typename T>
bool SafeQueue<T>::isClosed() {
return m_end;
}
template<typename T>
int SafeQueue<T>::size() {
return m_que.size();
}
}

View file

@ -0,0 +1,31 @@
#pragma once
#include <algorithm>
#include <string>
namespace VUtils {
class StringUtils {
public:
static void leftTrim(std::string &s);
static void rightTrim(std::string &s);
static void trim(std::string &s);
static std::string leftTrimCopy(std::string s);
static std::string rightTrimCopy(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::string urlDecode(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 bool hasNullByte(int size, const char string[1024]);
};
}// namespace VUtils

View file

@ -0,0 +1,24 @@
#pragma once
#include <cstdint>
#include <linux/hidraw.h>
#include <libudev.h>
#include <hidapi/hidapi.h>
class HIDHelper {
public:
HIDHelper();
~HIDHelper();
int openDevices();
int get_feature_report(unsigned char *buf, int size) const;
int send_feature_report(unsigned char *buf, int size) const;
void close_ctrl_device();
hid_device *m_ledDevice{};
int ctrl_device{};
protected:
bool ctrlDeviceWork(udev_list_entry *cur, udev_device *usb_dev, udev_device *raw_dev, udev *udev, unsigned int product_id);
bool findLED(hid_device_info *, unsigned int);
uint16_t m_products[3] = { 0x3098, 0x307a, 0x0000 };
};

View file

@ -0,0 +1,58 @@
#pragma once
#include <pulse/error.h>
#include <pulse/pulseaudio.h>
#include <pulse/simple.h>
#include <unistd.h>
#include <string>
#include <fstream>
#include <memory>
#include <mutex>
#include <VUtils/Environment.h>
#include <VulcanoLE/Audio/FFT.h>
#include <VulcanoLE/Audio/Types.h>
static const char k_record_stream_name[] = "vulcanoLE";
static const char k_record_stream_description[] = "Keyboard Input Stream";
static const int32_t k_sample_rate = 44100;
static const int32_t k_channels = 2;
static const std::string k_default_monitor_postfix = ".monitor";
class AudioGrabber {
public:
enum class ReqMode {
FFT = 0,
RMS = 1,
PEAK = 2,
ALL = 3
};
AudioGrabber();
~AudioGrabber();
bool read(pcm_stereo_sample *buffer, uint32_t buffer_size);
static AudioGrabber* createAudioGrabber();
void init();
FFT fft;
ReqMode requestMode = ReqMode::FFT;
double loudness = 0.0;
float getLoudness();
bool doWork();
VUtils::Environment *env = nullptr;
private:
std::mutex m_mtx;
pcm_stereo_sample *m_pcm_buffer{};
pa_simple *m_pulseaudio_simple{};
pa_mainloop *m_pulseaudio_mainloop{};
std::string m_pulseaudio_default_source_name;
void populate_default_source_name();
bool open_pulseaudio_source(uint32_t max_buffer_size);
static void pulseaudio_context_state_callback(pa_context *c,
void *userdata);
static void pulseaudio_server_info_callback(pa_context *context,
const pa_server_info *i,
void *userdata);
void calculateRMS(pcm_stereo_sample *pFrame);
void calculatePEAK(pcm_stereo_sample *pFrame);
double m_scale = 1.0;
};

View file

@ -0,0 +1,24 @@
#pragma once
#include <mutex>
#include <fftw3.h>
#include "Types.h"
class FFT {
public:
FFT();
~FFT();
void process(pcm_stereo_sample *pFrame);
outputSample *getData();
bool prepareInput(pcm_stereo_sample *buffer, uint32_t sample_size);
protected:
double *m_fftw_input_left{};
double *m_fftw_input_right{};
fftw_complex *m_fftw_output_left{};
fftw_complex *m_fftw_output_right{};
outputSample *m_sample = new outputSample(FFT_SIZE);
fftw_plan m_fftw_plan_left{};
fftw_plan m_fftw_plan_right{};
std::mutex m_mtx;
size_t m_fftw_results;
};

View file

@ -0,0 +1,23 @@
#pragma once
#define FFT_SIZE 1024
#define BUFFER_SIZE 2048
struct stereo_sample_frame {
float l;
float r;
};
using pcm_stereo_sample = struct stereo_sample_frame;
struct outputSample {
explicit outputSample(int fftSize) {
leftChannel = new double[fftSize];
rightChannel = new double[fftSize];
}
~outputSample() {
delete[] leftChannel;
delete[] rightChannel;
}
double *leftChannel;
double *rightChannel;
};

View file

@ -0,0 +1,20 @@
#pragma once
#include <thread>
#include <VulcanoLE/Audio/AudioGrabber.h>
#include <VulcanoLE/Visual/VisPlugins.h>
#include <VUtils/Environment.h>
class VisAudioRunner {
public:
VisAudioRunner(AudioGrabber*, VIZ::VisPlugins*);
~VisAudioRunner();
void init();
void run() const;
static VisAudioRunner* create();
AudioGrabber* grabber;
VIZ::VisPlugins* plugins;
bool isActive = true;
std::thread thread;
VUtils::Environment *env = nullptr;
};

View file

@ -0,0 +1,48 @@
#pragma once
#include <VulcanoLE/API/HIDHelper.h>
#define NUM_KEYS 144
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
} keys;
typedef struct led_map_type {
rgba key[NUM_KEYS];
} led_map;
class Vulcan121 {
public:
explicit Vulcan121(HIDHelper *helper);
~Vulcan121() = default;
int send_led_map(led_map *src, bool deleteMap = false);
int send_led_to(rgba rgb);
bool send_init_sequence();
bool query_ctrl_report(unsigned char);
bool send_ctrl_report(unsigned char id);
bool wait_for_ctrl_dev();
static led_map *createEmptyLEDMap();
struct DATA {
int num_rows = 6;
int num_keys = 144;
};
int getColumnsForRow(int row);
int getRowsForColumns(int col);
int getIndex(int row, int col);
protected:
// we need some mapping feature! rows and cols dont have the same amount of keys. so the struct needs
HIDHelper *m_helper;
rgba *rv_fixed[NUM_KEYS]{};
rgba rv_color_off = { .r = 0x0000, .g = 0x0000, .b = 0x0000 };
keys *keyMapRow[6];
keys *keyMapCols[0]; // need to find out the count!
};

View file

@ -0,0 +1,18 @@
#pragma once
#include <VulcanoLE/Visual/VIZ.h>
#include <VulcanoLE/Audio/AudioGrabber.h>
#include <VulcanoLE/Keyboards/Vulcan121.h>
namespace VIZ {
class Loudness : public VIZ {
public:
Loudness(AudioGrabber *pGrabber, Vulcan121 *pVulcan121);
~Loudness() override = default;
void on_setup() override;
void on_tick() override;
float lastVal = 0;
const char *name() override;
std::string m_name = "Loudness Meter";
};
}

View file

@ -0,0 +1,22 @@
#pragma once
#include <VulcanoLE/Visual/VIZ.h>
#include <VulcanoLE/Audio/AudioGrabber.h>
namespace VIZ {
struct Spectrum : public VIZ {
Spectrum(AudioGrabber *pGrabber, Vulcan121 *pVulcan121);
~Spectrum() override = default;
void on_setup() override;
void on_tick() override;
double lastVal = 0;
const char *name() override;
std::string m_name = "Spectrum One";
rgba colors[3] = {
{ 0, 30, 150, 0 },
{ 150, 150, 0, 0 },
{ 150, 0, 40, 0 }
};
};
}

View file

@ -0,0 +1,26 @@
#pragma once
#include <VulcanoLE/Visual/VIZ.h>
namespace VIZ {
class WeirdSpec : public VIZ {
protected:
int decayRate = 10;
double lastPeak = -1;
double threshold = 15;
public:
WeirdSpec(AudioGrabber *pGrabber, Vulcan121 *pVulcan121);
~WeirdSpec() override = default;
void on_setup() override;
void on_tick() override;
void switchOnPeak(double);
int tick = 0;
bool left = true;
rgba colors[2] = {
{ 0, 30, 150, 0 },
{ 0, 150, 30, 0 }
};
const char *name() override;
std::string m_name = "US Police Like Spectrum";
};
}

View file

@ -0,0 +1,16 @@
#pragma once
#include <VulcanoLE/Audio/AudioGrabber.h>
#include <VulcanoLE/Keyboards/Vulcan121.h>
namespace VIZ {
struct VIZ {
VIZ(AudioGrabber *pGrabber, Vulcan121 *pVulcan121) : grabber(pGrabber), keyboard(pVulcan121) {}
virtual ~VIZ() = default;
virtual void on_setup() = 0;
virtual void on_tick() = 0;
Vulcan121 *keyboard{};
Vulcan121::DATA keyboardData = Vulcan121::DATA{};
AudioGrabber *grabber{};
virtual const char *name() = 0;
};
}

View file

@ -0,0 +1,25 @@
#pragma once
#include <vector>
#include <VulcanoLE/Scripts/Spectrum.h>
#define VIZSIZE 3
namespace VIZ {
struct VisPlugins {
int mode = 0;
void init(HIDHelper *, AudioGrabber*);
void on_startup();
void on_tick();
void on_shutdown();
void setCurrentMode(int);
~VisPlugins();
VUtils::Environment *env;
protected:
VIZ *viz[VIZSIZE]{};
VIZ *currentVis;
Vulcan121 *keyboard;
AudioGrabber *grabber;
};
}