From 352513328704e4b36e4ab060c9740aa7a18a8648 Mon Sep 17 00:00:00 2001 From: snt Date: Tue, 14 May 2024 20:49:28 +0200 Subject: [PATCH] filtros funcionando --- src/dmxPersonality.h | 15 ++- src/libremediaserver-audio.cpp | 27 +++-- src/libremediaserver-audio.h | 1 + src/miniaudioengine.cpp | 188 ++++++++++++++++++++++++++------- src/miniaudioengine.h | 21 ++-- 5 files changed, 195 insertions(+), 57 deletions(-) diff --git a/src/dmxPersonality.h b/src/dmxPersonality.h index 82f9468..a9977d8 100644 --- a/src/dmxPersonality.h +++ b/src/dmxPersonality.h @@ -10,6 +10,19 @@ #define ENTRY_POINT_COARSE 5 #define ENTRY_POINT_FINE 4 #define PITCH 7 -#define LAYER_CHANNELS 9 +#define VOL1 9 +#define VOL2 10 +#define LOW_FREQ 11 +#define LOW_Q 12 +#define MIDLOW_FREQ 13 +#define MIDLOW_Q 14 +#define MIDLOW_GAIN 15 +#define MIDHIGH_FREQ 16 +#define MIDHIGH_Q 17 +#define MIDHIGH_GAIN 18 +#define HIGH_FREQ 19 +#define HIGH_Q 20 + +#define LAYER_CHANNELS 21 #endif // DMXPERSONALITY_H diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 39c700d..d516e6c 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -26,10 +26,11 @@ libreMediaServerAudio::libreMediaServerAudio() m_settings = Settings::getInstance(); m_settings->readFile(); m_ui = m_settings->getShowUi(); + m_layersQty = m_settings->getLayersNumber(); m_dmxSettings = m_settings->getDmxSettings(); m_mediaLibrary = new MediaLibrary; m_mediaLibrary->initMediaLibrary(); - for (int i = 0; i < MAX_LAYERS; i++) { + for (uint i = 0; i < m_layersQty; i++) { m_currentMedia[i] = ""; m_currentStatus[i] = Status::Iddle; #ifdef NOGUI @@ -39,24 +40,24 @@ libreMediaServerAudio::libreMediaServerAudio() m_updateUi[i][3] = -1; #endif } - m_ola = new olaThread(this, m_settings->getLayersNumber()); - Q_CHECK_PTR(m_ola); - m_ola->blockSignals(true); - m_ola->registerUniverse(); - if (!m_mae.startEngine()) { + if (!m_mae.startEngine(m_layersQty)) { cout << "Can not start Audio Engine!" << endl; - this->~libreMediaServerAudio(); + exit(-1); } uint *audioDevList = m_settings->getAudioDeviceId(); if (!m_mae.startDevice(audioDevList, m_settings->getAudioDeviceQty())) { cout << "Can not start Audio Device!" << audioDevList << endl; - this->~libreMediaServerAudio(); + exit(-1); } - cout << "Core init Complete. Start reading DMX." << endl; - m_ola->blockSignals(false); + m_ola = new olaThread(this, m_layersQty); + Q_CHECK_PTR(m_ola); + m_ola->blockSignals(true); + m_ola->registerUniverse(); #ifdef NOGUI m_ola->start(QThread::TimeCriticalPriority ); #endif + m_ola->blockSignals(false); + cout << "Core init Complete." << endl; } libreMediaServerAudio::~libreMediaServerAudio() @@ -74,7 +75,8 @@ void libreMediaServerAudio::loadMedia(int layer, int folder, int file) if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0) return; if (QFile::exists(mediaFile)){ - m_mae.loadMedia(layer, mediaFile.toLatin1().data(), m_dmxSettings.at(layer).audioDevice); + m_mae.loadMedia(layer, mediaFile.toLatin1().data(),\ + m_dmxSettings.at(layer).audioDevice); m_currentMedia[layer] = mediaFile; #ifndef NOGUI if (m_ui) @@ -138,6 +140,9 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) m_played.append(m_ola->getValue(layer, DMX_FILE)); } #endif + } else if (channel >= LOW_FREQ) { + m_mae.filterParamChanged(layer, m_dmxSettings.at(layer).audioDevice, channel, value); + } } #ifndef NOGUI diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index aed7e45..898d408 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -57,6 +57,7 @@ private: QList m_dmxSettings; bool m_ui; QList m_played; + uint m_layersQty; #ifndef NOGUI QTimer *m_refreshUi; libreMediaServerAudioUi *m_lmsUi; diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 6e9c1c9..01e274a 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -1,35 +1,35 @@ #include "miniaudioengine.h" -#define LPF_BIAS 0.9f -#define LPF_CUTOFF_FACTOR 80 -#define HPF_CUTOFF_FACTOR 1 -#define LPF_ORDER 8 +#include "dmxPersonality.h" -MiniAudioEngine::MiniAudioEngine() -{ - for (int i =0; i < MAX_LAYERS; i++) { - m_mediaLoaded[i] = false; - m_currentLayerValues[i].status = Status::Iddle; - m_currentLayerValues[i].pan = 128; - m_currentLayerValues[i].pitch = 128; - m_currentLayerValues[i].vol = 0; - m_currentLayerValues[i].cursor = 0; - } -} +#define LPF_BIAS 0.9f +#define FILTER_ORDER 2 +#define LPF_CUTOFF_FACTOR 2 +#define HPF_CUTOFF_FACTOR 20 + +MiniAudioEngine::MiniAudioEngine() {} void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { (void)pInput; - (void)pDevice; ma_result result; result = ma_engine_read_pcm_frames((ma_engine*)pDevice->pUserData, pOutput, frameCount, NULL); if (result != MA_SUCCESS) { - cout << "1"; + cout << "Error " << result << ": error audio callback."; } } void MiniAudioEngine::stopEngine() { + for (uint i = 0; i < m_layersQty; i++) { + ma_sound_uninit(&m_currentSound[i]); + } for (uint i = 0; i < m_devicesSelected; i++) { + for (uint j = 0; j < m_layersQty; j++) { + ma_hpf_node_uninit(&m_filterBank[i][j].hpf, NULL); + ma_lpf_node_uninit(&m_filterBank[i][j].lpf, NULL); + ma_peak_node_uninit(&m_filterBank[i][j].mLow, NULL); + ma_peak_node_uninit(&m_filterBank[i][j].mHigh, NULL); + } ma_engine_uninit(&m_engine[i]); ma_device_uninit(&m_device[i]); } @@ -37,10 +37,19 @@ void MiniAudioEngine::stopEngine() ma_resource_manager_uninit(&m_resourceManager); } -bool MiniAudioEngine::startEngine() +bool MiniAudioEngine::startEngine(uint layers) { ma_result result; + m_layersQty = layers; + for (uint i =0; i < m_layersQty; i++) { + m_mediaLoaded[i] = false; + m_currentLayerValues[i].status = Status::Iddle; + m_currentLayerValues[i].pan = 128; + m_currentLayerValues[i].pitch = 128; + m_currentLayerValues[i].vol = 0; + m_currentLayerValues[i].cursor = 0; + } result = this->startContext(); if (result != MA_SUCCESS) return false; result = this->getAllAudioDevices(); @@ -48,41 +57,74 @@ bool MiniAudioEngine::startEngine() return true; } -ma_result MiniAudioEngine::setNodeGraph(int id) { +// lpf -> hpf -> mLow -> mHigh -> engine +ma_result MiniAudioEngine::createFilterBank(int id, uint layer) +{ ma_result result; - ma_lpf_node_config lpfNodeConfig = ma_lpf_node_config_init(CHANNELS, SAMPLE_RATE, SAMPLE_RATE / LPF_CUTOFF_FACTOR, LPF_ORDER); ma_node_graph *ng = ma_engine_get_node_graph(&m_engine[id]); - result = ma_lpf_node_init(ng, &lpfNodeConfig, NULL, &m_filterBank[id].lpfNode); + ma_node *endpoint = ma_engine_get_endpoint(&m_engine[id]); + filterBank *fb = &m_filterBank[id][layer]; + + ma_lpf_node_config lpfConfig = ma_lpf_node_config_init(CHANNELS, SAMPLE_RATE, SAMPLE_RATE / LPF_CUTOFF_FACTOR, FILTER_ORDER); + fb->lpfConfig = ma_lpf_config_init(FORMAT, CHANNELS, SAMPLE_RATE, SAMPLE_RATE / LPF_CUTOFF_FACTOR, FILTER_ORDER); + result = ma_lpf_node_init(ng, &lpfConfig, NULL, &fb->lpf); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to initialize low pass filter node." << endl; return result; } - ma_node *endpoint = ma_engine_get_endpoint(&m_engine[id]); - // ToDo: ampliar dimensión a m_filterBank con las capas - ma_hpf_node_config hpfNodeConfig = ma_hpf_node_config_init(CHANNELS, SAMPLE_RATE, SAMPLE_RATE / HPF_CUTOFF_FACTOR, LPF_ORDER); - result = ma_hpf_node_init(ng, &hpfNodeConfig, NULL, &m_filterBank[id].hpfNode); + ma_hpf_node_config hpfConfig = ma_hpf_node_config_init(CHANNELS, SAMPLE_RATE, HPF_CUTOFF_FACTOR, FILTER_ORDER); + fb->hpfConfig = ma_hpf_config_init(FORMAT, CHANNELS, SAMPLE_RATE, HPF_CUTOFF_FACTOR, FILTER_ORDER); + result = ma_hpf_node_init(ng, &hpfConfig, NULL, &fb->hpf); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to initialize high pass filter node." << endl; return result; } - result = ma_node_attach_output_bus(&m_filterBank[id].lpfNode, 0, &m_filterBank[id].hpfNode, 0); + ma_peak_node_config mLowConfig = ma_peak_node_config_init(CHANNELS, SAMPLE_RATE, 1.0, 5.0, 300); // double gainDB, double q, double frequency); + fb->mLowConfig = ma_peak2_config_init(FORMAT, CHANNELS, SAMPLE_RATE, 100.0, 50.0, 1000); + result = ma_peak_node_init(ng, &mLowConfig, NULL, &fb->mLow); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to initialize peak low filter node." << endl; + return result; + } + ma_peak_node_config mHighConfig = ma_peak_node_config_init(CHANNELS, SAMPLE_RATE, 0.0, 0.0, 1000); // double gainDB, double q, double frequency); + fb->mHighConfig = ma_peak2_config_init(FORMAT, CHANNELS, SAMPLE_RATE, 0.0, 0.0, 220); + result = ma_peak_node_init(ng, &mHighConfig, NULL, &fb->mHigh); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to initialize peak high filter node." << endl; + return result; + } + result = ma_node_attach_output_bus(&fb->lpf, 0, &fb->hpf, 0); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to attach low pass filter node." << endl; return result; } - // ToDo: add peak filters - result = ma_node_attach_output_bus(&m_filterBank[id].hpfNode, 0, endpoint, 0); + result = ma_node_attach_output_bus(&fb->hpf, 0, &fb->mLow, 0); if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to attach low pass filter node." << endl; + cout << "ERROR " << result << ": Failed to attach Mid Low pass filter node." << endl; return result; } -/* - result = ma_node_set_state(&m_filterBank[id].lpfNode, ma_node_state::ma_node_state_started); + result = ma_node_attach_output_bus(&fb->mLow, 0, &fb->mHigh, 0); if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to set state to filter node." << endl; + cout << "ERROR " << result << ": Failed to attach high peaks filter node." << endl; return result; - }*/ + } + result = ma_node_attach_output_bus(&fb->mHigh, 0, endpoint, 0); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach high peaks filter node." << endl; + return result; + } + return result; +} + +ma_result MiniAudioEngine::setNodeGraph(int id) { + ma_result result = MA_SUCCESS; + uint i = 0; + + while (result == MA_SUCCESS && i < m_layersQty) { + result = this->createFilterBank(id, i); + i++; + } return (result); } @@ -174,8 +216,11 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file, uint audioDevice) ma_result result; // ToDo: ver si s puede attach dos dispositivos a la vez. si no: - // enchufar a un splitter al sonido y attach cada uno de los lados. - // iniciar un sonido por cada capa + // - enchufar a un splitter al sonido y attach cada uno de los lados. + // - iniciar un sonido por cada capa, copiar la capa en otro dispositivo + // - splitter al final de filterBank, esas señales se mezclan en un nodo mudo + // y se escribe la mezcla en un buffer. Mezclar el buffer en disco con el + // del otro device en el audio callback . if (m_mediaLoaded[layer] == true) { ma_sound_uninit(&m_currentSound[layer]); @@ -188,14 +233,11 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file, uint audioDevice) cout << "Error " << result << ": Failed to load file " << file << endl; return result; } - result = ma_node_attach_output_bus(&m_currentSound[layer], 0, &m_filterBank[audioDevice].lpfNode, 0); + result = ma_node_attach_output_bus(&m_currentSound[layer], 0, &m_filterBank[audioDevice][layer].lpf, 0); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to attach output bus " << audioDevice << endl; //return result; } - // ToDo: ampliar dimensión a m_filterBank con las capas - // attach las capas en los dispositivos - // master cada capa? al principio o final del filtro? m_mediaLoaded[layer] = true; this->refreshValues(layer); m_currentLayerValues[layer].media = file; @@ -357,3 +399,71 @@ void MiniAudioEngine::refreshValues(int layer) this->pitchChanged(layer, m_currentLayerValues[layer].pitch); this->playbackChanged(layer, m_currentLayerValues[layer].status); } + +ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int channel, int value) +{ + ma_result result = MA_SUCCESS; + + filterBank *fb = &m_filterBank[audioDevice][layer]; + + if (channel == LOW_FREQ) { + fb->hpfConfig.cutoffFrequency = (value * 2) + 20; + result = ma_hpf_node_reinit(&fb->hpfConfig, &fb->hpf); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to set frecuency Low filter node." << endl; + return result; + } + } else if (channel == HIGH_FREQ) { + fb->lpfConfig.cutoffFrequency = 22000 - (value * 80); + result = ma_lpf_node_reinit(&fb->lpfConfig, &fb->lpf); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to set frecuency High filter node." << endl; + return result; + } + } else if (channel == MIDLOW_FREQ) { + fb->mLowConfig.frequency = 60 + (value * 4); + result = ma_peak_node_reinit(&fb->mLowConfig, &fb->mLow); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to set frecuency Mid Low pass filter node." << endl; + return result; + } + cout << "frec " << fb->mLowConfig.frequency << endl; + } else if (channel == MIDLOW_Q) { + fb->mLowConfig.q = (double)( value / 32.0f) + 0.50; + result = ma_peak_node_reinit(&fb->mLowConfig, &fb->mLow); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to set Q Mid Low filter node." << endl; + return result; + } + cout << "Q " << fb->mLowConfig.q << endl; + } else if (channel == MIDLOW_GAIN) { + fb->mLowConfig.gainDB = (double)(value / 8.0f) - 16.0f; + result = ma_peak_node_reinit(&fb->mLowConfig, &fb->mLow); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to set gain Mid Low filter node." << endl; + return result; + } + } else if (channel == MIDHIGH_FREQ) { + fb->mHighConfig.frequency = 400 + (value * 32); + result = ma_peak_node_reinit(&fb->mHighConfig, &fb->mHigh); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to set frecuency Mid High filter node." << endl; + return result; + } + } else if (channel == MIDHIGH_Q) { + fb->mHighConfig.q = (double)( value / 32.0f) + 0.50; + result = ma_peak_node_reinit(&fb->mHighConfig, &fb->mHigh); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to set Q Mid High filter node." << endl; + return result; + } + } else if (channel == MIDHIGH_GAIN) { + fb->mHighConfig.gainDB = (double)(value / 8.0f) - 16.0f; + result = ma_peak_node_reinit(&fb->mHighConfig, &fb->mHigh); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to set gain Mid High filter node." << endl; + return result; + } + } + return (result); +} diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index fec6c07..d5d798b 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -19,12 +19,18 @@ using namespace std; typedef struct { - ma_hpf_node hpfNode; - ma_lpf_node lpfNode; - ma_peak_node midLowNode; - ma_peak_node midHighNode; + ma_hpf_node hpf; + ma_hpf_config hpfConfig; + ma_lpf_node lpf; + ma_lpf_config lpfConfig; + ma_peak_node mLow; + ma_peak_config mLowConfig; + ma_peak_node mHigh; + ma_notch_node notch; + ma_peak_config mHighConfig; } filterBank; + class MiniAudioEngine { friend class libreMediaServerAudio; @@ -32,7 +38,7 @@ class MiniAudioEngine public: MiniAudioEngine(); void stopEngine(); - bool startEngine(); + bool startEngine(uint layersQty); bool startDevice(uint *id, uint nb); static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); @@ -50,6 +56,7 @@ protected: inline float getVol(int layer) { return ma_sound_get_volume(&m_currentSound[layer]); } inline bool getAtEnd(int layer) { return m_currentSound[layer].atEnd; } + ma_result filterParamChanged(int layer, int audioDevice, int channel, int value); private: ma_resource_manager_config m_resourceManagerConfig; @@ -62,14 +69,16 @@ private: ma_sound m_currentSound[MAX_LAYERS]; ma_bool8 m_mediaLoaded[MAX_LAYERS]; layerData m_currentLayerValues[MAX_LAYERS]; - filterBank m_filterBank[MAX_LAYERS]; + filterBank m_filterBank[MAX_AUDIODEVICES][MAX_LAYERS]; ma_engine m_engine[MAX_AUDIODEVICES]; + uint m_layersQty; ma_result getAllAudioDevices(); ma_result startContext(); void refreshValues(int layer); ma_result seekToCursor(int layer, int cursor); ma_result setNodeGraph(int id); + ma_result createFilterBank(int id, uint layer); }; #endif // MINIAUDIOENGINE_H