From 103a33820ef8c407f6b02519c1e286378d2bd0e3 Mon Sep 17 00:00:00 2001 From: snt Date: Fri, 10 May 2024 20:03:14 +0200 Subject: [PATCH 1/7] pan y pitchs faders horizontales, funciona varias instancias con multidispositivo y patcheable en jack. --- docs/changelog.txt | 10 ++- docs/roadmap.txt | 3 - src/audiolayerwidget.cpp | 33 +++++----- src/audiolayerwidget.h | 1 + src/audiowidget.cpp | 5 +- src/audiowidget.h | 1 + src/defines.h | 12 ++-- src/libremediaserver-audio.cpp | 5 +- src/miniaudioengine.cpp | 29 +++------ src/miniaudioengine.h | 6 +- src/slidergroup.cpp | 108 ++++++++++++++++++--------------- src/slidergroup.h | 80 +++++++++++++++++++++++- 12 files changed, 188 insertions(+), 105 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 5c7e0b6..c324e44 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -13,8 +13,8 @@ v 0.2.0 Antígona (26/05/2024) + Pan. + Show faders values. New SliderGroup class. + Entry Point 16 bits. -+ Refactor AudioMasterWidget to AudioDMXReceptionWidget. -+ Read mp3, flac, wav (mp3 has given some errors seeking cursor...). ++ Refactor AudioMasterWidget to dmxWidget. ++ Read mp3, flac, wav (mp3 has given some errors seeking cursors...). Audio Engine is working at 48Khz and 32 bits pcm float, if media files are encoding at same configuration, it saves a resampling operation later live. + Removed settings dialog, only read xml conf file at startup. + Real dynamic variable number of layers based on conf file setting. + OlaThread send double channels (volume, entry point, load media) only once for each dmx frame buffer. @@ -23,8 +23,12 @@ v 0.2.0 Antígona (26/05/2024) + New Status "Iddle" in playbacks if is not loaded. + New DMX personality version, better sort for audio needs (first load media, set vol, pan, etc, last playback order); + Refresh layer values when it loads a new sound file. -+ No QtSignals for sending data, better performance about 20% in my machine. Now, libremediaserver only updates values in AudioWidget, ui refresh is doing with a timer in audiowidget, so there is not problems between graphical and ola thread (the callback). ++ No QtSignals for sending data, better performance about 20% in my machine. Now, libremediaserver only updates values in AudioWidget, ui refresh is doing with a timer in audiowidget, so there is not problems between graphical and ola thread (the callback). Signals are used only from Ui to libreMediaServer to notify user interactions and Qtimers. + Load media files from ui clicking in the media labels. ++ New Play Modes: + - Play all medias found in one folder. + - Play all medias in one folder consecutevily. + - Play all medias in one folder randomly. v 0.1.3 Leúcade (19/04/2024) diff --git a/docs/roadmap.txt b/docs/roadmap.txt index 0771257..9385090 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -26,9 +26,6 @@ v 0.2.2 v 0.2.1 - Multi devices output. -- Play Mode: - - Play all medias found in folder consecutevily or random, with loop. - - Play all medias, consecutevily and random, with loop. - mute/panic on layer. - Master Bus Layer: - each layer will have one "Gain" prefader that acts in source, "Vol" in v 1.3. diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index e8d22bd..2655938 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -46,11 +46,11 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_progressTime = new QTimeEdit; m_progressTime->setToolTip("Current Time"); m_progressTime->setObjectName("Current Time"); - m_progressTime->setDisplayFormat("mm:ss:zz"); + m_progressTime->setDisplayFormat("mm:ss:zzz"); m_progressTime->setReadOnly(true); m_progressTime->setButtonSymbols(QAbstractSpinBox::NoButtons); m_progressTime->setMinimumWidth(80); - m_progressTime->setMaximumWidth(80); + //m_progressTime->setMaximumWidth(80); m_progressTime->setFocusPolicy(Qt::NoFocus); m_progressTime->setAlignment(Qt::AlignHCenter); m_progressTime->setContentsMargins(0,0,0,0); @@ -68,22 +68,22 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): status->addWidget(m_progressTime); status->addWidget(m_totalTimeValue); layout->addLayout(status); - QHBoxLayout *volumeBox = new QHBoxLayout; - m_volume = new SliderGroup("Vol", 0 , 100, 2, NULL); - volumeBox->addWidget(m_volume); - connect(m_volume, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int))); + QVBoxLayout *volumeBox = new QVBoxLayout; + m_pitch = new SliderGroup("Pitch", 0 , 255, 0, NULL); + volumeBox->addWidget(m_pitch); + connect(m_pitch, SIGNAL(valueChanged(int)), this, SLOT(pitchChanged(int))); m_pan = new SliderGroup("Pan", 0 , 255, 0, NULL); volumeBox->addWidget(m_pan); connect(m_pan, SIGNAL(valueChanged(int)), this, SLOT(panChanged(int))); - m_pitch = new SliderGroup("Pitch", 0 , 255, 0, NULL); - volumeBox->addWidget(m_pitch); + m_volume = new SliderGroup("Vol", 0 , 100, 2, NULL); + volumeBox->addWidget(m_volume); + connect(m_volume, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int))); volumeBox->setSpacing(0); volumeBox->setContentsMargins(0, 0, 0, 0); - connect(m_pitch, SIGNAL(valueChanged(int)), this, SLOT(pitchChanged(int))); layout->addLayout(volumeBox); layout->setAlignment(Qt::AlignHCenter); layout->setSpacing(0); - layout->setContentsMargins(2, 2, 2, 2); + layout->setContentsMargins(1, 1, 1, 1); this->setLayout(layout); } @@ -113,13 +113,17 @@ void AudioLayerWidget::toggleSuspendResume() switch (m_status) { case Status::PlayingLoop: case Status::PlayingOnce: + case Status::PlayingFolder: + case Status::PlayingFolderLoop: + case Status::PlayingFolderRandom: + m_oldStatus = m_status; this->setPlaybackStatus(Status::Paused); emit uiPlaybackChanged(m_layer, Status::Paused); break; case Status::Paused: case Status::Stopped: - this->setPlaybackStatus(Status::PlayingLoop); - emit uiPlaybackChanged(m_layer, Status::PlayingLoop); + this->setPlaybackStatus(m_oldStatus); + emit uiPlaybackChanged(m_layer, m_oldStatus); case Status::Iddle: break; } @@ -174,10 +178,9 @@ void AudioLayerWidget::setMediaFile(QString file) void AudioLayerWidget::setPlaybackStatus(Status s) { - Status status = static_cast(s); m_suspendResumeButton->blockSignals(true); - m_status = status; - m_suspendResumeButton->setText(StatusStr[status]); + m_status = s; + m_suspendResumeButton->setText(StatusStr[s]); m_suspendResumeButton->blockSignals(false); } diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index 9380b81..cae18d4 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -21,6 +21,7 @@ public: private: Status m_status; + Status m_oldStatus; int m_layer; QPushButton *m_suspendResumeButton; ClickableLabel *m_fileValue; diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index 8bd077c..e163da3 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -5,7 +5,8 @@ AudioWidget::AudioWidget(QWidget *parent) : QWidget(parent) , m_layout(new QHBoxLayout()) { - for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) { + m_layers = Settings::getInstance()->getLayersNumber(); + for (uint i= 0; i < m_layers; i++ ) { AudioLayerWidget *alw = new AudioLayerWidget(this, i); m_layout->insertWidget(i, alw); connect(alw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SIGNAL(uiSliderChanged(int, Slider, int))); @@ -64,7 +65,7 @@ void AudioWidget::cursorChanged(int layer, float cursor) void AudioWidget::refreshUi() { - for (int i = 0; i < MAX_LAYERS; i++) + for (uint i = 0; i < m_layers; i++) { if (m_layerUpdate[i].updated) { QLayoutItem * const item = m_layout->itemAt(i); diff --git a/src/audiowidget.h b/src/audiowidget.h index dd9b1f1..c314656 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -18,6 +18,7 @@ private: QHBoxLayout *m_layout; layerData m_layerUpdate[MAX_LAYERS]; QTimer *m_refreshUi; + uint m_layers; public slots: void volChanged(int layer, float vol); diff --git a/src/defines.h b/src/defines.h index ff299c1..2355059 100644 --- a/src/defines.h +++ b/src/defines.h @@ -7,7 +7,7 @@ #define DEFAULT_FILE "lms-audio.xlm" #define MAX_LAYERS 4 #define MAX_AUDIODEVICES 8 -#define UI_REFRESH_TIME 66 +#define UI_REFRESH_TIME 100 #define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks struct dmxSetting { @@ -32,12 +32,12 @@ static const char* StatusStr[] = { "Stop", "Pause", - "Playing One", - "Playing One Loop", + "Play One", + "Play One Loop", "Iddle", - "Playing Folder", - "Playing Folder Loop", - "Playing Folder Random", + "Play Folder", + "Play Folder Loop", + "Play Folder Rand", 0x0 }; diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index a9868fd..8f16ebc 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -122,7 +122,8 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) #ifndef NOGUI if (m_ui) { m_lmsUi->m_aw->playbackChanged(layer, s); - //m_lmsUi->m_aw->cursorChanged(layer, m_mae.getCursor(layer)); + m_played.clear(); + m_played.append(m_ola->getValue(layer, DMX_FILE)); } #endif } @@ -153,8 +154,6 @@ void libreMediaServerAudio::refreshUi() { m_updateUi[i][3] = -1; } if (m_mae.getAtEnd(i)) { - if (m_played.isEmpty()) - m_played.append(m_ola->getValue(i, DMX_FILE)); if (m_currentStatus[i] == Status::PlayingOnce) { m_currentStatus[i] = Status::Stopped; } diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 9204636..264871b 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -85,7 +85,7 @@ ma_result MiniAudioEngine::startContext() resourceManagerConfig = ma_resource_manager_config_init(); resourceManagerConfig.decodedFormat = ma_format_f32; /* ma_format_f32 should almost always be used as that's what the engine (and most everything else) uses for mixing. */ resourceManagerConfig.decodedChannels = 0; - resourceManagerConfig.decodedSampleRate = ma_standard_sample_rate_48000; + resourceManagerConfig.decodedSampleRate = ma_standard_sample_rate_44100; resourceManagerConfig.jobThreadCount = 4; result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager); if (result != MA_SUCCESS) { @@ -129,6 +129,7 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file) result = ma_sound_init_from_file(&engine, file, \ MA_SOUND_FLAG_NO_SPATIALIZATION \ | MA_SOUND_FLAG_DECODE \ + | MA_SOUND_FLAG_STREAM \ /*| MA_SOUND_FLAG_NO_PITCH \*/ , NULL, NULL, &m_currentSound[layer]); if (result != MA_SUCCESS) @@ -144,22 +145,15 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file) float MiniAudioEngine::getDuration(int layer) { ma_result result; - ma_uint64 lengthInPCMFrames; - ma_uint32 sampleRate; float ret; if (m_mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; - result = ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &lengthInPCMFrames); + result = ma_sound_get_length_in_seconds(&m_currentSound[layer], &ret); if (result != MA_SUCCESS) { return result; } - result = ma_sound_get_data_format(&m_currentSound[layer], NULL, NULL, &sampleRate, NULL, 0); - if (result != MA_SUCCESS) { - return MA_ERROR; - } - ret = 1000.0f * (lengthInPCMFrames / float(sampleRate)); - return ret; + return (ret * 1000); } float MiniAudioEngine::getCursor(int layer) @@ -233,27 +227,25 @@ ma_result MiniAudioEngine::playbackChanged(int layer, Status status) if (m_mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; + bool loop = false; switch (status) { case Status::Paused: result = ma_sound_stop_with_fade_in_milliseconds(&m_currentSound[layer], FADE_TIME); break; case Status::Stopped: - result = ma_sound_stop_with_fade_in_milliseconds(&m_currentSound[layer], FADE_TIME); + ma_sound_stop_with_fade_in_milliseconds(&m_currentSound[layer], FADE_TIME); result = this->seekToCursor(layer, m_currentLayerValues[layer].cursor); break; case Status::PlayingLoop: - ma_sound_set_stop_time_in_milliseconds(&m_currentSound[layer], ~(ma_uint64)0); - ma_sound_set_looping(&m_currentSound[layer], true); - result = ma_sound_start(&m_currentSound[layer]); - break; + loop = true; case Status::PlayingOnce: case Status::PlayingFolder: case Status::PlayingFolderLoop: case Status::PlayingFolderRandom: ma_sound_set_stop_time_in_milliseconds(&m_currentSound[layer], ~(ma_uint64)0); - ma_sound_set_looping(&m_currentSound[layer], false); + ma_sound_set_looping(&m_currentSound[layer], loop); result = ma_sound_start(&m_currentSound[layer]); - break; + //this->volChanged(layer, m_currentLayerValues[layer].vol); // glitch when seek to cursor, how flush the audio buffer? default: break; } @@ -273,8 +265,7 @@ ma_result MiniAudioEngine::seekToCursor(int layer, int cursor) if (result != MA_SUCCESS) { return result; } start = (cursor * end) / 65025; result = ma_sound_seek_to_pcm_frame(&m_currentSound[layer], start); - //if (result != MA_SUCCESS) { return result; } - //result = ma_data_source_set_loop_point_in_pcm_frames(&m_currentSound[layer], start, end); + //result = ma_data_source_set_loop_point_in_pcm_frames(&m_currentSound[layer], start, end); // this do nothing here, it must be done after set_looping or start? return (result); } diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 6e1393c..103126e 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -1,11 +1,15 @@ #ifndef MINIAUDIOENGINE_H #define MINIAUDIOENGINE_H +#define MA_ENABLE_ONLY_SPECIFIC_BACKENDS 1 +#define MA_ENABLE_JACK 1 +#define MA_NO_GENERATION 1 +#define MA_DEBUG_OUTPUT 1 +#define MA_DISABLE_PULSEAUDIO #define MINIAUDIO_IMPLEMENTATION #include "miniaudio.h" #include "defines.h" // MAX_LAYERS #include // prints messages -#define MA_DEBUG_OUTPUT class MiniAudioEngine { diff --git a/src/slidergroup.cpp b/src/slidergroup.cpp index 9ef9680..4395a8d 100644 --- a/src/slidergroup.cpp +++ b/src/slidergroup.cpp @@ -1,5 +1,17 @@ #include "slidergroup.h" #include +#include + +DoubleSpinBoxClickable::DoubleSpinBoxClickable(QWidget *parent) + : QDoubleSpinBox{parent} {} + +DoubleSpinBoxClickable::~DoubleSpinBoxClickable() {} + +SliderClickDisable::SliderClickDisable(QWidget *parent) + : QSlider{parent} {} + +SliderClickDisable::~SliderClickDisable() {} + SliderGroup::SliderGroup(QString name, int min, int max, @@ -7,42 +19,46 @@ SliderGroup::SliderGroup(QString name, QWidget *parent) : QWidget(parent) { - QVBoxLayout *layout = new QVBoxLayout; + QBoxLayout *layout; + if (decimals) { + layout = new QVBoxLayout; + slider.setOrientation(Qt::Vertical); + } + else { + layout = new QHBoxLayout; + slider.setOrientation(Qt::Horizontal); + slider.setMinimumHeight(10); + } layout->setAlignment(Qt::AlignHCenter); layout->setContentsMargins(0, 0, 0, 0); - //this->setMaximumWidth(40); - slider = new QSlider(Qt::Orientation::Vertical); - slider->setFocusPolicy(Qt::StrongFocus); - slider->setTickPosition(QSlider::TicksBothSides); - slider->setTickInterval((max - min) / 11); - slider->setMinimumHeight(0); - slider->setSingleStep(1); - slider->setRange(min, max); - slider->setValue(0); - slider->setMinimumWidth(50); - slider->setToolTip(name); - slider->setStyleSheet("QSlider {" + slider.setFocusPolicy(Qt::StrongFocus); + slider.setTickPosition(QSlider::TicksBothSides); + slider.setTickInterval((max - min) / 11); + slider.setMinimumHeight(0); + slider.setSingleStep(1); + slider.setRange(min, max); + slider.setValue(0); + slider.setMinimumWidth(50); + slider.setToolTip(name); + slider.setStyleSheet("QSlider {" "border: 1px solid #5a4855;" - "margin: 0px;" - "height: 200px;" - "width: 50px;}" + "margin: 0px;}" ); - slider->setContentsMargins(0, 0, 0, 0); - valueBox = new QDoubleSpinBox(); - valueBox->setFocusPolicy(Qt::NoFocus); - valueBox->setButtonSymbols(QAbstractSpinBox::NoButtons); - valueBox->setMinimumWidth(50); - valueBox->setRange(min, max); - valueBox->setValue(0); - valueBox->setDecimals(decimals); - valueBox->setObjectName(name); - valueBox->setToolTip(name); - valueBox->setAlignment(Qt::AlignHCenter); - valueBox->setContentsMargins(0, 0, 0, 0); - connect(slider, SIGNAL(valueChanged(int)), this, SLOT(sliderValueChanged(int))); - //connect(slider, SIGNAL(mousePressEvent(QMouseEvent)), this, SLOT(mousePressEvent(QMouseEvent *))); - layout->addWidget(slider); - layout->addWidget(valueBox); + slider.setContentsMargins(0, 0, 0, 0); + valueBox.setFocusPolicy(Qt::NoFocus); + valueBox.setButtonSymbols(QAbstractSpinBox::NoButtons); + valueBox.setMinimumWidth(50); + valueBox.setRange(min, max); + valueBox.setValue(0); + valueBox.setDecimals(decimals); + valueBox.setObjectName(name); + valueBox.setToolTip(name); + valueBox.setAlignment(Qt::AlignHCenter); + valueBox.setContentsMargins(0, 0, 0, 0); + connect(&slider, SIGNAL(valueChanged(int)), this, SLOT(sliderValueChanged(int))); + connect(&valueBox, SIGNAL(enableSlider()), this, SLOT(enableSlider())); + layout->addWidget(&slider); + layout->addWidget(&valueBox); this->setStyleSheet("border: 1px solid #5a4855;" "width: 50px;" "margin: 0px;" @@ -55,27 +71,19 @@ SliderGroup::SliderGroup(QString name, void SliderGroup::sliderValueChanged(int value) { - valueBox->blockSignals(true); - valueBox->setValue(value); - valueBox->blockSignals(false); + valueBox.blockSignals(true); + valueBox.setValue(value); + valueBox.blockSignals(false); emit valueChanged(value); }; void SliderGroup::setValue(float value) { - slider->blockSignals(true); - valueBox->blockSignals(true); - if (int(value) != slider->value()) - slider->setValue(value); - valueBox->setValue(value); - slider->blockSignals(false); - valueBox->blockSignals(false); -} - -void SliderGroup::mousePressEvent(QMouseEvent* event) { - Q_UNUSED(event); - if (slider->isEnabled()) - slider->setDisabled(true); - else - slider->setDisabled(false); + slider.blockSignals(true); + valueBox.blockSignals(true); + if (int(value) != slider.value()) + slider.setValue(value); + valueBox.setValue(value); + slider.blockSignals(false); + valueBox.blockSignals(false); } diff --git a/src/slidergroup.h b/src/slidergroup.h index 5bfeeb8..b6940b1 100644 --- a/src/slidergroup.h +++ b/src/slidergroup.h @@ -5,6 +5,78 @@ #include #include #include +#include +#include +#include +/* +//slider->installEventFilter(new QSliderAnalyser); +class QSliderAnalyser + : public QObject +{ + public: + QSliderAnalyser() + { + } + + virtual ~QSliderAnalyser() + { + } + + protected: + bool eventFilter(QObject* object, QEvent* event) override + { + if (event->type() == QEvent::MouseButtonPress) { + qDebug() << event->type() << object->objectName(); + } + return QObject::eventFilter(object, event); + } +};*/ + +class DoubleSpinBoxClickable: public QDoubleSpinBox +{ + Q_OBJECT + +public: + DoubleSpinBoxClickable(QWidget *parent = 0); + ~DoubleSpinBoxClickable(); + +signals: + void enableSlider(); + +protected: + void mousePressEvent ( QMouseEvent * event ) + { + if (event->button() == Qt::LeftButton) { + qDebug() << "enabling slider"; + emit(enableSlider()); + } + event->accept(); + } +}; + +class SliderClickDisable + : public QSlider +{ + Q_OBJECT + +public: + explicit SliderClickDisable(QWidget *parent = Q_NULLPTR); + ~SliderClickDisable(); + +protected: + void mousePressEvent ( QMouseEvent * event ) + { + if (event->button() == Qt::RightButton) + { + if (this->isEnabled()) { + qDebug() << "disabling slider"; + this->setDisabled(true); + } + event->accept(); + } + QSlider::mousePressEvent(event); + } +}; class SliderGroup : public QWidget { @@ -25,10 +97,12 @@ public slots: void sliderValueChanged(int value); private: - QSlider *slider; - QDoubleSpinBox *valueBox; + SliderClickDisable slider; + DoubleSpinBoxClickable valueBox; + +private slots: + void enableSlider() { slider.setEnabled(true); } - void mousePressEvent(QMouseEvent* event); }; #endif From 8c69da5f9d4886e96805e4a8e70f74fd06e762e4 Mon Sep 17 00:00:00 2001 From: snt Date: Fri, 10 May 2024 21:04:26 +0200 Subject: [PATCH 2/7] funcionando multidispositivo, cada capa se patchea a un dispositivo de audio. --- docs/lms-audio.xlm | 10 ++++----- src/defines.h | 1 + src/libremediaserver-audio.cpp | 10 ++++++--- src/miniaudioengine.cpp | 37 ++++++++++++++++------------------ src/miniaudioengine.h | 10 ++++----- src/settings.cpp | 4 +--- src/settings.h | 3 ++- 7 files changed, 38 insertions(+), 37 deletions(-) diff --git a/docs/lms-audio.xlm b/docs/lms-audio.xlm index 4274267..b2ea7ed 100644 --- a/docs/lms-audio.xlm +++ b/docs/lms-audio.xlm @@ -1,8 +1,8 @@ - - - - - + + + + + diff --git a/src/defines.h b/src/defines.h index 2355059..a885485 100644 --- a/src/defines.h +++ b/src/defines.h @@ -14,6 +14,7 @@ struct dmxSetting { int address; unsigned int universe; int layer; + int audioDevice; }; enum Status diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 8f16ebc..10cef51 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -26,6 +26,7 @@ libreMediaServerAudio::libreMediaServerAudio() m_settings = Settings::getInstance(); m_settings->readFile(); m_ui = m_settings->getShowUi(); + m_dmxSettings = m_settings->getDmxSettings(); m_mediaLibrary = new MediaLibrary; m_mediaLibrary->initMediaLibrary(); for (int i = 0; i < MAX_LAYERS; i++) { @@ -42,7 +43,10 @@ libreMediaServerAudio::libreMediaServerAudio() Q_CHECK_PTR(m_ola); m_ola->blockSignals(true); m_ola->registerUniverse(); - m_mae.startEngine(m_settings->getAudioDeviceId()); + m_mae.startEngine(); + uint *audioDevList = m_settings->getAudioDeviceId(); + for (uint i = 0; i < m_settings->getAudioDeviceQty(); i++) + m_mae.startDevice(audioDevList[i], i); qDebug("Core init Complete. Start reading DMX."); m_ola->blockSignals(false); #ifdef NOGUI @@ -62,7 +66,7 @@ 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_mae.loadMedia(layer, mediaFile.toLatin1().data(), m_dmxSettings.at(layer).audioDevice); m_currentMedia[layer] = mediaFile; #ifndef NOGUI if (m_ui) @@ -247,7 +251,7 @@ void libreMediaServerAudio::uiLoadMedia(int layer, QString mediaFile) if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0) return; - result = m_mae.loadMedia(layer, mediaFile.toLatin1().data()); + result = m_mae.loadMedia(layer, mediaFile.toLatin1().data(), m_dmxSettings[layer].audioDevice); if (result == MA_SUCCESS) { m_currentMedia[layer] = mediaFile; m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 264871b..6051105 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -21,60 +21,57 @@ void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const void MiniAudioEngine::stopEngine() { - ma_engine_uninit(&engine); - ma_device_uninit(&device); + ma_engine_uninit(&engine[0]); + ma_device_uninit(&device[0]); ma_context_uninit(&context); ma_resource_manager_uninit(&resourceManager); } -bool MiniAudioEngine::startEngine(uint n) +bool MiniAudioEngine::startEngine() { ma_result result; result = this->startContext(); if (result != MA_SUCCESS) return result; result = this->getAllAudioDevices(); - if (result != MA_SUCCESS) return result; - result = this->startDevice(n); return result; } -ma_result MiniAudioEngine::startDevice(uint id) +ma_result MiniAudioEngine::startDevice(uint systemId, uint internalId) { ma_result result; ma_device_config deviceConfig; ma_engine_config engineConfig; - if (id >= playbackDeviceCount) - id = playbackDeviceCount - 1; + if (systemId >= playbackDeviceCount) + systemId = playbackDeviceCount - 1; deviceConfig = ma_device_config_init(ma_device_type_playback); - deviceConfig.playback.pDeviceID = &pPlaybackDeviceInfos[id].id; + deviceConfig.playback.pDeviceID = &pPlaybackDeviceInfos[systemId].id; deviceConfig.playback.format = resourceManager.config.decodedFormat; deviceConfig.playback.channels = 0; deviceConfig.sampleRate = resourceManager.config.decodedSampleRate; deviceConfig.dataCallback = audioDataCallback; - deviceConfig.pUserData = &engine; - result = ma_device_init(&context, &deviceConfig, &device); + deviceConfig.pUserData = &engine[internalId]; + result = ma_device_init(&context, &deviceConfig, &device[internalId]); if (result != MA_SUCCESS) { - qCritical("Failed to initialize audio device %s.", pPlaybackDeviceInfos[id].name); + qCritical("Failed to initialize audio device %s.", pPlaybackDeviceInfos[systemId].name); return result; } engineConfig = ma_engine_config_init(); - engineConfig.pDevice = &device; + engineConfig.pDevice = &device[internalId]; engineConfig.pResourceManager = &resourceManager; engineConfig.noAutoStart = MA_TRUE; - result = ma_engine_init(NULL, &engine); + result = ma_engine_init(NULL, &engine[internalId]); if (result != MA_SUCCESS) { qCritical("Failed to initialize audio engine."); return result; } - result = ma_engine_start(&engine); + result = ma_engine_start(&engine[internalId]); if (result != MA_SUCCESS) { - qCritical("Failed to start audio engine %i.", id); + qCritical("Failed to start audio engine %i.", systemId); return result; } - iChosenDevice = id; - qInfo("Initialized audio device %d : %s", id, pPlaybackDeviceInfos[id].name); + qInfo("Initialized audio device internal: %ui system: %d %s", internalId, systemId, pPlaybackDeviceInfos[systemId].name); return result; } @@ -117,7 +114,7 @@ ma_result MiniAudioEngine::getAllAudioDevices() return result; } -ma_result MiniAudioEngine::loadMedia(int layer, char *file) +ma_result MiniAudioEngine::loadMedia(int layer, char *file, uint audioDevice) { ma_result result; @@ -126,7 +123,7 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file) ma_sound_uninit(&m_currentSound[layer]); m_mediaLoaded[layer] = false; } - result = ma_sound_init_from_file(&engine, file, \ + result = ma_sound_init_from_file(&engine[audioDevice], file, \ MA_SOUND_FLAG_NO_SPATIALIZATION \ | MA_SOUND_FLAG_DECODE \ | MA_SOUND_FLAG_STREAM \ diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 103126e..b91d718 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -18,11 +18,12 @@ class MiniAudioEngine public: MiniAudioEngine(); void stopEngine(); - bool startEngine(uint id); + bool startEngine(); + ma_result startDevice(uint id, uint internalId); static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); protected: - ma_result loadMedia(int layer, char *media ); + ma_result loadMedia(int layer, char *media, uint audioDevice); void volChanged(int layer, float vol); void panChanged(int layer, float pan); void pitchChanged(int layer, float pitch); @@ -42,15 +43,14 @@ private: ma_device_info* pPlaybackDeviceInfos; ma_uint32 playbackDeviceCount; ma_uint32 iChosenDevice; - ma_engine engine; - ma_device device; + ma_engine engine[MAX_AUDIODEVICES]; + ma_device device[MAX_AUDIODEVICES]; ma_context context; ma_sound m_currentSound[MAX_LAYERS]; ma_bool8 m_mediaLoaded[MAX_LAYERS]; layerData m_currentLayerValues[MAX_LAYERS]; ma_result getAllAudioDevices(); - ma_result startDevice(uint id); ma_result startContext(); void refreshValues(int layer); ma_result seekToCursor(int layer, int cursor); diff --git a/src/settings.cpp b/src/settings.cpp index 9d06394..6527bcb 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -51,16 +51,14 @@ void Settings::readFromFile(QString file) { if(xmlReader->name() == "audioDevice") { m_audioDeviceQty = xmlReader->attributes().value("devicesNumber").toLocal8Bit().toInt(); for (uint i = 0; i < m_audioDeviceQty; i++) - { m_audioDeviceId[i] = xmlReader->attributes().value(QString("id%1").arg(i)).toLocal8Bit().toInt(); - } - } if(xmlReader->name() == "layer") { dmxSetting temp; temp.address = xmlReader->attributes().value("dmx").toLocal8Bit().toInt() - 1; temp.universe = xmlReader->attributes().value("universe").toLocal8Bit().toInt(); temp.layer = xmlReader->attributes().value("id").toLocal8Bit().toInt(); + temp.audioDevice = xmlReader->attributes().value("audioDevice").toLocal8Bit().toInt(); m_settings.append(temp); if (!m_universe.contains(temp.universe)) { m_universe.insert(temp.universe); diff --git a/src/settings.h b/src/settings.h index f27da6a..6e51d14 100644 --- a/src/settings.h +++ b/src/settings.h @@ -22,7 +22,8 @@ public: inline QString getPathMedia() { return m_pathmedia; } inline QList getDmxSettings() { return m_settings; } inline int getLayersNumber() { return m_layersNumber; } - inline int getAudioDeviceId() { return m_audioDeviceId[0]; } + inline uint *getAudioDeviceId() { return m_audioDeviceId; } + inline uint getAudioDeviceQty() { return m_audioDeviceQty; } inline bool getShowUi() { return m_ui; } void readFile(); void readFromFile(QString file); From 7cd4c8fbd84d917806c4eecf6c3220b5ac4106e2 Mon Sep 17 00:00:00 2001 From: snt Date: Sun, 12 May 2024 23:23:26 +0200 Subject: [PATCH 3/7] prototipo de filtro funcionando, muy sucio. --- docs/changelog.txt | 13 +- docs/roadmap.txt | 2 +- src/libremediaserver-audio.cpp | 16 +- src/libremediaserver-audio.h | 4 + src/miniaudioengine.cpp | 286 ++++++++++++++++++++++++--------- src/miniaudioengine.h | 53 ++++-- 6 files changed, 276 insertions(+), 98 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index c324e44..ef76b53 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -29,24 +29,21 @@ v 0.2.0 Antígona (26/05/2024) - Play all medias found in one folder. - Play all medias in one folder consecutevily. - Play all medias in one folder randomly. ++ Multi audio devices output. v 0.1.3 Leúcade (19/04/2024) - + Ubuntu 22.04 jammy. + Qt 5.15.3. + Pitch. + Loop. v 0.1.2 Mayordomo (12/08/2015) - -- GUI config. -- Several bugs tested in real world. -- Variable layers. -- SFML as audio engine. ++ GUI config. ++ Variable layers. ++ SFML as audio engine. v 0.1.1 Pascual (24/09/2014) - + First Version: 4 layers playing .ogg. + Needs Open Lighting Arquitecture => 0.9.0. + Pure Data as audio engine. - ++ Qt4 diff --git a/docs/roadmap.txt b/docs/roadmap.txt index 9385090..154fd78 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -25,7 +25,6 @@ v 0.2.2 - Octopus Sound Card support (6 outputs - 8 inputs). v 0.2.1 -- Multi devices output. - mute/panic on layer. - Master Bus Layer: - each layer will have one "Gain" prefader that acts in source, "Vol" in v 1.3. @@ -46,6 +45,7 @@ v 0.2.1 - ¿Exit Point? is it needed? - Hardening: check return errors, try/catch exceptions, i'm too happy.... - Tests: errors on wrong conf file. +- Ui/Ux: seek cursor playback v0.2.0: - Vumeter or indicator about audio output in layer and master, add to sliderGroup. diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 10cef51..39c700d 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -43,11 +43,16 @@ libreMediaServerAudio::libreMediaServerAudio() Q_CHECK_PTR(m_ola); m_ola->blockSignals(true); m_ola->registerUniverse(); - m_mae.startEngine(); + if (!m_mae.startEngine()) { + cout << "Can not start Audio Engine!" << endl; + this->~libreMediaServerAudio(); + } uint *audioDevList = m_settings->getAudioDeviceId(); - for (uint i = 0; i < m_settings->getAudioDeviceQty(); i++) - m_mae.startDevice(audioDevList[i], i); - qDebug("Core init Complete. Start reading DMX."); + if (!m_mae.startDevice(audioDevList, m_settings->getAudioDeviceQty())) { + cout << "Can not start Audio Device!" << audioDevList << endl; + this->~libreMediaServerAudio(); + } + cout << "Core init Complete. Start reading DMX." << endl; m_ola->blockSignals(false); #ifdef NOGUI m_ola->start(QThread::TimeCriticalPriority ); @@ -58,6 +63,9 @@ libreMediaServerAudio::~libreMediaServerAudio() { m_ola->stop(); m_mae.stopEngine(); + sleep(1); + cout << "bye!" << endl; + exit(0); } void libreMediaServerAudio::loadMedia(int layer, int folder, int file) diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index d83446a..aed7e45 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -20,6 +20,10 @@ #ifndef LIBREMEDIASERVERAUDIO_H #define LIBREMEDIASERVERAUDIO_H + +#include +using namespace std; + #include "medialibrary.h" #include "miniaudioengine.h" #include "olathread.h" diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 6051105..a0445c9 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -1,5 +1,15 @@ #include "miniaudioengine.h" -#include //enum macro +#define LPF_BIAS 0.9f /* Higher values means more bias towards the low pass filter (the low pass filter will be more audible). Lower values means more bias towards the echo. Must be between 0 and 1. */ +#define LPF_CUTOFF_FACTOR 80 /* High values = more filter. */ +#define LPF_ORDER 8 + +//static filterBank m_filterBank[MAX_LAYERS]; +//static ma_node_graph m_nodeGraph[MAX_LAYERS]; +//static soundNode m_soundNode[MAX_LAYERS]; + +static ma_lpf_node g_lpfNode[MAX_AUDIODEVICES]; +static ma_engine m_engine[MAX_AUDIODEVICES]; + MiniAudioEngine::MiniAudioEngine() { for (int i =0; i < MAX_LAYERS; i++) { @@ -12,19 +22,37 @@ MiniAudioEngine::MiniAudioEngine() } } -void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) +void MiniAudioEngine::audioDataCallback1(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { (void)pInput; - //Do master audio processing before sending to device. - ma_engine_read_pcm_frames((ma_engine*)pDevice->pUserData, pOutput, frameCount, NULL); + (void)pDevice; + ma_result result; + result = ma_engine_read_pcm_frames((ma_engine*)pDevice->pUserData, pOutput, frameCount, NULL); + if (result != MA_SUCCESS) { + cout << "1"; + } +} + +void MiniAudioEngine::audioDataCallback2(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 << "2"; + } } void MiniAudioEngine::stopEngine() { - ma_engine_uninit(&engine[0]); - ma_device_uninit(&device[0]); - ma_context_uninit(&context); - ma_resource_manager_uninit(&resourceManager); + for (uint i = 0; i < m_devicesSelected; i++) { + ma_engine_uninit(&m_engine[i]); + ma_device_uninit(&m_device[i]); + } + ma_context_uninit(&m_context); + ma_resource_manager_uninit(&m_resourceManager); } bool MiniAudioEngine::startEngine() @@ -32,66 +60,144 @@ bool MiniAudioEngine::startEngine() ma_result result; result = this->startContext(); - if (result != MA_SUCCESS) return result; + if (result != MA_SUCCESS) return false; result = this->getAllAudioDevices(); - return result; + if (result != MA_SUCCESS) return false; + return true; } -ma_result MiniAudioEngine::startDevice(uint systemId, uint internalId) -{ +ma_result MiniAudioEngine::setNodeGraph(int id) { ma_result result; + + //ma_node_graph_config nodeGraphConfig = ma_node_graph_config_init(CHANNELS); + //result = ma_node_graph_init(&nodeGraphConfig, NULL, &m_nodeGraph[id]); + //if (result != MA_SUCCESS) { + // cout << "ERROR " << result << ": Failed to initialize node graph."; + // return MA_ERROR; + //} +/* + ma_loshelf2_config losConfig = ma_loshelf2_config_init(FORMAT, CHANNELS, SAMPLE_RATE, 1, 0.5, 83.3); // double gainDB, double shelfSlope, double frequency) + result = ma_loshelf2_init(&losConfig, NULL, &m_filterBank[id].loShelfNode); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Can not init loShelf node." << endl; + return result; + } + ma_engine m; + ma_node_graph *ng = (ma_node_graph *)(&m_engine[id]); + ma_node *node = ma_node_graph_get_endpoint(ng); + node = ma_engine_get_endpoint(&m_engine[id]); + ma_node_base nodeBase = ng->endpoint; + result = ma_node_attach_output_bus(&m_filterBank[id].loShelfNode, 0, &nodeBase, 0); + //result = ma_node_attach_output_bus(&m_filterBank[id].loShelfNode, 0, ma_engine_get_endpoint(engine), 0); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Can not attach filter to graph endpoint." << endl; + return result; + }*/ +/* + ma_splitter_node_config splitterConfig = ma_splitter_node_config_init(ma_engine_get_channels(&engine[0])); + result = ma_splitter_node_init(ng, &splitterConfig, NULL, &m_filterBank[layer].outputNode); + if (result != MA_SUCCESS) { + cout << "Can not init splitter node." << endl; + return result; + } + result = ma_node_attach_output_bus(&m_filterBank[layer].loShelfNode, 0, &m_filterBank[layer].outputNode, 0); + if (result != MA_SUCCESS) { + cout << "Can not attach loShelf to output." << endl; + return result; + } + result = ma_node_attach_output_bus(&m_filterBank[layer].outputNode, 0, ma_node_graph_get_endpoint(ng), 0); + if (result != MA_SUCCESS) { + cout << "Can not attach splitter to graph endpoint." << endl; + return result; + } + }*/ + /* Low Pass Filter. */ + 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, &g_lpfNode[id]); + 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]); + result = ma_node_attach_output_bus(&g_lpfNode[id], 0, endpoint, 0); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach low pass filter node." << endl; + return result; + } + result = ma_node_set_output_bus_volume(&g_lpfNode[id], 0, LPF_BIAS); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to set volume low pass filter node." << endl; + return result; + } + ma_node_set_state(&g_lpfNode[id], ma_node_state::ma_node_state_started); + return (result); +} + +bool MiniAudioEngine::startDevice(uint *systemId, uint nb) +{ + ma_result result = MA_SUCCESS; ma_device_config deviceConfig; ma_engine_config engineConfig; - if (systemId >= playbackDeviceCount) - systemId = playbackDeviceCount - 1; - deviceConfig = ma_device_config_init(ma_device_type_playback); - deviceConfig.playback.pDeviceID = &pPlaybackDeviceInfos[systemId].id; - deviceConfig.playback.format = resourceManager.config.decodedFormat; - deviceConfig.playback.channels = 0; - deviceConfig.sampleRate = resourceManager.config.decodedSampleRate; - deviceConfig.dataCallback = audioDataCallback; - deviceConfig.pUserData = &engine[internalId]; - result = ma_device_init(&context, &deviceConfig, &device[internalId]); - if (result != MA_SUCCESS) { - qCritical("Failed to initialize audio device %s.", pPlaybackDeviceInfos[systemId].name); - return result; + m_devicesSelected = nb; + for (uint internalId = 0; internalId < nb; internalId++) { + deviceConfig = ma_device_config_init(ma_device_type_playback); + deviceConfig.playback.pDeviceID = &m_pPlaybackDeviceInfos[systemId[internalId]].id; + deviceConfig.playback.format = m_resourceManager.config.decodedFormat; + deviceConfig.playback.channels = 0; + deviceConfig.sampleRate = m_resourceManager.config.decodedSampleRate; + if (internalId == 0) + deviceConfig.dataCallback = audioDataCallback1; + else + deviceConfig.dataCallback = audioDataCallback2; + deviceConfig.pUserData = &m_engine[internalId]; + result = ma_device_init(&m_context, &deviceConfig, &m_device[internalId]); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to initialize audio device " << m_pPlaybackDeviceInfos[*systemId].name << endl; + return false; + } + engineConfig = ma_engine_config_init(); + engineConfig.pDevice = &m_device[internalId]; + engineConfig.pResourceManager = &m_resourceManager; + engineConfig.noAutoStart = MA_TRUE; + result = ma_engine_init(&engineConfig, &m_engine[internalId]); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to initialize audio engine" << endl; + return false; + } + result = this->setNodeGraph(internalId); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to set node graph " << systemId[internalId] << endl; + return false; + } + result = ma_engine_start(&m_engine[internalId]); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to start audio engine" << systemId[internalId] << endl; + return false; + } + cout << "Initialized Audio Device. internalId: " << internalId << " systemId: " << systemId[internalId] << " " << m_pPlaybackDeviceInfos[systemId[internalId]].name << endl; } - engineConfig = ma_engine_config_init(); - engineConfig.pDevice = &device[internalId]; - engineConfig.pResourceManager = &resourceManager; - engineConfig.noAutoStart = MA_TRUE; - result = ma_engine_init(NULL, &engine[internalId]); - if (result != MA_SUCCESS) { - qCritical("Failed to initialize audio engine."); - return result; - } - result = ma_engine_start(&engine[internalId]); - if (result != MA_SUCCESS) { - qCritical("Failed to start audio engine %i.", systemId); - return result; - } - qInfo("Initialized audio device internal: %ui system: %d %s", internalId, systemId, pPlaybackDeviceInfos[systemId].name); - return result; + return true; } ma_result MiniAudioEngine::startContext() { ma_result result; - resourceManagerConfig = ma_resource_manager_config_init(); - resourceManagerConfig.decodedFormat = ma_format_f32; /* ma_format_f32 should almost always be used as that's what the engine (and most everything else) uses for mixing. */ - resourceManagerConfig.decodedChannels = 0; - resourceManagerConfig.decodedSampleRate = ma_standard_sample_rate_44100; - resourceManagerConfig.jobThreadCount = 4; - result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager); + m_resourceManagerConfig = ma_resource_manager_config_init(); + m_resourceManagerConfig.decodedFormat = FORMAT; + m_resourceManagerConfig.decodedChannels = CHANNELS; + m_resourceManagerConfig.decodedSampleRate = SAMPLE_RATE; + m_resourceManagerConfig.jobThreadCount = 4; + result = ma_resource_manager_init(&m_resourceManagerConfig, &m_resourceManager); if (result != MA_SUCCESS) { - qCritical("Failed to initialize audio resource manager."); + cout << "Error " << result << ": Failed to initialize audio resource manager." << endl; return result; } - result = ma_context_init(NULL, 0, NULL, &context); + result = ma_context_init(NULL, 0, NULL, &m_context); if (result != MA_SUCCESS) { - qCritical("Failed to initialize audio context."); + cout << "Error " << result << ": Failed to initialize audio context." << endl; } return result; } @@ -101,15 +207,15 @@ ma_result MiniAudioEngine::getAllAudioDevices() { ma_result result; - result = ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, NULL, NULL); + result = ma_context_get_devices(&m_context, &m_pPlaybackDeviceInfos, &m_playbackDeviceCount, NULL, NULL); if (result != MA_SUCCESS) { - qWarning("Failed to enumerate playback devices.\n"); - ma_context_uninit(&context); + cout << "Error" << result << ": Failed to enumerate playback devices." << endl; + ma_context_uninit(&m_context); return result; } - printf("Audio devices available:\n"); - for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < playbackDeviceCount; iAvailableDevice += 1) { - qInfo("%d: : %s", iAvailableDevice, pPlaybackDeviceInfos[iAvailableDevice].name); + cout << "Audio devices available:" << endl; + for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < m_playbackDeviceCount; iAvailableDevice += 1) { + cout << iAvailableDevice << " : " << m_pPlaybackDeviceInfos[iAvailableDevice].name << endl; } return result; } @@ -123,19 +229,49 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file, uint audioDevice) ma_sound_uninit(&m_currentSound[layer]); m_mediaLoaded[layer] = false; } - result = ma_sound_init_from_file(&engine[audioDevice], file, \ +/* + ma_sound_config soundConfig = ma_sound_config_init(); + soundConfig = ma_sound_config_init(); + soundConfig.pFilePath = file; + soundConfig.pInitialAttachment = &m_filterBank[layer].loShelfNode; + soundConfig.initialAttachmentInputBusIndex = 0; + soundConfig.channelsIn = 0; + soundConfig.channelsOut = CHANNELS; + //soundConfig.monoExpansionMode; + soundConfig.flags = MA_SOUND_FLAG_NO_SPATIALIZATION; + // | MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT; + //| MA_SOUND_FLAG_STREAM | MA_SOUND_FLAG_NO_PITCH + soundConfig.volumeSmoothTimeInPCMFrames = 480; + //soundConfig.initialSeekPointInPCMFrames; + //soundConfig.rangeBegInPCMFrames; + //soundConfig.rangeEndInPCMFrames; + //soundConfig.loopPointBegInPCMFrames; + //soundConfig.loopPointEndInPCMFrames; + //soundConfig.isLooping; + //soundConfig.endCallback; + //soundConfig.pEndCallbackUserData; + + result = ma_sound_init_ex(&m_engine[audioDevice], &soundConfig, &m_currentSound[layer]); + if (result != MA_SUCCESS) { + cout << "Error" << result << ": Failed to load file " << file << endl; + return result; + }*/ + result = ma_sound_init_from_file(&m_engine[audioDevice], file, \ MA_SOUND_FLAG_NO_SPATIALIZATION \ - | MA_SOUND_FLAG_DECODE \ - | MA_SOUND_FLAG_STREAM \ - /*| MA_SOUND_FLAG_NO_PITCH \*/ + // | MA_SOUND_FLAG_DECODE // | MA_SOUND_FLAG_STREAM // | MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT , NULL, NULL, &m_currentSound[layer]); - if (result != MA_SUCCESS) - qWarning("Failed to load file %s", file); - else { - m_mediaLoaded[layer] = true; - this->refreshValues(layer); - m_currentLayerValues[layer].media = file; + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to load file " << file << endl; + return result; } + result = ma_node_attach_output_bus(&m_currentSound[layer], 0, &g_lpfNode[audioDevice], 0); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to attach output bus " << audioDevice << endl; + //return result; + } + m_mediaLoaded[layer] = true; + this->refreshValues(layer); + m_currentLayerValues[layer].media = file; return result; } @@ -163,7 +299,7 @@ float MiniAudioEngine::getCursor(int layer) result = ma_sound_get_cursor_in_seconds(&m_currentSound[layer], &ret); if (result != MA_SUCCESS) { - qWarning("%i can not get cursor error %i", layer, result); + cout << "Error" << result << ": Can not get cursor " << layer << endl; ret = MA_ERROR; } return ret; @@ -177,11 +313,17 @@ ma_result MiniAudioEngine::printFormatInfo(int layer) if (m_mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; - ma_result result = ma_sound_get_data_format(&m_currentSound[layer], &format, &channels, &sampleRate, NULL, 0); - if (result != MA_SUCCESS) - qWarning("%i failed to get data format %i\n", layer, result); - else - qInfo() << "Layer:" << layer << m_currentLayerValues[layer].media << "samples/sec:" << sampleRate << "format:" << format << "channels:" << channels; + ma_result result = ma_sound_get_data_format(&m_currentSound[layer], \ + &format, &channels, &sampleRate, NULL, 0); + if (result != MA_SUCCESS) { + cout << "Error" << result << ": Failed to get data format " << layer; + cout << endl; + } else { + cout << "Layer: " << layer; + cout << m_currentLayerValues[layer].media.toLatin1().data(); + cout << " samples/sec:" << sampleRate << " format:" << format; + cout << " channels:" << channels << endl; + } return result; } diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index b91d718..4f24ce7 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -9,7 +9,32 @@ #define MINIAUDIO_IMPLEMENTATION #include "miniaudio.h" #include "defines.h" // MAX_LAYERS -#include // prints messages +#include +using namespace std; + +/* Data Format */ +#define FORMAT ma_format_f32 /* Must always be f32. */ +#define CHANNELS 2 +#define SAMPLE_RATE 48000 + +typedef struct +{ + ma_node_base node; + ma_loshelf2 loShelfNode; + ma_peak2 midLowNode; + ma_peak2 midHighNode; + ma_hishelf2 hiShelfNode; + ma_splitter_node outputNode; +} filterBank; + +typedef struct +{ + ma_node_base input; + ma_data_source_node node; + ma_decoder decoder; + filterBank filters; +} soundNode; + class MiniAudioEngine { @@ -19,8 +44,13 @@ public: MiniAudioEngine(); void stopEngine(); bool startEngine(); - ma_result startDevice(uint id, uint internalId); - static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); + bool startDevice(uint *id, uint nb); + static void audioDataCallback1(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); + static void audioDataCallback2(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); + + ma_device m_device[MAX_AUDIODEVICES]; + ma_sound m_currentSound[MAX_LAYERS]; + ma_bool8 m_mediaLoaded[MAX_LAYERS]; protected: ma_result loadMedia(int layer, char *media, uint audioDevice); @@ -38,22 +68,19 @@ protected: inline bool getAtEnd(int layer) { return m_currentSound[layer].atEnd; } private: - ma_resource_manager_config resourceManagerConfig; - ma_resource_manager resourceManager; - ma_device_info* pPlaybackDeviceInfos; - ma_uint32 playbackDeviceCount; - ma_uint32 iChosenDevice; - ma_engine engine[MAX_AUDIODEVICES]; - ma_device device[MAX_AUDIODEVICES]; - ma_context context; - ma_sound m_currentSound[MAX_LAYERS]; - ma_bool8 m_mediaLoaded[MAX_LAYERS]; + ma_resource_manager_config m_resourceManagerConfig; + ma_resource_manager m_resourceManager; + ma_context m_context; + ma_device_info* m_pPlaybackDeviceInfos; + ma_uint32 m_playbackDeviceCount; + ma_uint32 m_devicesSelected; layerData m_currentLayerValues[MAX_LAYERS]; ma_result getAllAudioDevices(); ma_result startContext(); void refreshValues(int layer); ma_result seekToCursor(int layer, int cursor); + ma_result setNodeGraph(int id); }; #endif // MINIAUDIOENGINE_H From f87c908d300f93ec646a269d712d7fbfb38473f4 Mon Sep 17 00:00:00 2001 From: snt Date: Mon, 13 May 2024 02:22:34 +0200 Subject: [PATCH 4/7] wip filtros --- src/miniaudioengine.cpp | 139 ++++++++++------------------------------ src/miniaudioengine.h | 31 +++------ 2 files changed, 43 insertions(+), 127 deletions(-) diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index a0445c9..6e9c1c9 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -1,15 +1,9 @@ #include "miniaudioengine.h" -#define LPF_BIAS 0.9f /* Higher values means more bias towards the low pass filter (the low pass filter will be more audible). Lower values means more bias towards the echo. Must be between 0 and 1. */ -#define LPF_CUTOFF_FACTOR 80 /* High values = more filter. */ +#define LPF_BIAS 0.9f +#define LPF_CUTOFF_FACTOR 80 +#define HPF_CUTOFF_FACTOR 1 #define LPF_ORDER 8 -//static filterBank m_filterBank[MAX_LAYERS]; -//static ma_node_graph m_nodeGraph[MAX_LAYERS]; -//static soundNode m_soundNode[MAX_LAYERS]; - -static ma_lpf_node g_lpfNode[MAX_AUDIODEVICES]; -static ma_engine m_engine[MAX_AUDIODEVICES]; - MiniAudioEngine::MiniAudioEngine() { for (int i =0; i < MAX_LAYERS; i++) { @@ -22,7 +16,7 @@ MiniAudioEngine::MiniAudioEngine() } } -void MiniAudioEngine::audioDataCallback1(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) +void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { (void)pInput; (void)pDevice; @@ -33,18 +27,6 @@ void MiniAudioEngine::audioDataCallback1(ma_device* pDevice, void* pOutput, cons } } -void MiniAudioEngine::audioDataCallback2(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 << "2"; - } -} - void MiniAudioEngine::stopEngine() { for (uint i = 0; i < m_devicesSelected; i++) { @@ -69,68 +51,38 @@ bool MiniAudioEngine::startEngine() ma_result MiniAudioEngine::setNodeGraph(int id) { ma_result result; - //ma_node_graph_config nodeGraphConfig = ma_node_graph_config_init(CHANNELS); - //result = ma_node_graph_init(&nodeGraphConfig, NULL, &m_nodeGraph[id]); - //if (result != MA_SUCCESS) { - // cout << "ERROR " << result << ": Failed to initialize node graph."; - // return MA_ERROR; - //} -/* - ma_loshelf2_config losConfig = ma_loshelf2_config_init(FORMAT, CHANNELS, SAMPLE_RATE, 1, 0.5, 83.3); // double gainDB, double shelfSlope, double frequency) - result = ma_loshelf2_init(&losConfig, NULL, &m_filterBank[id].loShelfNode); - if (result != MA_SUCCESS) { - cout << "Error " << result << ": Can not init loShelf node." << endl; - return result; - } - ma_engine m; - ma_node_graph *ng = (ma_node_graph *)(&m_engine[id]); - ma_node *node = ma_node_graph_get_endpoint(ng); - node = ma_engine_get_endpoint(&m_engine[id]); - ma_node_base nodeBase = ng->endpoint; - result = ma_node_attach_output_bus(&m_filterBank[id].loShelfNode, 0, &nodeBase, 0); - //result = ma_node_attach_output_bus(&m_filterBank[id].loShelfNode, 0, ma_engine_get_endpoint(engine), 0); - if (result != MA_SUCCESS) { - cout << "Error " << result << ": Can not attach filter to graph endpoint." << endl; - return result; - }*/ -/* - ma_splitter_node_config splitterConfig = ma_splitter_node_config_init(ma_engine_get_channels(&engine[0])); - result = ma_splitter_node_init(ng, &splitterConfig, NULL, &m_filterBank[layer].outputNode); - if (result != MA_SUCCESS) { - cout << "Can not init splitter node." << endl; - return result; - } - result = ma_node_attach_output_bus(&m_filterBank[layer].loShelfNode, 0, &m_filterBank[layer].outputNode, 0); - if (result != MA_SUCCESS) { - cout << "Can not attach loShelf to output." << endl; - return result; - } - result = ma_node_attach_output_bus(&m_filterBank[layer].outputNode, 0, ma_node_graph_get_endpoint(ng), 0); - if (result != MA_SUCCESS) { - cout << "Can not attach splitter to graph endpoint." << endl; - return result; - } - }*/ - /* Low Pass Filter. */ 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, &g_lpfNode[id]); + result = ma_lpf_node_init(ng, &lpfNodeConfig, NULL, &m_filterBank[id].lpfNode); 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]); - result = ma_node_attach_output_bus(&g_lpfNode[id], 0, endpoint, 0); + // 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); + 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); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to attach low pass filter node." << endl; return result; } - result = ma_node_set_output_bus_volume(&g_lpfNode[id], 0, LPF_BIAS); + // ToDo: add peak filters + result = ma_node_attach_output_bus(&m_filterBank[id].hpfNode, 0, endpoint, 0); if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to set volume low pass filter node." << endl; + cout << "ERROR " << result << ": Failed to attach low pass filter node." << endl; return result; } - ma_node_set_state(&g_lpfNode[id], ma_node_state::ma_node_state_started); +/* + result = ma_node_set_state(&m_filterBank[id].lpfNode, ma_node_state::ma_node_state_started); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to set state to filter node." << endl; + return result; + }*/ return (result); } @@ -147,10 +99,7 @@ bool MiniAudioEngine::startDevice(uint *systemId, uint nb) deviceConfig.playback.format = m_resourceManager.config.decodedFormat; deviceConfig.playback.channels = 0; deviceConfig.sampleRate = m_resourceManager.config.decodedSampleRate; - if (internalId == 0) - deviceConfig.dataCallback = audioDataCallback1; - else - deviceConfig.dataCallback = audioDataCallback2; + deviceConfig.dataCallback = audioDataCallback; deviceConfig.pUserData = &m_engine[internalId]; result = ma_device_init(&m_context, &deviceConfig, &m_device[internalId]); if (result != MA_SUCCESS) { @@ -209,7 +158,7 @@ ma_result MiniAudioEngine::getAllAudioDevices() result = ma_context_get_devices(&m_context, &m_pPlaybackDeviceInfos, &m_playbackDeviceCount, NULL, NULL); if (result != MA_SUCCESS) { - cout << "Error" << result << ": Failed to enumerate playback devices." << endl; + cout << "Error " << result << ": Failed to enumerate playback devices." << endl; ma_context_uninit(&m_context); return result; } @@ -224,51 +173,29 @@ 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 if (m_mediaLoaded[layer] == true) { ma_sound_uninit(&m_currentSound[layer]); m_mediaLoaded[layer] = false; } -/* - ma_sound_config soundConfig = ma_sound_config_init(); - soundConfig = ma_sound_config_init(); - soundConfig.pFilePath = file; - soundConfig.pInitialAttachment = &m_filterBank[layer].loShelfNode; - soundConfig.initialAttachmentInputBusIndex = 0; - soundConfig.channelsIn = 0; - soundConfig.channelsOut = CHANNELS; - //soundConfig.monoExpansionMode; - soundConfig.flags = MA_SOUND_FLAG_NO_SPATIALIZATION; - // | MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT; - //| MA_SOUND_FLAG_STREAM | MA_SOUND_FLAG_NO_PITCH - soundConfig.volumeSmoothTimeInPCMFrames = 480; - //soundConfig.initialSeekPointInPCMFrames; - //soundConfig.rangeBegInPCMFrames; - //soundConfig.rangeEndInPCMFrames; - //soundConfig.loopPointBegInPCMFrames; - //soundConfig.loopPointEndInPCMFrames; - //soundConfig.isLooping; - //soundConfig.endCallback; - //soundConfig.pEndCallbackUserData; - - result = ma_sound_init_ex(&m_engine[audioDevice], &soundConfig, &m_currentSound[layer]); - if (result != MA_SUCCESS) { - cout << "Error" << result << ": Failed to load file " << file << endl; - return result; - }*/ result = ma_sound_init_from_file(&m_engine[audioDevice], file, \ MA_SOUND_FLAG_NO_SPATIALIZATION \ - // | MA_SOUND_FLAG_DECODE // | MA_SOUND_FLAG_STREAM // | MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT , NULL, NULL, &m_currentSound[layer]); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to load file " << file << endl; return result; } - result = ma_node_attach_output_bus(&m_currentSound[layer], 0, &g_lpfNode[audioDevice], 0); + result = ma_node_attach_output_bus(&m_currentSound[layer], 0, &m_filterBank[audioDevice].lpfNode, 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; @@ -316,10 +243,10 @@ ma_result MiniAudioEngine::printFormatInfo(int layer) ma_result result = ma_sound_get_data_format(&m_currentSound[layer], \ &format, &channels, &sampleRate, NULL, 0); if (result != MA_SUCCESS) { - cout << "Error" << result << ": Failed to get data format " << layer; + cout << "Error " << result << ": Failed to get data format " << layer; cout << endl; } else { - cout << "Layer: " << layer; + cout << "Layer:" << layer << " "; cout << m_currentLayerValues[layer].media.toLatin1().data(); cout << " samples/sec:" << sampleRate << " format:" << format; cout << " channels:" << channels << endl; diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 4f24ce7..fec6c07 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -19,23 +19,12 @@ using namespace std; typedef struct { - ma_node_base node; - ma_loshelf2 loShelfNode; - ma_peak2 midLowNode; - ma_peak2 midHighNode; - ma_hishelf2 hiShelfNode; - ma_splitter_node outputNode; + ma_hpf_node hpfNode; + ma_lpf_node lpfNode; + ma_peak_node midLowNode; + ma_peak_node midHighNode; } filterBank; -typedef struct -{ - ma_node_base input; - ma_data_source_node node; - ma_decoder decoder; - filterBank filters; -} soundNode; - - class MiniAudioEngine { friend class libreMediaServerAudio; @@ -45,12 +34,7 @@ public: void stopEngine(); bool startEngine(); bool startDevice(uint *id, uint nb); - static void audioDataCallback1(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); - static void audioDataCallback2(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); - - ma_device m_device[MAX_AUDIODEVICES]; - ma_sound m_currentSound[MAX_LAYERS]; - ma_bool8 m_mediaLoaded[MAX_LAYERS]; + static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); protected: ma_result loadMedia(int layer, char *media, uint audioDevice); @@ -74,7 +58,12 @@ private: ma_device_info* m_pPlaybackDeviceInfos; ma_uint32 m_playbackDeviceCount; ma_uint32 m_devicesSelected; + ma_device m_device[MAX_AUDIODEVICES]; + ma_sound m_currentSound[MAX_LAYERS]; + ma_bool8 m_mediaLoaded[MAX_LAYERS]; layerData m_currentLayerValues[MAX_LAYERS]; + filterBank m_filterBank[MAX_LAYERS]; + ma_engine m_engine[MAX_AUDIODEVICES]; ma_result getAllAudioDevices(); ma_result startContext(); From 352513328704e4b36e4ab060c9740aa7a18a8648 Mon Sep 17 00:00:00 2001 From: snt Date: Tue, 14 May 2024 20:49:28 +0200 Subject: [PATCH 5/7] 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 From 3244ea2abcee1cb65af7051e29091dd4b804bc92 Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 15 May 2024 00:16:49 +0200 Subject: [PATCH 6/7] =?UTF-8?q?cambio=20la=20configuraci=C3=B3n=20del=20ba?= =?UTF-8?q?nco=20de=20filtros=20a=20la=20de=20SSL.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/dmxPersonality.h | 22 ++--- src/libremediaserver-audio.cpp | 3 +- src/miniaudioengine.cpp | 158 ++++++++++++++++++++++----------- src/miniaudioengine.h | 14 +-- 4 files changed, 128 insertions(+), 69 deletions(-) diff --git a/src/dmxPersonality.h b/src/dmxPersonality.h index a9977d8..b083ae6 100644 --- a/src/dmxPersonality.h +++ b/src/dmxPersonality.h @@ -1,19 +1,19 @@ #ifndef DMXPERSONALITY_H #define DMXPERSONALITY_H -#define VOLUME_COARSE 3 -#define PAN 6 #define DMX_FOLDER 0 #define DMX_FILE 1 -#define PLAYBACK 8 #define VOLUME_FINE 2 -#define ENTRY_POINT_COARSE 5 +#define VOLUME_COARSE 3 #define ENTRY_POINT_FINE 4 +#define ENTRY_POINT_COARSE 5 +#define PAN 6 #define PITCH 7 -#define VOL1 9 -#define VOL2 10 -#define LOW_FREQ 11 -#define LOW_Q 12 +#define PLAYBACK 8 +#define HP_FREQ 9 +#define LOW_FREQ 10 +#define LOW_Q 11 +#define LOW_GAIN 12 #define MIDLOW_FREQ 13 #define MIDLOW_Q 14 #define MIDLOW_GAIN 15 @@ -22,7 +22,9 @@ #define MIDHIGH_GAIN 18 #define HIGH_FREQ 19 #define HIGH_Q 20 - -#define LAYER_CHANNELS 21 +#define HIGH_GAIN 21 +#define SEND1 22 +#define SEND2 23 +#define LAYER_CHANNELS 24 #endif // DMXPERSONALITY_H diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index d516e6c..07ab9a8 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -140,9 +140,8 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) m_played.append(m_ola->getValue(layer, DMX_FILE)); } #endif - } else if (channel >= LOW_FREQ) { + } else if (channel >= HP_FREQ && channel <= HIGH_GAIN) { m_mae.filterParamChanged(layer, m_dmxSettings.at(layer).audioDevice, channel, value); - } } #ifndef NOGUI diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 01e274a..9dbd3c8 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -1,10 +1,8 @@ #include "miniaudioengine.h" #include "dmxPersonality.h" -#define LPF_BIAS 0.9f -#define FILTER_ORDER 2 -#define LPF_CUTOFF_FACTOR 2 -#define HPF_CUTOFF_FACTOR 20 +#define BIAS 0.99f +#define FILTER_ORDER 3 MiniAudioEngine::MiniAudioEngine() {} @@ -26,9 +24,11 @@ void MiniAudioEngine::stopEngine() 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_loshelf_node_uninit(&m_filterBank[i][j].loshelf, NULL); ma_peak_node_uninit(&m_filterBank[i][j].mLow, NULL); ma_peak_node_uninit(&m_filterBank[i][j].mHigh, NULL); + ma_hishelf_node_uninit(&m_filterBank[i][j].hishelf, NULL); + ma_splitter_node_uninit(&m_filterBank[i][j].output, NULL); } ma_engine_uninit(&m_engine[i]); ma_device_uninit(&m_device[i]); @@ -57,7 +57,6 @@ bool MiniAudioEngine::startEngine(uint layers) return true; } -// lpf -> hpf -> mLow -> mHigh -> engine ma_result MiniAudioEngine::createFilterBank(int id, uint layer) { ma_result result; @@ -66,52 +65,76 @@ ma_result MiniAudioEngine::createFilterBank(int id, uint layer) 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_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); + fb->hpfConfig = ma_hpf_node_config_init(CHANNELS, SAMPLE_RATE, 16, FILTER_ORDER); + result = ma_hpf_node_init(ng, &fb->hpfConfig, NULL, &fb->hpf); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to initialize high pass filter node." << endl; return result; } - 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); + + fb->loshelfConfig = ma_loshelf_node_config_init(CHANNELS, SAMPLE_RATE, 0.0f, 1.0f, 30); + result = ma_loshelf_node_init(ng, &fb->loshelfConfig, NULL, &fb->loshelf); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to initialize low pass filter node." << endl; + return result; + } + + fb->mLowConfig = ma_peak_node_config_init(CHANNELS, SAMPLE_RATE, 0.0, 4.0, 200); // double gainDB, double q, double frequency); + result = ma_peak_node_init(ng, &fb->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); + + fb->mHighConfig = ma_peak_node_config_init(CHANNELS, SAMPLE_RATE, 0.0, 0.0, 600); // double gainDB, double q, double frequency); + result = ma_peak_node_init(ng, &fb->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); + + fb->hishelfConfig = ma_hishelf_node_config_init(CHANNELS, SAMPLE_RATE, 0.0f, 1.0f, 20000); + result = ma_hishelf_node_init(ng, &fb->hishelfConfig, NULL, &fb->hishelf); if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to attach low pass filter node." << endl; + cout << "ERROR " << result << ": Failed to initialize hi shelf filter node." << endl; return result; } - result = ma_node_attach_output_bus(&fb->hpf, 0, &fb->mLow, 0); + + ma_splitter_node_config splitterConfig = ma_splitter_node_config_init(CHANNELS); + result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->output); if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to attach Mid Low pass filter node." << endl; + cout << "ERROR " << result << ": Failed to initialize output node." << endl; + return result; + } + + result = ma_node_attach_output_bus(&fb->hpf, 0, &fb->loshelf, 0); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach high pass pass filter node." << endl; + return result; + } + result = ma_node_attach_output_bus(&fb->loshelf, 0, &fb->mLow, 0); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach low shelf filter node." << endl; return result; } result = ma_node_attach_output_bus(&fb->mLow, 0, &fb->mHigh, 0); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach low peaks filter node." << endl; + return result; + } + result = ma_node_attach_output_bus(&fb->mHigh, 0, &fb->hishelf, 0); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to attach high peaks filter node." << endl; return result; } - result = ma_node_attach_output_bus(&fb->mHigh, 0, endpoint, 0); + result = ma_node_attach_output_bus(&fb->hishelf, 0, &fb->output, 0); if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to attach high peaks filter node." << endl; + cout << "ERROR " << result << ": Failed to attach high shelf filter node." << endl; + return result; + } + result = ma_node_attach_output_bus(&fb->output, 0, endpoint, 0); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach output node to engine." << endl; return result; } return result; @@ -233,7 +256,7 @@ 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][layer].lpf, 0); + result = ma_node_attach_output_bus(&m_currentSound[layer], 0, &m_filterBank[audioDevice][layer].hpf, 0); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to attach output bus " << audioDevice << endl; //return result; @@ -406,64 +429,97 @@ ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int ch 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 (channel == HP_FREQ) { + fb->hpfConfig.hpf.cutoffFrequency = double((value * 1.31) + 16.0f); // 16 - 350 + result = ma_hpf_node_reinit(&fb->hpfConfig.hpf, &fb->hpf); if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to set frecuency Low filter node." << endl; + cout << "ERROR " << result << ": Failed to set frecuency high pass 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); + } else if (channel == LOW_FREQ) { + fb->loshelfConfig.loshelf.frequency = 30 + (value * 1.647); // 30 - 450 + result = ma_loshelf_node_reinit(&fb->loshelfConfig.loshelf, &fb->loshelf); if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to set frecuency High filter node." << endl; + cout << "ERROR " << result << ": Failed to set frecuency low shelf filter node." << endl; + return result; + } + } else if (channel == LOW_Q) { + fb->loshelfConfig.loshelf.shelfSlope = (double)(value / 32.0f) + 0.1f; // 0.1 - 8 + result = ma_loshelf_node_reinit(&fb->loshelfConfig.loshelf, &fb->loshelf); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed set Q low shelf filter node." << endl; + return result; + } + } else if (channel == LOW_GAIN) { + fb->loshelfConfig.loshelf.gainDB = (double)(value / 21.25f) - 6.023528412f; + result = ma_loshelf_node_reinit(&fb->loshelfConfig.loshelf, &fb->loshelf); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed set gain low shelf 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); + fb->mLowConfig.peak.frequency = 200 + (value * 9.019607843); // 200 - 450 + result = ma_peak_node_reinit(&fb->mLowConfig.peak, &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); + fb->mLowConfig.peak.q = (double)( value / 64.0f) + 0.10; // 0.1 - 4 + result = ma_peak_node_reinit(&fb->mLowConfig.peak, &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); + fb->mLowConfig.peak.gainDB = (double)(value / 7.0833333333333f) - 18.0f; + result = ma_peak_node_reinit(&fb->mLowConfig.peak, &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); + fb->mHighConfig.peak.frequency = 600 + (value * 25.09803922); // 600 - 7000 + result = ma_peak_node_reinit(&fb->mHighConfig.peak, &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); + fb->mHighConfig.peak.q = (double)( value / 64.0f) + 0.10; // 0.1 - 4 + result = ma_peak_node_reinit(&fb->mHighConfig.peak, &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); + fb->mHighConfig.peak.gainDB = (double)(value / 7.0833333333333f) - 18.0f; + result = ma_peak_node_reinit(&fb->mHighConfig.peak, &fb->mHigh); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to set gain Mid High filter node." << endl; return result; } + } else if (channel == HIGH_FREQ) { + fb->hishelfConfig.hishelf.frequency = 1500 + (value * 56.8627451); // 1500 - 16000 + result = ma_hishelf_node_reinit(&fb->hishelfConfig.hishelf, &fb->hishelf); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to frecuency high shelf filter node." << endl; + return result; + } + } else if (channel == HIGH_Q) { + fb->hishelfConfig.hishelf.shelfSlope = (double)( value / 32.0f) + 0.1f; + result = ma_hishelf_node_reinit(&fb->hishelfConfig.hishelf, &fb->hishelf); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed set Q high shelf filter node." << endl; + return result; + } + } else if (channel == HIGH_GAIN) { + fb->hishelfConfig.hishelf.gainDB = (double)(value / 21.25) - 6.023528412f; + result = ma_hishelf_node_reinit(&fb->hishelfConfig.hishelf, &fb->hishelf); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed set gain high shelf filter node." << endl; + return result; + } } return (result); } diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index d5d798b..332c1bf 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -20,14 +20,16 @@ using namespace std; typedef struct { ma_hpf_node hpf; - ma_hpf_config hpfConfig; - ma_lpf_node lpf; - ma_lpf_config lpfConfig; + ma_hpf_node_config hpfConfig; + ma_loshelf_node loshelf; + ma_loshelf_node_config loshelfConfig; ma_peak_node mLow; - ma_peak_config mLowConfig; + ma_peak_node_config mLowConfig; ma_peak_node mHigh; - ma_notch_node notch; - ma_peak_config mHighConfig; + ma_peak_node_config mHighConfig; + ma_hishelf_node hishelf; + ma_hishelf_node_config hishelfConfig; + ma_splitter_node output; } filterBank; From 7bc339dfe334265b87060de00aa296eca249ef97 Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 15 May 2024 01:25:44 +0200 Subject: [PATCH 7/7] =?UTF-8?q?a=C3=B1adidos=20filtros?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/LibreMediaServer_Audio.hed | 168 +++++++++++++++++--------------- 1 file changed, 91 insertions(+), 77 deletions(-) diff --git a/docs/LibreMediaServer_Audio.hed b/docs/LibreMediaServer_Audio.hed index fda3e2d..1598cab 100644 --- a/docs/LibreMediaServer_Audio.hed +++ b/docs/LibreMediaServer_Audio.hed @@ -1,79 +1,93 @@ ް׆ˌĠ򝤫鿰맫͓Ԕ -ҊÅЁ䍡 +ҊÅЁ䍡 ӽ -Ꭸʆ -ɑ -ɬ -򉇁 -Ԑɉ - -ٿդϨ҃ -񀠧ڔ -ڑŌ -򻴧 - - - - - - - - -쏎ބ -힇ݳ - -Ԓlj - -Ŷ§ -ÐŽÊ -𡭟Ē - -܊ -񢰽 -зм -񓎍 -ҭ -ܻۏ -ڑן -ޏ - -Ƴ - - - -Ǖ - -𓎍Ԏ - - -Ξ -ֆ - -ց - -ᱯ -݈ - -؈ - -馹 -۴ -𓎍 - - - - - -𓎑 - - - -Ɨ - - - -Ӌ -쏎 - - - +͌وГ +䩴؍ + + +ǁ + +ήƵ +ꂨ⑯ɞɅ +ˆ +㨥 +פ + +Θב +˻ + +ūî +䈍 +п +¥߸ڋ +Ĩ© +勌㊈ +͹ +ˢ݈ +ɢƢ +񍒍Й +˟ + +ǔ +檵 +Ӡ̧׀ +ꗪㄮϞѝ +ᯠ쫶 +ϼȡ嵶 +ᄨڍ֟ + +ڱ +񔸼񣏎 +ڔ + + +֐ + +̽ɤ +甯؞τ + + + + + + +𣇒 +Ԇ + +䷩ +ߍ + + + + + + + + + + +܂ +쏎 +מ + + +Ӽ + + + + + + + + + + +͚ʝǓ + + + +ݽ + + + +