From 7aea8f6cf1490c524c11f537f513e937be5de9d7 Mon Sep 17 00:00:00 2001 From: snt Date: Sat, 20 Apr 2024 20:19:16 +0200 Subject: [PATCH 01/49] WIP miniaudio working, some sigsev while playing... --- docs/changelog.txt | 22 ++-- docs/compiling.txt | 4 +- docs/lms-audio.xlm | 3 +- docs/roadmap.txt | 42 ++++---- libremediaserver-audio.pro | 13 ++- src/audiolayerwidget.cpp | 179 +++++++++++++++++++-------------- src/audiolayerwidget.h | 44 +++----- src/audiomasterwidget.cpp | 12 +-- src/audiomasterwidget.h | 2 +- src/audiowidget.cpp | 126 ++++++++++++++++++++--- src/audiowidget.h | 25 ++++- src/defines.h | 9 +- src/libremediaserver-audio.cpp | 91 ++++++++--------- src/libremediaserver-audio.h | 15 +-- src/libremediaserver-audio.ui | 8 +- src/main.cpp | 9 +- src/medialibrary.cpp | 25 ++--- src/medialibrary.h | 1 + src/settings.cpp | 5 + src/settings.h | 12 ++- src/settingsdialog.cpp | 56 +++++++++-- src/settingsdialog.h | 5 + src/settingsdialog.ui | 60 ++++++----- 23 files changed, 469 insertions(+), 299 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 4ecb84b..d019bb8 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -1,18 +1,14 @@ ******************************************************************************* Libre Media Server Audio - An Open source Media Server for arts and performing. -(c) Santiago Noreña 2012-2024 -Code: https://git.criptomart.net/libremediaserver +(c) Criptomart - Santiago Noreña 2012-2024 +https://git.criptomart.net/libremediaserver ******************************************************************************* Lbre Media Server ChangeLog -v 0.1.3 (28/05/2024) - -+ Ubuntu 22.04 jammy. -+ Use SFML as audio engine. -+ Qt 5.15.3. -+ pitch. -+ loop. +v 1.4 +- change engine to miniaudio. +- Select sound device output. - pan. - Show faders values. --> Hacer UI por fader: mute/centrado, valor, visualizador: @@ -20,6 +16,14 @@ v 0.1.3 (28/05/2024) - SettingsDialog. - Load/save conf file. +v 0.1.3 (19/04/2024) + ++ Ubuntu 22.04 jammy. ++ Use SFML as audio engine. ++ Qt 5.15.3. ++ pitch. ++ loop. + v 0.1.2 (12/08/2015) - GUI config diff --git a/docs/compiling.txt b/docs/compiling.txt index d44317b..0648d90 100644 --- a/docs/compiling.txt +++ b/docs/compiling.txt @@ -1,6 +1,6 @@ ******************************************************************************* -Libre Media Server Audio - An Open source Media Server. -(c) Santiago Noreña 2014-2024 +Libre Media Server Audio - An Open source Media Server for arts and performing. +(c) Criptomart - Santiago Noreña 2012-2024 https://git.criptomart.net/libremediaserver ******************************************************************************* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. diff --git a/docs/lms-audio.xlm b/docs/lms-audio.xlm index 37e53c9..49aac0e 100644 --- a/docs/lms-audio.xlm +++ b/docs/lms-audio.xlm @@ -1,5 +1,6 @@ - + + diff --git a/docs/roadmap.txt b/docs/roadmap.txt index 4dde0af..91b9a4b 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -1,15 +1,18 @@ ******************************************************************************* Libre Media Server Audio - An Open source Media Server for arts and performing. -(c) Santiago Noreña 2012-2024 -Code: https://git.criptomart.net/libremediaserver +(c) Criptomart - Santiago Noreña 2012-2024 +https://git.criptomart.net/libremediaserver ******************************************************************************* Libre Media Server Roadmap -(or a whislist...) +(en continuo crecimiento...) -v 0.2.1 +v 0.2.x - skin, UI/UX - live input. +- insertar/bypass/eliminar audio procesadores sin reiniciar por capa y master. (compresor, equs). +- FX en capas master para que se puedan usar como envíos de auxiliar. +- Enroutado de masters en otros masters (retorno de efectos). v 0.2.0 - Use sACN directly. @@ -17,15 +20,13 @@ v 0.2.0 + hay que empaquetar OLA, incluirlo en el binario, o implementar sACN y linkarlo estáticamente. + https://github.com/ETCLabs/sACN - Qt6. -- audio processing (eq, rev, compresor, ...). +- audio processing (eq, rev, compresor, ...) por master y capa. - CIPT/MSex, send icons play-pause-stop. - Rasp build. - Octopus Sound Card support (6 outputs - 8 inputs). v 1.5 -- Select sound device output. -- Multi device output, router layers to devices and audio outputs. - - Jack/pipewire integration? +- Multi devices output. - Rose noise and sine generator in menu to test system. - Play Mode: - Play all medias found in folder consecutevily or random, with loop. @@ -34,18 +35,19 @@ v 1.5 - loop points. - play offset. ¿stop offset? - number of layers configured in conf file, up to 256. -- Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante. -- Master Layer: - - Mute. - - Pan. +- Master Bus Layer: + - each layer will have one "Gain" prefader that acts in source, "Vol" in v 1.3. + - each layer will have one volume dmx channel for each bus layer. One aux "Send" prefader. + - mute/panic. + - fader + value + - pan. + - magicq .hed + - audio device linked, outputs will be redirected there. + - dmx address + universe settings. - Keyboards strokes, select files from ui. +- Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante. - LOGs y entrada de comandos. - Bufgix: depurar errores cuando no carga la librería de medias, cambia el númmero de capas, cambia el universo, etc. - -v 1.4 -- pan. -- Show faders values. - --> Hacer UI por fader: mute/centrado, valor, visualizador: - --> Hacer UI con la visualización de tiempos. -- SettingsDialog. -- Load/save conf file. +- Refactor AudioMasterWidget to AudioDMXReceptionWidget. Master functions will be in AudioWidget. +- New control mode without pitch control, it saves resources. MA_SOUND_FLAG_NO_PITCH +- Vumeter or indicator about audio output in layer and master. diff --git a/libremediaserver-audio.pro b/libremediaserver-audio.pro index e3c5816..5e1f73f 100644 --- a/libremediaserver-audio.pro +++ b/libremediaserver-audio.pro @@ -2,6 +2,7 @@ TEMPLATE = app TARGET = libremediaserver-audio QT += webkitwidgets widgets HEADERS += src/libremediaserver-audio.h \ + src/miniaudio.h \ src/medialibrary.h \ src/olathread.h \ src/audiolayerwidget.h \ @@ -13,6 +14,7 @@ HEADERS += src/libremediaserver-audio.h \ src/settingsdialog.h \ src/layersettingswidget.h SOURCES += src/main.cpp \ + src/miniaudio.c \ src/libremediaserver-audio.cpp \ src/medialibrary.cpp \ src/olathread.cpp \ @@ -25,12 +27,13 @@ SOURCES += src/main.cpp \ FORMS += src/libremediaserver-audio.ui \ src/settingsdialog.ui \ src/layersettingswidget.ui -LIBS += -lola -lolacommon +CCFLAG += -msse2 -mavx2 #-fsanitize=address -g -O0 +QMAKE_CXXFLAGS += $$(CXXFLAG) +#QMAKE_CXXFLAGS += -fsanitize=address -g -O0 +QMAKE_CFLAGS += $$(CCFLAG) +QMAKE_LFLAGS += $$(LDFLAG) +LIBS += -lola -lolacommon -ldl -lpthread -lm # -lcitp -LIBS += -L$$PWD/SFML/lib/ -lsfml-audio -lsfml-system -INCLUDEPATH += $$PWD/SFML/include -DEPENDPATH += $$PWD/SFML/include -PRE_TARGETDEPS += $$PWD/SFML/lib/libsfml-audio.so $$PWD/SFML/lib/libsfml-system.so OTHER_FILES += \ LICENSE.txt \ docs/compiling.txt \ diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index a989031..90735c4 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -1,31 +1,20 @@ #include "audiolayerwidget.h" -#include - -#include -#include -#include -#include AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name): QGroupBox(parent) , m_suspendResumeButton(0) - , m_watchDMX(new QTimer(this)) - , m_currentMedia(" ") - , m_running(false) + , m_refreshGUI(new QTimer(this)) + , m_currentMedia("") + , m_mediaLoaded(false) { - this->setTitle(name); - QVBoxLayout *layout = new QVBoxLayout; QHBoxLayout *status = new QHBoxLayout; m_statusLabel = new QLabel; m_statusLabel->setText(STATUS_LABEL); m_statusValue = new QLabel; -// m_receiveDMX = new QCheckBox("Receiving DMX", this); -// m_receiveDMX->setChecked(false); -// status->addWidget(m_receiveDMX); status->addWidget(m_statusLabel); status->addWidget(m_statusValue); m_loopCheck = new QCheckBox(); @@ -58,8 +47,8 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name): m_volumeLabel = new QLabel; m_volumeLabel->setText(tr(VOLUME_LABEL)); m_volumeSlider = new QSlider(Qt::Horizontal); - m_volumeSlider->setMinimum(0); - m_volumeSlider->setMaximum(90); + m_volumeSlider->setMinimum(-100); + m_volumeSlider->setMaximum(100); m_volumeSlider->setSingleStep(1); m_volumeIndicator = new QLabel; volumeBox->addWidget(m_volumeLabel, 0, 0); @@ -111,13 +100,8 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name): progressTime->addWidget(m_totalTimeValue); layout->addLayout(progressTime); - QHBoxLayout *progressSlider = new QHBoxLayout; - m_progressLabel = new QLabel; - m_progressLabel->setText(PROGRESS_LABEL); m_progressSlider = new QSlider(Qt::Horizontal); - progressSlider->addWidget(m_progressLabel); - progressSlider->addWidget(m_progressSlider); - layout->addLayout(progressSlider); + layout->addWidget(m_progressSlider); m_suspendResumeButton = new QPushButton(this); m_suspendResumeButton->setText(tr(SUSPEND_LABEL)); @@ -125,12 +109,8 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name): layout->addWidget(m_suspendResumeButton); this->setLayout(layout); - - connect(m_watchDMX, SIGNAL(timeout()), - this, SLOT(refreshGUI())); - m_watchDMX->start(100); - - m_music.setAttenuation(0); + connect(m_refreshGUI, SIGNAL(timeout()), this, SLOT(refreshGUI())); + m_refreshGUI->start(100); } AudioLayerWidget::~AudioLayerWidget() @@ -140,36 +120,42 @@ AudioLayerWidget::~AudioLayerWidget() void AudioLayerWidget::volumeChanged(int value) { - m_music.setVolume(value); + float result; + + if (m_mediaLoaded == false) + return; + result = ma_volume_linear_to_db(value); + ma_sound_group_set_volume(¤tSound, result); } void AudioLayerWidget::panChanged(int value) { - m_music.setRelativeToListener(true); - sf::Vector3f pos = m_music.getPosition(); - //m_music.setSpati(0, 0, 0); - qreal pan = (value - 128) / 64.0f; - qWarning("change pan %f", pan); - //m_music.setPosition(pan, 0.0, sqrtf(1.0 + pan*pan)); - m_music.setPosition(pan, 0.0f, -1.0f); - //pos = m_music.getPosition(); - qWarning("%f %f %f", pos.x, pos.y, pos.z); - qWarning("is rel %i", m_music.isRelativeToListener()); + float result; + if (m_mediaLoaded == false) + return; + result = (value / 128.0) - 128; + ma_sound_group_set_pan(¤tSound, result); } void AudioLayerWidget::pitchChanged(int value) { - m_music.setPitch(qreal(value / 128.0 )); + float result; + if (m_mediaLoaded == false) + return; + result = (value / 128.0) - 128; + ma_sound_group_set_pitch(¤tSound, result); } void AudioLayerWidget::loopChanged(int value) { - m_music.setLoop(value); + if (m_mediaLoaded == false) + return; + ma_sound_set_looping(¤tSound, value); } void AudioLayerWidget::setVol(qreal vol) { - m_music.setVolume(vol); + this->volumeChanged(vol); m_volumeSlider->blockSignals(true); m_volumeSlider->setValue(vol); m_volumeIndicator->setText(QString::number(vol)); @@ -186,7 +172,7 @@ void AudioLayerWidget::setPan(qreal pan) void AudioLayerWidget::setPitch(qreal pitch) { - m_music.setPitch(float(pitch / 128 )); + this->pitchChanged(pitch); m_pitchSlider->blockSignals(true); m_pitchSlider->setValue(pitch); m_pitchSlider->blockSignals(false); @@ -194,6 +180,12 @@ void AudioLayerWidget::setPitch(qreal pitch) void AudioLayerWidget::loadMedia(QString file) { + ma_result result; + ma_format *format = 0; + ma_uint32 *channels = 0; + ma_uint32 *sampleRate = 0; + + if (m_currentMedia.compare(file) == 0 ) { return; } @@ -201,21 +193,46 @@ void AudioLayerWidget::loadMedia(QString file) qWarning("Can not access to file %s", file.toLatin1().constData()); return; } - // Load an ogg music file - if (!m_music.openFromFile(file.toStdString())) { - qWarning("Can not open file %s", file.toLatin1().constData()); + ma_engine engine = AudioWidget::getInstance()->getEngine(); + if (currentSound.ownsDataSource == true) + { + ma_sound_uninit(¤tSound); + } + result = ma_sound_init_from_file(&engine, file.toLatin1(), MA_SOUND_FLAG_NO_SPATIALIZATION | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM, NULL, NULL, ¤tSound); + if (result != MA_SUCCESS) { + qWarning("WARNING: Failed to load sound %s", file.toLatin1().constData()); return; } - m_currentMedia = file; - durationChanged(m_music.getDuration().asMilliseconds()); + float pLength = this->getDuration(); + result = ma_sound_get_data_format(¤tSound, format, channels, sampleRate, NULL, 0); + if (result != MA_SUCCESS) { + qWarning("WARNING: Failed to get data format %s", file.toLatin1().constData()); + return; + } + m_mediaLoaded = true; + durationChanged(pLength * 1000); fileLoaded(file); - // Display music informations std::cout << "File loaded: " << file.toLatin1().constData() << " : " << std::endl; - std::cout << " " << m_music.getDuration().asSeconds() << " seconds"; - std::cout << " " << m_music.getSampleRate() << " samples / sec"; - std::cout << " " << m_music.getChannelCount() << " channels" << std::endl; + std::cout << " " << pLength << " seconds"; + std::cout << " -- " << sampleRate << " samples/sec"; + std::cout << " -- " << format << " format"; + std::cout << " -- " << channels << " channels" << std::endl; +} + +float AudioLayerWidget::getDuration() +{ + float pLength; + + if (m_mediaLoaded == false) + return 0; + ma_result result = ma_sound_get_length_in_seconds(¤tSound, &pLength); + if (result != MA_SUCCESS) { + qWarning("WARNING: Failed to get total duration %s", m_currentMedia.toLatin1().constData()); + return 0; + } + return pLength; } void AudioLayerWidget::fileLoaded(QString file) @@ -236,56 +253,66 @@ void AudioLayerWidget::durationChanged(qint64 dur) void AudioLayerWidget::play(bool loop) { - m_music.play(); - m_music.setLoop(loop); + if (m_mediaLoaded == false) + return; + ma_sound_set_looping(¤tSound, loop); + ma_sound_start(¤tSound); m_loopCheck->blockSignals(true); - m_loopCheck->setChecked(m_music.getLoop()); + m_loopCheck->setChecked(loop); m_loopCheck->blockSignals(false); } void AudioLayerWidget::pause() { - m_music.pause(); + if (m_mediaLoaded == false) + return; + ma_sound_stop(¤tSound); } void AudioLayerWidget::stop() { - m_music.stop(); + if (m_mediaLoaded == false) + return; + ma_sound_stop(¤tSound); + ma_sound_seek_to_pcm_frame(¤tSound, 0); + m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(0)); + m_statusValue->setText(STOP_LABEL); + m_suspendResumeButton->setText(tr(STOP_LABEL)); + m_progressSlider->setValue(0); } void AudioLayerWidget::refreshGUI() { -// m_receiveDMX->setChecked(false); - int progress; - switch (m_music.getStatus()) { - case sf::SoundSource::Playing: - progress = m_music.getPlayingOffset().asMilliseconds(); + float progress; + + if (m_mediaLoaded == false) + return; + if (currentSound.ownsDataSource == 0) + return; + switch (ma_sound_is_playing(¤tSound)) { + case true: + ma_sound_get_cursor_in_seconds(¤tSound, &progress); + progress *= 1000; m_progressSlider->setValue(progress); m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(progress)); m_statusValue->setText(PLAY_LABEL); m_suspendResumeButton->setText(tr(SUSPEND_LABEL)); break; - case sf::SoundSource::Paused: + case false: m_statusValue->setText(PAUSE_LABEL); m_suspendResumeButton->setText(tr(RESUME_LABEL)); break; - case sf::SoundSource::Stopped: - m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(0)); - m_statusValue->setText(STOP_LABEL); - m_suspendResumeButton->setText(tr(RESUME_LABEL)); - m_progressSlider->setValue(0); - break; } - //m_loopCheck->blockSignals(true); - //m_loopCheck->setChecked(m_music.getLoop()); - //m_loopCheck->blockSignals(false); } void AudioLayerWidget::toggleSuspendResume() { - if (m_music.getStatus() == sf::SoundSource::Playing) { - m_music.pause(); + if (m_mediaLoaded == false) + return; + if (ma_sound_is_playing(¤tSound)) { + this->pause(); } else { - m_music.play(); + if (ma_sound_at_end(¤tSound)) + ma_sound_seek_to_pcm_frame(¤tSound, 0); + ma_sound_start(¤tSound); } } - diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index 2d214d2..7362bd6 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -1,22 +1,25 @@ #ifndef AUDIOLAYERWIDGET_H #define AUDIOLAYERWIDGET_H -#include +#include +#include +#include +#include #include +#include +#include #include #include #include #include -#include #include #include #include -#include -#include - #include "defines.h" +#include "audiowidget.h" +#include "miniaudio.h" class AudioLayerWidget : public QGroupBox { @@ -32,20 +35,8 @@ public: * @param file name with full path */ void loadMedia(QString file); - - /** - * @brief play - */ void play(bool loop); - - /** - * @brief stop - */ void stop(); - - /** - * @brief pause - */ void pause(); /** @@ -53,20 +44,11 @@ public: * @param vol volume range 0 -100 */ void setVol(qreal vol); - - /** - * @brief resume - */ void resume(); - void setPan(qreal pan); - void setPitch(qreal pitch); - void setLoop(bool on); - //void setEntryPoint(qreal entry); - //void setEndPoint(qreal end); public slots: @@ -120,14 +102,12 @@ private: QLabel * m_folderLabel; QLabel * m_folderValue; - //QCheckBox *m_receiveDMX; - QTimer *m_watchDMX; - + QTimer *m_refreshGUI; QString m_currentMedia; + ma_sound currentSound; + ma_bool8 m_mediaLoaded; - bool m_running; - - sf::Music m_music; + float getDuration(); private slots: diff --git a/src/audiomasterwidget.cpp b/src/audiomasterwidget.cpp index 4d0f1bb..c8a2db1 100644 --- a/src/audiomasterwidget.cpp +++ b/src/audiomasterwidget.cpp @@ -1,22 +1,12 @@ #include "audiomasterwidget.h" -#include - AudioMasterWidget::AudioMasterWidget(QWidget *parent) : QGroupBox(parent) - //, m_file(new QLabel) - //, m_folder(new QLabel) - //, m_vol(new QSlider) - //, m_mute(new QCheckBox) - //, m_status(new QLabel) , m_receiveDMX(new QCheckBox) , m_watchDMX(new QTimer) { QVBoxLayout *vbox = new QVBoxLayout; - //vbox->addWidget(m_status); - //vbox->addWidget(m_vol); - //vbox->addWidget(m_mute); - m_receiveDMX->setText("Receiving DMX"); + m_receiveDMX->setText("DMX signal"); vbox->addWidget(m_receiveDMX); this->setLayout(vbox); connect(m_watchDMX, SIGNAL(timeout()), diff --git a/src/audiomasterwidget.h b/src/audiomasterwidget.h index 4df388c..bdac3e5 100644 --- a/src/audiomasterwidget.h +++ b/src/audiomasterwidget.h @@ -6,7 +6,7 @@ #include #include #include - +#include //#include "ui_audiomasterwidget.h" diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index 1d7ddc8..f4cf44f 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -1,4 +1,5 @@ #include "audiowidget.h" +#include "miniaudio.c" AudioWidget *AudioWidget::_instance = 0; @@ -11,30 +12,117 @@ AudioWidget *AudioWidget::getInstance() { return _instance; } -AudioWidget::AudioWidget() +AudioWidget::AudioWidget() : + engineCount(0) { + this->startEngine(); layout = new QHBoxLayout(); for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) { - layout->insertWidget(i, new AudioLayerWidget(this, tr("Layer %1").arg(i))); + layout->insertWidget(i, new AudioLayerWidget(this, tr("Layer %1").arg(i + 1))); } setLayout(layout); -// qDebug( "Init AudioWidget"); +} + +void data_callback(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 AudioWidget::startEngine(int n) +{ + this->startContext(); + this->startDevice(n); +} + +void AudioWidget::startDevice(int id) +{ + ma_result result; + ma_device_config deviceConfig; + ma_engine_config engineConfig; + + deviceConfig = ma_device_config_init(ma_device_type_playback); + deviceConfig.playback.pDeviceID = &pPlaybackDeviceInfos[id].id; + deviceConfig.playback.format = resourceManager.config.decodedFormat; + deviceConfig.playback.channels = 0; + deviceConfig.sampleRate = resourceManager.config.decodedSampleRate; + deviceConfig.dataCallback = data_callback; + deviceConfig.pUserData = &engines[engineCount]; + result = ma_device_init(&context, &deviceConfig, &devices[engineCount]); + if (result != MA_SUCCESS) { + qCritical("Failed to initialize audio device %s.", pPlaybackDeviceInfos[id].name); + return; + } + engineConfig = ma_engine_config_init(); + engineConfig.pDevice = &devices[engineCount]; + engineConfig.pResourceManager = &resourceManager; + engineConfig.noAutoStart = MA_TRUE; + result = ma_engine_init(NULL, &engines[engineCount]); + if (result != MA_SUCCESS) { + qCritical("Failed to initialize audio engine."); + return; + } + result = ma_engine_start(&engines[engineCount]); + if (result != MA_SUCCESS) { + qCritical("Failed to start audio engine %d.", engineCount); + } + //engineCount +=1; + iChosenDevice = id; + qInfo("Initialized audio device %d: %s", id, pPlaybackDeviceInfos[id].name); +} + +void AudioWidget::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 = 0; + resourceManagerConfig.jobThreadCount = 0; + result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager); + if (result != MA_SUCCESS) { + qCritical("Failed to initialize audio resource manager."); + return; + } + result = ma_context_init(NULL, 0, NULL, &context); + if (result != MA_SUCCESS) { + qCritical("Failed to initialize audio context."); + return; + } +} + +void AudioWidget::startEngine() +{ + this->startContext(); + this->getAllAudioDevices(); + iChosenDevice = Settings::getInstance()->getAudioDeviceId(); + this->startDevice(iChosenDevice); +} + +ma_engine AudioWidget::getEngine() +{ + return(engines[engineCount]); +} + +void AudioWidget::stopEngine() +{ + ma_engine_uninit(&engines[engineCount]); + ma_device_uninit(&devices[engineCount]); + ma_context_uninit(&context); + ma_resource_manager_uninit(&resourceManager); } void AudioWidget::mediaLoaded(int layer, QString media) { QLayoutItem * const item = layout->itemAt(layer); dynamic_cast(item->widget())->loadMedia(media); -// qDebug() << "AudioWidget::mediaLoaded Received layer: " << layer -// << "Media: " << media; } void AudioWidget::volChanged(int layer, qreal vol) { QLayoutItem * const item = layout->itemAt(layer); dynamic_cast(item->widget())->setVol(vol); -// qDebug() << "AudioWidget::volChanged Received layer: " << layer -// << "Vol : " << vol; - } void AudioWidget::panChanged(int layer, qreal vol) { @@ -65,10 +153,20 @@ void AudioWidget::playbackChanged(int layer, Status status) break; } } -/* -void AudioWidget::layerReceived(int layer) -{ - QLayoutItem * const item = layout->itemAt(layer); - dynamic_cast(item->widget())->updateWatchDMX(true); -}*/ +// enum all audio devices in system +void AudioWidget::getAllAudioDevices() +{ + ma_result result; + + result = ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, NULL, NULL); + if (result != MA_SUCCESS) { + qCritical("Failed to enumerate playback devices."); + ma_context_uninit(&context); + return; + } + for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < playbackDeviceCount; iAvailableDevice += 1) { + qInfo("%d: : %s", iAvailableDevice, pPlaybackDeviceInfos[iAvailableDevice].name); + } + return ; +} diff --git a/src/audiowidget.h b/src/audiowidget.h index 2243a34..bf3c7c9 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -4,12 +4,14 @@ #include #include #include +#include + #include "audiomasterwidget.h" #include "audiolayerwidget.h" -#include "defines.h" #include "settings.h" +#include "miniaudio.h" +#include "defines.h" -#include "SFML/Audio/SoundSource.hpp" class AudioWidget : public QWidget { @@ -19,20 +21,37 @@ class AudioWidget : public QWidget public: + static AudioWidget *getInstance(); + ma_engine getEngine(); + void stopEngine(); + void startEngine(int id); + ma_device_info* pPlaybackDeviceInfos; + ma_uint32 playbackDeviceCount; + ma_uint32 iChosenDevice; + protected: - static AudioWidget *getInstance(); void mediaLoaded(int layer, QString media ); void volChanged(int layer, qreal vol); void panChanged(int layer, qreal pan); void pitchChanged(int layer, qreal pitch); void playbackChanged(int layer, Status status); + void startEngine(); private: static AudioWidget *_instance; AudioWidget(); QHBoxLayout *layout; + ma_engine engines[MAX_DEVICES]; + ma_uint32 engineCount; + ma_device devices[MAX_DEVICES]; + ma_context context; + ma_resource_manager_config resourceManagerConfig; + ma_resource_manager resourceManager; + void getAllAudioDevices(); + void startDevice(int id); + void startContext(); signals: diff --git a/src/defines.h b/src/defines.h index 961ec69..bc57975 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,7 +1,7 @@ #ifndef DEFINES_H #define DEFINES_H -#define VERSION "LibreMediaServer-Audio 0.1.3" +#define VERSION "LibreMediaServer-Audio 0.1.4" #define COPYRIGHT "(C) 2014-2024 Santi Norena lms@criptomart.net" #define LICENSE "GPL 3 License. See LICENSE.txt and credits.txt for details" @@ -9,11 +9,6 @@ #define DEFAULT_FILE "lms-audio.xlm" -const int DurationSeconds = 1; -const int ToneSampleRateHz = 600; -const int DataSampleRateHz = 44100; -const int BufferSize = 262144; - #define SUSPEND_LABEL "Pause playback" #define RESUME_LABEL "Resume playback" @@ -33,6 +28,8 @@ const int BufferSize = 262144; #define NOTIFY_INTERVAL 150 #define PULL_TIMER_INTERVAL 10 +#define MAX_DEVICES 16 +#define MAX_SOUNDS 4096 // struct where save the DMX settings for each layer struct dmxSetting { diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index d34abe9..0c223bc 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -1,7 +1,8 @@ /* - Libre Media Server - A Media Server Sotfware for stage and performing - Copyright (C) 2012-2024 Santi Noreña lms@criptomart.net + Libre Media Server Audio - An Open source Media Server for arts and performing. + (c) Criptomart - Santiago Noreña 2012-2024 + https://git.criptomart.net/libremediaserver This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,21 +20,16 @@ #include "libremediaserver-audio.h" -// QTextEdit * libreMediaServerAudio::textEdit = 0; libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) : QMainWindow(parent) { - Q_UNUSED(args); - ui.setupUi(this); - this->setWindowTitle(VERSION); + Q_UNUSED(args); + ui.setupUi(this); + this->setWindowTitle(VERSION); - // Lee la configuración por defecto - Settings::getInstance()->readFile(); - - // Inicia el objeto de conexión a ola - ola = new olaThread(); - Q_CHECK_PTR(ola); + Settings *set = Settings::getInstance(); + set->readFile(); /* if (args.contains("-log")) { // Inicia el widget Terminal @@ -54,43 +50,35 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) textEdit, SLOT(append(QString)), Qt::QueuedConnection); */ - this->setWindowTitle(VERSION); + this->setWindowTitle(VERSION); + qDebug() << VERSION; + qDebug() << COPYRIGHT; + qDebug() << LICENSE; -// qDebug() << QDate::currentDate().toString() << " "<< QTime::currentTime().toString(); - qDebug() << VERSION; - qDebug() << COPYRIGHT; - qDebug() << LICENSE; - - setCentralWidget(AudioWidget::getInstance()); - - // Inicia el widget Master. - amw = new AudioMasterWidget(this); - QDockWidget *topWidget = new QDockWidget(tr("Master"), this); - topWidget->setAllowedAreas(Qt::TopDockWidgetArea); - topWidget->setWidget(amw); - addDockWidget(Qt::TopDockWidgetArea, topWidget); - - // Conectamos los menus + // start audio engine + MediaLibrary::getInstance()->initMediaLibrary(); + setCentralWidget(AudioWidget::getInstance()); + amw = new AudioMasterWidget(this); + QDockWidget *topWidget = new QDockWidget(tr("Master"), this); + topWidget->setAllowedAreas(Qt::TopDockWidgetArea); + topWidget->setWidget(amw); + addDockWidget(Qt::TopDockWidgetArea, topWidget); + // ola setup + ola = new olaThread(); + Q_CHECK_PTR(ola); + connect(set, SIGNAL(registerUniverse(int)), ola, SLOT(registerUniverse(int))); + ola->registerUniverse(); // register now all the universes + ola->blockSignals(true); + connect(ola, SIGNAL (layerReceived()), amw, SLOT(updateWatchDMX())); + connect(ola, SIGNAL(dmxOutput(int, int, int)), this, SLOT(dmxInput(int, int, int))); + connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup())); + ola->start(QThread::TimeCriticalPriority ); + ola->blockSignals(false); + // menus connect(ui.actionOpen_conf, SIGNAL(triggered()), this, SLOT(openFile())); connect(ui.actionSave_conf, SIGNAL(triggered()), this, SLOT(saveFile())); connect(ui.action_Settings, SIGNAL(triggered()), this, SLOT(settings())); - connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup())); - - connect(Settings::getInstance(), SIGNAL( registerUniverse(int) ), - ola, SLOT( registerUniverse(int) ) ); - ola->registerUniverse(); // register now all the universes - ola->blockSignals(true); - connect(ola, SIGNAL (layerReceived()), - amw, SLOT(updateWatchDMX())); - - // Inicia la media Library - MediaLibrary::getInstance()->initMediaLibrary(); - - // Inicia la lectura de datos DMX - ola->start(QThread::TimeCriticalPriority ); - ola->blockSignals(false); - connect(ola, SIGNAL( dmxOutput(int, int, int) ), - this, SLOT( dmxInput(int, int, int) ) ); + connect(set, SIGNAL(audioDeviceChanged(int)), this, SLOT(audioDeviceChanged(int))); qDebug("Init Complete"); } @@ -101,8 +89,7 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) libreMediaServerAudio::~libreMediaServerAudio() { ola->stop(); -// qDebug() << QDate::currentDate() << QTime::currentTime(); -// qDebug() << "********************************************************************************"; + AudioWidget::getInstance()->stopEngine(); } /////////////////////////////////////////////////////////////////// @@ -174,11 +161,11 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) break; case VOLUME_COARSE: f = ( value * 0x100 ) + ola->getValue(layer, VOLUME_FINE); - AudioWidget::getInstance()->volChanged(layer, f / 655.35); + AudioWidget::getInstance()->volChanged(layer, (f / 655.35)); break; case VOLUME_FINE: f = ( ola->getValue(layer, VOLUME_COARSE) * 0x100 ) + value; - AudioWidget::getInstance()->volChanged(layer, f / 655.35); + AudioWidget::getInstance()->volChanged(layer, (f / 655.35)); break; case PAN: AudioWidget::getInstance()->panChanged(layer, value); @@ -208,3 +195,9 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) break; } } + +void libreMediaServerAudio::audioDeviceChanged(int id) +{ + AudioWidget::getInstance()->stopEngine(); + AudioWidget::getInstance()->startEngine(id); +} diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index babed0e..ea88afe 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -1,6 +1,7 @@ /* - Libre Media Server - A Media Server Sotfware for stage and performing - Copyright (C) 2012-2014 Santiago Noreña libremediaserver@gmail.com + Libre Media Server Audio - An Open source Media Server for arts and performing. + (c) Criptomart - Santiago Noreña 2012-2024 + https://git.criptomart.net/libremediaserver This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,17 +27,17 @@ #include #include #include - +#include #include #include -#include "medialibrary.h" #include "audiowidget.h" -#include "settings.h" +#include "medialibrary.h" #include "olathread.h" +#include "settings.h" #include "audiomasterwidget.h" -#include "defines.h" #include "settingsdialog.h" +#include "defines.h" #include "ui_libremediaserver-audio.h" @@ -70,7 +71,7 @@ private: void save(QFile *file); public slots: -// inline void toTerminal(QString msg) { textEdit->append(msg); } + void audioDeviceChanged(int id); private slots: diff --git a/src/libremediaserver-audio.ui b/src/libremediaserver-audio.ui index b4cec80..3256e49 100644 --- a/src/libremediaserver-audio.ui +++ b/src/libremediaserver-audio.ui @@ -7,8 +7,8 @@ 0 0 - 126 - 89 + 199 + 218 @@ -20,8 +20,8 @@ 0 0 - 126 - 29 + 199 + 22 diff --git a/src/main.cpp b/src/main.cpp index 4797866..c82efa8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,8 @@ /* - Libre Media Server - A media server for audio playback in stage arts - controlled by lingting protocols (DMX, ArtNet, ACN,...) - Copyright (C) 2015-2024 Santi Noreña lms@criptomart.net + Libre Media Server Audio - An Open source Media Server for arts and performing. + (c) Criptomart - Santiago Noreña 2012-2024 + https://git.criptomart.net/libremediaserver This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,9 +18,6 @@ along with this program. If not, see . */ -#include -//#include -//#include #include "libremediaserver-audio.h" // Handler for pipe the stderr to a log file and texEdit diff --git a/src/medialibrary.cpp b/src/medialibrary.cpp index e196001..ee46837 100644 --- a/src/medialibrary.cpp +++ b/src/medialibrary.cpp @@ -1,7 +1,5 @@ #include "medialibrary.h" -#include - MediaLibrary *MediaLibrary::_instance = 0; MediaLibrary *MediaLibrary::getInstance() { @@ -20,7 +18,6 @@ MediaLibrary::MediaLibrary(QObject *parent) : } void MediaLibrary::initMediaLibrary() { - qDebug("starting the media library"); QDir dir; if (!dir.cd(Settings::getInstance()->getPathMedia())) { qWarning("Can not cd to the path: %s", Settings::getInstance()->getPathMedia().toLatin1().constData()); @@ -46,7 +43,7 @@ void MediaLibrary::initMediaLibrary() { } /** - * This set every media file included in one library/folder + * fill the struct with all files in one library/folder */ QList MediaLibrary::getMediaInformation(QDir dir) { @@ -60,31 +57,27 @@ QList MediaLibrary::getMediaInformation(QDir dir) // Update the data base with the new file mediainf.Number = i; mediainf.MediaName = fileInfo.absoluteFilePath(); - mediainf.MediaLength = 1000; // ¿?¿?¿?¿? + mediainf.MediaLength = 1000; mediaList.append(mediainf); } return mediaList; } -/** Selects one media path from the library - * +/** + * returns the path to a media file from the library. */ - QString MediaLibrary::requestNewFile(int folder, int file){ - // Select one mediafile from the media library if (!m_media) { - qWarning("Media Library not init. Set a correct path to medias library"); + qWarning("MediaLibrary is not init. Set a correct path to media library"); return NULL; } QString newfile; if (folder < m_media->size()) { if (file < m_media->at(folder).m_MediaInformation.size()) { newfile = m_media->at(folder).m_MediaInformation.at(file).MediaName; - } else { - qDebug("MediaLibrary::requestNewFile(): Requested file is greater than files in library"); - } - } else { - qDebug("MediaLibrary::requestNewFile(): Requested folder is greater than media libraries"); - } + } else + qInfo("requestNewFile: Requested file %i is greater than files in library %i", file, m_media->at(folder).m_MediaInformation.size()); + } else + qInfo("requestNewFile: Requested folder %i is greater than media libraries %i", folder, m_media->size()); return newfile; } diff --git a/src/medialibrary.h b/src/medialibrary.h index 2f69234..e6b0b79 100644 --- a/src/medialibrary.h +++ b/src/medialibrary.h @@ -3,6 +3,7 @@ #include #include +#include #include "defines.h" #include "settings.h" diff --git a/src/settings.cpp b/src/settings.cpp index c328237..10485d1 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -28,6 +28,7 @@ void Settings::setPathMedia(QString path) // - The number of sources/layers controlled by DMX // - The first DMX channel of each source/layer // - The universe to bind in OLA +// - Audio device id void Settings::readFromFile(QString file) { QFile* xmlFile = new QFile(file); if (!xmlFile->open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -58,6 +59,10 @@ void Settings::readFromFile(QString file) { continue; } } + if(xmlReader->name() == "audioDevice") { + m_audioDeviceId = xmlReader->attributes().value("id").toLocal8Bit().toInt(); + continue; + } QString add = "layer"; add.append(QString("%1").arg(counter)); if((xmlReader->name() == add)) { diff --git a/src/settings.h b/src/settings.h index 990b3ca..f1c8eec 100644 --- a/src/settings.h +++ b/src/settings.h @@ -8,6 +8,7 @@ #include #include "medialibrary.h" +#include "audiowidget.h" #include "defines.h" /** @@ -96,6 +97,11 @@ public: else m_layersNumber = LAYERS_NUMBER; } + + inline int getAudioDeviceId() { return m_audioDeviceId; } + inline void setAudioDeviceId(int id) { m_audioDeviceId = id; } + + private: static Settings *_instance; @@ -106,6 +112,9 @@ private: // The path to media library QString m_pathmedia; + // The SO audio device id used + uint m_audioDeviceId; + /** Constructor * */ @@ -153,8 +162,7 @@ signals: */ void registerUniverse(int universe); -public slots: - + void audioDeviceChanged(int id); }; #endif // SETTINGS_H diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 98904d7..e5b8de7 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -2,18 +2,20 @@ #include "ui_settingsdialog.h" SettingsDialog::SettingsDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::SettingsDialog) + QDialog(parent) + , ui(new Ui::SettingsDialog) + , m_deviceDialog(NULL) { ui->setupUi(this); this->setWindowTitle("Settings"); ui->layersNumber->setValue(Settings::getInstance()->getLayersNumber()); - QString path("Path to root folder of the media tree: /n"); - path.append(Settings::getInstance()->getPathMedia()); - ui->mediaPath->setText(path); - - connect(ui->mediaPatchButton, SIGNAL(clicked()), + //QString path("Path to root folder of the media tree: /n"); + //path.append(Settings::getInstance()->getPathMedia()); + //ui->mediaPath->setText(path); + connect(ui->mediaPathButton, SIGNAL(clicked()), this, SLOT(changeMediaPath())); + connect(ui->audioDeviceButton , SIGNAL(clicked()), + this, SLOT(changeAudioDevice())); connect(ui->layersNumber, SIGNAL(valueChanged(int)), this, SLOT(layersChanged(int))); int layer = 0; @@ -42,7 +44,45 @@ void SettingsDialog::changeMediaPath() QString file = fileNames.at(0); Settings::getInstance()->setPathMedia(file); QString desc = tr("Media Path Changed to: %1").arg(file); - qDebug("%s", desc.toLatin1().constData()); + qInfo("%s", desc.toLatin1().constData()); +} + +void SettingsDialog::changeAudioDevice() +{ + if (!m_deviceDialog) + { + m_deviceDialog = new QDialog( this ); + } + QLabel *msgLabel = new QLabel; + AudioWidget *aw = AudioWidget::getInstance(); + QString *msg = new QString; + for (uint iAvailableDevice = 0; iAvailableDevice < aw->playbackDeviceCount; iAvailableDevice += 1) { + msg->append(tr("%1 : %2\n").arg(iAvailableDevice).arg(aw->pPlaybackDeviceInfos[iAvailableDevice].name)); + } + msgLabel->setText(msg->toLatin1()); + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(msgLabel); + QSpinBox *res = new QSpinBox; + res->setRange(0, aw->playbackDeviceCount); + res->setValue(AudioWidget::getInstance()->iChosenDevice); + layout->addWidget(res); + QPushButton *closeButton = new QPushButton(tr("Close")); + connect(closeButton, SIGNAL(clicked()), this, SLOT(closeAudioDeviceDialog())); + closeButton->setDefault(true); + layout->addWidget(closeButton); + m_deviceDialog->setLayout(layout); + m_deviceDialog->setModal(true); + m_deviceDialog->show(); +} + +void SettingsDialog::closeAudioDeviceDialog() +{ + QLayoutItem * const item = m_deviceDialog->layout()->itemAt(1); + int value = dynamic_cast(item->widget())->value(); + Settings::getInstance()->setAudioDeviceId(value); + qInfo("device selected: %i", value); + m_deviceDialog->close(); + emit Settings::getInstance()->audioDeviceChanged(value); } void SettingsDialog::layersChanged(int val) diff --git a/src/settingsdialog.h b/src/settingsdialog.h index b4c7acc..665c465 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -21,11 +21,16 @@ public: private slots: void changeMediaPath(); + void changeAudioDevice(); + void closeAudioDeviceDialog(); + private: Ui::SettingsDialog *ui; + QDialog *m_deviceDialog; private slots: void layersChanged(int val); + }; #endif // SETTINGSDIALOG_H diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 6b5aaa2..325e5b7 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -7,7 +7,7 @@ 0 0 400 - 429 + 563 @@ -16,9 +16,9 @@ - 290 - 390 - 101 + 10 + 530 + 381 32 @@ -26,14 +26,14 @@ Qt::Horizontal - QDialogButtonBox::Close + QDialogButtonBox::Cancel|QDialogButtonBox::Ok 10 - 40 + 50 52 31 @@ -63,8 +63,8 @@ - 60 - 40 + 70 + 50 111 21 @@ -73,25 +73,12 @@ Layers Number - + 10 10 - 371 - 21 - - - - TextLabel - - - - - - 200 - 40 - 191 + 171 31 @@ -108,14 +95,33 @@ - 9 - 99 - 381 - 281 + 0 + 80 + 401 + 451 + + + + 210 + 10 + 181 + 31 + + + + Change Audio Device + + + false + + + false + + -- 2.39.5 From 521f1fc6d7be4e16aa2178596ff6bb342a7da43b Mon Sep 17 00:00:00 2001 From: snt Date: Mon, 22 Apr 2024 19:14:49 +0200 Subject: [PATCH 02/49] =?UTF-8?q?funcionando=20con=20dmx,=20controles=20Ui?= =?UTF-8?q?=20muestran=20info=20pero=20no=20act=C3=BAan=20sobre=20el=20son?= =?UTF-8?q?ido.=20Refactorizado=20todos=20lo=20m=C3=A9todos=20que=20intera?= =?UTF-8?q?ct=C3=BAan=20con=20el=20sonido=20a=20miniaudioengine?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libremediaserver-audio.pro | 2 + src/audiolayerwidget.cpp | 260 +++++++++++---------------------- src/audiolayerwidget.h | 108 ++++---------- src/audiomasterwidget.h | 13 +- src/audiowidget.cpp | 191 +++++++----------------- src/audiowidget.h | 37 ++--- src/defines.h | 28 ++-- src/libremediaserver-audio.cpp | 40 ++--- src/libremediaserver-audio.h | 48 ++---- src/miniaudioengine.cpp | 238 ++++++++++++++++++++++++++++++ src/miniaudioengine.h | 48 ++++++ src/settingsdialog.cpp | 4 +- 12 files changed, 516 insertions(+), 501 deletions(-) create mode 100644 src/miniaudioengine.cpp create mode 100644 src/miniaudioengine.h diff --git a/libremediaserver-audio.pro b/libremediaserver-audio.pro index 5e1f73f..d86932e 100644 --- a/libremediaserver-audio.pro +++ b/libremediaserver-audio.pro @@ -4,6 +4,7 @@ QT += webkitwidgets widgets HEADERS += src/libremediaserver-audio.h \ src/miniaudio.h \ src/medialibrary.h \ + src/miniaudioengine.h \ src/olathread.h \ src/audiolayerwidget.h \ src/dmxPersonality.h \ @@ -17,6 +18,7 @@ SOURCES += src/main.cpp \ src/miniaudio.c \ src/libremediaserver-audio.cpp \ src/medialibrary.cpp \ + src/miniaudioengine.cpp \ src/olathread.cpp \ src/audiolayerwidget.cpp \ src/audiowidget.cpp \ diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 90735c4..d62c165 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -4,59 +4,50 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name): QGroupBox(parent) , m_suspendResumeButton(0) - , m_refreshGUI(new QTimer(this)) - , m_currentMedia("") - , m_mediaLoaded(false) + , m_volumeIndicator(new QSpinBox) + , m_panIndicator(new QSpinBox) + , m_pitchIndicator(new QSpinBox) { this->setTitle(name); QVBoxLayout *layout = new QVBoxLayout; - QHBoxLayout *status = new QHBoxLayout; + QGridLayout *status = new QGridLayout; m_statusLabel = new QLabel; m_statusLabel->setText(STATUS_LABEL); m_statusValue = new QLabel; - status->addWidget(m_statusLabel); - status->addWidget(m_statusValue); - m_loopCheck = new QCheckBox(); - m_loopCheckLabel = new QLabel; - m_loopCheckLabel->setText("Loop"); - connect(m_loopCheck, SIGNAL(stateChanged(int)), this, SLOT(loopChanged(int))); - status->addWidget(m_loopCheck); - status->addWidget(m_loopCheckLabel); - layout->addLayout(status); - - QHBoxLayout *folderLoaded = new QHBoxLayout; + status->addWidget(m_statusLabel, 0, 0); + status->addWidget(m_statusValue, 0, 2); m_folderLabel = new QLabel; m_folderLabel->setText(FOLDER_LABEL); m_folderValue = new QLabel; m_folderValue->setMaximumWidth(200); - folderLoaded->addWidget(m_folderLabel); - folderLoaded->addWidget(m_folderValue); - layout->addLayout(folderLoaded); - - QHBoxLayout *fileLoaded = new QHBoxLayout; + status->addWidget(m_folderLabel, 1, 0); + status->addWidget(m_folderValue, 1, 1); m_fileLabel = new QLabel; m_fileLabel->setText(FILE_LABEL); m_fileValue = new QLabel; m_fileValue->setMaximumWidth(200); - fileLoaded->addWidget(m_fileLabel); - fileLoaded->addWidget(m_fileValue); - layout->addLayout(fileLoaded); + status->addWidget(m_fileLabel, 1, 2); + status->addWidget(m_fileValue, 1, 3); + layout->addLayout(status); QGridLayout *volumeBox = new QGridLayout; m_volumeLabel = new QLabel; m_volumeLabel->setText(tr(VOLUME_LABEL)); m_volumeSlider = new QSlider(Qt::Horizontal); - m_volumeSlider->setMinimum(-100); + m_volumeSlider->setMinimum(0); m_volumeSlider->setMaximum(100); m_volumeSlider->setSingleStep(1); - m_volumeIndicator = new QLabel; + m_volumeIndicator->setRange(0, 100); + m_volumeIndicator->setValue(0); + m_volumeIndicator->setMaximumWidth(40); + m_volumeIndicator->setButtonSymbols(QAbstractSpinBox::NoButtons); volumeBox->addWidget(m_volumeLabel, 0, 0); volumeBox->addWidget(m_volumeSlider, 0, 1); volumeBox->addWidget(m_volumeIndicator, 0, 2); connect(m_volumeSlider, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int))); connect(m_volumeSlider, &QSlider::valueChanged, this, [=] () { - m_volumeIndicator->setText(QString::number(m_volumeSlider->value())); + m_volumeIndicator->setValue(m_volumeSlider->value()); }); m_panLabel = new QLabel; m_panLabel->setText("Pan"); @@ -64,18 +55,34 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name): m_panSlider->setMinimum(0); m_panSlider->setMaximum(255); m_panSlider->setSingleStep(1); + m_panIndicator->setRange(0, 255); + m_panIndicator->setValue(128); + m_panIndicator->setMaximumWidth(40); + m_panIndicator->setButtonSymbols(QAbstractSpinBox::NoButtons); + connect(m_panSlider, &QSlider::valueChanged, this, [=] () { + m_panIndicator->setValue(m_panSlider->value()); + }); connect(m_panSlider, SIGNAL(valueChanged(int)), this, SLOT(panChanged(int))); volumeBox->addWidget(m_panLabel, 1, 0); volumeBox->addWidget(m_panSlider, 1, 1); + volumeBox->addWidget(m_panIndicator, 1, 2); m_pitchLabel = new QLabel; m_pitchLabel->setText("Pitch"); m_pitchSlider = new QSlider(Qt::Horizontal); m_pitchSlider->setMinimum(0); m_pitchSlider->setMaximum(255); m_pitchSlider->setSingleStep(1); + m_pitchIndicator->setRange(0, 255); + m_pitchIndicator->setValue(128); + m_pitchIndicator->setMaximumWidth(40); + m_pitchIndicator->setButtonSymbols(QAbstractSpinBox::NoButtons); + connect(m_pitchSlider, &QSlider::valueChanged, this, [=] () { + m_pitchIndicator->setValue(m_pitchSlider->value()); + }); connect(m_pitchSlider, SIGNAL(valueChanged(int)), this, SLOT(pitchChanged(int))); volumeBox->addWidget(m_pitchLabel, 2, 0); volumeBox->addWidget(m_pitchSlider, 2, 1); + volumeBox->addWidget(m_pitchIndicator, 2, 2); layout->addLayout(volumeBox); QHBoxLayout *progressTime = new QHBoxLayout; @@ -102,15 +109,12 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name): m_progressSlider = new QSlider(Qt::Horizontal); layout->addWidget(m_progressSlider); - m_suspendResumeButton = new QPushButton(this); m_suspendResumeButton->setText(tr(SUSPEND_LABEL)); connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume())); layout->addWidget(m_suspendResumeButton); this->setLayout(layout); - connect(m_refreshGUI, SIGNAL(timeout()), this, SLOT(refreshGUI())); - m_refreshGUI->start(100); } AudioLayerWidget::~AudioLayerWidget() @@ -118,123 +122,69 @@ AudioLayerWidget::~AudioLayerWidget() } +// From UI. void AudioLayerWidget::volumeChanged(int value) { - float result; - - if (m_mediaLoaded == false) - return; - result = ma_volume_linear_to_db(value); - ma_sound_group_set_volume(¤tSound, result); + (void)value; + // ToDo: call the audio engine } void AudioLayerWidget::panChanged(int value) { - float result; - if (m_mediaLoaded == false) - return; - result = (value / 128.0) - 128; - ma_sound_group_set_pan(¤tSound, result); + (void)value; + // ToDo: call the audio engine } void AudioLayerWidget::pitchChanged(int value) { - float result; - if (m_mediaLoaded == false) - return; - result = (value / 128.0) - 128; - ma_sound_group_set_pitch(¤tSound, result); + (void)value; + // ToDo: call the audio engine } void AudioLayerWidget::loopChanged(int value) { - if (m_mediaLoaded == false) - return; - ma_sound_set_looping(¤tSound, value); + (void)value; + // ToDo: call the audio engine } +void AudioLayerWidget::toggleSuspendResume() +{ + switch (m_status) { + case Status::PlayingLoop: + case Status::PlayingOnce: + this->setPlaybackStatus(Status::Paused); + case Status::Paused: + case Status::Stopped: + this->setPlaybackStatus(Status::PlayingOnce); + } + // ToDo: call the audio engine +} + +// from DMX signals void AudioLayerWidget::setVol(qreal vol) { - this->volumeChanged(vol); m_volumeSlider->blockSignals(true); m_volumeSlider->setValue(vol); - m_volumeIndicator->setText(QString::number(vol)); + m_volumeIndicator->setValue(vol); m_volumeSlider->blockSignals(false); } void AudioLayerWidget::setPan(qreal pan) { - this->panChanged(pan); m_panSlider->blockSignals(true); m_panSlider->setValue(pan); + m_panIndicator->setValue(pan); m_panSlider->blockSignals(false); } void AudioLayerWidget::setPitch(qreal pitch) { - this->pitchChanged(pitch); m_pitchSlider->blockSignals(true); m_pitchSlider->setValue(pitch); + m_pitchIndicator->setValue(pitch); m_pitchSlider->blockSignals(false); } -void AudioLayerWidget::loadMedia(QString file) -{ - ma_result result; - ma_format *format = 0; - ma_uint32 *channels = 0; - ma_uint32 *sampleRate = 0; - - - if (m_currentMedia.compare(file) == 0 ) { - return; - } - if (!QFile::exists(file)) { - qWarning("Can not access to file %s", file.toLatin1().constData()); - return; - } - ma_engine engine = AudioWidget::getInstance()->getEngine(); - if (currentSound.ownsDataSource == true) - { - ma_sound_uninit(¤tSound); - } - result = ma_sound_init_from_file(&engine, file.toLatin1(), MA_SOUND_FLAG_NO_SPATIALIZATION | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM, NULL, NULL, ¤tSound); - if (result != MA_SUCCESS) { - qWarning("WARNING: Failed to load sound %s", file.toLatin1().constData()); - return; - } - m_currentMedia = file; - float pLength = this->getDuration(); - result = ma_sound_get_data_format(¤tSound, format, channels, sampleRate, NULL, 0); - if (result != MA_SUCCESS) { - qWarning("WARNING: Failed to get data format %s", file.toLatin1().constData()); - return; - } - m_mediaLoaded = true; - durationChanged(pLength * 1000); - fileLoaded(file); - // Display music informations - std::cout << "File loaded: " << file.toLatin1().constData() << " : " << std::endl; - std::cout << " " << pLength << " seconds"; - std::cout << " -- " << sampleRate << " samples/sec"; - std::cout << " -- " << format << " format"; - std::cout << " -- " << channels << " channels" << std::endl; -} - -float AudioLayerWidget::getDuration() -{ - float pLength; - - if (m_mediaLoaded == false) - return 0; - ma_result result = ma_sound_get_length_in_seconds(¤tSound, &pLength); - if (result != MA_SUCCESS) { - qWarning("WARNING: Failed to get total duration %s", m_currentMedia.toLatin1().constData()); - return 0; - } - return pLength; -} - void AudioLayerWidget::fileLoaded(QString file) { QStringList list = file.split("/"); @@ -245,74 +195,40 @@ void AudioLayerWidget::fileLoaded(QString file) } } +void AudioLayerWidget::setPlaybackStatus(Status status) +{ + m_status = status; + if (status == Status::Stopped) + m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(0)); + QString tmp; + switch (status) { + case Status::Paused: + tmp.append("Paused"); + break; + case Status::PlayingLoop: + tmp.append("Playing Loop"); + break; + case Status::PlayingOnce: + tmp.append("Playing one"); + break; + case Status::Stopped: + tmp.append("Stopped"); + break; + } + m_statusValue->setText(tmp); + m_suspendResumeButton->setText(tmp); +} + void AudioLayerWidget::durationChanged(qint64 dur) { + dur *= 1000; m_progressSlider->setMaximum(dur); m_totalTimeValue->setTime(QTime::fromMSecsSinceStartOfDay(dur)); } -void AudioLayerWidget::play(bool loop) +void AudioLayerWidget::refreshUi(float progress) { - if (m_mediaLoaded == false) - return; - ma_sound_set_looping(¤tSound, loop); - ma_sound_start(¤tSound); - m_loopCheck->blockSignals(true); - m_loopCheck->setChecked(loop); - m_loopCheck->blockSignals(false); -} - -void AudioLayerWidget::pause() -{ - if (m_mediaLoaded == false) - return; - ma_sound_stop(¤tSound); -} - -void AudioLayerWidget::stop() -{ - if (m_mediaLoaded == false) - return; - ma_sound_stop(¤tSound); - ma_sound_seek_to_pcm_frame(¤tSound, 0); - m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(0)); - m_statusValue->setText(STOP_LABEL); - m_suspendResumeButton->setText(tr(STOP_LABEL)); - m_progressSlider->setValue(0); -} - -void AudioLayerWidget::refreshGUI() { - float progress; - - if (m_mediaLoaded == false) - return; - if (currentSound.ownsDataSource == 0) - return; - switch (ma_sound_is_playing(¤tSound)) { - case true: - ma_sound_get_cursor_in_seconds(¤tSound, &progress); - progress *= 1000; - m_progressSlider->setValue(progress); - m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(progress)); - m_statusValue->setText(PLAY_LABEL); - m_suspendResumeButton->setText(tr(SUSPEND_LABEL)); - break; - case false: - m_statusValue->setText(PAUSE_LABEL); - m_suspendResumeButton->setText(tr(RESUME_LABEL)); - break; - } -} - -void AudioLayerWidget::toggleSuspendResume() -{ - if (m_mediaLoaded == false) - return; - if (ma_sound_is_playing(¤tSound)) { - this->pause(); - } else { - if (ma_sound_at_end(¤tSound)) - ma_sound_seek_to_pcm_frame(¤tSound, 0); - ma_sound_start(¤tSound); - } + progress *= 1000; + m_progressSlider->setValue(progress); + m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(progress)); } diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index 7362bd6..e5270d5 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -4,9 +4,7 @@ #include #include -#include #include -#include #include #include #include @@ -16,117 +14,63 @@ #include #include #include +#include #include "defines.h" -#include "audiowidget.h" -#include "miniaudio.h" class AudioLayerWidget : public QGroupBox { Q_OBJECT public: - explicit AudioLayerWidget(QWidget *parent = 0, QString name = "Layer"); ~AudioLayerWidget(); - - /** - * @brief load a new media file - * @param file name with full path - */ - void loadMedia(QString file); - void play(bool loop); - void stop(); - void pause(); - - /** - * @brief set the Volume - * @param vol volume range 0 -100 - */ void setVol(qreal vol); void resume(); void setPan(qreal pan); void setPitch(qreal pitch); void setLoop(bool on); - //void setEntryPoint(qreal entry); - //void setEndPoint(qreal end); - -public slots: - - /** - * @brief connected with the button - */ - void toggleSuspendResume(); - - /** - * @brief Connected with the slider - * @param volume 0 -100 range - */ - void volumeChanged(int vol); - void panChanged(int vol); - void pitchChanged(int vol); - void loopChanged(int vol); + void setPlaybackStatus(Status status); + inline Status getPlaybackStatus() { return m_status; } private: - QPushButton *m_suspendResumeButton; QLabel *m_statusLabel; QLabel * m_statusValue; - - QLabel *m_volumeLabel; - QSlider *m_volumeSlider; - QLabel *m_volumeIndicator; - - QLabel *m_panLabel; - QSlider *m_panSlider; - - QLabel *m_pitchLabel; - QSlider *m_pitchSlider; - - QLabel *m_loopCheckLabel; - QCheckBox *m_loopCheck; - - QLabel * m_progressLabel; - QSlider *m_progressSlider; - - QLabel *m_progressTimeLabel; - QTimeEdit *m_progressTime; - - QLabel *m_totalTimeLabel; - QTimeEdit *m_totalTimeValue; - QLabel *m_fileLabel; QLabel *m_fileValue; - QLabel * m_folderLabel; QLabel * m_folderValue; - QTimer *m_refreshGUI; - QString m_currentMedia; - ma_sound currentSound; - ma_bool8 m_mediaLoaded; + QLabel *m_volumeLabel; + QSlider *m_volumeSlider; + QSpinBox *m_volumeIndicator; + QLabel *m_panLabel; + QSlider *m_panSlider; + QSpinBox *m_panIndicator; + QLabel *m_pitchLabel; + QSlider *m_pitchSlider; + QSpinBox *m_pitchIndicator; - float getDuration(); + QLabel * m_progressLabel; + QSlider *m_progressSlider; + QLabel *m_progressTimeLabel; + QTimeEdit *m_progressTime; + QLabel *m_totalTimeLabel; + QTimeEdit *m_totalTimeValue; -private slots: + Status m_status; - /** - * @brief Update the GUI elements with the name of the new file loaded - * @param file - */ +public slots: + void toggleSuspendResume(); + void volumeChanged(int vol); + void panChanged(int vol); + void pitchChanged(int vol); + void loopChanged(int vol); void fileLoaded(QString file); - - /** - * @brief Update the GUI elements with the duration of the new file loaded - * @param dur The duration of the track in miliseconds - */ void durationChanged(qint64 dur); - - /** - * @brief Update the variable elements in GUI - */ - void refreshGUI(); + void refreshUi(float progress); }; #endif // AUDIOLAYERWIDGET_H diff --git a/src/audiomasterwidget.h b/src/audiomasterwidget.h index bdac3e5..51218c8 100644 --- a/src/audiomasterwidget.h +++ b/src/audiomasterwidget.h @@ -8,14 +8,8 @@ #include #include -//#include "ui_audiomasterwidget.h" -/* -namespace Ui { -class AudioMasterWidget; -}*/ - -class AudioMasterWidget : public QGroupBox //, public Ui::AudioMasterWidget +class AudioMasterWidget : public QGroupBox { Q_OBJECT @@ -28,11 +22,6 @@ public slots: void updateWatchDMX(); private: - //QLabel *m_file; - //QLabel *m_folder; - //QSlider *m_vol; - //QCheckBox *m_mute; - //QLabel *m_status; QCheckBox *m_receiveDMX; QTimer *m_watchDMX; diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index f4cf44f..160182d 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -1,172 +1,91 @@ #include "audiowidget.h" -#include "miniaudio.c" -AudioWidget *AudioWidget::_instance = 0; - -AudioWidget *AudioWidget::getInstance() { - - if (_instance == 0) { - _instance = new AudioWidget(); - Q_CHECK_PTR(_instance); - } - return _instance; -} AudioWidget::AudioWidget() : - engineCount(0) + m_layout(new QHBoxLayout()) + , m_refreshUi(new QTimer(this)) { - this->startEngine(); - layout = new QHBoxLayout(); + for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) { - layout->insertWidget(i, new AudioLayerWidget(this, tr("Layer %1").arg(i + 1))); + m_layout->insertWidget(i, new AudioLayerWidget(this, tr("Layer %1").arg(i + 1))); } - setLayout(layout); + setLayout(m_layout); + connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); + m_refreshUi->start(UI_REFRESH_TIME); } -void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) +bool AudioWidget::startEngine(int id) { - (void)pInput; - //Do master audio processing before sending to device. - ma_engine_read_pcm_frames((ma_engine*)pDevice->pUserData, pOutput, frameCount, NULL); + return (m_mae.startEngine(id)); } -void AudioWidget::startEngine(int n) +bool AudioWidget::startEngine() { - this->startContext(); - this->startDevice(n); -} - -void AudioWidget::startDevice(int id) -{ - ma_result result; - ma_device_config deviceConfig; - ma_engine_config engineConfig; - - deviceConfig = ma_device_config_init(ma_device_type_playback); - deviceConfig.playback.pDeviceID = &pPlaybackDeviceInfos[id].id; - deviceConfig.playback.format = resourceManager.config.decodedFormat; - deviceConfig.playback.channels = 0; - deviceConfig.sampleRate = resourceManager.config.decodedSampleRate; - deviceConfig.dataCallback = data_callback; - deviceConfig.pUserData = &engines[engineCount]; - result = ma_device_init(&context, &deviceConfig, &devices[engineCount]); - if (result != MA_SUCCESS) { - qCritical("Failed to initialize audio device %s.", pPlaybackDeviceInfos[id].name); - return; - } - engineConfig = ma_engine_config_init(); - engineConfig.pDevice = &devices[engineCount]; - engineConfig.pResourceManager = &resourceManager; - engineConfig.noAutoStart = MA_TRUE; - result = ma_engine_init(NULL, &engines[engineCount]); - if (result != MA_SUCCESS) { - qCritical("Failed to initialize audio engine."); - return; - } - result = ma_engine_start(&engines[engineCount]); - if (result != MA_SUCCESS) { - qCritical("Failed to start audio engine %d.", engineCount); - } - //engineCount +=1; - iChosenDevice = id; - qInfo("Initialized audio device %d: %s", id, pPlaybackDeviceInfos[id].name); -} - -void AudioWidget::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 = 0; - resourceManagerConfig.jobThreadCount = 0; - result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager); - if (result != MA_SUCCESS) { - qCritical("Failed to initialize audio resource manager."); - return; - } - result = ma_context_init(NULL, 0, NULL, &context); - if (result != MA_SUCCESS) { - qCritical("Failed to initialize audio context."); - return; - } -} - -void AudioWidget::startEngine() -{ - this->startContext(); - this->getAllAudioDevices(); - iChosenDevice = Settings::getInstance()->getAudioDeviceId(); - this->startDevice(iChosenDevice); -} - -ma_engine AudioWidget::getEngine() -{ - return(engines[engineCount]); + return (m_mae.startEngine(Settings::getInstance()->getAudioDeviceId())); } void AudioWidget::stopEngine() { - ma_engine_uninit(&engines[engineCount]); - ma_device_uninit(&devices[engineCount]); - ma_context_uninit(&context); - ma_resource_manager_uninit(&resourceManager); + m_mae.stopEngine(); } -void AudioWidget::mediaLoaded(int layer, QString media) +void AudioWidget::mediaLoaded(int layer, QString file) { - QLayoutItem * const item = layout->itemAt(layer); - dynamic_cast(item->widget())->loadMedia(media); + ma_result result; + + if (m_currentMedia[layer].compare(file) == 0 ) { + return; + } + if (!QFile::exists(file)) { + qWarning("Can not access to file %s", file.toLatin1().constData()); + return; + } + result = m_mae.loadMedia(layer, file.toLatin1().data()); + if (result != MA_SUCCESS) { + qWarning("can not open file %s", file.toLatin1().constData()); + return; + } + m_currentMedia[layer] = file; + float pLength = m_mae.getDuration(layer); + qInfo("File loaded: %s - Duration: %f secs", file.toLatin1().constData(), pLength); + m_mae.printFormatInfo(layer); + QLayoutItem * const item = m_layout->itemAt(layer); + dynamic_cast(item->widget())->fileLoaded(file); + dynamic_cast(item->widget())->durationChanged(pLength); } void AudioWidget::volChanged(int layer, qreal vol) { - QLayoutItem * const item = layout->itemAt(layer); + m_mae.volChanged(layer, vol); + QLayoutItem * const item = m_layout->itemAt(layer); dynamic_cast(item->widget())->setVol(vol); } -void AudioWidget::panChanged(int layer, qreal vol) { - QLayoutItem * const item = layout->itemAt(layer); - dynamic_cast(item->widget())->setPan(vol); +void AudioWidget::panChanged(int layer, qreal pan) { + m_mae.panChanged(layer, pan); + QLayoutItem * const item = m_layout->itemAt(layer); + dynamic_cast(item->widget())->setPan(pan); } -void AudioWidget::pitchChanged(int layer, qreal vol) { - QLayoutItem * const item = layout->itemAt(layer); - dynamic_cast(item->widget())->setPitch(vol); +void AudioWidget::pitchChanged(int layer, qreal pitch) { + m_mae.pitchChanged(layer, pitch); + QLayoutItem * const item = m_layout->itemAt(layer); + dynamic_cast(item->widget())->setPitch(pitch); } void AudioWidget::playbackChanged(int layer, Status status) { - QLayoutItem * const item = layout->itemAt(layer); - switch (status) { - case PlayingOnce: - dynamic_cast(item->widget())->play(false); - break; - case Stopped: - dynamic_cast(item->widget())->stop(); - break; - case Paused: - dynamic_cast(item->widget())->pause(); - break; - case PlayingLoop: - dynamic_cast(item->widget())->play(true); - break; - } + m_mae.playbackChanged(layer, status); + QLayoutItem * const item = m_layout->itemAt(layer); + dynamic_cast(item->widget())->setPlaybackStatus(status); } -// enum all audio devices in system -void AudioWidget::getAllAudioDevices() -{ - ma_result result; - - result = ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, NULL, NULL); - if (result != MA_SUCCESS) { - qCritical("Failed to enumerate playback devices."); - ma_context_uninit(&context); - return; +void AudioWidget::refreshUi() { + for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) { + QLayoutItem * const item = m_layout->itemAt(i); + AudioLayerWidget *aw = dynamic_cast(item->widget()); + Status s = aw->getPlaybackStatus(); + if (s == Status::PlayingOnce || s == Status::PlayingLoop) { + aw->refreshUi(m_mae.getCursor(i)); + } } - for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < playbackDeviceCount; iAvailableDevice += 1) { - qInfo("%d: : %s", iAvailableDevice, pPlaybackDeviceInfos[iAvailableDevice].name); - } - return ; } diff --git a/src/audiowidget.h b/src/audiowidget.h index bf3c7c9..b35ecbd 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -9,7 +9,7 @@ #include "audiomasterwidget.h" #include "audiolayerwidget.h" #include "settings.h" -#include "miniaudio.h" +#include "miniaudioengine.h" #include "defines.h" @@ -20,43 +20,26 @@ class AudioWidget : public QWidget Q_OBJECT public: - - static AudioWidget *getInstance(); - ma_engine getEngine(); + AudioWidget(); + bool startEngine(); + bool startEngine(int id); void stopEngine(); - void startEngine(int id); - ma_device_info* pPlaybackDeviceInfos; - ma_uint32 playbackDeviceCount; - ma_uint32 iChosenDevice; protected: - void mediaLoaded(int layer, QString media ); void volChanged(int layer, qreal vol); void panChanged(int layer, qreal pan); void pitchChanged(int layer, qreal pitch); void playbackChanged(int layer, Status status); - void startEngine(); private: + MiniAudioEngine m_mae; + QString m_currentMedia[MAX_LAYERS]; + QHBoxLayout *m_layout; + QTimer *m_refreshUi; - static AudioWidget *_instance; - AudioWidget(); - QHBoxLayout *layout; - ma_engine engines[MAX_DEVICES]; - ma_uint32 engineCount; - ma_device devices[MAX_DEVICES]; - ma_context context; - ma_resource_manager_config resourceManagerConfig; - ma_resource_manager resourceManager; - void getAllAudioDevices(); - void startDevice(int id); - void startContext(); - -signals: - -public slots: - +private slots: + void refreshUi(); }; #endif // AUDIOWIDGET_H diff --git a/src/defines.h b/src/defines.h index bc57975..b34cf0c 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,40 +1,40 @@ #ifndef DEFINES_H #define DEFINES_H +#include +#include +#include + #define VERSION "LibreMediaServer-Audio 0.1.4" #define COPYRIGHT "(C) 2014-2024 Santi Norena lms@criptomart.net" #define LICENSE "GPL 3 License. See LICENSE.txt and credits.txt for details" - #define LAYERS_NUMBER 4 // esto tiene que desaparecer - #define DEFAULT_FILE "lms-audio.xlm" - -#define SUSPEND_LABEL "Pause playback" -#define RESUME_LABEL "Resume playback" - -#define PLAY_LABEL "Playing" -#define STOP_LABEL "Stopped" +#define SUSPEND_LABEL "Pause" +#define RESUME_LABEL "Resume" +#define PLAY_LABEL "Play" +#define STOP_LABEL "Stop" #define PAUSE_LABEL "Pause" #define IDDLE_LABEL "Iddle playback" - #define VOLUME_LABEL "Volume" #define PROGRESS_LABEL "Progress" #define PROGRESS_TIME_LABEL "Current" -#define REMAINING_TIME "Remaining Time: " +#define REMAINING_TIME "Remaining" #define TOTAL_TIME_LABEL "Total" -#define FILE_LABEL "File:" -#define FOLDER_LABEL "Folder:" +#define FILE_LABEL "File: " +#define FOLDER_LABEL "Folder: " #define STATUS_LABEL "Status: " - #define NOTIFY_INTERVAL 150 #define PULL_TIMER_INTERVAL 10 #define MAX_DEVICES 16 #define MAX_SOUNDS 4096 +#define MAX_LAYERS 16 +#define UI_REFRESH_TIME 100 // struct where save the DMX settings for each layer struct dmxSetting { int address; - uint universe; + quint8 universe; bool updated; int layer; }; diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 0c223bc..a458db6 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -30,6 +30,7 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) Settings *set = Settings::getInstance(); set->readFile(); + connect(set, SIGNAL(audioDeviceChanged(int)), this, SLOT(audioDeviceChanged(int))); /* if (args.contains("-log")) { // Inicia el widget Terminal @@ -57,7 +58,8 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) // start audio engine MediaLibrary::getInstance()->initMediaLibrary(); - setCentralWidget(AudioWidget::getInstance()); + aw = new AudioWidget; + setCentralWidget(aw); amw = new AudioMasterWidget(this); QDockWidget *topWidget = new QDockWidget(tr("Master"), this); topWidget->setAllowedAreas(Qt::TopDockWidgetArea); @@ -66,20 +68,20 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) // ola setup ola = new olaThread(); Q_CHECK_PTR(ola); - connect(set, SIGNAL(registerUniverse(int)), ola, SLOT(registerUniverse(int))); - ola->registerUniverse(); // register now all the universes ola->blockSignals(true); + connect(set, SIGNAL(registerUniverse(int)), ola, SLOT(registerUniverse(int))); connect(ola, SIGNAL (layerReceived()), amw, SLOT(updateWatchDMX())); connect(ola, SIGNAL(dmxOutput(int, int, int)), this, SLOT(dmxInput(int, int, int))); connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup())); + ola->registerUniverse(); ola->start(QThread::TimeCriticalPriority ); - ola->blockSignals(false); // menus connect(ui.actionOpen_conf, SIGNAL(triggered()), this, SLOT(openFile())); connect(ui.actionSave_conf, SIGNAL(triggered()), this, SLOT(saveFile())); connect(ui.action_Settings, SIGNAL(triggered()), this, SLOT(settings())); - connect(set, SIGNAL(audioDeviceChanged(int)), this, SLOT(audioDeviceChanged(int))); - qDebug("Init Complete"); + aw->startEngine(); + qDebug("Init Complete."); + ola->blockSignals(false); } /////////////////////////////////////////////////////////////////// @@ -89,7 +91,7 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) libreMediaServerAudio::~libreMediaServerAudio() { ola->stop(); - AudioWidget::getInstance()->stopEngine(); + aw->stopEngine(); } /////////////////////////////////////////////////////////////////// @@ -151,27 +153,27 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) aux = ola->getValue(layer, DMX_FILE); mediaFile = MediaLibrary::getInstance()->requestNewFile(value, aux); if (QFile::exists(mediaFile)) - AudioWidget::getInstance()->mediaLoaded(layer, mediaFile); + aw->mediaLoaded(layer, mediaFile); break; case DMX_FILE:// File aux = ola->getValue(layer, DMX_FOLDER); mediaFile = MediaLibrary::getInstance()->requestNewFile(aux, value); if (QFile::exists(mediaFile)) - AudioWidget::getInstance()->mediaLoaded(layer, mediaFile); + aw->mediaLoaded(layer, mediaFile); break; case VOLUME_COARSE: f = ( value * 0x100 ) + ola->getValue(layer, VOLUME_FINE); - AudioWidget::getInstance()->volChanged(layer, (f / 655.35)); + aw->volChanged(layer, (f / 655.35)); break; case VOLUME_FINE: f = ( ola->getValue(layer, VOLUME_COARSE) * 0x100 ) + value; - AudioWidget::getInstance()->volChanged(layer, (f / 655.35)); + aw->volChanged(layer, (f / 655.35)); break; case PAN: - AudioWidget::getInstance()->panChanged(layer, value); + aw->panChanged(layer, value); break; case PITCH: - AudioWidget::getInstance()->pitchChanged(layer, value); + aw->pitchChanged(layer, value); break; case PLAYBACK: if (value == 0) @@ -179,16 +181,16 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) aux = value / 25; switch (aux) { case 0 : - AudioWidget::getInstance()->playbackChanged(layer, PlayingOnce); + aw->playbackChanged(layer, PlayingOnce); break; case 1 : - AudioWidget::getInstance()->playbackChanged(layer, Stopped); + aw->playbackChanged(layer, Stopped); break; case 2 : - AudioWidget::getInstance()->playbackChanged(layer, Paused); + aw->playbackChanged(layer, Paused); break; case 3 : - AudioWidget::getInstance()->playbackChanged(layer, PlayingLoop); + aw->playbackChanged(layer, PlayingLoop); break; } default: @@ -198,6 +200,6 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) void libreMediaServerAudio::audioDeviceChanged(int id) { - AudioWidget::getInstance()->stopEngine(); - AudioWidget::getInstance()->startEngine(id); + aw->stopEngine(); + aw->startEngine(id); } diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index ea88afe..751ffcd 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -20,6 +20,7 @@ #ifndef LIBREMEDIASERVERAUDIO_H #define LIBREMEDIASERVERAUDIO_H + #include #include #include @@ -29,7 +30,9 @@ #include #include #include -#include +#include +#include +#include #include "audiowidget.h" #include "medialibrary.h" @@ -48,58 +51,29 @@ class libreMediaServerAudio : public QMainWindow Q_OBJECT public: - libreMediaServerAudio (QStringList args, QWidget *parent = 0); virtual ~libreMediaServerAudio(); - Ui::LibreMediaServerAudio ui; -// static QTextEdit *textEdit; // Terminal de feedback - -protected: - private: - // void MessageHandler(QtMsgType type, const QMessageLogContext &logcontext, const QString &msg); - AudioMasterWidget *amw; + AudioWidget *aw; + AudioMasterWidget *amw; + olaThread *ola; - olaThread *ola; - - void open_start(); - void save_finish(); - void open(QFile *file); - void save(QFile *file); + void open_start(); + void save_finish(); + void open(QFile *file); + void save(QFile *file); public slots: void audioDeviceChanged(int id); private slots: - - /** - * @brief Shows the OLA web setup page - */ void olasetup(); - - /** - * @brief Parser for new dmx data arriving - * @param layer - * @param channel - * @param value - */ void dmxInput(int layer, int channel, int value); - - // Menu File - /** - * @brief REad from dis a configuration file - */ void openFile(); - /** - * @brief Write to disk a configuration file - */ void saveFile(); - /** - * @brief OPen the settings dialog - */ void settings(); }; diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp new file mode 100644 index 0000000..ed010a6 --- /dev/null +++ b/src/miniaudioengine.cpp @@ -0,0 +1,238 @@ +#include "miniaudioengine.h" + +MiniAudioEngine::MiniAudioEngine() +{ + +} + +void MiniAudioEngine::audioDataCallback(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 MiniAudioEngine::stopEngine() +{ + ma_engine_uninit(&engine); + ma_device_uninit(&device); + ma_context_uninit(&context); + ma_resource_manager_uninit(&resourceManager); +} + +bool MiniAudioEngine::startEngine(int n) +{ + ma_result result; + + result = this->startContext(); + if (result != MA_SUCCESS) { + return result; + } + this->getAllAudioDevices(); + result = this->startDevice(n); + return result; +} + +ma_result MiniAudioEngine::startDevice(int id) +{ + ma_result result; + ma_device_config deviceConfig; + ma_engine_config engineConfig; + + deviceConfig = ma_device_config_init(ma_device_type_playback); + deviceConfig.playback.pDeviceID = &pPlaybackDeviceInfos[id].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); + if (result != MA_SUCCESS) { + printf("Failed to initialize audio device %s.", pPlaybackDeviceInfos[id].name); + return result; + } + engineConfig = ma_engine_config_init(); + engineConfig.pDevice = &device; + engineConfig.pResourceManager = &resourceManager; + engineConfig.noAutoStart = MA_TRUE; + result = ma_engine_init(NULL, &engine); + if (result != MA_SUCCESS) { + printf("Failed to initialize audio engine."); + return result; + } + result = ma_engine_start(&engine); + if (result != MA_SUCCESS) { + printf("Failed to start audio engine %i.", id); + return result; + } + iChosenDevice = id; + printf("Initialized audio device %d: %s", id, pPlaybackDeviceInfos[id].name); + return result; +} + +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 = 0; + resourceManagerConfig.jobThreadCount = 0; + result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager); + if (result != MA_SUCCESS) { + printf("Failed to initialize audio resource manager."); + return result; + } + result = ma_context_init(NULL, 0, NULL, &context); + if (result != MA_SUCCESS) { + printf("Failed to initialize audio context."); + } + return result; +} + +// enum all audio devices in system +ma_result MiniAudioEngine::getAllAudioDevices() +{ + ma_result result; + + result = ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, NULL, NULL); + if (result != MA_SUCCESS) { + printf("Failed to enumerate playback devices.\n"); + ma_context_uninit(&context); + return result; + } + printf("Audio devices detected in system:\n"); + for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < playbackDeviceCount; iAvailableDevice += 1) { + qInfo("%d: : %s", iAvailableDevice, pPlaybackDeviceInfos[iAvailableDevice].name); + } + return result; +} + +ma_result MiniAudioEngine::loadMedia(int layer, char *file) +{ + ma_result result; + + if (m_mediaLoaded[layer] == true) + { + qInfo("removing sound %i", layer); + ma_sound_uninit(&m_currentSound[layer]); + m_mediaLoaded[layer] = false; + } + result = ma_sound_init_from_file(&engine, file, \ + MA_SOUND_FLAG_NO_SPATIALIZATION \ + /*| MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE \ + | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC \ + | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM \*/ + , NULL, NULL, &m_currentSound[layer]); + if (result != MA_SUCCESS) + qWarning("Failed to load file %s", file); + else { + m_mediaLoaded[layer] = true; + this->volChanged(layer, 0); + } + return result; +} + +float MiniAudioEngine::getDuration(int layer) +{ + ma_result result; + float ret = 0; + + if (m_mediaLoaded[layer] == false) + return MA_DOES_NOT_EXIST; + result = ma_sound_get_length_in_seconds(&m_currentSound[layer], &ret); + if (result != MA_SUCCESS) + { + qWarning("Can not get duration %i", layer); + ret = 0; + } + return ret; +} + +float MiniAudioEngine::getCursor(int layer) +{ + ma_result result; + float ret = 0; + + if (m_mediaLoaded[layer] == false) + return MA_DOES_NOT_EXIST; + result = ma_sound_get_cursor_in_seconds(&m_currentSound[layer], &ret); + if (result != MA_SUCCESS) + { + qWarning("Can not get cursor %i", layer); + ret = 0; + } + return ret; +} + +ma_result MiniAudioEngine::printFormatInfo(int layer) +{ + ma_format format; + ma_uint32 channels; + ma_uint32 sampleRate; + + 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("Failed to get data format %i\n", layer); + return MA_INVALID_DATA; + } + qInfo("samples/sec: %u format: %u channels: %u", sampleRate, format, channels); + return result; +} + +// Expects between 0 and 100 vol value in db +void MiniAudioEngine::volChanged(int layer, float vol) +{ + float result; + + if (m_mediaLoaded[layer] == false) + return; + result = ma_volume_linear_to_db(1.00000000 + (vol / 800.0)); + ma_sound_group_set_volume(&m_currentSound[layer], result); +} + +void MiniAudioEngine::panChanged(int layer, float value) +{ + float result; + + if (m_mediaLoaded[layer] == false) + return; + result = (value / 128.0) - 1.0; + ma_sound_group_set_pan(&m_currentSound[layer], result); +} + +void MiniAudioEngine::pitchChanged(int layer, float value) +{ + float result; + + if (m_mediaLoaded[layer] == false) + return; + result = value / 128.0; + ma_sound_group_set_pitch(&m_currentSound[layer], result); +} + +void MiniAudioEngine::playbackChanged(int layer, Status status) +{ + if (m_mediaLoaded[layer] == false) + return; + switch (status) { + case Status::Paused: + ma_sound_stop(&m_currentSound[layer]); + break; + case Status::Stopped: + ma_sound_stop(&m_currentSound[layer]); + ma_sound_seek_to_pcm_frame(&m_currentSound[layer], 0); + break; + case Status::PlayingLoop: + ma_sound_set_looping(&m_currentSound[layer], true); + ma_sound_start(&m_currentSound[layer]); + break; + case Status::PlayingOnce: + ma_sound_set_looping(&m_currentSound[layer], false); + ma_sound_start(&m_currentSound[layer]); + break; + } +} diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h new file mode 100644 index 0000000..8cda15b --- /dev/null +++ b/src/miniaudioengine.h @@ -0,0 +1,48 @@ +#ifndef MINIAUDIOENGINE_H +#define MINIAUDIOENGINE_H + +#define MINIAUDIO_IMPLEMENTATION +#include "miniaudio.h" + +#include "defines.h" //MAX_LAYERS +#include // for printf + +class MiniAudioEngine +{ + friend class AudioWidget; + +public: + MiniAudioEngine(); + void stopEngine(); + bool startEngine(int id); + static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); + +protected: + // slots for DMX input + ma_result loadMedia(int layer, char *media ); + void volChanged(int layer, float vol); + void panChanged(int layer, float pan); + void pitchChanged(int layer, float pitch); + void playbackChanged(int layer, Status status); + float getDuration(int layer); + float getCursor(int layer); + ma_result printFormatInfo(int layer); + +private: + ma_resource_manager_config resourceManagerConfig; + ma_resource_manager resourceManager; + ma_device_info* pPlaybackDeviceInfos; + ma_uint32 playbackDeviceCount; + ma_uint32 iChosenDevice; + ma_engine engine; + ma_device device; + ma_context context; + ma_sound m_currentSound[MAX_LAYERS]; + ma_bool8 m_mediaLoaded[MAX_LAYERS]; + + ma_result getAllAudioDevices(); + ma_result startDevice(int id); + ma_result startContext(); +}; + +#endif // MINIAUDIOENGINE_H diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index e5b8de7..cbe19a5 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -53,7 +53,7 @@ void SettingsDialog::changeAudioDevice() { m_deviceDialog = new QDialog( this ); } - QLabel *msgLabel = new QLabel; +/* QLabel *msgLabel = new QLabel; AudioWidget *aw = AudioWidget::getInstance(); QString *msg = new QString; for (uint iAvailableDevice = 0; iAvailableDevice < aw->playbackDeviceCount; iAvailableDevice += 1) { @@ -72,7 +72,7 @@ void SettingsDialog::changeAudioDevice() layout->addWidget(closeButton); m_deviceDialog->setLayout(layout); m_deviceDialog->setModal(true); - m_deviceDialog->show(); + m_deviceDialog->show();*/ } void SettingsDialog::closeAudioDeviceDialog() -- 2.39.5 From abf5d3340fe735b58bf45e3ba11108f9566792e3 Mon Sep 17 00:00:00 2001 From: snt Date: Mon, 22 Apr 2024 20:39:05 +0200 Subject: [PATCH 03/49] =?UTF-8?q?wip=20acciones=20desde=20ui,=20la=20prime?= =?UTF-8?q?ra=20capa=20hace=20bien=20el=20pause=20pero=20el=20resto=20no.?= =?UTF-8?q?=20s=C3=B3lo=20reciben=20datos=20las=20ptres=20primeras=20capas?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/audiolayerwidget.cpp | 32 +++++++++++++++++++++++--------- src/audiolayerwidget.h | 15 +++++++++------ src/audiowidget.cpp | 26 +++++++++++++++++++++++--- src/audiowidget.h | 5 +++++ src/defines.h | 8 +++++++- src/olathread.cpp | 10 ++++------ src/olathread.h | 2 +- src/settings.cpp | 4 ++-- src/settings.h | 4 ++-- 9 files changed, 76 insertions(+), 30 deletions(-) diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index d62c165..1eb4364 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -1,8 +1,9 @@ #include "audiolayerwidget.h" -AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name): +AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name, int layer): QGroupBox(parent) + , m_layer(layer) , m_suspendResumeButton(0) , m_volumeIndicator(new QSpinBox) , m_panIndicator(new QSpinBox) @@ -93,7 +94,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name): m_progressTime->setDisplayFormat("h:mm:ss:zzz"); m_progressTime->setReadOnly(true); m_progressTime->setButtonSymbols(QAbstractSpinBox::NoButtons); - m_progressTime->setMaximumWidth(120); + m_progressTime->setMaximumWidth(100); progressTime->addWidget(m_progressTimeLabel); progressTime->addWidget(m_progressTime); m_totalTimeLabel = new QLabel; @@ -102,7 +103,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name): m_totalTimeValue->setDisplayFormat("h:mm:ss:zzz"); m_totalTimeValue->setReadOnly(true); m_totalTimeValue->setButtonSymbols(QAbstractSpinBox::NoButtons); - m_totalTimeValue->setMaximumWidth(120); + m_totalTimeValue->setMaximumWidth(100); progressTime->addWidget(m_totalTimeLabel); progressTime->addWidget(m_totalTimeValue); layout->addLayout(progressTime); @@ -153,11 +154,14 @@ void AudioLayerWidget::toggleSuspendResume() case Status::PlayingLoop: case Status::PlayingOnce: this->setPlaybackStatus(Status::Paused); + emit uiPlaybackChanged(m_layer, Status::Paused); + break; case Status::Paused: case Status::Stopped: this->setPlaybackStatus(Status::PlayingOnce); + emit uiPlaybackChanged(m_layer, Status::PlayingOnce); + break; } - // ToDo: call the audio engine } // from DMX signals @@ -195,13 +199,10 @@ void AudioLayerWidget::fileLoaded(QString file) } } -void AudioLayerWidget::setPlaybackStatus(Status status) +QString AudioLayerWidget::getStatus() { - m_status = status; - if (status == Status::Stopped) - m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(0)); QString tmp; - switch (status) { + switch (m_status) { case Status::Paused: tmp.append("Paused"); break; @@ -215,8 +216,21 @@ void AudioLayerWidget::setPlaybackStatus(Status status) tmp.append("Stopped"); break; } + return tmp; +} + +void AudioLayerWidget::setPlaybackStatus(Status status) +{ + m_status = status; + if (status == Status::Stopped) + m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(0)); + QString tmp = this->getStatus(); + m_statusValue->blockSignals(true); + m_suspendResumeButton->blockSignals(true); m_statusValue->setText(tmp); m_suspendResumeButton->setText(tmp); + m_statusValue->blockSignals(false); + m_suspendResumeButton->blockSignals(false); } void AudioLayerWidget::durationChanged(qint64 dur) diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index e5270d5..78d0b4a 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -23,7 +23,7 @@ class AudioLayerWidget : public QGroupBox Q_OBJECT public: - explicit AudioLayerWidget(QWidget *parent = 0, QString name = "Layer"); + explicit AudioLayerWidget(QWidget *parent = 0, QString name = "Layer", int layer = 0); ~AudioLayerWidget(); void setVol(qreal vol); void resume(); @@ -32,17 +32,18 @@ public: void setLoop(bool on); void setPlaybackStatus(Status status); inline Status getPlaybackStatus() { return m_status; } + QString getStatus(); private: + Status m_status; + int m_layer; QPushButton *m_suspendResumeButton; - QLabel *m_statusLabel; QLabel * m_statusValue; QLabel *m_fileLabel; QLabel *m_fileValue; QLabel * m_folderLabel; QLabel * m_folderValue; - QLabel *m_volumeLabel; QSlider *m_volumeSlider; QSpinBox *m_volumeIndicator; @@ -52,7 +53,6 @@ private: QLabel *m_pitchLabel; QSlider *m_pitchSlider; QSpinBox *m_pitchIndicator; - QLabel * m_progressLabel; QSlider *m_progressSlider; QLabel *m_progressTimeLabel; @@ -60,8 +60,6 @@ private: QLabel *m_totalTimeLabel; QTimeEdit *m_totalTimeValue; - Status m_status; - public slots: void toggleSuspendResume(); void volumeChanged(int vol); @@ -71,6 +69,11 @@ public slots: void fileLoaded(QString file); void durationChanged(qint64 dur); void refreshUi(float progress); + +signals: + void uiPlaybackChanged(int layer, Status s); + void uiSliderChanged(int layer, Slider s, Status status); + }; #endif // AUDIOLAYERWIDGET_H diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index 160182d..700b846 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -5,10 +5,12 @@ AudioWidget::AudioWidget() : m_layout(new QHBoxLayout()) , m_refreshUi(new QTimer(this)) { - for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) { - m_layout->insertWidget(i, new AudioLayerWidget(this, tr("Layer %1").arg(i + 1))); - } + AudioLayerWidget *alw = new AudioLayerWidget(this, tr("Layer %1").arg(i + 1), i); + m_layout->insertWidget(i, alw); + connect(alw, SIGNAL(uiSliderAction(int, Slider, qreal)), this, SLOT(uiSliderAction(int, Status))); + connect(alw, SIGNAL(uiPlaybackChanged(int, Status)), this, SLOT(uiChangePlaybackStatus(int, Status))); + } setLayout(m_layout); connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); m_refreshUi->start(UI_REFRESH_TIME); @@ -89,3 +91,21 @@ void AudioWidget::refreshUi() { } } } + +void AudioWidget::uiSliderAction(int layer, Slider s, qreal value) +{ + switch (s){ + case Slider::Volume: + this->volChanged(layer, value); + case Slider::Pan: + this->panChanged(layer, value); + case Slider::Pitch: + this->pitchChanged(layer, value); + } +} + +void AudioWidget::uiChangePlaybackStatus(int layer, Status s) { + qDebug("changing playback %i %i", layer, s); + m_mae.playbackChanged(layer, s); +} + diff --git a/src/audiowidget.h b/src/audiowidget.h index b35ecbd..48f2b4b 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -16,6 +16,7 @@ class AudioWidget : public QWidget { friend class libreMediaServerAudio; + friend class AudioLayerWidget; Q_OBJECT @@ -38,6 +39,10 @@ private: QHBoxLayout *m_layout; QTimer *m_refreshUi; +public slots: + void uiSliderAction(int layer, Slider s, qreal value); + void uiChangePlaybackStatus(int layer, Status s); + private slots: void refreshUi(); }; diff --git a/src/defines.h b/src/defines.h index b34cf0c..50fe3ec 100644 --- a/src/defines.h +++ b/src/defines.h @@ -8,7 +8,6 @@ #define VERSION "LibreMediaServer-Audio 0.1.4" #define COPYRIGHT "(C) 2014-2024 Santi Norena lms@criptomart.net" #define LICENSE "GPL 3 License. See LICENSE.txt and credits.txt for details" -#define LAYERS_NUMBER 4 // esto tiene que desaparecer #define DEFAULT_FILE "lms-audio.xlm" #define SUSPEND_LABEL "Pause" #define RESUME_LABEL "Resume" @@ -62,5 +61,12 @@ enum Status PlayingLoop, }; +enum Slider +{ + Volume, + Pan, + Pitch, +}; + #endif // DEFINES_H diff --git a/src/olathread.cpp b/src/olathread.cpp index 900fc3b..5808cb5 100644 --- a/src/olathread.cpp +++ b/src/olathread.cpp @@ -6,18 +6,16 @@ olaThread::olaThread(QObject *parent) Q_UNUSED(parent); m_counter = 0; gettimeofday(&m_last_data, NULL); - // Init the dmx buffer to 0 - for (int i=0; i < LAYERS_NUMBER; i++) + for (int i=0; i < MAX_LAYERS; i++) { for (int j=0; j < LAYER_CHANNELS; j++) { m_dmx[i][j] = 0; } } - init(); // start the ola connection + init(); } - // --- DECONSTRUCTOR --- olaThread::~olaThread() { stop(); } @@ -70,7 +68,7 @@ void olaThread::NewDmx(const ola::client::DMXMetadata &data, emit layerReceived(); foreach (const dmxSetting &i, Settings::getInstance()->getDmxSettings()) { // loop for reading the channels by layer. if(i.universe == universe && i.address > -1) { // Compare if the layer is from this universe AND if the DMX address is 0 or greater, process this layer. - for (int j = 0; j < LAYER_CHANNELS; j++){ + for (int j = 0; j < MAX_LAYERS; j++){ int value = buffer.Get((i.address) + j); // Get the value for this channel. if (m_dmx[i.layer][j] != value) { // Compare the new value with the old value. emit dmxOutput(i.layer,j,value); @@ -103,7 +101,7 @@ bool olaThread::CheckDataLoss() { void olaThread::resendDmx() { // qDebug() << "Resending DMX info"; - for (int i = 0; i < Settings::getInstance()->getLayersNumber(); i++) { // loop for reading the channels by layer. + for (int i = 0; i < MAX_LAYERS; i++) { // loop for reading the channels by layer. for (int j = 0; j < LAYER_CHANNELS; j++){ emit dmxOutput(i, j, m_dmx[i][j]); } diff --git a/src/olathread.h b/src/olathread.h index 7e7a5a1..070922e 100644 --- a/src/olathread.h +++ b/src/olathread.h @@ -50,7 +50,7 @@ private: unsigned int m_counter; struct timeval m_last_data; // Last DMX frame received - int m_dmx[LAYERS_NUMBER][LAYER_CHANNELS]; // DMX Buffer. Habría que cambiarlo si queremos hacer las capas dinámicas + int m_dmx[MAX_LAYERS][LAYER_CHANNELS]; // DMX Buffer. Habría que cambiarlo si queremos hacer las capas dinámicas /** * @brief Callback from ola. Control de errores en el registro de Universos en OLA diff --git a/src/settings.cpp b/src/settings.cpp index 10485d1..4dc7bff 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -42,7 +42,7 @@ void Settings::readFromFile(QString file) { QXmlStreamReader* xmlReader = new QXmlStreamReader(xmlFile); int counter = 0; //Parse the XML until we reach end of it - while(!xmlReader->atEnd() && !xmlReader->hasError() && counter < LAYERS_NUMBER) { + while(!xmlReader->atEnd() && !xmlReader->hasError() && counter < MAX_LAYERS) { // Read next element QXmlStreamReader::TokenType token = xmlReader->readNext(); //If token is just StartDocument - go to next @@ -75,8 +75,8 @@ void Settings::readFromFile(QString file) { m_universe.insert(temp.universe); // emit registerUniverse(temp.universe); } + counter++; } - counter++; } } diff --git a/src/settings.h b/src/settings.h index f1c8eec..2301d53 100644 --- a/src/settings.h +++ b/src/settings.h @@ -92,10 +92,10 @@ public: */ inline void setLayersNumber(int layersNumber) { - if (layersNumber <= LAYERS_NUMBER) + if (layersNumber <= MAX_LAYERS) m_layersNumber = layersNumber; else - m_layersNumber = LAYERS_NUMBER; + m_layersNumber = MAX_LAYERS; } inline int getAudioDeviceId() { return m_audioDeviceId; } -- 2.39.5 From b59cc92c5f16198a11ac1214583b93fd69b6c48d Mon Sep 17 00:00:00 2001 From: snt Date: Tue, 23 Apr 2024 01:16:52 +0200 Subject: [PATCH 04/49] funcionando controles ui --- src/audiolayerwidget.cpp | 34 +++++--------------- src/audiolayerwidget.h | 3 +- src/audiowidget.cpp | 14 ++++---- src/audiowidget.h | 3 +- src/defines.h | 5 +-- src/libremediaserver-audio.cpp | 3 +- src/libremediaserver-audio.ui | 10 ++++-- src/olathread.cpp | 39 +++++++---------------- src/olathread.h | 58 ++++++---------------------------- src/settings.cpp | 6 ---- 10 files changed, 50 insertions(+), 125 deletions(-) diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 1eb4364..3c58b2c 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -13,23 +13,14 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name, int layer): QVBoxLayout *layout = new QVBoxLayout; QGridLayout *status = new QGridLayout; - m_statusLabel = new QLabel; - m_statusLabel->setText(STATUS_LABEL); m_statusValue = new QLabel; - status->addWidget(m_statusLabel, 0, 0); - status->addWidget(m_statusValue, 0, 2); - m_folderLabel = new QLabel; - m_folderLabel->setText(FOLDER_LABEL); + status->addWidget(m_statusValue, 1, 1); m_folderValue = new QLabel; - m_folderValue->setMaximumWidth(200); - status->addWidget(m_folderLabel, 1, 0); - status->addWidget(m_folderValue, 1, 1); - m_fileLabel = new QLabel; - m_fileLabel->setText(FILE_LABEL); + m_folderValue->setMaximumWidth(100); + status->addWidget(m_folderValue, 0, 0); m_fileValue = new QLabel; - m_fileValue->setMaximumWidth(200); - status->addWidget(m_fileLabel, 1, 2); - status->addWidget(m_fileValue, 1, 3); + m_fileValue->setMaximumWidth(100); + status->addWidget(m_fileValue, 0, 2); layout->addLayout(status); QGridLayout *volumeBox = new QGridLayout; @@ -126,26 +117,17 @@ AudioLayerWidget::~AudioLayerWidget() // From UI. void AudioLayerWidget::volumeChanged(int value) { - (void)value; - // ToDo: call the audio engine + emit(uiSliderChanged(m_layer, Slider::Volume, value)); } void AudioLayerWidget::panChanged(int value) { - (void)value; - // ToDo: call the audio engine + emit(uiSliderChanged(m_layer, Slider::Pan, value)); } void AudioLayerWidget::pitchChanged(int value) { - (void)value; - // ToDo: call the audio engine -} - -void AudioLayerWidget::loopChanged(int value) -{ - (void)value; - // ToDo: call the audio engine + emit(uiSliderChanged(m_layer, Slider::Pitch, value)); } void AudioLayerWidget::toggleSuspendResume() diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index 78d0b4a..f91858f 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -65,14 +65,13 @@ public slots: void volumeChanged(int vol); void panChanged(int vol); void pitchChanged(int vol); - void loopChanged(int vol); void fileLoaded(QString file); void durationChanged(qint64 dur); void refreshUi(float progress); signals: void uiPlaybackChanged(int layer, Status s); - void uiSliderChanged(int layer, Slider s, Status status); + void uiSliderChanged(int layer, Slider s, int value); }; diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index 700b846..d1274d6 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -8,7 +8,7 @@ AudioWidget::AudioWidget() : for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) { AudioLayerWidget *alw = new AudioLayerWidget(this, tr("Layer %1").arg(i + 1), i); m_layout->insertWidget(i, alw); - connect(alw, SIGNAL(uiSliderAction(int, Slider, qreal)), this, SLOT(uiSliderAction(int, Status))); + connect(alw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SLOT(uiSliderAction(int, Slider, int))); connect(alw, SIGNAL(uiPlaybackChanged(int, Status)), this, SLOT(uiChangePlaybackStatus(int, Status))); } setLayout(m_layout); @@ -92,20 +92,22 @@ void AudioWidget::refreshUi() { } } -void AudioWidget::uiSliderAction(int layer, Slider s, qreal value) +void AudioWidget::uiSliderAction(int layer, Slider s, int value) { switch (s){ case Slider::Volume: - this->volChanged(layer, value); + m_mae.volChanged(layer, value); + break; case Slider::Pan: - this->panChanged(layer, value); + m_mae.panChanged(layer, value); + break; case Slider::Pitch: - this->pitchChanged(layer, value); + m_mae.pitchChanged(layer, value); + break; } } void AudioWidget::uiChangePlaybackStatus(int layer, Status s) { - qDebug("changing playback %i %i", layer, s); m_mae.playbackChanged(layer, s); } diff --git a/src/audiowidget.h b/src/audiowidget.h index 48f2b4b..26f63b1 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -3,7 +3,6 @@ #include #include -#include #include #include "audiomasterwidget.h" @@ -40,7 +39,7 @@ private: QTimer *m_refreshUi; public slots: - void uiSliderAction(int layer, Slider s, qreal value); + void uiSliderAction(int layer, Slider s, int value); void uiChangePlaybackStatus(int layer, Status s); private slots: diff --git a/src/defines.h b/src/defines.h index 50fe3ec..ca94591 100644 --- a/src/defines.h +++ b/src/defines.h @@ -15,14 +15,11 @@ #define STOP_LABEL "Stop" #define PAUSE_LABEL "Pause" #define IDDLE_LABEL "Iddle playback" -#define VOLUME_LABEL "Volume" +#define VOLUME_LABEL "Vol" #define PROGRESS_LABEL "Progress" #define PROGRESS_TIME_LABEL "Current" #define REMAINING_TIME "Remaining" #define TOTAL_TIME_LABEL "Total" -#define FILE_LABEL "File: " -#define FOLDER_LABEL "Folder: " -#define STATUS_LABEL "Status: " #define NOTIFY_INTERVAL 150 #define PULL_TIMER_INTERVAL 10 #define MAX_DEVICES 16 diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index a458db6..f8193e7 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -66,7 +66,7 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) topWidget->setWidget(amw); addDockWidget(Qt::TopDockWidgetArea, topWidget); // ola setup - ola = new olaThread(); + ola = new olaThread(this, set->getLayersNumber()); Q_CHECK_PTR(ola); ola->blockSignals(true); connect(set, SIGNAL(registerUniverse(int)), ola, SLOT(registerUniverse(int))); @@ -82,6 +82,7 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) aw->startEngine(); qDebug("Init Complete."); ola->blockSignals(false); + ola->resendDmx(); } /////////////////////////////////////////////////////////////////// diff --git a/src/libremediaserver-audio.ui b/src/libremediaserver-audio.ui index 3256e49..2090b50 100644 --- a/src/libremediaserver-audio.ui +++ b/src/libremediaserver-audio.ui @@ -7,7 +7,7 @@ 0 0 - 199 + 114 218 @@ -20,7 +20,7 @@ 0 0 - 199 + 114 22 @@ -33,7 +33,13 @@ + + + Help + + + diff --git a/src/olathread.cpp b/src/olathread.cpp index 5808cb5..1453e2d 100644 --- a/src/olathread.cpp +++ b/src/olathread.cpp @@ -1,10 +1,11 @@ #include "olathread.h" -olaThread::olaThread(QObject *parent) +olaThread::olaThread(QObject *parent, int layers) : + m_counter(0) + , m_layers(layers) { Q_UNUSED(parent); - m_counter = 0; gettimeofday(&m_last_data, NULL); for (int i=0; i < MAX_LAYERS; i++) { @@ -41,7 +42,6 @@ void olaThread::init() void olaThread::run() { - emit toTerminal("Start reading DMX"); m_clientWrapper->GetSelectServer()->Run(); } @@ -64,15 +64,13 @@ void olaThread::NewDmx(const ola::client::DMXMetadata &data, { m_counter++; gettimeofday(&m_last_data, NULL); - uint universe = data.universe; - emit layerReceived(); - foreach (const dmxSetting &i, Settings::getInstance()->getDmxSettings()) { // loop for reading the channels by layer. - if(i.universe == universe && i.address > -1) { // Compare if the layer is from this universe AND if the DMX address is 0 or greater, process this layer. - for (int j = 0; j < MAX_LAYERS; j++){ - int value = buffer.Get((i.address) + j); // Get the value for this channel. - if (m_dmx[i.layer][j] != value) { // Compare the new value with the old value. - emit dmxOutput(i.layer,j,value); + foreach (const dmxSetting &i, Settings::getInstance()->getDmxSettings()) { + if(i.universe == data.universe && i.address > -1) { + for (int j = 0; j < LAYER_CHANNELS; j++){ + int value = buffer.Get((i.address) + j); + if (m_dmx[i.layer][j] != value) { m_dmx[i.layer][j] = value; + emit dmxOutput(i.layer,j,value); } } } @@ -82,17 +80,13 @@ void olaThread::NewDmx(const ola::client::DMXMetadata &data, /** * Check for data loss each 4 seconds. */ - bool olaThread::CheckDataLoss() { struct timeval now, diff; if (timerisset(&m_last_data)) { gettimeofday(&now, NULL); timersub(&now, &m_last_data, &diff); if (diff.tv_sec > 4 || (diff.tv_sec == 4 && diff.tv_usec > 4000000)) { - // loss of data - qDebug()<< "olaThread| Can not read one or several universes"; - emit toTerminal("olaThread: Can not read one universe"); - // return false; // Retorna false para deshabilitar el callback + qInfo()<< "olaThread| Can not read one or several universes"; } } return true; @@ -100,8 +94,7 @@ bool olaThread::CheckDataLoss() { void olaThread::resendDmx() { -// qDebug() << "Resending DMX info"; - for (int i = 0; i < MAX_LAYERS; i++) { // loop for reading the channels by layer. + for (int i = 0; i < m_layers; i++) { for (int j = 0; j < LAYER_CHANNELS; j++){ emit dmxOutput(i, j, m_dmx[i][j]); } @@ -110,19 +103,11 @@ void olaThread::resendDmx() void olaThread::socketClosed() { - qWarning("ola close the connection. Trying reopening it... "); - emit toTerminal("OLA closed the connection. Tryin reopening it... "); - + qWarning("ola closed connection. Try reopening it... "); m_clientWrapper->GetSelectServer()->Terminate(); m_client = NULL; m_clientWrapper = NULL; - - // setup ola connection init(); - - // register universes registerUniverse(); - - // start thread run(); } diff --git a/src/olathread.h b/src/olathread.h index 070922e..9692d9e 100644 --- a/src/olathread.h +++ b/src/olathread.h @@ -5,7 +5,6 @@ #include #include -#include #include #include @@ -25,7 +24,7 @@ class olaThread : public QThread public: - olaThread(QObject *parent = 0); + olaThread(QObject *parent = 0, int layers = 0); virtual ~olaThread(); /** Retorna el valor de un canal @@ -37,9 +36,6 @@ public: return m_dmx[layer][channel]; } - /** - * @brief resendDMX emite todo el buffer DMX - */ void resendDmx(); private: @@ -49,78 +45,49 @@ private: ola::client::OlaClient *m_client; unsigned int m_counter; struct timeval m_last_data; // Last DMX frame received - - int m_dmx[MAX_LAYERS][LAYER_CHANNELS]; // DMX Buffer. Habría que cambiarlo si queremos hacer las capas dinámicas + int m_layers; + int m_dmx[MAX_LAYERS][LAYER_CHANNELS]; /** * @brief Callback from ola. Control de errores en el registro de Universos en OLA * typedef SingleUseCallback1 ola::client::SetCallback * @param ola::client::Result &error * @return void - * - * */ inline void RegisterComplete(const ola::client::Result &error) { if (error.Success()) { qDebug("Register Universe success"); - emit toTerminal("Register Universe success"); } else { qWarning("Register command failed: %s", error.Error().c_str()); - emit toTerminal("olaThread| Register command failed " + QString::fromStdString(error.Error())); } } - /** * @brief Check if the dmx info is arriving each 4 seconds * @return bool */ bool CheckDataLoss(); - /** * @brief RepeteableDMXCallBack from ola called when arrives a new dmx frame * typedef Callback2 ola::client::RepeatableDMXCallback - * This is called one for second if there is not updated in the DMX frame. We need emit only the channels that - * has changed to save resources. - * - * + * This is called one for second if there is not updated in the DMX frame. + * emit only the channels that has been changed. */ void NewDmx(const ola::client::DMXMetadata &dmx_meta, const ola::DmxBuffer &buffer); // - /** * @brief Sometimes the ola server closes the connection. This is a callback to handle this event an reconect to ola - * - * */ void socketClosed(); - - /** - * @brief Open the connection with olad and start processing data. - * - * - */ - void init(); + void init(); public slots: - - void stop(); // Close the connection with olad. - - /** - * @brief register one Universe - * void ola::client::OlaClient::RegisterUniverse(unsigned int universe,RegisterAction register_action,SetCallback * callback - * @param universe - */ + void stop(); inline void registerUniverse(int universe) { - qDebug("Registering universe %d", universe); + qInfo("Registering universe %d", universe); m_client->RegisterUniverse(universe, ola::client::REGISTER, ola::NewSingleCallback (this, &olaThread::RegisterComplete)); } - - /** - * @brief Register all the universes again - * - */ inline void registerUniverse() { QSet unis = Settings::getInstance()->getUniverses(); foreach (const int &universe, unis) { @@ -128,15 +95,8 @@ public slots: } } -protected slots: - signals: - -// void finished(); // Signal for closing. Not used now. - void dmxOutput(int layer, int channel, int value); // Signal when a channel has changed - void toTerminal(QString message); - void universeReceived(uint universe); - void layerReceived(); + void dmxOutput(int layer, int channel, int value); }; using namespace ola; diff --git a/src/settings.cpp b/src/settings.cpp index 4dc7bff..510685f 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -73,27 +73,22 @@ void Settings::readFromFile(QString file) { m_settings.append(temp); if (!m_universe.contains(temp.universe)) { m_universe.insert(temp.universe); -// emit registerUniverse(temp.universe); } counter++; } } } - if(xmlReader->hasError()) { QMessageBox::critical(NULL,"File xml Parse Error ", xmlReader->errorString(), QMessageBox::Ok); qWarning("File xml Parse Error %s", xmlReader->errorString().toLatin1().constData()); return; } - //close reader and flush file xmlReader->clear(); xmlFile->close(); - delete xmlReader; delete xmlFile; } - /** Read the default file * */ @@ -110,7 +105,6 @@ void Settings::changeLayerSetup(int layer, int universe, int address) m_settings.replace(layer, temp); if (!m_universe.contains(temp.universe)) { m_universe.insert(temp.universe); -// emit registerUniverse(temp.universe); } } -- 2.39.5 From 8b5d9414d14aed76df454190a62696c7a59d4630 Mon Sep 17 00:00:00 2001 From: snt Date: Tue, 23 Apr 2024 20:16:24 +0200 Subject: [PATCH 05/49] funcionando sin la parte de las settings. --- docs/changelog.txt | 17 +- docs/roadmap.txt | 8 +- libremediaserver-audio.pro | 10 +- src/audiolayerwidget.cpp | 177 +++++++------------ src/audiolayerwidget.h | 14 +- src/audiowidget.cpp | 8 + src/audiowidget.h | 3 +- src/{audiomasterwidget.cpp => dmxwidget.cpp} | 17 +- src/{audiomasterwidget.h => dmxwidget.h} | 17 +- src/libremediaserver-audio.cpp | 64 ++----- src/libremediaserver-audio.h | 7 +- src/medialibrary.cpp | 7 - src/miniaudioengine.cpp | 13 ++ src/miniaudioengine.h | 1 + src/olathread.cpp | 1 + src/olathread.h | 1 + src/settings.cpp | 3 - src/settings.h | 146 ++------------- src/slidergroup.cpp | 30 ++++ src/slidergroup.h | 38 ++++ 20 files changed, 239 insertions(+), 343 deletions(-) rename src/{audiomasterwidget.cpp => dmxwidget.cpp} (51%) rename src/{audiomasterwidget.h => dmxwidget.h} (54%) create mode 100644 src/slidergroup.cpp create mode 100644 src/slidergroup.h diff --git a/docs/changelog.txt b/docs/changelog.txt index d019bb8..7ad0243 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -6,15 +6,14 @@ https://git.criptomart.net/libremediaserver Lbre Media Server ChangeLog -v 1.4 -- change engine to miniaudio. -- Select sound device output. -- pan. -- Show faders values. - --> Hacer UI por fader: mute/centrado, valor, visualizador: - --> Hacer UI con la visualización de tiempos. -- SettingsDialog. -- Load/save conf file. +v 0.1.4 ++ change engine to miniaudio. Refactor all audio methods to MiniAudioEngine. ++ Select sound device output. ++ pan. ++ Show faders values. ++ play offset. ++ Refactor AudioMasterWidget to AudioDMXReceptionWidget. Master functions will be in AudioWidget. ++ mp3, flac, wav (mp3 has given some errors seeking cursor...). v 0.1.3 (19/04/2024) diff --git a/docs/roadmap.txt b/docs/roadmap.txt index 91b9a4b..1171e6b 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -32,8 +32,6 @@ v 1.5 - Play all medias found in folder consecutevily or random, with loop. - Play all medias, consecutevily and random, with loop. - mute/panic on layer. -- loop points. -- play offset. ¿stop offset? - number of layers configured in conf file, up to 256. - Master Bus Layer: - each layer will have one "Gain" prefader that acts in source, "Vol" in v 1.3. @@ -44,10 +42,12 @@ v 1.5 - magicq .hed - audio device linked, outputs will be redirected there. - dmx address + universe settings. -- Keyboards strokes, select files from ui. +- Keyboards strokes, load media files from ui. - Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante. - LOGs y entrada de comandos. - Bufgix: depurar errores cuando no carga la librería de medias, cambia el númmero de capas, cambia el universo, etc. -- Refactor AudioMasterWidget to AudioDMXReceptionWidget. Master functions will be in AudioWidget. - New control mode without pitch control, it saves resources. MA_SOUND_FLAG_NO_PITCH - Vumeter or indicator about audio output in layer and master. +- SettingsDialog. +- Load/save conf file. +- ¿stop offset? is it needed? diff --git a/libremediaserver-audio.pro b/libremediaserver-audio.pro index d86932e..8add248 100644 --- a/libremediaserver-audio.pro +++ b/libremediaserver-audio.pro @@ -2,6 +2,7 @@ TEMPLATE = app TARGET = libremediaserver-audio QT += webkitwidgets widgets HEADERS += src/libremediaserver-audio.h \ + src/dmxwidget.h \ src/miniaudio.h \ src/medialibrary.h \ src/miniaudioengine.h \ @@ -9,12 +10,13 @@ HEADERS += src/libremediaserver-audio.h \ src/audiolayerwidget.h \ src/dmxPersonality.h \ src/audiowidget.h \ - src/audiomasterwidget.h \ src/defines.h \ src/settings.h \ src/settingsdialog.h \ - src/layersettingswidget.h + src/layersettingswidget.h \ + src/slidergroup.h SOURCES += src/main.cpp \ + src/dmxwidget.cpp \ src/miniaudio.c \ src/libremediaserver-audio.cpp \ src/medialibrary.cpp \ @@ -22,10 +24,10 @@ SOURCES += src/main.cpp \ src/olathread.cpp \ src/audiolayerwidget.cpp \ src/audiowidget.cpp \ - src/audiomasterwidget.cpp \ src/settings.cpp \ src/settingsdialog.cpp \ - src/layersettingswidget.cpp + src/layersettingswidget.cpp \ + src/slidergroup.cpp FORMS += src/libremediaserver-audio.ui \ src/settingsdialog.ui \ src/layersettingswidget.ui diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 3c58b2c..1a5996c 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -5,102 +5,61 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name, int layer): QGroupBox(parent) , m_layer(layer) , m_suspendResumeButton(0) - , m_volumeIndicator(new QSpinBox) - , m_panIndicator(new QSpinBox) - , m_pitchIndicator(new QSpinBox) { this->setTitle(name); QVBoxLayout *layout = new QVBoxLayout; - QGridLayout *status = new QGridLayout; - m_statusValue = new QLabel; - status->addWidget(m_statusValue, 1, 1); - m_folderValue = new QLabel; - m_folderValue->setMaximumWidth(100); - status->addWidget(m_folderValue, 0, 0); - m_fileValue = new QLabel; - m_fileValue->setMaximumWidth(100); - status->addWidget(m_fileValue, 0, 2); - layout->addLayout(status); - - QGridLayout *volumeBox = new QGridLayout; - m_volumeLabel = new QLabel; - m_volumeLabel->setText(tr(VOLUME_LABEL)); - m_volumeSlider = new QSlider(Qt::Horizontal); - m_volumeSlider->setMinimum(0); - m_volumeSlider->setMaximum(100); - m_volumeSlider->setSingleStep(1); - m_volumeIndicator->setRange(0, 100); - m_volumeIndicator->setValue(0); - m_volumeIndicator->setMaximumWidth(40); - m_volumeIndicator->setButtonSymbols(QAbstractSpinBox::NoButtons); - volumeBox->addWidget(m_volumeLabel, 0, 0); - volumeBox->addWidget(m_volumeSlider, 0, 1); - volumeBox->addWidget(m_volumeIndicator, 0, 2); - connect(m_volumeSlider, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int))); - connect(m_volumeSlider, &QSlider::valueChanged, this, [=] () { - m_volumeIndicator->setValue(m_volumeSlider->value()); - }); - m_panLabel = new QLabel; - m_panLabel->setText("Pan"); - m_panSlider = new QSlider(Qt::Horizontal); - m_panSlider->setMinimum(0); - m_panSlider->setMaximum(255); - m_panSlider->setSingleStep(1); - m_panIndicator->setRange(0, 255); - m_panIndicator->setValue(128); - m_panIndicator->setMaximumWidth(40); - m_panIndicator->setButtonSymbols(QAbstractSpinBox::NoButtons); - connect(m_panSlider, &QSlider::valueChanged, this, [=] () { - m_panIndicator->setValue(m_panSlider->value()); - }); - connect(m_panSlider, SIGNAL(valueChanged(int)), this, SLOT(panChanged(int))); - volumeBox->addWidget(m_panLabel, 1, 0); - volumeBox->addWidget(m_panSlider, 1, 1); - volumeBox->addWidget(m_panIndicator, 1, 2); - m_pitchLabel = new QLabel; - m_pitchLabel->setText("Pitch"); - m_pitchSlider = new QSlider(Qt::Horizontal); - m_pitchSlider->setMinimum(0); - m_pitchSlider->setMaximum(255); - m_pitchSlider->setSingleStep(1); - m_pitchIndicator->setRange(0, 255); - m_pitchIndicator->setValue(128); - m_pitchIndicator->setMaximumWidth(40); - m_pitchIndicator->setButtonSymbols(QAbstractSpinBox::NoButtons); - connect(m_pitchSlider, &QSlider::valueChanged, this, [=] () { - m_pitchIndicator->setValue(m_pitchSlider->value()); - }); - connect(m_pitchSlider, SIGNAL(valueChanged(int)), this, SLOT(pitchChanged(int))); - volumeBox->addWidget(m_pitchLabel, 2, 0); - volumeBox->addWidget(m_pitchSlider, 2, 1); - volumeBox->addWidget(m_pitchIndicator, 2, 2); - layout->addLayout(volumeBox); - QHBoxLayout *progressTime = new QHBoxLayout; - m_progressTimeLabel = new QLabel; - m_progressTimeLabel->setText(PROGRESS_TIME_LABEL); + //m_progressTimeLabel = new QLabel; + //m_progressTimeLabel->setText(PROGRESS_TIME_LABEL); + //progressTime->addWidget(m_progressTimeLabel); m_progressTime = new QTimeEdit; m_progressTime->text(); m_progressTime->setDisplayFormat("h:mm:ss:zzz"); m_progressTime->setReadOnly(true); m_progressTime->setButtonSymbols(QAbstractSpinBox::NoButtons); - m_progressTime->setMaximumWidth(100); - progressTime->addWidget(m_progressTimeLabel); + m_progressTime->setMaximumWidth(90); + m_progressTime->setFocusPolicy(Qt::NoFocus); progressTime->addWidget(m_progressTime); - m_totalTimeLabel = new QLabel; - m_totalTimeLabel->setText(TOTAL_TIME_LABEL); + //m_totalTimeLabel = new QLabel; + //m_totalTimeLabel->setText(TOTAL_TIME_LABEL); + //progressTime->addWidget(m_totalTimeLabel); m_totalTimeValue = new QTimeEdit; m_totalTimeValue->setDisplayFormat("h:mm:ss:zzz"); m_totalTimeValue->setReadOnly(true); m_totalTimeValue->setButtonSymbols(QAbstractSpinBox::NoButtons); - m_totalTimeValue->setMaximumWidth(100); - progressTime->addWidget(m_totalTimeLabel); + m_totalTimeValue->setMaximumWidth(90); + m_totalTimeValue->setFocusPolicy(Qt::NoFocus); progressTime->addWidget(m_totalTimeValue); layout->addLayout(progressTime); m_progressSlider = new QSlider(Qt::Horizontal); + m_progressSlider->setFocusPolicy(Qt::NoFocus); layout->addWidget(m_progressSlider); + + QGridLayout *status = new QGridLayout; + m_statusValue = new QLabel; + status->addWidget(m_statusValue, 0, 0); + m_folderValue = new QLabel; + m_folderValue->setMaximumWidth(200); + status->addWidget(m_folderValue, 1, 0); + m_fileValue = new QLabel; + m_fileValue->setMaximumWidth(200); + status->addWidget(m_fileValue, 2, 0); + layout->addLayout(status); + + QHBoxLayout *volumeBox = new QHBoxLayout; + m_volume = new SliderGroup("Vol", 0 , 100, NULL); + volumeBox->addWidget(m_volume); + connect(m_volume, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int))); + m_pan = new SliderGroup("Pan", 0 , 255, NULL); + volumeBox->addWidget(m_pan); + connect(m_pan, SIGNAL(valueChanged(int)), this, SLOT(panChanged(int))); + m_pitch = new SliderGroup("Pitch", 0 , 255, NULL); + volumeBox->addWidget(m_pitch); + connect(m_pitch, SIGNAL(valueChanged(int)), this, SLOT(pitchChanged(int))); + layout->addLayout(volumeBox); + m_suspendResumeButton = new QPushButton(this); m_suspendResumeButton->setText(tr(SUSPEND_LABEL)); connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume())); @@ -149,26 +108,23 @@ void AudioLayerWidget::toggleSuspendResume() // from DMX signals void AudioLayerWidget::setVol(qreal vol) { - m_volumeSlider->blockSignals(true); - m_volumeSlider->setValue(vol); - m_volumeIndicator->setValue(vol); - m_volumeSlider->blockSignals(false); + m_volume->blockSignals(true); + m_volume->setValue(vol); + m_volume->blockSignals(false); } void AudioLayerWidget::setPan(qreal pan) { - m_panSlider->blockSignals(true); - m_panSlider->setValue(pan); - m_panIndicator->setValue(pan); - m_panSlider->blockSignals(false); + m_pan->blockSignals(true); + m_pan->setValue(pan); + m_pan->blockSignals(false); } void AudioLayerWidget::setPitch(qreal pitch) { - m_pitchSlider->blockSignals(true); - m_pitchSlider->setValue(pitch); - m_pitchIndicator->setValue(pitch); - m_pitchSlider->blockSignals(false); + m_pitch->blockSignals(true); + m_pitch->setValue(pitch); + m_pitch->blockSignals(false); } void AudioLayerWidget::fileLoaded(QString file) @@ -181,36 +137,35 @@ void AudioLayerWidget::fileLoaded(QString file) } } -QString AudioLayerWidget::getStatus() -{ - QString tmp; - switch (m_status) { - case Status::Paused: - tmp.append("Paused"); - break; - case Status::PlayingLoop: - tmp.append("Playing Loop"); - break; - case Status::PlayingOnce: - tmp.append("Playing one"); - break; - case Status::Stopped: - tmp.append("Stopped"); - break; - } - return tmp; -} - void AudioLayerWidget::setPlaybackStatus(Status status) { m_status = status; if (status == Status::Stopped) m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(0)); - QString tmp = this->getStatus(); m_statusValue->blockSignals(true); m_suspendResumeButton->blockSignals(true); - m_statusValue->setText(tmp); - m_suspendResumeButton->setText(tmp); + switch (m_status) { + case Status::Paused: + m_statusValue->setText("Pause"); + m_statusValue->setStyleSheet("QLabel { color : red; }"); + m_suspendResumeButton->setText("Pause"); + break; + case Status::PlayingLoop: + m_statusValue->setText("Play Loop"); + m_statusValue->setStyleSheet("QLabel { color : green; }"); + m_suspendResumeButton->setText("Play Loop"); + break; + case Status::PlayingOnce: + m_statusValue->setText("Play One"); + m_statusValue->setStyleSheet("QLabel { color : green; }"); + m_suspendResumeButton->setText("Play One"); + break; + case Status::Stopped: + m_statusValue->setText("Stop"); + m_statusValue->setStyleSheet("QLabel { color : red; }"); + m_suspendResumeButton->setText("Stop"); + break; + } m_statusValue->blockSignals(false); m_suspendResumeButton->blockSignals(false); } diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index f91858f..a484227 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -17,6 +17,7 @@ #include #include "defines.h" +#include "slidergroup.h" class AudioLayerWidget : public QGroupBox { @@ -32,7 +33,6 @@ public: void setLoop(bool on); void setPlaybackStatus(Status status); inline Status getPlaybackStatus() { return m_status; } - QString getStatus(); private: Status m_status; @@ -44,15 +44,9 @@ private: QLabel *m_fileValue; QLabel * m_folderLabel; QLabel * m_folderValue; - QLabel *m_volumeLabel; - QSlider *m_volumeSlider; - QSpinBox *m_volumeIndicator; - QLabel *m_panLabel; - QSlider *m_panSlider; - QSpinBox *m_panIndicator; - QLabel *m_pitchLabel; - QSlider *m_pitchSlider; - QSpinBox *m_pitchIndicator; + SliderGroup *m_volume; + SliderGroup *m_pan; + SliderGroup *m_pitch; QLabel * m_progressLabel; QSlider *m_progressSlider; QLabel *m_progressTimeLabel; diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index d1274d6..63ca562 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -81,6 +81,14 @@ void AudioWidget::playbackChanged(int layer, Status status) dynamic_cast(item->widget())->setPlaybackStatus(status); } +void AudioWidget::entryPointChanged(int layer, int cursor) +{ + m_mae.setCursor(layer, cursor); + QLayoutItem * const item = m_layout->itemAt(layer); + AudioLayerWidget *aw = dynamic_cast(item->widget()); + aw->refreshUi(m_mae.getCursor(layer)); +} + void AudioWidget::refreshUi() { for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) { QLayoutItem * const item = m_layout->itemAt(i); diff --git a/src/audiowidget.h b/src/audiowidget.h index 26f63b1..cee8dd1 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -5,7 +5,7 @@ #include #include -#include "audiomasterwidget.h" +#include "dmxwidget.h" #include "audiolayerwidget.h" #include "settings.h" #include "miniaudioengine.h" @@ -31,6 +31,7 @@ protected: void panChanged(int layer, qreal pan); void pitchChanged(int layer, qreal pitch); void playbackChanged(int layer, Status status); + void entryPointChanged(int layer, int cursor); private: MiniAudioEngine m_mae; diff --git a/src/audiomasterwidget.cpp b/src/dmxwidget.cpp similarity index 51% rename from src/audiomasterwidget.cpp rename to src/dmxwidget.cpp index c8a2db1..4383a76 100644 --- a/src/audiomasterwidget.cpp +++ b/src/dmxwidget.cpp @@ -1,29 +1,32 @@ -#include "audiomasterwidget.h" +#include "dmxwidget.h" -AudioMasterWidget::AudioMasterWidget(QWidget *parent) : +dmxWidget::dmxWidget(QWidget *parent) : QGroupBox(parent) , m_receiveDMX(new QCheckBox) , m_watchDMX(new QTimer) { + this->setFocusPolicy(Qt::FocusPolicy::NoFocus); QVBoxLayout *vbox = new QVBoxLayout; m_receiveDMX->setText("DMX signal"); vbox->addWidget(m_receiveDMX); this->setLayout(vbox); connect(m_watchDMX, SIGNAL(timeout()), this, SLOT(watchDMXExpired())); - m_watchDMX->start(1000); + m_watchDMX->start(2000); } -AudioMasterWidget::~AudioMasterWidget() +dmxWidget::~dmxWidget() { } -void AudioMasterWidget::watchDMXExpired() { +void dmxWidget::watchDMXExpired() { m_receiveDMX->setChecked(false); } -void AudioMasterWidget::updateWatchDMX() +void dmxWidget::updateWatchDMX(int uni) { - m_receiveDMX->setChecked(true); + (void)uni; + if (m_receiveDMX->isChecked() == false) + m_receiveDMX->setChecked(true); } diff --git a/src/audiomasterwidget.h b/src/dmxwidget.h similarity index 54% rename from src/audiomasterwidget.h rename to src/dmxwidget.h index 51218c8..e1540a1 100644 --- a/src/audiomasterwidget.h +++ b/src/dmxwidget.h @@ -1,5 +1,5 @@ -#ifndef AUDIOMASTERWIDGET_H -#define AUDIOMASTERWIDGET_H +#ifndef DMXWIDGET_H +#define DMXWIDGET_H #include #include @@ -7,19 +7,18 @@ #include #include #include +#include - -class AudioMasterWidget : public QGroupBox +class dmxWidget : public QGroupBox { Q_OBJECT public: - AudioMasterWidget(QWidget *parent); - - ~AudioMasterWidget(); + dmxWidget(QWidget *parent); + ~dmxWidget(); public slots: - void updateWatchDMX(); + void updateWatchDMX(int uni); private: QCheckBox *m_receiveDMX; @@ -30,4 +29,4 @@ private slots: }; -#endif // AUDIOMASTERWIDGET_H +#endif // DMXWIDGET_H diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index f8193e7..6f6e263 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -27,55 +27,30 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) Q_UNUSED(args); ui.setupUi(this); this->setWindowTitle(VERSION); - Settings *set = Settings::getInstance(); set->readFile(); connect(set, SIGNAL(audioDeviceChanged(int)), this, SLOT(audioDeviceChanged(int))); -/* - if (args.contains("-log")) { - // Inicia el widget Terminal - textEdit = new QTextEdit; - textEdit->setReadOnly(true); - QDockWidget *bottomWidget = new QDockWidget(tr("Terminal"), this); - bottomWidget->setAllowedAreas(Qt::BottomDockWidgetArea); - bottomWidget->setWidget(textEdit); - addDockWidget(Qt::BottomDockWidgetArea, bottomWidget); - connect(ola, SIGNAL(toTerminal(QString)), - textEdit, SLOT(append(QString)), Qt::QueuedConnection); - }*/ - - /* connect(MediaLibrary::getInstance(), SIGNAL(debug(QString)), - textEdit, SLOT(append(QString)), Qt::QueuedConnection); - - connect(MediaLibrary::getInstance(), SIGNAL(warning(QString)), - textEdit, SLOT(append(QString)), Qt::QueuedConnection); - */ - this->setWindowTitle(VERSION); qDebug() << VERSION; qDebug() << COPYRIGHT; qDebug() << LICENSE; - - // start audio engine MediaLibrary::getInstance()->initMediaLibrary(); aw = new AudioWidget; setCentralWidget(aw); - amw = new AudioMasterWidget(this); + m_dmxWidget = new dmxWidget(this); QDockWidget *topWidget = new QDockWidget(tr("Master"), this); topWidget->setAllowedAreas(Qt::TopDockWidgetArea); - topWidget->setWidget(amw); + topWidget->setWidget(m_dmxWidget); addDockWidget(Qt::TopDockWidgetArea, topWidget); - // ola setup ola = new olaThread(this, set->getLayersNumber()); Q_CHECK_PTR(ola); ola->blockSignals(true); connect(set, SIGNAL(registerUniverse(int)), ola, SLOT(registerUniverse(int))); - connect(ola, SIGNAL (layerReceived()), amw, SLOT(updateWatchDMX())); + connect(ola, SIGNAL (universeReceived(int)), m_dmxWidget, SLOT(updateWatchDMX(int))); connect(ola, SIGNAL(dmxOutput(int, int, int)), this, SLOT(dmxInput(int, int, int))); connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup())); ola->registerUniverse(); ola->start(QThread::TimeCriticalPriority ); - // menus connect(ui.actionOpen_conf, SIGNAL(triggered()), this, SLOT(openFile())); connect(ui.actionSave_conf, SIGNAL(triggered()), this, SLOT(saveFile())); connect(ui.action_Settings, SIGNAL(triggered()), this, SLOT(settings())); @@ -85,21 +60,12 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) ola->resendDmx(); } -/////////////////////////////////////////////////////////////////// -// Destructor -/////////////////////////////////////////////////////////////////// - libreMediaServerAudio::~libreMediaServerAudio() { ola->stop(); aw->stopEngine(); } -/////////////////////////////////////////////////////////////////// -// Menu File -/////////////////////////////////////////////////////////////////// - -// Open a configuration File void libreMediaServerAudio::openFile() { QFileDialog dialog(this); @@ -110,7 +76,7 @@ void libreMediaServerAudio::openFile() QFile file(fileNames.at(0)); // open(&file); } -// Save configuration File + void libreMediaServerAudio::saveFile() { QFileDialog dialog(this); @@ -128,11 +94,6 @@ void libreMediaServerAudio::settings() sd->show(); } - -/////////////////////////////////////////////////////////////////// -// OLA Stuff -/////////////////////////////////////////////////////////////////// - void libreMediaServerAudio::olasetup() { QWebView *view = new QWebView(); @@ -142,21 +103,20 @@ void libreMediaServerAudio::olasetup() void libreMediaServerAudio::dmxInput(int layer, int channel, int value) { -// This qDebug slows all the program. Uncomment only for debugging purpouse and comment again in normal use -// qDebug() << tr("olaInterface|") << "newdmx layer" << layer << "channel" << channel << "value" << value; if (layer > LAYER_CHANNELS) return; QString mediaFile = NULL; int aux; qreal f; + int r; switch(channel){ - case DMX_FOLDER:// Folder + case DMX_FOLDER: aux = ola->getValue(layer, DMX_FILE); mediaFile = MediaLibrary::getInstance()->requestNewFile(value, aux); if (QFile::exists(mediaFile)) aw->mediaLoaded(layer, mediaFile); break; - case DMX_FILE:// File + case DMX_FILE: aux = ola->getValue(layer, DMX_FOLDER); mediaFile = MediaLibrary::getInstance()->requestNewFile(aux, value); if (QFile::exists(mediaFile)) @@ -176,6 +136,14 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) case PITCH: aw->pitchChanged(layer, value); break; + case ENTRY_POINT_COARSE: + r = ( value * 0x100 ) + ola->getValue(layer, ENTRY_POINT_FINE); + aw->entryPointChanged(layer, r); + break; + case ENTRY_POINT_FINE: + r = ( ola->getValue(layer, ENTRY_POINT_COARSE) * 0x100 ) + value; + aw->entryPointChanged(layer, r); + break; case PLAYBACK: if (value == 0) break; @@ -193,6 +161,8 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) case 3 : aw->playbackChanged(layer, PlayingLoop); break; + default : + break; } default: break; diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index 751ffcd..78b347b 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -20,7 +20,6 @@ #ifndef LIBREMEDIASERVERAUDIO_H #define LIBREMEDIASERVERAUDIO_H - #include #include #include @@ -38,7 +37,7 @@ #include "medialibrary.h" #include "olathread.h" #include "settings.h" -#include "audiomasterwidget.h" +#include "dmxwidget.h" #include "settingsdialog.h" #include "defines.h" @@ -56,9 +55,8 @@ public: Ui::LibreMediaServerAudio ui; private: -// void MessageHandler(QtMsgType type, const QMessageLogContext &logcontext, const QString &msg); AudioWidget *aw; - AudioMasterWidget *amw; + dmxWidget *m_dmxWidget; olaThread *ola; void open_start(); @@ -75,6 +73,7 @@ private slots: void openFile(); void saveFile(); void settings(); + }; #endif // LIBREMEDIASERVERAUDIO_H diff --git a/src/medialibrary.cpp b/src/medialibrary.cpp index ee46837..38e8d87 100644 --- a/src/medialibrary.cpp +++ b/src/medialibrary.cpp @@ -42,9 +42,6 @@ void MediaLibrary::initMediaLibrary() { } } -/** - * fill the struct with all files in one library/folder - */ QList MediaLibrary::getMediaInformation(QDir dir) { QList mediaList; @@ -54,7 +51,6 @@ QList MediaLibrary::getMediaInformation(QDir dir) QFileInfo fileInfo; for (int i = 0; i < filelist.size(); ++i) { fileInfo = filelist.at(i); - // Update the data base with the new file mediainf.Number = i; mediainf.MediaName = fileInfo.absoluteFilePath(); mediainf.MediaLength = 1000; @@ -63,9 +59,6 @@ QList MediaLibrary::getMediaInformation(QDir dir) return mediaList; } -/** - * returns the path to a media file from the library. - */ QString MediaLibrary::requestNewFile(int folder, int file){ if (!m_media) { qWarning("MediaLibrary is not init. Set a correct path to media library"); diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index ed010a6..ae74043 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -236,3 +236,16 @@ void MiniAudioEngine::playbackChanged(int layer, Status status) break; } } + +void MiniAudioEngine::setCursor(int layer, int cursor) +{ + ma_uint64 f; + + if (m_mediaLoaded[layer] == false) + return; + ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &f); + f = (cursor * f) / 65025; + ma_sound_seek_to_pcm_frame(&m_currentSound[layer], f); + //ma_sound_set_start_time_in_pcm_frames(&m_currentSound[layer], f); + //ma_data_source_set_range_in_pcm_frames(&m_currentSound[layer], f, total); +} diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 8cda15b..c38c793 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -26,6 +26,7 @@ protected: void playbackChanged(int layer, Status status); float getDuration(int layer); float getCursor(int layer); + void setCursor(int layer, int cursor); ma_result printFormatInfo(int layer); private: diff --git a/src/olathread.cpp b/src/olathread.cpp index 1453e2d..fdfe041 100644 --- a/src/olathread.cpp +++ b/src/olathread.cpp @@ -75,6 +75,7 @@ void olaThread::NewDmx(const ola::client::DMXMetadata &data, } } } + emit universeReceived(data.universe); } /** diff --git a/src/olathread.h b/src/olathread.h index 9692d9e..ee18824 100644 --- a/src/olathread.h +++ b/src/olathread.h @@ -97,6 +97,7 @@ public slots: signals: void dmxOutput(int layer, int channel, int value); + void universeReceived(int uni); }; using namespace ola; diff --git a/src/settings.cpp b/src/settings.cpp index 510685f..b0aab3a 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -89,9 +89,6 @@ void Settings::readFromFile(QString file) { delete xmlFile; } -/** Read the default file - * - */ void Settings::readFile() { readFromFile(DEFAULT_FILE); } diff --git a/src/settings.h b/src/settings.h index 2301d53..5b9c813 100644 --- a/src/settings.h +++ b/src/settings.h @@ -11,157 +11,49 @@ #include "audiowidget.h" #include "defines.h" -/** - * This class stores the settings on lms. - * Is a singleton with set and get methods to manage the settings - * Also writes and reads the settings files. - */ - class Settings : public QObject { Q_OBJECT public: - - static Settings *getInstance(); //Singleton - - /** - * @brief getUniverses - * @return - */ - inline QSet getUniverses() { return m_universe; } - - /** - * @brief getPathMedia - * @return - */ - inline QString getPathMedia() { return m_pathmedia; } - - /** - * @brief setPathMedia - * @param path - */ - void setPathMedia(QString path); - - /** - * @brief getDmxSettings - * @return - */ - inline QList getDmxSettings() { return m_settings; } - - /** - * @brief Get the number of layer currently used - * @return - */ - inline int getLayersNumber() { return m_layersNumber; } - - /** - * @brief Get the number of universes registered - * @return - */ - inline int getUniverseNumber() { return m_universe.size(); } - - /** - * @brief Read the default xml configuration file at startup - */ - void readFile(); - - /** - * @brief changeLayerSetup - * @param layer - * @param universe - * @param address - */ - void changeLayerSetup(int layer, int universe, int address); - - /** - * @brief removeLayer - * @param layer - */ - void removeLayer(int layer); - - /** - * @brief addLayer - */ - void addLayer(); - - /** - * @brief olaThread::setLayersNumber - * @param layersNumber - * - */ - inline void setLayersNumber(int layersNumber) - { + static Settings *getInstance(); + inline QSet getUniverses() { return m_universe; } + inline QString getPathMedia() { return m_pathmedia; } + void setPathMedia(QString path); + inline QList getDmxSettings() { return m_settings; } + inline int getLayersNumber() { return m_layersNumber; } + inline int getUniverseNumber() { return m_universe.size(); } + void readFile(); + void changeLayerSetup(int layer, int universe, int address); + void removeLayer(int layer); + void addLayer(); + inline void setLayersNumber(int layersNumber) + { if (layersNumber <= MAX_LAYERS) m_layersNumber = layersNumber; else m_layersNumber = MAX_LAYERS; - } - - inline int getAudioDeviceId() { return m_audioDeviceId; } - inline void setAudioDeviceId(int id) { m_audioDeviceId = id; } - + } + inline int getAudioDeviceId() { return m_audioDeviceId; } + inline void setAudioDeviceId(int id) { m_audioDeviceId = id; } private: - static Settings *_instance; - - // The list where we store the settings by layer QList m_settings; - - // The path to media library QString m_pathmedia; - - // The SO audio device id used uint m_audioDeviceId; + QSet m_universe; + int m_layersNumber; - /** Constructor - * - */ explicit Settings(QObject *parent = 0); - - QSet m_universe; // Registered universes. - - int m_layersNumber; // Number of layers in wich divide the dmx frame. Each layer, one source. - - /** - * @brief readFromFile - * @param file - */ - void readFromFile(QString file); - - /** - * @brief writeFile - * @param filename - */ + void readFromFile(QString file); // void writeFile(QString filename); // Not implemented yet - - /** - * @brief writeFile - * overload - */ // void writeFile(); // Not implemented yet signals: - - /** - * @brief pathChanged - * @param path - */ void pathChanged(QString path); - - /** - * @brief layersNumber - * @param number - */ void layersNumber(int number); - - /** - * @brief DMXConf - * @param universe - */ void registerUniverse(int universe); - void audioDeviceChanged(int id); }; diff --git a/src/slidergroup.cpp b/src/slidergroup.cpp new file mode 100644 index 0000000..9b7e234 --- /dev/null +++ b/src/slidergroup.cpp @@ -0,0 +1,30 @@ +#include "slidergroup.h" + +SliderGroup::SliderGroup(const QString &title, \ + int min, + int max, + QWidget *parent) + : QGroupBox(title, parent) +{ + this->setFlat(true); + this->setTitle(title); + slider = new QSlider(Qt::Orientation::Vertical); + slider->setFocusPolicy(Qt::StrongFocus); + slider->setTickPosition(QSlider::TicksBothSides); + slider->setTickInterval((max - min) / 11); + slider->setSingleStep(1); + slider->setRange(min, max); + //slider->setInvertedAppearance(false); + //slider->setInvertedControls(false); + valueBox = new QSpinBox(); + valueBox->setFocusPolicy(Qt::NoFocus); + valueBox->setButtonSymbols(QAbstractSpinBox::NoButtons); + valueBox->setMaximumWidth(40); + valueBox->setRange(min, max); + connect(slider, &QSlider::valueChanged, valueBox, &QSpinBox::setValue); + connect(slider, SIGNAL(valueChanged(int)), this, SLOT(sliderValueChanged(int))); + QVBoxLayout *slidersLayout = new QVBoxLayout(); + slidersLayout->addWidget(valueBox); + slidersLayout->addWidget(slider); + setLayout(slidersLayout); +} diff --git a/src/slidergroup.h b/src/slidergroup.h new file mode 100644 index 0000000..9b7b704 --- /dev/null +++ b/src/slidergroup.h @@ -0,0 +1,38 @@ +#ifndef SLIDERGROUP_H +#define SLIDERGROUP_H + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QDial; +class QScrollBar; +class QSlider; +QT_END_NAMESPACE + +class SliderGroup : public QGroupBox +{ + Q_OBJECT + +public: + SliderGroup(const QString &title, + int min, + int max, + QWidget *parent = nullptr); + +signals: + void valueChanged(int value); + +public slots: + inline void setValue(int value) { slider->setValue(value); }; + inline void sliderValueChanged(int value) { emit valueChanged(value); }; + +private: + QSlider *slider; + QSpinBox *valueBox; +}; + +#endif -- 2.39.5 From 6cfe89aa7c64405a33f060c57d9ae13d1364c817 Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 24 Apr 2024 14:00:02 +0200 Subject: [PATCH 06/49] bump version 0.2.0 --- docs/LibreMediaServer_Audio.hed | 131 ++++++++++++++++++-------------- docs/changelog.txt | 14 ++-- docs/lms-audio.xlm | 4 +- docs/roadmap.txt | 5 +- src/defines.h | 2 +- src/main.cpp | 4 +- 6 files changed, 92 insertions(+), 68 deletions(-) diff --git a/docs/LibreMediaServer_Audio.hed b/docs/LibreMediaServer_Audio.hed index 82be283..5da3a28 100644 --- a/docs/LibreMediaServer_Audio.hed +++ b/docs/LibreMediaServer_Audio.hed @@ -1,55 +1,76 @@ -ް׆ˌĠ򝤫鿰맫͓ԔҊÅЁ -ܥ -ңә -鿡 - -Ŷ -툢 -Ս - -߿ԁ -ö -ś— -髶 - - - - - - - - -х - - -ܛ - - - - -ǐ - - -ً - -ۃ - -붪 - - -܎ -Ė -쾡 -Ǖ - -𓎍 -ł - - - - - - - - - +ް׆ˌĠ򝤫鿰맫͓Ԕ +ҊÅЁ䍡 +ӽ +䉭ėĈ +ϛ +Ӧ +ڑ +ė + +ݍ +Ȫ +웣傪Ⓨ֚ +ކՂ +߸“ +Ŷ +ѝ +ωƀ + + + + +ŕ +ʷí +̙ +򴹤 +ԥѼ܅ +𗹣َ +̚ +Რ + +Ņ +⽬ +̫ +喤쏎ʁǏ + +߬ػс +썎ޛ + +쏎 + + + +Ճ + +尨 +ގ + +ލ +ƕ + +ŗ + + + + + +ˤ + + + + + +쏐 + + + +쏎 +󩼿 + + + +ÛƘ + + + + diff --git a/docs/changelog.txt b/docs/changelog.txt index 7ad0243..89eaf47 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -6,16 +6,18 @@ https://git.criptomart.net/libremediaserver Lbre Media Server ChangeLog -v 0.1.4 -+ change engine to miniaudio. Refactor all audio methods to MiniAudioEngine. +v 0.2.0 Antigona (24/04/2024) ++ change engine to miniaudio because is imposible pan in SFML and it has not access to low API and audio processing. ++ Refactor all audio methods to MiniAudioEngine. + Select sound device output. + pan. + Show faders values. + play offset. -+ Refactor AudioMasterWidget to AudioDMXReceptionWidget. Master functions will be in AudioWidget. ++ Refactor AudioMasterWidget to AudioDMXReceptionWidget. + mp3, flac, wav (mp3 has given some errors seeking cursor...). ++ settings dialog not working, only read the conf file at startup. -v 0.1.3 (19/04/2024) +v 0.1.3 Unreleased (19/04/2024) + Ubuntu 22.04 jammy. + Use SFML as audio engine. @@ -23,14 +25,14 @@ v 0.1.3 (19/04/2024) + pitch. + loop. -v 0.1.2 (12/08/2015) +v 0.1.2 Mayordomo (12/08/2015) - GUI config - Several bugs tested in real world - variable layers - SFML as audio engine -v 0.1.1 (24/09/2014) +v 0.1.1 Pascual (24/09/2014) + First Version: 4 layers playing .ogg + Needs Open Lighting Arquitecture => 0.9.0 diff --git a/docs/lms-audio.xlm b/docs/lms-audio.xlm index 49aac0e..cc498ca 100644 --- a/docs/lms-audio.xlm +++ b/docs/lms-audio.xlm @@ -1,8 +1,8 @@ - + - + diff --git a/docs/roadmap.txt b/docs/roadmap.txt index 1171e6b..4b96379 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -14,7 +14,7 @@ v 0.2.x - FX en capas master para que se puedan usar como envíos de auxiliar. - Enroutado de masters en otros masters (retorno de efectos). -v 0.2.0 +v 0.2.2 - Use sACN directly. + la instalación de OLA es mediante compilación, el repo de paquetes no está actualizado, nada user-friendly. + hay que empaquetar OLA, incluirlo en el binario, o implementar sACN y linkarlo estáticamente. @@ -25,7 +25,7 @@ v 0.2.0 - Rasp build. - Octopus Sound Card support (6 outputs - 8 inputs). -v 1.5 +v 0.2.1 - Multi devices output. - Rose noise and sine generator in menu to test system. - Play Mode: @@ -51,3 +51,4 @@ v 1.5 - SettingsDialog. - Load/save conf file. - ¿stop offset? is it needed? +- decouple MiniAudioEngine from AudioWidget, starts whith no gui or with gui in a dedicated thread. diff --git a/src/defines.h b/src/defines.h index ca94591..341bd0e 100644 --- a/src/defines.h +++ b/src/defines.h @@ -5,7 +5,7 @@ #include #include -#define VERSION "LibreMediaServer-Audio 0.1.4" +#define VERSION "LibreMediaServerAudio 0.2.0 Antigona Release" #define COPYRIGHT "(C) 2014-2024 Santi Norena lms@criptomart.net" #define LICENSE "GPL 3 License. See LICENSE.txt and credits.txt for details" #define DEFAULT_FILE "lms-audio.xlm" diff --git a/src/main.cpp b/src/main.cpp index c82efa8..25d84e0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -142,11 +142,11 @@ int main(int argc, char *argv[]) { qInstallMessageHandler(MessageHandler); }*/ -// qInstallMessageHandler(MessageHandler); + QApplication app(argc, argv); QStringList args = app.arguments(); - // parse the command line + if (args.size() > 1) { if (args.contains("-v")) -- 2.39.5 From 63f25e8209c93d612fc4b1e28e50e066f42ce5bf Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 24 Apr 2024 15:07:00 +0200 Subject: [PATCH 07/49] changed some printf to qlogs --- src/miniaudioengine.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index ae74043..6fb6709 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -48,7 +48,7 @@ ma_result MiniAudioEngine::startDevice(int id) deviceConfig.pUserData = &engine; result = ma_device_init(&context, &deviceConfig, &device); if (result != MA_SUCCESS) { - printf("Failed to initialize audio device %s.", pPlaybackDeviceInfos[id].name); + qCritical("Failed to initialize audio device %s.", pPlaybackDeviceInfos[id].name); return result; } engineConfig = ma_engine_config_init(); @@ -57,16 +57,16 @@ ma_result MiniAudioEngine::startDevice(int id) engineConfig.noAutoStart = MA_TRUE; result = ma_engine_init(NULL, &engine); if (result != MA_SUCCESS) { - printf("Failed to initialize audio engine."); + qCritical("Failed to initialize audio engine."); return result; } result = ma_engine_start(&engine); if (result != MA_SUCCESS) { - printf("Failed to start audio engine %i.", id); + qCritical("Failed to start audio engine %i.", id); return result; } iChosenDevice = id; - printf("Initialized audio device %d: %s", id, pPlaybackDeviceInfos[id].name); + qInfo("Initialized audio device %d: %s", id, pPlaybackDeviceInfos[id].name); return result; } @@ -81,12 +81,12 @@ ma_result MiniAudioEngine::startContext() resourceManagerConfig.jobThreadCount = 0; result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager); if (result != MA_SUCCESS) { - printf("Failed to initialize audio resource manager."); + qCritical("Failed to initialize audio resource manager."); return result; } result = ma_context_init(NULL, 0, NULL, &context); if (result != MA_SUCCESS) { - printf("Failed to initialize audio context."); + qCritical("Failed to initialize audio context."); } return result; } @@ -98,7 +98,7 @@ ma_result MiniAudioEngine::getAllAudioDevices() result = ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, NULL, NULL); if (result != MA_SUCCESS) { - printf("Failed to enumerate playback devices.\n"); + qWarning("Failed to enumerate playback devices.\n"); ma_context_uninit(&context); return result; } @@ -246,6 +246,4 @@ void MiniAudioEngine::setCursor(int layer, int cursor) ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &f); f = (cursor * f) / 65025; ma_sound_seek_to_pcm_frame(&m_currentSound[layer], f); - //ma_sound_set_start_time_in_pcm_frames(&m_currentSound[layer], f); - //ma_data_source_set_range_in_pcm_frames(&m_currentSound[layer], f, total); } -- 2.39.5 From 32a1e5cb0cdc30227e28c3d2221c0e7ee554a480 Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 24 Apr 2024 17:41:40 +0200 Subject: [PATCH 08/49] process double channels only once in each frame --- docs/changelog.txt | 1 + docs/roadmap.txt | 8 ++++--- src/audiolayerwidget.cpp | 20 +++++------------ src/audiolayerwidget.h | 8 +++---- src/audiowidget.cpp | 6 ++--- src/audiowidget.h | 6 ++--- src/defines.h | 8 +++++++ src/libremediaserver-audio.cpp | 16 +++----------- src/miniaudioengine.h | 2 -- src/olathread.cpp | 40 ++++++++++++++++++++++++++++++---- src/olathread.h | 1 + 11 files changed, 70 insertions(+), 46 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 89eaf47..4882ec8 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -16,6 +16,7 @@ v 0.2.0 Antigona (24/04/2024) + Refactor AudioMasterWidget to AudioDMXReceptionWidget. + mp3, flac, wav (mp3 has given some errors seeking cursor...). + settings dialog not working, only read the conf file at startup. ++ variable number of layers. v 0.1.3 Unreleased (19/04/2024) diff --git a/docs/roadmap.txt b/docs/roadmap.txt index 4b96379..9622ccd 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -32,7 +32,6 @@ v 0.2.1 - Play all medias found in folder consecutevily or random, with loop. - Play all medias, consecutevily and random, with loop. - mute/panic on layer. -- number of layers configured in conf file, up to 256. - Master Bus Layer: - each layer will have one "Gain" prefader that acts in source, "Vol" in v 1.3. - each layer will have one volume dmx channel for each bus layer. One aux "Send" prefader. @@ -44,11 +43,14 @@ v 0.2.1 - dmx address + universe settings. - Keyboards strokes, load media files from ui. - Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante. -- LOGs y entrada de comandos. +- Logs, verbosity, timestamp. - Bufgix: depurar errores cuando no carga la librería de medias, cambia el númmero de capas, cambia el universo, etc. - New control mode without pitch control, it saves resources. MA_SOUND_FLAG_NO_PITCH - Vumeter or indicator about audio output in layer and master. - SettingsDialog. - Load/save conf file. - ¿stop offset? is it needed? -- decouple MiniAudioEngine from AudioWidget, starts whith no gui or with gui in a dedicated thread. +- decouple MiniAudioEngine from AudioWidget, starts whith no gui or with audio in a dedicated thread. +- olathread, send double channels only once for each dmx frame buffer. +- New Status "Iddle" in playbacks if is not loaded. +- check return errors, we are too happy.... diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 1a5996c..e54501d 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -106,21 +106,21 @@ void AudioLayerWidget::toggleSuspendResume() } // from DMX signals -void AudioLayerWidget::setVol(qreal vol) +void AudioLayerWidget::setVol(int vol) { m_volume->blockSignals(true); m_volume->setValue(vol); m_volume->blockSignals(false); } -void AudioLayerWidget::setPan(qreal pan) +void AudioLayerWidget::setPan(int pan) { m_pan->blockSignals(true); m_pan->setValue(pan); m_pan->blockSignals(false); } -void AudioLayerWidget::setPitch(qreal pitch) +void AudioLayerWidget::setPitch(int pitch) { m_pitch->blockSignals(true); m_pitch->setValue(pitch); @@ -144,33 +144,25 @@ void AudioLayerWidget::setPlaybackStatus(Status status) m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(0)); m_statusValue->blockSignals(true); m_suspendResumeButton->blockSignals(true); + m_statusValue->setText(StatusStr[status]); + m_suspendResumeButton->setText(StatusStr[status]); switch (m_status) { case Status::Paused: - m_statusValue->setText("Pause"); m_statusValue->setStyleSheet("QLabel { color : red; }"); - m_suspendResumeButton->setText("Pause"); break; case Status::PlayingLoop: - m_statusValue->setText("Play Loop"); - m_statusValue->setStyleSheet("QLabel { color : green; }"); - m_suspendResumeButton->setText("Play Loop"); - break; case Status::PlayingOnce: - m_statusValue->setText("Play One"); m_statusValue->setStyleSheet("QLabel { color : green; }"); - m_suspendResumeButton->setText("Play One"); break; case Status::Stopped: - m_statusValue->setText("Stop"); m_statusValue->setStyleSheet("QLabel { color : red; }"); - m_suspendResumeButton->setText("Stop"); break; } m_statusValue->blockSignals(false); m_suspendResumeButton->blockSignals(false); } -void AudioLayerWidget::durationChanged(qint64 dur) +void AudioLayerWidget::durationChanged(float dur) { dur *= 1000; m_progressSlider->setMaximum(dur); diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index a484227..1d9d534 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -26,10 +26,10 @@ class AudioLayerWidget : public QGroupBox public: explicit AudioLayerWidget(QWidget *parent = 0, QString name = "Layer", int layer = 0); ~AudioLayerWidget(); - void setVol(qreal vol); + void setVol(int vol); void resume(); - void setPan(qreal pan); - void setPitch(qreal pitch); + void setPan(int pan); + void setPitch(int pitch); void setLoop(bool on); void setPlaybackStatus(Status status); inline Status getPlaybackStatus() { return m_status; } @@ -60,7 +60,7 @@ public slots: void panChanged(int vol); void pitchChanged(int vol); void fileLoaded(QString file); - void durationChanged(qint64 dur); + void durationChanged(float dur); void refreshUi(float progress); signals: diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index 63ca562..a46ebf5 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -56,19 +56,19 @@ void AudioWidget::mediaLoaded(int layer, QString file) dynamic_cast(item->widget())->durationChanged(pLength); } -void AudioWidget::volChanged(int layer, qreal vol) { +void AudioWidget::volChanged(int layer, int vol) { m_mae.volChanged(layer, vol); QLayoutItem * const item = m_layout->itemAt(layer); dynamic_cast(item->widget())->setVol(vol); } -void AudioWidget::panChanged(int layer, qreal pan) { +void AudioWidget::panChanged(int layer, int pan) { m_mae.panChanged(layer, pan); QLayoutItem * const item = m_layout->itemAt(layer); dynamic_cast(item->widget())->setPan(pan); } -void AudioWidget::pitchChanged(int layer, qreal pitch) { +void AudioWidget::pitchChanged(int layer, int pitch) { m_mae.pitchChanged(layer, pitch); QLayoutItem * const item = m_layout->itemAt(layer); dynamic_cast(item->widget())->setPitch(pitch); diff --git a/src/audiowidget.h b/src/audiowidget.h index cee8dd1..bc24ab7 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -27,9 +27,9 @@ public: protected: void mediaLoaded(int layer, QString media ); - void volChanged(int layer, qreal vol); - void panChanged(int layer, qreal pan); - void pitchChanged(int layer, qreal pitch); + void volChanged(int layer, int vol); + void panChanged(int layer, int pan); + void pitchChanged(int layer, int pitch); void playbackChanged(int layer, Status status); void entryPointChanged(int layer, int cursor); diff --git a/src/defines.h b/src/defines.h index 341bd0e..2111578 100644 --- a/src/defines.h +++ b/src/defines.h @@ -58,6 +58,14 @@ enum Status PlayingLoop, }; +static const char* StatusStr[] = +{ + "Stop", + "Pause", + "Playing One", + "Playing Loop", +}; + enum Slider { Volume, diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 6f6e263..94f6d92 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -48,12 +48,12 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) connect(set, SIGNAL(registerUniverse(int)), ola, SLOT(registerUniverse(int))); connect(ola, SIGNAL (universeReceived(int)), m_dmxWidget, SLOT(updateWatchDMX(int))); connect(ola, SIGNAL(dmxOutput(int, int, int)), this, SLOT(dmxInput(int, int, int))); - connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup())); ola->registerUniverse(); ola->start(QThread::TimeCriticalPriority ); connect(ui.actionOpen_conf, SIGNAL(triggered()), this, SLOT(openFile())); connect(ui.actionSave_conf, SIGNAL(triggered()), this, SLOT(saveFile())); connect(ui.action_Settings, SIGNAL(triggered()), this, SLOT(settings())); + connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup())); aw->startEngine(); qDebug("Init Complete."); ola->blockSignals(false); @@ -107,8 +107,6 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) return; QString mediaFile = NULL; int aux; - qreal f; - int r; switch(channel){ case DMX_FOLDER: aux = ola->getValue(layer, DMX_FILE); @@ -123,12 +121,8 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) aw->mediaLoaded(layer, mediaFile); break; case VOLUME_COARSE: - f = ( value * 0x100 ) + ola->getValue(layer, VOLUME_FINE); - aw->volChanged(layer, (f / 655.35)); - break; case VOLUME_FINE: - f = ( ola->getValue(layer, VOLUME_COARSE) * 0x100 ) + value; - aw->volChanged(layer, (f / 655.35)); + aw->volChanged(layer, (value / 650.25)); break; case PAN: aw->panChanged(layer, value); @@ -137,12 +131,8 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) aw->pitchChanged(layer, value); break; case ENTRY_POINT_COARSE: - r = ( value * 0x100 ) + ola->getValue(layer, ENTRY_POINT_FINE); - aw->entryPointChanged(layer, r); - break; case ENTRY_POINT_FINE: - r = ( ola->getValue(layer, ENTRY_POINT_COARSE) * 0x100 ) + value; - aw->entryPointChanged(layer, r); + aw->entryPointChanged(layer, value); break; case PLAYBACK: if (value == 0) diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index c38c793..d9dc13a 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -3,7 +3,6 @@ #define MINIAUDIO_IMPLEMENTATION #include "miniaudio.h" - #include "defines.h" //MAX_LAYERS #include // for printf @@ -18,7 +17,6 @@ public: static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); protected: - // slots for DMX input ma_result loadMedia(int layer, char *media ); void volChanged(int layer, float vol); void panChanged(int layer, float pan); diff --git a/src/olathread.cpp b/src/olathread.cpp index fdfe041..70002f1 100644 --- a/src/olathread.cpp +++ b/src/olathread.cpp @@ -38,6 +38,7 @@ void olaThread::init() m_client->SetDMXCallback(ola::NewCallback(this, &olaThread::NewDmx)); m_clientWrapper->GetSelectServer()->RegisterRepeatingTimeout(4000, ola::NewCallback(this, &olaThread::CheckDataLoss)); m_client->SetCloseHandler(ola::NewSingleCallback(this, &olaThread::socketClosed)); + m_dmxSettings = Settings::getInstance()->getDmxSettings(); } void olaThread::run() @@ -62,19 +63,50 @@ void olaThread::stop() void olaThread::NewDmx(const ola::client::DMXMetadata &data, const ola::DmxBuffer &buffer) { - m_counter++; - gettimeofday(&m_last_data, NULL); - foreach (const dmxSetting &i, Settings::getInstance()->getDmxSettings()) { + bool volSent = false; + bool entrySent = false; + + foreach (const dmxSetting &i, m_dmxSettings) { if(i.universe == data.universe && i.address > -1) { for (int j = 0; j < LAYER_CHANNELS; j++){ int value = buffer.Get((i.address) + j); if (m_dmx[i.layer][j] != value) { m_dmx[i.layer][j] = value; - emit dmxOutput(i.layer,j,value); + switch (j) { + case 0: + value = (value * 0x100) + buffer.Get(i.address + 6); + emit dmxOutput(i.layer,j,value); + volSent = true; + break; + case 7: + value = (value * 0x100) + buffer.Get(i.address + 8); + emit dmxOutput(i.layer,j,value); + entrySent = true; + break; + case 6: + if (volSent == false) + { + value = (buffer.Get(i.address) * 0x100) + value; + emit dmxOutput(i.layer,j,value); + } + break; + case 8: + if (entrySent == false) + { + value = (buffer.Get(i.address + 7) * 0x100) + value; + emit dmxOutput(i.layer,j,value); + } + break; + default: + emit dmxOutput(i.layer,j,value); + break; + } } } } } + m_counter++; + gettimeofday(&m_last_data, NULL); emit universeReceived(data.universe); } diff --git a/src/olathread.h b/src/olathread.h index ee18824..5ad75c8 100644 --- a/src/olathread.h +++ b/src/olathread.h @@ -47,6 +47,7 @@ private: struct timeval m_last_data; // Last DMX frame received int m_layers; int m_dmx[MAX_LAYERS][LAYER_CHANNELS]; + QList m_dmxSettings; /** * @brief Callback from ola. Control de errores en el registro de Universos en OLA -- 2.39.5 From 3613d8fa517dc36ccb287a55994be25909ea3ec5 Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 24 Apr 2024 20:23:20 +0200 Subject: [PATCH 09/49] indicador de volumen con dos decimales --- docs/changelog.txt | 1 + docs/roadmap.txt | 3 +- src/audiolayerwidget.cpp | 28 +++----- src/audiolayerwidget.h | 14 ++-- src/audiowidget.cpp | 2 +- src/audiowidget.h | 2 +- src/defines.h | 20 +----- src/libremediaserver-audio.cpp | 2 +- src/main.cpp | 125 --------------------------------- src/miniaudioengine.cpp | 9 +-- src/slidergroup.cpp | 25 +++++-- src/slidergroup.h | 9 +-- 12 files changed, 53 insertions(+), 187 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 4882ec8..48b0ddf 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -17,6 +17,7 @@ v 0.2.0 Antigona (24/04/2024) + mp3, flac, wav (mp3 has given some errors seeking cursor...). + settings dialog not working, only read the conf file at startup. + variable number of layers. ++ olathread, send double channels only once for each dmx frame buffer. v 0.1.3 Unreleased (19/04/2024) diff --git a/docs/roadmap.txt b/docs/roadmap.txt index 9622ccd..8ff57d7 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -27,7 +27,6 @@ v 0.2.2 v 0.2.1 - Multi devices output. -- Rose noise and sine generator in menu to test system. - Play Mode: - Play all medias found in folder consecutevily or random, with loop. - Play all medias, consecutevily and random, with loop. @@ -41,6 +40,7 @@ v 0.2.1 - magicq .hed - audio device linked, outputs will be redirected there. - dmx address + universe settings. +- Rose noise and sine generator in menu to test system. - Keyboards strokes, load media files from ui. - Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante. - Logs, verbosity, timestamp. @@ -51,6 +51,5 @@ v 0.2.1 - Load/save conf file. - ¿stop offset? is it needed? - decouple MiniAudioEngine from AudioWidget, starts whith no gui or with audio in a dedicated thread. -- olathread, send double channels only once for each dmx frame buffer. - New Status "Iddle" in playbacks if is not loaded. - check return errors, we are too happy.... diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index e54501d..99e1996 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -10,9 +10,6 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name, int layer): QVBoxLayout *layout = new QVBoxLayout; QHBoxLayout *progressTime = new QHBoxLayout; - //m_progressTimeLabel = new QLabel; - //m_progressTimeLabel->setText(PROGRESS_TIME_LABEL); - //progressTime->addWidget(m_progressTimeLabel); m_progressTime = new QTimeEdit; m_progressTime->text(); m_progressTime->setDisplayFormat("h:mm:ss:zzz"); @@ -21,9 +18,6 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name, int layer): m_progressTime->setMaximumWidth(90); m_progressTime->setFocusPolicy(Qt::NoFocus); progressTime->addWidget(m_progressTime); - //m_totalTimeLabel = new QLabel; - //m_totalTimeLabel->setText(TOTAL_TIME_LABEL); - //progressTime->addWidget(m_totalTimeLabel); m_totalTimeValue = new QTimeEdit; m_totalTimeValue->setDisplayFormat("h:mm:ss:zzz"); m_totalTimeValue->setReadOnly(true); @@ -49,19 +43,19 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name, int layer): layout->addLayout(status); QHBoxLayout *volumeBox = new QHBoxLayout; - m_volume = new SliderGroup("Vol", 0 , 100, NULL); + m_volume = new SliderGroup("Vol", 0 , 100, 2, NULL); volumeBox->addWidget(m_volume); - connect(m_volume, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int))); - m_pan = new SliderGroup("Pan", 0 , 255, NULL); + connect(m_volume, SIGNAL(valueChanged(float)), this, SLOT(volumeChanged(float))); + 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, NULL); + connect(m_pan, SIGNAL(valueChanged(float)), this, SLOT(panChanged(float))); + m_pitch = new SliderGroup("Pitch", 0 , 255, 0, NULL); volumeBox->addWidget(m_pitch); - connect(m_pitch, SIGNAL(valueChanged(int)), this, SLOT(pitchChanged(int))); + connect(m_pitch, SIGNAL(valueChanged(float)), this, SLOT(pitchChanged(float))); layout->addLayout(volumeBox); m_suspendResumeButton = new QPushButton(this); - m_suspendResumeButton->setText(tr(SUSPEND_LABEL)); + m_suspendResumeButton->setText(StatusStr[Status::Stopped]); connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume())); layout->addWidget(m_suspendResumeButton); @@ -74,17 +68,17 @@ AudioLayerWidget::~AudioLayerWidget() } // From UI. -void AudioLayerWidget::volumeChanged(int value) +void AudioLayerWidget::volumeChanged(float value) { emit(uiSliderChanged(m_layer, Slider::Volume, value)); } -void AudioLayerWidget::panChanged(int value) +void AudioLayerWidget::panChanged(float value) { emit(uiSliderChanged(m_layer, Slider::Pan, value)); } -void AudioLayerWidget::pitchChanged(int value) +void AudioLayerWidget::pitchChanged(float value) { emit(uiSliderChanged(m_layer, Slider::Pitch, value)); } @@ -106,7 +100,7 @@ void AudioLayerWidget::toggleSuspendResume() } // from DMX signals -void AudioLayerWidget::setVol(int vol) +void AudioLayerWidget::setVol(float vol) { m_volume->blockSignals(true); m_volume->setValue(vol); diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index 1d9d534..13f829f 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -26,7 +26,7 @@ class AudioLayerWidget : public QGroupBox public: explicit AudioLayerWidget(QWidget *parent = 0, QString name = "Layer", int layer = 0); ~AudioLayerWidget(); - void setVol(int vol); + void setVol(float vol); void resume(); void setPan(int pan); void setPitch(int pitch); @@ -38,27 +38,21 @@ private: Status m_status; int m_layer; QPushButton *m_suspendResumeButton; - QLabel *m_statusLabel; QLabel * m_statusValue; - QLabel *m_fileLabel; QLabel *m_fileValue; - QLabel * m_folderLabel; QLabel * m_folderValue; SliderGroup *m_volume; SliderGroup *m_pan; SliderGroup *m_pitch; - QLabel * m_progressLabel; QSlider *m_progressSlider; - QLabel *m_progressTimeLabel; QTimeEdit *m_progressTime; - QLabel *m_totalTimeLabel; QTimeEdit *m_totalTimeValue; public slots: void toggleSuspendResume(); - void volumeChanged(int vol); - void panChanged(int vol); - void pitchChanged(int vol); + void volumeChanged(float vol); + void panChanged(float pan); + void pitchChanged(float pitch); void fileLoaded(QString file); void durationChanged(float dur); void refreshUi(float progress); diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index a46ebf5..4b35a5c 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -56,7 +56,7 @@ void AudioWidget::mediaLoaded(int layer, QString file) dynamic_cast(item->widget())->durationChanged(pLength); } -void AudioWidget::volChanged(int layer, int vol) { +void AudioWidget::volChanged(int layer, float vol) { m_mae.volChanged(layer, vol); QLayoutItem * const item = m_layout->itemAt(layer); dynamic_cast(item->widget())->setVol(vol); diff --git a/src/audiowidget.h b/src/audiowidget.h index bc24ab7..61c640c 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -27,7 +27,7 @@ public: protected: void mediaLoaded(int layer, QString media ); - void volChanged(int layer, int vol); + void volChanged(int layer, float vol); void panChanged(int layer, int pan); void pitchChanged(int layer, int pitch); void playbackChanged(int layer, Status status); diff --git a/src/defines.h b/src/defines.h index 2111578..780c461 100644 --- a/src/defines.h +++ b/src/defines.h @@ -9,23 +9,8 @@ #define COPYRIGHT "(C) 2014-2024 Santi Norena lms@criptomart.net" #define LICENSE "GPL 3 License. See LICENSE.txt and credits.txt for details" #define DEFAULT_FILE "lms-audio.xlm" -#define SUSPEND_LABEL "Pause" -#define RESUME_LABEL "Resume" -#define PLAY_LABEL "Play" -#define STOP_LABEL "Stop" -#define PAUSE_LABEL "Pause" -#define IDDLE_LABEL "Iddle playback" -#define VOLUME_LABEL "Vol" -#define PROGRESS_LABEL "Progress" -#define PROGRESS_TIME_LABEL "Current" -#define REMAINING_TIME "Remaining" -#define TOTAL_TIME_LABEL "Total" -#define NOTIFY_INTERVAL 150 -#define PULL_TIMER_INTERVAL 10 -#define MAX_DEVICES 16 -#define MAX_SOUNDS 4096 #define MAX_LAYERS 16 -#define UI_REFRESH_TIME 100 +#define UI_REFRESH_TIME 200 // struct where save the DMX settings for each layer struct dmxSetting { @@ -63,7 +48,8 @@ static const char* StatusStr[] = "Stop", "Pause", "Playing One", - "Playing Loop", + "Playing Loop", + NULL }; enum Slider diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 94f6d92..f20d038 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -122,7 +122,7 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) break; case VOLUME_COARSE: case VOLUME_FINE: - aw->volChanged(layer, (value / 650.25)); + aw->volChanged(layer, (value / 65025.0f)); break; case PAN: aw->panChanged(layer, value); diff --git a/src/main.cpp b/src/main.cpp index 25d84e0..bfadafe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -20,133 +20,11 @@ #include "libremediaserver-audio.h" -// Handler for pipe the stderr to a log file and texEdit -//bool initMessageHandler = false; -//QFile outFile; -//QMutex mutex; -//QMutexLocker mutexLocker(mutex); -/* -void MessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) -{ - Q_UNUSED(context); -// mutex.lock(); - // Create the log dir and log file - if (!initMessageHandler) { - QDir dir; - if (!dir.exists("log")) { - if (!dir.mkdir("log")) { - qDebug()<<"MessageHandler: Can not create log folder"; - return; - } - } - QString filename; - QDate date = QDate::currentDate(); - QTime time = QTime::currentTime(); - filename.append("./log/log_"); - filename.append(date.toString("ddMMyy-")); - filename.append(time.toString("hhmmss.txt")); - outFile.setFileName(filename); - if (!outFile.open(QIODevice::WriteOnly | QIODevice::Append)) { - qWarning("main/MessageHandler/Qfile::open: can not open log file"); - return; - } - initMessageHandler = true; - } - QTextStream ts(&outFile);*/ -/* if (libreMediaServerAudio::textEdit == 0) - { - QByteArray localMsg = msg.toLocal8Bit(); - switch (type) { - case QtDebugMsg: - fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function); - break; - case QtWarningMsg: - fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function); - break; - case QtCriticalMsg: - fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function); - break; - case QtFatalMsg: - fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function); - abort(); - } - } - else - { - QString txt; - switch (type) { - case QtDebugMsg: - txt.append("Debug from File: "); - txt.append(context.file); - txt.append(" Line: "); - txt.append(QString::number(context.line)); -// txt.append(" Function: "); -// txt.append(context.function); - txt.append(" Message: "); - txt.append(msg); -// libreMediaServerAudio::textEdit->append(msg);, context.file, context.line, context.function); - libreMediaServerAudio::textEdit->append(txt); - break; - case QtWarningMsg: - txt.append("Warning from File: "); - txt.append(context.file); - txt.append(" Line: "); - txt.append(QString::number(context.line)); - txt.append(" Function: "); - txt.append(context.function); - txt.append(" Message: "); - txt.append(msg); -// libreMediaServerAudio::textEdit->append(msg);, context.file, context.line, context.function); - libreMediaServerAudio::textEdit->append(txt); - abort(); - break; - case QtCriticalMsg: -// txt.append("Critical from File: "); - txt.append(context.file); - txt.append(" Line: "); - txt.append(QString::number(context.line)); - txt.append(" Function: "); - txt.append(context.function); - txt.append(" Message "); - txt.append(msg); -// libreMediaServerAudio::textEdit->append(msg);, context.file, context.line, context.function); - libreMediaServerAudio::textEdit->append(txt); - abort(); - break; - case QtFatalMsg: -// txt.append("Fatal from File: "); - txt.append(context.file); - txt.append(" Line: "); - txt.append(QString::number(context.line)); - txt.append(" Function: "); - txt.append(context.function); - txt.append(" Message: "); - txt.append(msg); -// libreMediaServerAudio::textEdit->append(msg);, context.file, context.line, context.function); - libreMediaServerAudio::textEdit->append(txt);// ts << txt << endl; - abort(); - } -// outFile.write(txt.toLatin1().constData(), txt.size()); -// ts << txt << endl; -// libreMediaServerAudio::textEdit->append(txt); - } -// mutex.unlock(); -}*/ int main(int argc, char *argv[]) { - - // ToDo: discriminar niveles de log y log a fichero segúna argumentos - /* - if (args.contains("-log")) - { - qInstallMessageHandler(MessageHandler); - }*/ - QApplication app(argc, argv); - QStringList args = app.arguments(); - if (args.size() > 1) { if (args.contains("-v")) @@ -163,7 +41,6 @@ int main(int argc, char *argv[]) qDebug() << LICENSE; qDebug() << "Help for command line options:"; qDebug() << "-v show the version and exits"; - qDebug() << "-log write the debug information to a log file instead stderr"; qDebug() << "-h this help"; return 0; } @@ -172,5 +49,3 @@ int main(int argc, char *argv[]) libreMediaServerAudio.show(); return app.exec(); } - - diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 6fb6709..5e11919 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -183,15 +183,16 @@ ma_result MiniAudioEngine::printFormatInfo(int layer) return result; } -// Expects between 0 and 100 vol value in db +// Expects between 0 and 1 vol value in db void MiniAudioEngine::volChanged(int layer, float vol) { - float result; + //float result; if (m_mediaLoaded[layer] == false) return; - result = ma_volume_linear_to_db(1.00000000 + (vol / 800.0)); - ma_sound_group_set_volume(&m_currentSound[layer], result); + //result = ma_volume_linear_to_db(1.00000000 + (vol / 8.0)); + //qInfo("vol %f %f", vol, result); + ma_sound_group_set_volume(&m_currentSound[layer], vol); } void MiniAudioEngine::panChanged(int layer, float value) diff --git a/src/slidergroup.cpp b/src/slidergroup.cpp index 9b7e234..e80a03f 100644 --- a/src/slidergroup.cpp +++ b/src/slidergroup.cpp @@ -3,6 +3,7 @@ SliderGroup::SliderGroup(const QString &title, \ int min, int max, + int decimals, QWidget *parent) : QGroupBox(title, parent) { @@ -14,17 +15,31 @@ SliderGroup::SliderGroup(const QString &title, \ slider->setTickInterval((max - min) / 11); slider->setSingleStep(1); slider->setRange(min, max); - //slider->setInvertedAppearance(false); - //slider->setInvertedControls(false); - valueBox = new QSpinBox(); + valueBox = new QDoubleSpinBox(); valueBox->setFocusPolicy(Qt::NoFocus); valueBox->setButtonSymbols(QAbstractSpinBox::NoButtons); - valueBox->setMaximumWidth(40); + valueBox->setMaximumWidth(45); valueBox->setRange(min, max); - connect(slider, &QSlider::valueChanged, valueBox, &QSpinBox::setValue); + valueBox->setDecimals(decimals); connect(slider, SIGNAL(valueChanged(int)), this, SLOT(sliderValueChanged(int))); QVBoxLayout *slidersLayout = new QVBoxLayout(); slidersLayout->addWidget(valueBox); slidersLayout->addWidget(slider); setLayout(slidersLayout); } + +void SliderGroup::sliderValueChanged(int value) +{ + if (valueBox->decimals() > 1) + value /= 100.0f; + emit valueChanged(value); + valueBox->setValue(value); +}; + +void SliderGroup::setValue(float value) +{ + if (valueBox->decimals() > 1) + value *= 100.0f; + slider->setValue(value); + valueBox->setValue(value); +} diff --git a/src/slidergroup.h b/src/slidergroup.h index 9b7b704..d1d34bf 100644 --- a/src/slidergroup.h +++ b/src/slidergroup.h @@ -21,18 +21,19 @@ public: SliderGroup(const QString &title, int min, int max, + int decimals, QWidget *parent = nullptr); signals: - void valueChanged(int value); + void valueChanged(float value); public slots: - inline void setValue(int value) { slider->setValue(value); }; - inline void sliderValueChanged(int value) { emit valueChanged(value); }; + void setValue(float value); + void sliderValueChanged(int value); private: QSlider *slider; - QSpinBox *valueBox; + QDoubleSpinBox *valueBox; }; #endif -- 2.39.5 From 66c2850e069cbf76ca0206facb5fb40eef34c803 Mon Sep 17 00:00:00 2001 From: snt Date: Thu, 25 Apr 2024 16:29:33 +0200 Subject: [PATCH 10/49] =?UTF-8?q?limpieza=20c=C3=B3digo=20no=20usado=20e?= =?UTF-8?q?=20includes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libremediaserver-audio.pro | 8 +-- src/audiolayerwidget.h | 13 +--- src/audiowidget.h | 13 +--- src/defines.h | 31 ++-------- src/dmxwidget.cpp | 2 +- src/dmxwidget.h | 5 +- src/libremediaserver-audio.cpp | 107 +++++++++++---------------------- src/libremediaserver-audio.h | 31 +--------- src/libremediaserver-audio.ui | 9 --- src/medialibrary.cpp | 10 --- src/medialibrary.h | 62 ++++++------------- src/miniaudioengine.cpp | 6 +- src/miniaudioengine.h | 4 +- src/olathread.cpp | 16 ++--- src/olathread.h | 7 +-- src/settings.cpp | 63 ------------------- src/settings.h | 21 ------- src/settingsdialog.h | 2 +- src/slidergroup.h | 11 +--- 19 files changed, 83 insertions(+), 338 deletions(-) diff --git a/libremediaserver-audio.pro b/libremediaserver-audio.pro index 8add248..a33e231 100644 --- a/libremediaserver-audio.pro +++ b/libremediaserver-audio.pro @@ -12,8 +12,6 @@ HEADERS += src/libremediaserver-audio.h \ src/audiowidget.h \ src/defines.h \ src/settings.h \ - src/settingsdialog.h \ - src/layersettingswidget.h \ src/slidergroup.h SOURCES += src/main.cpp \ src/dmxwidget.cpp \ @@ -25,12 +23,8 @@ SOURCES += src/main.cpp \ src/audiolayerwidget.cpp \ src/audiowidget.cpp \ src/settings.cpp \ - src/settingsdialog.cpp \ - src/layersettingswidget.cpp \ src/slidergroup.cpp -FORMS += src/libremediaserver-audio.ui \ - src/settingsdialog.ui \ - src/layersettingswidget.ui +FORMS += src/libremediaserver-audio.ui CCFLAG += -msse2 -mavx2 #-fsanitize=address -g -O0 QMAKE_CXXFLAGS += $$(CXXFLAG) #QMAKE_CXXFLAGS += -fsanitize=address -g -O0 diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index 13f829f..53401fb 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -1,20 +1,9 @@ #ifndef AUDIOLAYERWIDGET_H #define AUDIOLAYERWIDGET_H -#include - -#include -#include -#include -#include -#include #include -#include -#include #include -#include -#include -#include +#include #include "defines.h" #include "slidergroup.h" diff --git a/src/audiowidget.h b/src/audiowidget.h index 61c640c..254e59e 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -1,22 +1,15 @@ #ifndef AUDIOWIDGET_H #define AUDIOWIDGET_H -#include -#include -#include +#include -#include "dmxwidget.h" #include "audiolayerwidget.h" #include "settings.h" #include "miniaudioengine.h" -#include "defines.h" - +#include "defines.h" // MAX_LAYERS class AudioWidget : public QWidget { - friend class libreMediaServerAudio; - friend class AudioLayerWidget; - Q_OBJECT public: @@ -24,8 +17,6 @@ public: bool startEngine(); bool startEngine(int id); void stopEngine(); - -protected: void mediaLoaded(int layer, QString media ); void volChanged(int layer, float vol); void panChanged(int layer, int pan); diff --git a/src/defines.h b/src/defines.h index 780c461..68675c2 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,13 +1,10 @@ #ifndef DEFINES_H #define DEFINES_H -#include -#include -#include - -#define VERSION "LibreMediaServerAudio 0.2.0 Antigona Release" -#define COPYRIGHT "(C) 2014-2024 Santi Norena lms@criptomart.net" -#define LICENSE "GPL 3 License. See LICENSE.txt and credits.txt for details" +//#define VERSION "LibreMediaServerAudio 0.2.0 Antigona Release" +#define VERSION "Kike Substitutor - No AI required - v0.2.0" +#define COPYRIGHT "(C) 2014-2024 Santi Noreña " +#define LICENSE "GPL 3 Licensed. See LICENSE.txt.\nSound guys are not allowed to use this software." #define DEFAULT_FILE "lms-audio.xlm" #define MAX_LAYERS 16 #define UI_REFRESH_TIME 200 @@ -15,26 +12,10 @@ // struct where save the DMX settings for each layer struct dmxSetting { int address; - quint8 universe; - bool updated; + unsigned int universe; int layer; }; -// Media Information for MELIn packages. v1.0 -struct MediaFile { - quint8 Number; // 0-based contiguous index of the media. - QString MediaName;// Media name. - quint32 MediaLength;// Media length (in frames). -}; - -// Media Library for ELin packages v1.0 -struct MediaFolder { - quint8 m_Id; // Library id. - QString m_Name;// Library name. - quint8 m_ElementCount;// Number of elements in the library. - QList m_MediaInformation; // Pointer to the Medias Information List of this Library -}; - enum Status { Stopped, @@ -49,7 +30,7 @@ static const char* StatusStr[] = "Pause", "Playing One", "Playing Loop", - NULL + 0x0 }; enum Slider diff --git a/src/dmxwidget.cpp b/src/dmxwidget.cpp index 4383a76..60d4206 100644 --- a/src/dmxwidget.cpp +++ b/src/dmxwidget.cpp @@ -7,7 +7,7 @@ dmxWidget::dmxWidget(QWidget *parent) : { this->setFocusPolicy(Qt::FocusPolicy::NoFocus); QVBoxLayout *vbox = new QVBoxLayout; - m_receiveDMX->setText("DMX signal"); + m_receiveDMX->setText("DMX Signal"); vbox->addWidget(m_receiveDMX); this->setLayout(vbox); connect(m_watchDMX, SIGNAL(timeout()), diff --git a/src/dmxwidget.h b/src/dmxwidget.h index e1540a1..f3a6d7f 100644 --- a/src/dmxwidget.h +++ b/src/dmxwidget.h @@ -1,13 +1,10 @@ #ifndef DMXWIDGET_H #define DMXWIDGET_H -#include -#include -#include #include #include #include -#include +#include class dmxWidget : public QGroupBox { diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index f20d038..ab83519 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -25,73 +25,40 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) : QMainWindow(parent) { Q_UNUSED(args); + qDebug() << VERSION; + qDebug() << COPYRIGHT; + qDebug() << LICENSE; ui.setupUi(this); this->setWindowTitle(VERSION); Settings *set = Settings::getInstance(); set->readFile(); - connect(set, SIGNAL(audioDeviceChanged(int)), this, SLOT(audioDeviceChanged(int))); - this->setWindowTitle(VERSION); - qDebug() << VERSION; - qDebug() << COPYRIGHT; - qDebug() << LICENSE; - MediaLibrary::getInstance()->initMediaLibrary(); - aw = new AudioWidget; - setCentralWidget(aw); + m_mediaLibrary = new MediaLibrary; + m_mediaLibrary->initMediaLibrary(); + m_aw = new AudioWidget; + setCentralWidget(m_aw); m_dmxWidget = new dmxWidget(this); QDockWidget *topWidget = new QDockWidget(tr("Master"), this); topWidget->setAllowedAreas(Qt::TopDockWidgetArea); topWidget->setWidget(m_dmxWidget); addDockWidget(Qt::TopDockWidgetArea, topWidget); - ola = new olaThread(this, set->getLayersNumber()); - Q_CHECK_PTR(ola); - ola->blockSignals(true); - connect(set, SIGNAL(registerUniverse(int)), ola, SLOT(registerUniverse(int))); - connect(ola, SIGNAL (universeReceived(int)), m_dmxWidget, SLOT(updateWatchDMX(int))); - connect(ola, SIGNAL(dmxOutput(int, int, int)), this, SLOT(dmxInput(int, int, int))); - ola->registerUniverse(); - ola->start(QThread::TimeCriticalPriority ); - connect(ui.actionOpen_conf, SIGNAL(triggered()), this, SLOT(openFile())); - connect(ui.actionSave_conf, SIGNAL(triggered()), this, SLOT(saveFile())); - connect(ui.action_Settings, SIGNAL(triggered()), this, SLOT(settings())); - connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup())); - aw->startEngine(); + m_ola = new olaThread(this, set->getLayersNumber()); + Q_CHECK_PTR(m_ola); + m_ola->blockSignals(true); + connect(m_ola, SIGNAL (universeReceived(int)), m_dmxWidget, SLOT(updateWatchDMX(int))); + connect(m_ola, SIGNAL(dmxOutput(int, int, int)), this, SLOT(dmxInput(int, int, int))); + m_ola->registerUniverse(); + m_ola->start(QThread::TimeCriticalPriority ); + connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup())); + m_aw->startEngine(); qDebug("Init Complete."); - ola->blockSignals(false); - ola->resendDmx(); + m_ola->blockSignals(false); + m_ola->resendDmx(); } libreMediaServerAudio::~libreMediaServerAudio() { - ola->stop(); - aw->stopEngine(); -} - -void libreMediaServerAudio::openFile() -{ - QFileDialog dialog(this); - if (!dialog.exec()) - return; - QStringList fileNames; - fileNames = dialog.selectedFiles(); - QFile file(fileNames.at(0)); -// open(&file); -} - -void libreMediaServerAudio::saveFile() -{ - QFileDialog dialog(this); - if (!dialog.exec()) - return; - QStringList fileNames; - fileNames = dialog.selectedFiles(); - QFile file(fileNames.at(0)); -// save(&file); -} - -void libreMediaServerAudio::settings() -{ - SettingsDialog *sd = new SettingsDialog(); - sd->show(); + m_ola->stop(); + m_aw->stopEngine(); } void libreMediaServerAudio::olasetup() @@ -109,30 +76,30 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) int aux; switch(channel){ case DMX_FOLDER: - aux = ola->getValue(layer, DMX_FILE); - mediaFile = MediaLibrary::getInstance()->requestNewFile(value, aux); + aux = m_ola->getValue(layer, DMX_FILE); + mediaFile = m_mediaLibrary->requestNewFile(value, aux); if (QFile::exists(mediaFile)) - aw->mediaLoaded(layer, mediaFile); + m_aw->mediaLoaded(layer, mediaFile); break; case DMX_FILE: - aux = ola->getValue(layer, DMX_FOLDER); - mediaFile = MediaLibrary::getInstance()->requestNewFile(aux, value); + aux = m_ola->getValue(layer, DMX_FOLDER); + mediaFile = m_mediaLibrary->requestNewFile(aux, value); if (QFile::exists(mediaFile)) - aw->mediaLoaded(layer, mediaFile); + m_aw->mediaLoaded(layer, mediaFile); break; case VOLUME_COARSE: case VOLUME_FINE: - aw->volChanged(layer, (value / 65025.0f)); + m_aw->volChanged(layer, (value / 65025.0f)); break; case PAN: - aw->panChanged(layer, value); + m_aw->panChanged(layer, value); break; case PITCH: - aw->pitchChanged(layer, value); + m_aw->pitchChanged(layer, value); break; case ENTRY_POINT_COARSE: case ENTRY_POINT_FINE: - aw->entryPointChanged(layer, value); + m_aw->entryPointChanged(layer, value); break; case PLAYBACK: if (value == 0) @@ -140,16 +107,16 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) aux = value / 25; switch (aux) { case 0 : - aw->playbackChanged(layer, PlayingOnce); + m_aw->playbackChanged(layer, PlayingOnce); break; case 1 : - aw->playbackChanged(layer, Stopped); + m_aw->playbackChanged(layer, Stopped); break; case 2 : - aw->playbackChanged(layer, Paused); + m_aw->playbackChanged(layer, Paused); break; case 3 : - aw->playbackChanged(layer, PlayingLoop); + m_aw->playbackChanged(layer, PlayingLoop); break; default : break; @@ -158,9 +125,3 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) break; } } - -void libreMediaServerAudio::audioDeviceChanged(int id) -{ - aw->stopEngine(); - aw->startEngine(id); -} diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index 78b347b..9cd154b 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -20,31 +20,17 @@ #ifndef LIBREMEDIASERVERAUDIO_H #define LIBREMEDIASERVERAUDIO_H -#include #include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include #include "audiowidget.h" #include "medialibrary.h" #include "olathread.h" #include "settings.h" #include "dmxwidget.h" -#include "settingsdialog.h" #include "defines.h" - #include "ui_libremediaserver-audio.h" -class QMenu; - class libreMediaServerAudio : public QMainWindow { Q_OBJECT @@ -55,25 +41,14 @@ public: Ui::LibreMediaServerAudio ui; private: - AudioWidget *aw; + AudioWidget *m_aw; dmxWidget *m_dmxWidget; - olaThread *ola; - - void open_start(); - void save_finish(); - void open(QFile *file); - void save(QFile *file); - -public slots: - void audioDeviceChanged(int id); + olaThread *m_ola; + MediaLibrary *m_mediaLibrary; private slots: void olasetup(); void dmxInput(int layer, int channel, int value); - void openFile(); - void saveFile(); - void settings(); - }; #endif // LIBREMEDIASERVERAUDIO_H diff --git a/src/libremediaserver-audio.ui b/src/libremediaserver-audio.ui index 2090b50..6ade744 100644 --- a/src/libremediaserver-audio.ui +++ b/src/libremediaserver-audio.ui @@ -28,18 +28,9 @@ File - - - - - - Help - - - diff --git a/src/medialibrary.cpp b/src/medialibrary.cpp index 38e8d87..5834df0 100644 --- a/src/medialibrary.cpp +++ b/src/medialibrary.cpp @@ -1,15 +1,5 @@ #include "medialibrary.h" -MediaLibrary *MediaLibrary::_instance = 0; - -MediaLibrary *MediaLibrary::getInstance() { - - if (_instance == 0) { - _instance = new MediaLibrary(); - Q_CHECK_PTR(_instance); - } - return _instance; -} MediaLibrary::MediaLibrary(QObject *parent) : QObject(parent) diff --git a/src/medialibrary.h b/src/medialibrary.h index e6b0b79..5a0b55b 100644 --- a/src/medialibrary.h +++ b/src/medialibrary.h @@ -1,25 +1,32 @@ #ifndef MEDIALIBRARY_H #define MEDIALIBRARY_H -#include #include -#include -#include "defines.h" #include "settings.h" +#include "defines.h" + +// Media Information for MELIn packages. v1.0 +struct MediaFile { + quint8 Number; // 0-based contiguous index of the media. + QString MediaName;// Media name. + quint32 MediaLength;// Media length (in frames). +}; + +// Media Library for ELin packages v1.0 +struct MediaFolder { + quint8 m_Id; // Library id. + QString m_Name;// Library name. + quint8 m_ElementCount;// Number of elements in the library. + QList m_MediaInformation; // Pointer to the Medias Information List of this Library +}; class MediaLibrary : public QObject { - Q_OBJECT - friend class libreMediaserverAudio; // Not working... WHY? - friend class Settings; // working... - public: - - static MediaLibrary *getInstance(); - + MediaLibrary(QObject *parent = 0); /** * @brief request a new file from the media library * @param int folder - the folder required @@ -27,43 +34,12 @@ public: * @return QString the file required with full path */ QString requestNewFile(int folder, int layer); - - /** - * @brief Inicia la biblioteca de medios - */ void initMediaLibrary(); -protected: - - /** - * @brief Reload the media library on change of path or change the media files - */ - inline void rescanMediaLibrary() { - if (m_media != NULL) - delete m_media; - initMediaLibrary(); - } - private: + QList *m_media; + QList getMediaInformation(QDir dir); - explicit MediaLibrary(QObject *parent = 0); - static MediaLibrary *_instance; - -// Wich structure is more efficient for us? -// QList, QMap, QSet, QVector? - QList *m_media; // Library to save the folders/media libraries and index each media file inside - - /** - * @brief Returns a list withe the medias contained in a folder - * @param QDir - the directory when are the media - * @return QList The list with the medias in a folder - */ - QList getMediaInformation(QDir dir); // Get all the information of each media file in a dir - -signals: - -public slots: - }; #endif // MEDIALIBRARY_H diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 5e11919..6d5490c 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -183,15 +183,11 @@ ma_result MiniAudioEngine::printFormatInfo(int layer) return result; } -// Expects between 0 and 1 vol value in db +// Expects between 0 and 1 vol value void MiniAudioEngine::volChanged(int layer, float vol) { - //float result; - if (m_mediaLoaded[layer] == false) return; - //result = ma_volume_linear_to_db(1.00000000 + (vol / 8.0)); - //qInfo("vol %f %f", vol, result); ma_sound_group_set_volume(&m_currentSound[layer], vol); } diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index d9dc13a..9549602 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -3,8 +3,8 @@ #define MINIAUDIO_IMPLEMENTATION #include "miniaudio.h" -#include "defines.h" //MAX_LAYERS -#include // for printf +#include "defines.h" // MAX_LAYERS +#include // prints messages class MiniAudioEngine { diff --git a/src/olathread.cpp b/src/olathread.cpp index 70002f1..16c976f 100644 --- a/src/olathread.cpp +++ b/src/olathread.cpp @@ -73,27 +73,27 @@ void olaThread::NewDmx(const ola::client::DMXMetadata &data, if (m_dmx[i.layer][j] != value) { m_dmx[i.layer][j] = value; switch (j) { - case 0: - value = (value * 0x100) + buffer.Get(i.address + 6); + case VOLUME_COARSE: + value = (value * 0x100) + buffer.Get(i.address + VOLUME_FINE); emit dmxOutput(i.layer,j,value); volSent = true; break; - case 7: - value = (value * 0x100) + buffer.Get(i.address + 8); + case ENTRY_POINT_COARSE: + value = (value * 0x100) + buffer.Get(i.address + ENTRY_POINT_FINE); emit dmxOutput(i.layer,j,value); entrySent = true; break; - case 6: + case VOLUME_FINE: if (volSent == false) { - value = (buffer.Get(i.address) * 0x100) + value; + value = (buffer.Get(i.address + VOLUME_COARSE) * 0x100) + value; emit dmxOutput(i.layer,j,value); } break; - case 8: + case ENTRY_POINT_FINE: if (entrySent == false) { - value = (buffer.Get(i.address + 7) * 0x100) + value; + value = (buffer.Get(i.address + ENTRY_POINT_COARSE) * 0x100) + value; emit dmxOutput(i.layer,j,value); } break; diff --git a/src/olathread.h b/src/olathread.h index 5ad75c8..148e859 100644 --- a/src/olathread.h +++ b/src/olathread.h @@ -1,9 +1,6 @@ #ifndef OLATHREAD_H #define OLATHREAD_H -#include - -#include #include #include @@ -14,9 +11,9 @@ #include #include -#include "defines.h" #include "dmxPersonality.h" #include "settings.h" +#include "defines.h" class olaThread : public QThread { @@ -35,11 +32,9 @@ public: inline int getValue(int layer, int channel) { return m_dmx[layer][channel]; } - void resendDmx(); private: - void run (); ola::client::OlaClientWrapper *m_clientWrapper; ola::client::OlaClient *m_client; diff --git a/src/settings.cpp b/src/settings.cpp index b0aab3a..f664bb0 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -17,12 +17,6 @@ Settings::Settings(QObject *parent) : m_layersNumber = 0; } -void Settings::setPathMedia(QString path) -{ - m_pathmedia = path; - MediaLibrary::getInstance()->rescanMediaLibrary(); -} - // Read the dmx settings for dmx.xml At the moment we need: // - The path to the medias folder tree // - The number of sources/layers controlled by DMX @@ -92,60 +86,3 @@ void Settings::readFromFile(QString file) { void Settings::readFile() { readFromFile(DEFAULT_FILE); } - -void Settings::changeLayerSetup(int layer, int universe, int address) -{ - dmxSetting temp; - temp.address = address; - temp.universe = universe; - temp.layer = layer; - m_settings.replace(layer, temp); - if (!m_universe.contains(temp.universe)) { - m_universe.insert(temp.universe); - } -} - -void Settings::addLayer() -{ - dmxSetting temp; - temp.address = -1; - temp.universe = -1; - temp.layer = -1; - m_settings.append(temp); -} - -void Settings::removeLayer(int layer) -{ - m_settings.removeAt(layer); -} - -/* -void Settings::writeFile(QString filename) -{ - QFile* xmlFile = new QFile(filename); - if (!xmlFile->open(QIODevice::ReadOnly | QIODevice::Text)) { - QMessageBox::critical(NULL,"Load XML File Problem", - QString("Couldn't open %1 to load settings for olaInterface").arg(file), - QMessageBox::Ok); - return; - } - QXmlStreamWriter* xmlWriter = new QXmlStreamWriter(xmlFile); - - QXmlStreamWriter stream(&output); - stream.setAutoFormatting(true); - stream.writeStartDocument(); - - stream.writeStartElement("dmxSettings"); - stream.writeAttribute("href", "http://qt.nokia.com/"); - stream.writeTextElement("title", "Qt Home"); - stream.writeEndElement(); - - stream.writeEndDocument(); - -} - -void Settings::writeFile() -{ - writeFile(DEFAULT_FILE); -} -*/ diff --git a/src/settings.h b/src/settings.h index 5b9c813..8cd55bb 100644 --- a/src/settings.h +++ b/src/settings.h @@ -1,7 +1,6 @@ #ifndef SETTINGS_H #define SETTINGS_H -#include #include #include #include @@ -19,23 +18,10 @@ public: static Settings *getInstance(); inline QSet getUniverses() { return m_universe; } inline QString getPathMedia() { return m_pathmedia; } - void setPathMedia(QString path); inline QList getDmxSettings() { return m_settings; } inline int getLayersNumber() { return m_layersNumber; } - inline int getUniverseNumber() { return m_universe.size(); } void readFile(); - void changeLayerSetup(int layer, int universe, int address); - void removeLayer(int layer); - void addLayer(); - inline void setLayersNumber(int layersNumber) - { - if (layersNumber <= MAX_LAYERS) - m_layersNumber = layersNumber; - else - m_layersNumber = MAX_LAYERS; - } inline int getAudioDeviceId() { return m_audioDeviceId; } - inline void setAudioDeviceId(int id) { m_audioDeviceId = id; } private: static Settings *_instance; @@ -47,14 +33,7 @@ private: explicit Settings(QObject *parent = 0); void readFromFile(QString file); -// void writeFile(QString filename); // Not implemented yet -// void writeFile(); // Not implemented yet -signals: - void pathChanged(QString path); - void layersNumber(int number); - void registerUniverse(int universe); - void audioDeviceChanged(int id); }; #endif // SETTINGS_H diff --git a/src/settingsdialog.h b/src/settingsdialog.h index 665c465..aaf099b 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -4,8 +4,8 @@ #include #include #include + #include "settings.h" -#include "layersettingswidget.h" namespace Ui { class SettingsDialog; diff --git a/src/slidergroup.h b/src/slidergroup.h index d1d34bf..f5bae60 100644 --- a/src/slidergroup.h +++ b/src/slidergroup.h @@ -2,17 +2,10 @@ #define SLIDERGROUP_H #include -#include -#include -#include +#include +#include #include -QT_BEGIN_NAMESPACE -class QDial; -class QScrollBar; -class QSlider; -QT_END_NAMESPACE - class SliderGroup : public QGroupBox { Q_OBJECT -- 2.39.5 From 3e93ca95bb5917dc421734bd909ca24d51b0b9e6 Mon Sep 17 00:00:00 2001 From: snt Date: Thu, 25 Apr 2024 16:58:02 +0200 Subject: [PATCH 11/49] =?UTF-8?q?mejor=20inicio,=20todav=C3=ADa=20=20no=20?= =?UTF-8?q?es=20bueno=20porque=20manda=20el=20volumen=20antes=20de=20inici?= =?UTF-8?q?ar=20las=20media,=20por=20lo=20que=20no=20hace=20caso=20a=20esa?= =?UTF-8?q?=20info.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libremediaserver-audio.cpp | 5 ++--- src/medialibrary.cpp | 2 +- src/olathread.cpp | 9 --------- src/olathread.h | 3 --- 4 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index ab83519..0d595ec 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -47,12 +47,11 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) connect(m_ola, SIGNAL (universeReceived(int)), m_dmxWidget, SLOT(updateWatchDMX(int))); connect(m_ola, SIGNAL(dmxOutput(int, int, int)), this, SLOT(dmxInput(int, int, int))); m_ola->registerUniverse(); - m_ola->start(QThread::TimeCriticalPriority ); - connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup())); + connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup())); m_aw->startEngine(); qDebug("Init Complete."); m_ola->blockSignals(false); - m_ola->resendDmx(); + m_ola->start(QThread::TimeCriticalPriority ); } libreMediaServerAudio::~libreMediaServerAudio() diff --git a/src/medialibrary.cpp b/src/medialibrary.cpp index 5834df0..8617d0f 100644 --- a/src/medialibrary.cpp +++ b/src/medialibrary.cpp @@ -51,7 +51,7 @@ QList MediaLibrary::getMediaInformation(QDir dir) QString MediaLibrary::requestNewFile(int folder, int file){ if (!m_media) { - qWarning("MediaLibrary is not init. Set a correct path to media library"); + qWarning("MediaLibrary is not init, set a correct path."); return NULL; } QString newfile; diff --git a/src/olathread.cpp b/src/olathread.cpp index 16c976f..ed0998b 100644 --- a/src/olathread.cpp +++ b/src/olathread.cpp @@ -125,15 +125,6 @@ bool olaThread::CheckDataLoss() { return true; } -void olaThread::resendDmx() -{ - for (int i = 0; i < m_layers; i++) { - for (int j = 0; j < LAYER_CHANNELS; j++){ - emit dmxOutput(i, j, m_dmx[i][j]); - } - } -} - void olaThread::socketClosed() { qWarning("ola closed connection. Try reopening it... "); diff --git a/src/olathread.h b/src/olathread.h index 148e859..91d78b6 100644 --- a/src/olathread.h +++ b/src/olathread.h @@ -43,7 +43,6 @@ private: int m_layers; int m_dmx[MAX_LAYERS][LAYER_CHANNELS]; QList m_dmxSettings; - /** * @brief Callback from ola. Control de errores en el registro de Universos en OLA * typedef SingleUseCallback1 ola::client::SetCallback @@ -96,6 +95,4 @@ signals: void universeReceived(int uni); }; -using namespace ola; - #endif // OLATHREAD_H -- 2.39.5 From 4ee82c5e5fd7ec1f1d00ef174278c46875babb3e Mon Sep 17 00:00:00 2001 From: snt Date: Thu, 2 May 2024 14:12:09 +0200 Subject: [PATCH 12/49] comentario en personality --- src/dmxPersonality.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/dmxPersonality.h b/src/dmxPersonality.h index f17231e..1e42df7 100644 --- a/src/dmxPersonality.h +++ b/src/dmxPersonality.h @@ -21,9 +21,8 @@ 11 - Pitch */ -// ToDo: Tiene bastante sentido cambiar estos defines por un enum -// ¿Ganaría algo en eficiencia? En claridad del código sí. - +// ToDo: Mejor inicializacion, primero folder, file, después params, ultimo playback.7 +// quitar CONTROL no usado #define VOLUME_COARSE 0 #define PAN 1 #define DMX_FOLDER 2 -- 2.39.5 From 1fccbf64fdd0ea55b3f7c66661223ec4a2160fc4 Mon Sep 17 00:00:00 2001 From: snt Date: Sat, 4 May 2024 01:43:44 +0200 Subject: [PATCH 13/49] =?UTF-8?q?refactorizada=20la=20GUI,=20ola=20y=20aud?= =?UTF-8?q?ioengine=20se=20ejecutan=20fuera=20de=20widgets.=20Opci=C3=B3n?= =?UTF-8?q?=20para=20ejecutar=20sin=20mostrar=20la=20GUI.=20Los=20controle?= =?UTF-8?q?s=20de=20la=20interfaz=20no=20son=20reactivos,=20no=20est=C3=A1?= =?UTF-8?q?n=20conectados=20a=20las=20=C3=B3rdenes=20de=20audio.=20cambio?= =?UTF-8?q?=20en=20la=20personalidad=20dmx=20para=20procesar=20los=20canal?= =?UTF-8?q?es=20en=20mejor=20orden.=20evita=20mandar=20dos=20veces=20los?= =?UTF-8?q?=20canales=20dobles=20por=20cada=20dmx=20frame,=20incluyendo=20?= =?UTF-8?q?file/folder.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libremediaserver-audio.pro | 5 +- src/audiolayerwidget.cpp | 101 +++++------ src/audiolayerwidget.h | 8 +- src/audiowidget.cpp | 73 ++------ src/audiowidget.h | 21 +-- src/defines.h | 5 +- src/dmxPersonality.h | 43 ++--- src/libremediaserver-audio-gui.cpp | 48 ++++++ src/libremediaserver-audio-gui.h | 48 ++++++ ...audio.ui => libremediaserver-audio-gui.ui} | 0 src/libremediaserver-audio.cpp | 161 ++++++++++-------- src/libremediaserver-audio.h | 32 ++-- src/main.cpp | 39 ++--- src/main.h | 20 +++ src/miniaudioengine.cpp | 36 +++- src/miniaudioengine.h | 3 +- src/olathread.cpp | 59 ++++--- src/olathread.h | 2 +- src/slidergroup.cpp | 24 ++- src/slidergroup.h | 11 +- 20 files changed, 416 insertions(+), 323 deletions(-) create mode 100644 src/libremediaserver-audio-gui.cpp create mode 100644 src/libremediaserver-audio-gui.h rename src/{libremediaserver-audio.ui => libremediaserver-audio-gui.ui} (100%) create mode 100644 src/main.h diff --git a/libremediaserver-audio.pro b/libremediaserver-audio.pro index a33e231..154d1fe 100644 --- a/libremediaserver-audio.pro +++ b/libremediaserver-audio.pro @@ -3,6 +3,8 @@ TARGET = libremediaserver-audio QT += webkitwidgets widgets HEADERS += src/libremediaserver-audio.h \ src/dmxwidget.h \ + src/libremediaserver-audio-gui.h \ + src/main.h \ src/miniaudio.h \ src/medialibrary.h \ src/miniaudioengine.h \ @@ -15,6 +17,7 @@ HEADERS += src/libremediaserver-audio.h \ src/slidergroup.h SOURCES += src/main.cpp \ src/dmxwidget.cpp \ + src/libremediaserver-audio-gui.cpp \ src/miniaudio.c \ src/libremediaserver-audio.cpp \ src/medialibrary.cpp \ @@ -24,7 +27,7 @@ SOURCES += src/main.cpp \ src/audiowidget.cpp \ src/settings.cpp \ src/slidergroup.cpp -FORMS += src/libremediaserver-audio.ui +FORMS += src/libremediaserver-audio-gui.ui CCFLAG += -msse2 -mavx2 #-fsanitize=address -g -O0 QMAKE_CXXFLAGS += $$(CXXFLAG) #QMAKE_CXXFLAGS += -fsanitize=address -g -O0 diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 99e1996..ffb8341 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -1,64 +1,67 @@ #include "audiolayerwidget.h" +#include - -AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name, int layer): - QGroupBox(parent) +AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): + QWidget(parent) , m_layer(layer) , m_suspendResumeButton(0) { - this->setTitle(name); QVBoxLayout *layout = new QVBoxLayout; - QHBoxLayout *progressTime = new QHBoxLayout; + m_suspendResumeButton = new QPushButton(this); + m_suspendResumeButton->setText(StatusStr[Status::Iddle]); + m_suspendResumeButton->setMaximumWidth(200); + //connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume())); + layout->addWidget(m_suspendResumeButton); + + m_progress = new QProgressBar(this); + m_progress->setOrientation(Qt::Horizontal); + m_progress->setRange(0, 0); + m_progress->setValue(0); + m_progress->setFormat("%v / %m"); + m_progress->setMaximumWidth(200); + layout->addWidget(m_progress); + m_progressTime = new QTimeEdit; - m_progressTime->text(); + m_progressTime->setToolTip("Current Time"); + m_progressTime->setObjectName("Current Time"); m_progressTime->setDisplayFormat("h:mm:ss:zzz"); m_progressTime->setReadOnly(true); m_progressTime->setButtonSymbols(QAbstractSpinBox::NoButtons); - m_progressTime->setMaximumWidth(90); + m_progressTime->setMaximumWidth(88); m_progressTime->setFocusPolicy(Qt::NoFocus); - progressTime->addWidget(m_progressTime); m_totalTimeValue = new QTimeEdit; + m_totalTimeValue->setObjectName("Track Length"); + m_totalTimeValue->setToolTip("Track Length"); m_totalTimeValue->setDisplayFormat("h:mm:ss:zzz"); m_totalTimeValue->setReadOnly(true); m_totalTimeValue->setButtonSymbols(QAbstractSpinBox::NoButtons); - m_totalTimeValue->setMaximumWidth(90); + m_totalTimeValue->setMaximumWidth(88); m_totalTimeValue->setFocusPolicy(Qt::NoFocus); - progressTime->addWidget(m_totalTimeValue); - layout->addLayout(progressTime); - - m_progressSlider = new QSlider(Qt::Horizontal); - m_progressSlider->setFocusPolicy(Qt::NoFocus); - layout->addWidget(m_progressSlider); - - QGridLayout *status = new QGridLayout; - m_statusValue = new QLabel; - status->addWidget(m_statusValue, 0, 0); + QHBoxLayout *status = new QHBoxLayout; + status->addWidget(m_progressTime); + status->addWidget(m_totalTimeValue); + layout->addLayout(status); + QVBoxLayout *playback = new QVBoxLayout; m_folderValue = new QLabel; m_folderValue->setMaximumWidth(200); - status->addWidget(m_folderValue, 1, 0); + playback->addWidget(m_folderValue); m_fileValue = new QLabel; m_fileValue->setMaximumWidth(200); - status->addWidget(m_fileValue, 2, 0); - layout->addLayout(status); + playback->addWidget(m_fileValue); + layout->addLayout(playback); QHBoxLayout *volumeBox = new QHBoxLayout; - m_volume = new SliderGroup("Vol", 0 , 100, 2, NULL); + m_volume = new SliderGroup(0 , 100, 2, NULL); volumeBox->addWidget(m_volume); connect(m_volume, SIGNAL(valueChanged(float)), this, SLOT(volumeChanged(float))); - m_pan = new SliderGroup("Pan", 0 , 255, 0, NULL); + m_pan = new SliderGroup(0 , 255, 0, NULL); volumeBox->addWidget(m_pan); connect(m_pan, SIGNAL(valueChanged(float)), this, SLOT(panChanged(float))); - m_pitch = new SliderGroup("Pitch", 0 , 255, 0, NULL); + m_pitch = new SliderGroup(0 , 255, 0, NULL); volumeBox->addWidget(m_pitch); connect(m_pitch, SIGNAL(valueChanged(float)), this, SLOT(pitchChanged(float))); layout->addLayout(volumeBox); - - m_suspendResumeButton = new QPushButton(this); - m_suspendResumeButton->setText(StatusStr[Status::Stopped]); - connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume())); - layout->addWidget(m_suspendResumeButton); - this->setLayout(layout); } @@ -95,6 +98,7 @@ void AudioLayerWidget::toggleSuspendResume() case Status::Stopped: this->setPlaybackStatus(Status::PlayingOnce); emit uiPlaybackChanged(m_layer, Status::PlayingOnce); + case Status::Iddle: break; } } @@ -129,43 +133,40 @@ void AudioLayerWidget::fileLoaded(QString file) m_folderValue->setText(list.at(size - 2)); m_fileValue->setText(list.at(size - 1)); } + this->setPlaybackStatus(Status::Stopped); } void AudioLayerWidget::setPlaybackStatus(Status status) { m_status = status; if (status == Status::Stopped) - m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(0)); - m_statusValue->blockSignals(true); + m_progress->setValue(0); m_suspendResumeButton->blockSignals(true); - m_statusValue->setText(StatusStr[status]); m_suspendResumeButton->setText(StatusStr[status]); - switch (m_status) { - case Status::Paused: - m_statusValue->setStyleSheet("QLabel { color : red; }"); - break; - case Status::PlayingLoop: - case Status::PlayingOnce: - m_statusValue->setStyleSheet("QLabel { color : green; }"); - break; - case Status::Stopped: - m_statusValue->setStyleSheet("QLabel { color : red; }"); - break; - } - m_statusValue->blockSignals(false); m_suspendResumeButton->blockSignals(false); } void AudioLayerWidget::durationChanged(float dur) { - dur *= 1000; - m_progressSlider->setMaximum(dur); + m_progress->blockSignals(true); + m_progressTime->blockSignals(true); + m_totalTimeValue->blockSignals(true); + m_progress->setRange(0, dur); + m_progress->setValue(0); + m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(0)); m_totalTimeValue->setTime(QTime::fromMSecsSinceStartOfDay(dur)); + m_progress->blockSignals(false); + m_progressTime->blockSignals(false); + m_totalTimeValue->blockSignals(false); } void AudioLayerWidget::refreshUi(float progress) { progress *= 1000; - m_progressSlider->setValue(progress); + m_progress->blockSignals(true); + m_progressTime->blockSignals(true); + m_progress->setValue(progress); m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(progress)); + m_progress->blockSignals(false); + m_progressTime->blockSignals(false); } diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index 53401fb..df5853a 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -4,16 +4,17 @@ #include #include #include +#include #include "defines.h" #include "slidergroup.h" -class AudioLayerWidget : public QGroupBox +class AudioLayerWidget : public QWidget { Q_OBJECT public: - explicit AudioLayerWidget(QWidget *parent = 0, QString name = "Layer", int layer = 0); + explicit AudioLayerWidget(QWidget *parent = 0, int layer = 0); ~AudioLayerWidget(); void setVol(float vol); void resume(); @@ -27,15 +28,14 @@ private: Status m_status; int m_layer; QPushButton *m_suspendResumeButton; - QLabel * m_statusValue; QLabel *m_fileValue; QLabel * m_folderValue; SliderGroup *m_volume; SliderGroup *m_pan; SliderGroup *m_pitch; - QSlider *m_progressSlider; QTimeEdit *m_progressTime; QTimeEdit *m_totalTimeValue; + QProgressBar *m_progress; public slots: void toggleSuspendResume(); diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index 4b35a5c..69dc60d 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -3,119 +3,66 @@ AudioWidget::AudioWidget() : m_layout(new QHBoxLayout()) - , m_refreshUi(new QTimer(this)) { for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) { - AudioLayerWidget *alw = new AudioLayerWidget(this, tr("Layer %1").arg(i + 1), i); + AudioLayerWidget *alw = new AudioLayerWidget(this, i); m_layout->insertWidget(i, alw); connect(alw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SLOT(uiSliderAction(int, Slider, int))); connect(alw, SIGNAL(uiPlaybackChanged(int, Status)), this, SLOT(uiChangePlaybackStatus(int, Status))); } setLayout(m_layout); - connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); - m_refreshUi->start(UI_REFRESH_TIME); } -bool AudioWidget::startEngine(int id) +void AudioWidget::mediaLoaded(int layer, QString file, float duration) { - return (m_mae.startEngine(id)); -} - -bool AudioWidget::startEngine() -{ - return (m_mae.startEngine(Settings::getInstance()->getAudioDeviceId())); -} - -void AudioWidget::stopEngine() -{ - m_mae.stopEngine(); -} - -void AudioWidget::mediaLoaded(int layer, QString file) -{ - ma_result result; - - if (m_currentMedia[layer].compare(file) == 0 ) { - return; - } - if (!QFile::exists(file)) { - qWarning("Can not access to file %s", file.toLatin1().constData()); - return; - } - result = m_mae.loadMedia(layer, file.toLatin1().data()); - if (result != MA_SUCCESS) { - qWarning("can not open file %s", file.toLatin1().constData()); - return; - } - m_currentMedia[layer] = file; - float pLength = m_mae.getDuration(layer); - qInfo("File loaded: %s - Duration: %f secs", file.toLatin1().constData(), pLength); - m_mae.printFormatInfo(layer); QLayoutItem * const item = m_layout->itemAt(layer); dynamic_cast(item->widget())->fileLoaded(file); - dynamic_cast(item->widget())->durationChanged(pLength); + dynamic_cast(item->widget())->durationChanged(duration); } void AudioWidget::volChanged(int layer, float vol) { - m_mae.volChanged(layer, vol); QLayoutItem * const item = m_layout->itemAt(layer); dynamic_cast(item->widget())->setVol(vol); } void AudioWidget::panChanged(int layer, int pan) { - m_mae.panChanged(layer, pan); QLayoutItem * const item = m_layout->itemAt(layer); dynamic_cast(item->widget())->setPan(pan); } void AudioWidget::pitchChanged(int layer, int pitch) { - m_mae.pitchChanged(layer, pitch); QLayoutItem * const item = m_layout->itemAt(layer); dynamic_cast(item->widget())->setPitch(pitch); } void AudioWidget::playbackChanged(int layer, Status status) { - m_mae.playbackChanged(layer, status); QLayoutItem * const item = m_layout->itemAt(layer); dynamic_cast(item->widget())->setPlaybackStatus(status); } -void AudioWidget::entryPointChanged(int layer, int cursor) +void AudioWidget::cursorChanged(int layer, float cursor) { - m_mae.setCursor(layer, cursor); QLayoutItem * const item = m_layout->itemAt(layer); - AudioLayerWidget *aw = dynamic_cast(item->widget()); - aw->refreshUi(m_mae.getCursor(layer)); -} - -void AudioWidget::refreshUi() { - for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) { - QLayoutItem * const item = m_layout->itemAt(i); - AudioLayerWidget *aw = dynamic_cast(item->widget()); - Status s = aw->getPlaybackStatus(); - if (s == Status::PlayingOnce || s == Status::PlayingLoop) { - aw->refreshUi(m_mae.getCursor(i)); - } - } + AudioLayerWidget *alw = dynamic_cast(item->widget()); + alw->refreshUi(cursor); } void AudioWidget::uiSliderAction(int layer, Slider s, int value) { switch (s){ case Slider::Volume: - m_mae.volChanged(layer, value); + emit uiVolChanged(layer, value); break; case Slider::Pan: - m_mae.panChanged(layer, value); + emit uiPanChanged(layer, value); break; case Slider::Pitch: - m_mae.pitchChanged(layer, value); + emit uiPitchChanged(layer, value); break; } } void AudioWidget::uiChangePlaybackStatus(int layer, Status s) { - m_mae.playbackChanged(layer, s); + emit uiPlaybackChanged(layer, s); } - diff --git a/src/audiowidget.h b/src/audiowidget.h index 254e59e..3314127 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -14,28 +14,25 @@ class AudioWidget : public QWidget public: AudioWidget(); - bool startEngine(); - bool startEngine(int id); - void stopEngine(); - void mediaLoaded(int layer, QString media ); + void mediaLoaded(int layer, QString media, float duration); void volChanged(int layer, float vol); void panChanged(int layer, int pan); void pitchChanged(int layer, int pitch); void playbackChanged(int layer, Status status); - void entryPointChanged(int layer, int cursor); - -private: - MiniAudioEngine m_mae; - QString m_currentMedia[MAX_LAYERS]; + void cursorChanged(int layer, float cursor); QHBoxLayout *m_layout; - QTimer *m_refreshUi; public slots: void uiSliderAction(int layer, Slider s, int value); void uiChangePlaybackStatus(int layer, Status s); -private slots: - void refreshUi(); +signals: + void uiMediaLoaded(int layer, QString media ); + void uiVolChanged(int layer, float vol); + void uiPanChanged(int layer, int pan); + void uiPitchChanged(int layer, int pitch); + void uiPlaybackChanged(int layer, Status status); + void uiEntryPointChanged(int layer, int cursor); }; #endif // AUDIOWIDGET_H diff --git a/src/defines.h b/src/defines.h index 68675c2..dee7850 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,8 +1,7 @@ #ifndef DEFINES_H #define DEFINES_H -//#define VERSION "LibreMediaServerAudio 0.2.0 Antigona Release" -#define VERSION "Kike Substitutor - No AI required - v0.2.0" +#define VERSION "LibreMediaServerAudio 0.2.0 Antigona Release" #define COPYRIGHT "(C) 2014-2024 Santi Noreña " #define LICENSE "GPL 3 Licensed. See LICENSE.txt.\nSound guys are not allowed to use this software." #define DEFAULT_FILE "lms-audio.xlm" @@ -22,6 +21,7 @@ enum Status Paused, PlayingOnce, PlayingLoop, + Iddle }; static const char* StatusStr[] = @@ -30,6 +30,7 @@ static const char* StatusStr[] = "Pause", "Playing One", "Playing Loop", + "Iddle", 0x0 }; diff --git a/src/dmxPersonality.h b/src/dmxPersonality.h index 1e42df7..c56829e 100644 --- a/src/dmxPersonality.h +++ b/src/dmxPersonality.h @@ -1,39 +1,16 @@ #ifndef DMXPERSONALITY_H #define DMXPERSONALITY_H -/** Define the DMX personality to avoid dealing with - * numbers and change it easyly in case - * -1 - Volumen Coarse -2 - Pan -3 - Folder -4 - File -5 - Playback - 0-24 : Play once. - 25-49: Stop. Returns to start of file. - 50-74: Pause. It keeps the time of reproductions. - 75-99: Play loop. -6 - Control - Reservado, sin uso en este momento. -7 - Volume Fine -8 - Entry Point Coarse - Punto de entrada de reproducción. -9 - Entry Point Fine - El valor de estos dos canales en centésimas de segundo. -10 - Pan -11 - Pitch -*/ +#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 ENTRY_POINT_FINE 4 +#define PITCH 7 -// ToDo: Mejor inicializacion, primero folder, file, después params, ultimo playback.7 -// quitar CONTROL no usado -#define VOLUME_COARSE 0 -#define PAN 1 -#define DMX_FOLDER 2 -#define DMX_FILE 3 -#define PLAYBACK 4 -#define CONTROL 5 -#define VOLUME_FINE 6 -#define ENTRY_POINT_COARSE 7 -#define ENTRY_POINT_FINE 8 -#define PITCH 9 - -#define LAYER_CHANNELS 10 +#define LAYER_CHANNELS 9 #endif // DMXPERSONALITY_H diff --git a/src/libremediaserver-audio-gui.cpp b/src/libremediaserver-audio-gui.cpp new file mode 100644 index 0000000..a300229 --- /dev/null +++ b/src/libremediaserver-audio-gui.cpp @@ -0,0 +1,48 @@ +/* + + Libre Media Server Audio - An Open source Media Server for arts and performing. + (c) Criptomart - Santiago Noreña 2012-2024 + https://git.criptomart.net/libremediaserver + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "libremediaserver-audio-gui.h" + + +libreMediaServerAudioUi::libreMediaServerAudioUi(QWidget *parent) + : QMainWindow(parent) +{ + ui.setupUi(this); + this->setWindowTitle(VERSION); + m_aw = new AudioWidget; + setCentralWidget(m_aw); + m_dmxWidget = new dmxWidget(this); + QDockWidget *topWidget = new QDockWidget(tr("Master"), this); + topWidget->setAllowedAreas(Qt::TopDockWidgetArea); + topWidget->setWidget(m_dmxWidget); + addDockWidget(Qt::TopDockWidgetArea, topWidget); + connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup())); +} + +libreMediaServerAudioUi::~libreMediaServerAudioUi() +{ +} + +void libreMediaServerAudioUi::olasetup() +{ + QWebView *view = new QWebView(); + view->load(QUrl("http://localhost:9090/ola.html")); + view->show(); +} diff --git a/src/libremediaserver-audio-gui.h b/src/libremediaserver-audio-gui.h new file mode 100644 index 0000000..50b4d8b --- /dev/null +++ b/src/libremediaserver-audio-gui.h @@ -0,0 +1,48 @@ +/* + Libre Media Server Audio - An Open source Media Server for arts and performing. + (c) Criptomart - Santiago Noreña 2012-2024 + https://git.criptomart.net/libremediaserver + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef LIBREMEDIASERVERAUDIOUI_H +#define LIBREMEDIASERVERAUDIOUI_H + +#include +#include + +#include "audiowidget.h" +#include "dmxwidget.h" +#include "defines.h" +#include "ui_libremediaserver-audio-gui.h" + +class libreMediaServerAudioUi : public QMainWindow +{ + Q_OBJECT + +public: + libreMediaServerAudioUi(QWidget *parent = 0); + virtual ~libreMediaServerAudioUi(); + AudioWidget *m_aw; + dmxWidget *m_dmxWidget; + +private: + Ui::LibreMediaServerAudio ui; + +private slots: + void olasetup(); +}; + +#endif // LIBREMEDIASERVERAUDIOUI_H diff --git a/src/libremediaserver-audio.ui b/src/libremediaserver-audio-gui.ui similarity index 100% rename from src/libremediaserver-audio.ui rename to src/libremediaserver-audio-gui.ui diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 0d595ec..d049c44 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -21,50 +21,35 @@ #include "libremediaserver-audio.h" -libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) - : QMainWindow(parent) +libreMediaServerAudio::libreMediaServerAudio(bool gui) { - Q_UNUSED(args); - qDebug() << VERSION; - qDebug() << COPYRIGHT; - qDebug() << LICENSE; - ui.setupUi(this); - this->setWindowTitle(VERSION); + m_ui = gui; Settings *set = Settings::getInstance(); set->readFile(); m_mediaLibrary = new MediaLibrary; m_mediaLibrary->initMediaLibrary(); - m_aw = new AudioWidget; - setCentralWidget(m_aw); - m_dmxWidget = new dmxWidget(this); - QDockWidget *topWidget = new QDockWidget(tr("Master"), this); - topWidget->setAllowedAreas(Qt::TopDockWidgetArea); - topWidget->setWidget(m_dmxWidget); - addDockWidget(Qt::TopDockWidgetArea, topWidget); m_ola = new olaThread(this, set->getLayersNumber()); Q_CHECK_PTR(m_ola); m_ola->blockSignals(true); - connect(m_ola, SIGNAL (universeReceived(int)), m_dmxWidget, SLOT(updateWatchDMX(int))); connect(m_ola, SIGNAL(dmxOutput(int, int, int)), this, SLOT(dmxInput(int, int, int))); m_ola->registerUniverse(); - connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup())); - m_aw->startEngine(); + m_mae.startEngine(set->getAudioDeviceId()); qDebug("Init Complete."); m_ola->blockSignals(false); m_ola->start(QThread::TimeCriticalPriority ); +#ifndef NOGUI + if (m_ui) { + m_refreshUi = new QTimer(this); + connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); + m_refreshUi->start(UI_REFRESH_TIME); + } +#endif } libreMediaServerAudio::~libreMediaServerAudio() { m_ola->stop(); - m_aw->stopEngine(); -} - -void libreMediaServerAudio::olasetup() -{ - QWebView *view = new QWebView(); - view->load(QUrl("http://localhost:9090/ola.html")); - view->show(); + m_mae.stopEngine(); } void libreMediaServerAudio::dmxInput(int layer, int channel, int value) @@ -73,54 +58,82 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) return; QString mediaFile = NULL; int aux; - switch(channel){ - case DMX_FOLDER: - aux = m_ola->getValue(layer, DMX_FILE); - mediaFile = m_mediaLibrary->requestNewFile(value, aux); - if (QFile::exists(mediaFile)) - m_aw->mediaLoaded(layer, mediaFile); - break; - case DMX_FILE: - aux = m_ola->getValue(layer, DMX_FOLDER); - mediaFile = m_mediaLibrary->requestNewFile(aux, value); - if (QFile::exists(mediaFile)) - m_aw->mediaLoaded(layer, mediaFile); - break; - case VOLUME_COARSE: - case VOLUME_FINE: - m_aw->volChanged(layer, (value / 65025.0f)); - break; - case PAN: - m_aw->panChanged(layer, value); - break; - case PITCH: - m_aw->pitchChanged(layer, value); - break; - case ENTRY_POINT_COARSE: - case ENTRY_POINT_FINE: - m_aw->entryPointChanged(layer, value); - break; - case PLAYBACK: - if (value == 0) - break; - aux = value / 25; - switch (aux) { - case 0 : - m_aw->playbackChanged(layer, PlayingOnce); - break; - case 1 : - m_aw->playbackChanged(layer, Stopped); - break; - case 2 : - m_aw->playbackChanged(layer, Paused); - break; - case 3 : - m_aw->playbackChanged(layer, PlayingLoop); - break; - default : - break; + if (channel == DMX_FOLDER || channel == DMX_FILE){ + int folder = (value >> 8) & 0x000000FF; + int file = value & 0x000000FF; + mediaFile = m_mediaLibrary->requestNewFile(folder, file); + if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0) + return; + if (QFile::exists(mediaFile)){ + m_mae.loadMedia(layer, mediaFile.toLatin1().data()); +#ifndef NOGUI + if (m_ui) + m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); +#endif + m_currentMedia[layer] = mediaFile; + } + } else if (channel == VOLUME_COARSE || channel == VOLUME_FINE) { + m_mae.volChanged(layer, (value / 65025.0f)); +#ifndef NOGUI + if (m_ui) + m_lmsUi->m_aw->volChanged(layer, (value / 650.25f)); +#endif + } else if (channel == PAN) { + m_mae.panChanged(layer, value); +#ifndef NOGUI + if (m_ui) + m_lmsUi->m_aw->panChanged(layer, value); +#endif + } else if (channel == PITCH) { + m_mae.pitchChanged(layer, value); +#ifndef NOGUI + if (m_ui) + m_lmsUi->m_aw->pitchChanged(layer, value); +#endif + } else if (channel == ENTRY_POINT_COARSE || channel == ENTRY_POINT_FINE) { + m_mae.setCursor(layer, value); +#ifndef NOGUI + if (m_ui) + m_lmsUi->m_aw->cursorChanged(layer, m_mae.getCursor(layer)); +#endif + + } else if (channel == PLAYBACK && value > 0) { + Status s = m_mae.getStatus(layer); + aux = value / 25; + if (s != aux) { + if (aux == 0) + s = Status::PlayingOnce; + else if (aux == 1) + s = Status::Stopped; + else if (aux == 2) + s = Status::Paused; + else if (aux == 3) + s = Status::PlayingLoop; + m_mae.playbackChanged(layer, s); +#ifndef NOGUI + if (m_ui) + m_lmsUi->m_aw->playbackChanged(layer, s); +#endif } - default: - break; } } + +#ifndef NOGUI +void libreMediaServerAudio::refreshUi() { + if (!m_ui) + return; + for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) { + Status s = m_mae.getStatus(i); + if (s == Status::PlayingOnce || s == Status::PlayingLoop) { + m_lmsUi->m_aw->cursorChanged(i, m_mae.getCursor(i)); + } + } +} + +void libreMediaServerAudio::setUi(libreMediaServerAudioUi *lmsUi) +{ + m_lmsUi = lmsUi; + connect(m_ola, SIGNAL(universeReceived(int)), m_lmsUi->m_dmxWidget, SLOT(updateWatchDMX(int))); +}; + +#endif diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index 9cd154b..923a42b 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -20,35 +20,41 @@ #ifndef LIBREMEDIASERVERAUDIO_H #define LIBREMEDIASERVERAUDIO_H -#include -#include - -#include "audiowidget.h" #include "medialibrary.h" #include "olathread.h" #include "settings.h" -#include "dmxwidget.h" #include "defines.h" -#include "ui_libremediaserver-audio.h" +#ifndef NOGUI +#include "libremediaserver-audio-gui.h" +#endif -class libreMediaServerAudio : public QMainWindow +class libreMediaServerAudio : public QObject { Q_OBJECT public: - libreMediaServerAudio (QStringList args, QWidget *parent = 0); + libreMediaServerAudio(bool gui = false); virtual ~libreMediaServerAudio(); - Ui::LibreMediaServerAudio ui; + olaThread *m_ola; +#ifndef NOGUI + void setUi(libreMediaServerAudioUi *lmsUi); +#endif private: - AudioWidget *m_aw; - dmxWidget *m_dmxWidget; - olaThread *m_ola; MediaLibrary *m_mediaLibrary; + MiniAudioEngine m_mae; + QString m_currentMedia[MAX_LAYERS]; +#ifndef NOGUI + bool m_ui; + QTimer *m_refreshUi; + libreMediaServerAudioUi *m_lmsUi; +#endif private slots: - void olasetup(); void dmxInput(int layer, int channel, int value); +#ifndef NOGUI + void refreshUi(); +#endif }; #endif // LIBREMEDIASERVERAUDIO_H diff --git a/src/main.cpp b/src/main.cpp index bfadafe..99643b0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,34 +18,29 @@ along with this program. If not, see . */ -#include "libremediaserver-audio.h" +#include "main.h" +bool hasUi(int &argc, char *argv[]) +{ + for (int i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "--gui")) + return true; + } + return false; +} int main(int argc, char *argv[]) { QApplication app(argc, argv); - QStringList args = app.arguments(); - if (args.size() > 1) + + libreMediaServerAudio lms(hasUi(argc, argv)); +#ifndef NOGUI + if (hasUi(argc, argv)) { - if (args.contains("-v")) - { - qDebug() << VERSION; - qDebug() << COPYRIGHT; - qDebug() << LICENSE; - return 0; - } - if (args.contains("-h")) - { - qDebug() << VERSION; - qDebug() << COPYRIGHT; - qDebug() << LICENSE; - qDebug() << "Help for command line options:"; - qDebug() << "-v show the version and exits"; - qDebug() << "-h this help"; - return 0; - } + libreMediaServerAudioUi *lmsUi = new libreMediaServerAudioUi(); + lms.setUi(lmsUi); + lmsUi->show(); } - libreMediaServerAudio libreMediaServerAudio(args); - libreMediaServerAudio.show(); +#endif return app.exec(); } diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..1a96ff6 --- /dev/null +++ b/src/main.h @@ -0,0 +1,20 @@ +#ifndef MAIN_H +#define MAIN_H + +#include +#include + +#include "medialibrary.h" +#include "olathread.h" +#include "settings.h" +#include "libremediaserver-audio.h" +#include "libremediaserver-audio-gui.h" +#include "defines.h" + + olaThread *m_ola; + MediaLibrary *m_mediaLibrary; + + // slots + void dmxInput(int layer, int channel, int value); + +#endif // MAIN_H diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 6d5490c..7ec94ba 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -115,7 +115,6 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file) if (m_mediaLoaded[layer] == true) { - qInfo("removing sound %i", layer); ma_sound_uninit(&m_currentSound[layer]); m_mediaLoaded[layer] = false; } @@ -137,16 +136,21 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file) float MiniAudioEngine::getDuration(int layer) { ma_result result; - float ret = 0; + ma_uint64 lengthInPCMFrames; + ma_uint32 sampleRate; + float ret; if (m_mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; - result = ma_sound_get_length_in_seconds(&m_currentSound[layer], &ret); - if (result != MA_SUCCESS) - { - qWarning("Can not get duration %i", layer); - ret = 0; + result = ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &lengthInPCMFrames); + 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 result; + } + ret = 1000.0f * (lengthInPCMFrames / float(sampleRate)); return ret; } @@ -161,7 +165,7 @@ float MiniAudioEngine::getCursor(int layer) if (result != MA_SUCCESS) { qWarning("Can not get cursor %i", layer); - ret = 0; + ret = -1; } return ret; } @@ -231,6 +235,8 @@ void MiniAudioEngine::playbackChanged(int layer, Status status) ma_sound_set_looping(&m_currentSound[layer], false); ma_sound_start(&m_currentSound[layer]); break; + default: + break; } } @@ -244,3 +250,17 @@ void MiniAudioEngine::setCursor(int layer, int cursor) f = (cursor * f) / 65025; ma_sound_seek_to_pcm_frame(&m_currentSound[layer], f); } + +Status MiniAudioEngine::getStatus(int layer) +{ + if (m_mediaLoaded[layer] == ma_bool8(false)) + return Status::Iddle; + if (ma_sound_is_playing(&m_currentSound[layer])) { + if (ma_sound_is_looping(&m_currentSound[layer])) + return Status::PlayingLoop; + return Status::PlayingOnce; + } + if (this->getDuration(layer) > 0) + return Status::Paused; + return Status::Stopped; +} diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 9549602..2bf224b 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -8,7 +8,7 @@ class MiniAudioEngine { - friend class AudioWidget; + friend class libreMediaServerAudio; public: MiniAudioEngine(); @@ -26,6 +26,7 @@ protected: float getCursor(int layer); void setCursor(int layer, int cursor); ma_result printFormatInfo(int layer); + Status getStatus(int layer); private: ma_resource_manager_config resourceManagerConfig; diff --git a/src/olathread.cpp b/src/olathread.cpp index ed0998b..471775c 100644 --- a/src/olathread.cpp +++ b/src/olathread.cpp @@ -63,39 +63,58 @@ void olaThread::stop() void olaThread::NewDmx(const ola::client::DMXMetadata &data, const ola::DmxBuffer &buffer) { - bool volSent = false; - bool entrySent = false; - foreach (const dmxSetting &i, m_dmxSettings) { if(i.universe == data.universe && i.address > -1) { + bool volSent = false; + bool entrySent = false; + bool fileSent = false; for (int j = 0; j < LAYER_CHANNELS; j++){ int value = buffer.Get((i.address) + j); if (m_dmx[i.layer][j] != value) { m_dmx[i.layer][j] = value; switch (j) { - case VOLUME_COARSE: - value = (value * 0x100) + buffer.Get(i.address + VOLUME_FINE); + case DMX_FOLDER: + value *= 0x100; + value += buffer.Get(i.address + DMX_FILE); emit dmxOutput(i.layer,j,value); - volSent = true; + m_dmx[i.layer][DMX_FILE] = buffer.Get(i.address + DMX_FILE); + fileSent = true; break; - case ENTRY_POINT_COARSE: - value = (value * 0x100) + buffer.Get(i.address + ENTRY_POINT_FINE); + case DMX_FILE: + if (fileSent) + break; + value += buffer.Get(i.address + DMX_FOLDER) * 0x100; emit dmxOutput(i.layer,j,value); - entrySent = true; + m_dmx[i.layer][DMX_FOLDER] = buffer.Get(i.address + DMX_FOLDER); + fileSent = true; break; case VOLUME_FINE: - if (volSent == false) - { - value = (buffer.Get(i.address + VOLUME_COARSE) * 0x100) + value; - emit dmxOutput(i.layer,j,value); - } + value = (buffer.Get(i.address + VOLUME_COARSE) * 0x100) + value; + emit dmxOutput(i.layer,j,value); + m_dmx[i.layer][VOLUME_COARSE] = buffer.Get(i.address + VOLUME_COARSE); + volSent = true; + break; + case VOLUME_COARSE: + if (volSent) + break; + value = (value * 0x100) + buffer.Get(i.address + VOLUME_FINE); + emit dmxOutput(i.layer,j,value); + m_dmx[i.layer][VOLUME_FINE] = buffer.Get(i.address + VOLUME_FINE); + volSent = true; break; case ENTRY_POINT_FINE: - if (entrySent == false) - { - value = (buffer.Get(i.address + ENTRY_POINT_COARSE) * 0x100) + value; - emit dmxOutput(i.layer,j,value); - } + value = (buffer.Get(i.address + ENTRY_POINT_COARSE) * 0x100) + value; + emit dmxOutput(i.layer,j,value); + m_dmx[i.layer][ENTRY_POINT_COARSE] = buffer.Get(i.address + ENTRY_POINT_COARSE); + entrySent = true; + break; + case ENTRY_POINT_COARSE: + if (entrySent) + break; + value = (value * 0x100) + buffer.Get(i.address + ENTRY_POINT_FINE); + emit dmxOutput(i.layer,j,value); + m_dmx[i.layer][ENTRY_POINT_FINE] = buffer.Get(i.address + ENTRY_POINT_FINE); + entrySent = true; break; default: emit dmxOutput(i.layer,j,value); @@ -127,7 +146,7 @@ bool olaThread::CheckDataLoss() { void olaThread::socketClosed() { - qWarning("ola closed connection. Try reopening it... "); + qWarning("ola daemon closed connection, reopening it... "); m_clientWrapper->GetSelectServer()->Terminate(); m_client = NULL; m_clientWrapper = NULL; diff --git a/src/olathread.h b/src/olathread.h index 91d78b6..dcae35b 100644 --- a/src/olathread.h +++ b/src/olathread.h @@ -53,7 +53,7 @@ private: if (error.Success()) { qDebug("Register Universe success"); } else { - qWarning("Register command failed: %s", error.Error().c_str()); + qCritical("Register command failed: %s", error.Error().c_str()); } } /** diff --git a/src/slidergroup.cpp b/src/slidergroup.cpp index e80a03f..2941bc4 100644 --- a/src/slidergroup.cpp +++ b/src/slidergroup.cpp @@ -1,45 +1,43 @@ #include "slidergroup.h" -SliderGroup::SliderGroup(const QString &title, \ - int min, +SliderGroup::SliderGroup(int min, int max, int decimals, QWidget *parent) - : QGroupBox(title, parent) + : QWidget(parent) { - this->setFlat(true); - this->setTitle(title); + QVBoxLayout *layout = new QVBoxLayout; + layout->setAlignment(Qt::AlignHCenter); + this->setMaximumWidth(65); slider = new QSlider(Qt::Orientation::Vertical); slider->setFocusPolicy(Qt::StrongFocus); slider->setTickPosition(QSlider::TicksBothSides); slider->setTickInterval((max - min) / 11); slider->setSingleStep(1); slider->setRange(min, max); + slider->setMaximumWidth(65); valueBox = new QDoubleSpinBox(); valueBox->setFocusPolicy(Qt::NoFocus); valueBox->setButtonSymbols(QAbstractSpinBox::NoButtons); - valueBox->setMaximumWidth(45); + valueBox->setMaximumWidth(65); valueBox->setRange(min, max); valueBox->setDecimals(decimals); connect(slider, SIGNAL(valueChanged(int)), this, SLOT(sliderValueChanged(int))); - QVBoxLayout *slidersLayout = new QVBoxLayout(); - slidersLayout->addWidget(valueBox); - slidersLayout->addWidget(slider); - setLayout(slidersLayout); + layout->addWidget(slider); + layout->addWidget(valueBox); + this->setLayout(layout); } void SliderGroup::sliderValueChanged(int value) { + valueBox->setValue(value); if (valueBox->decimals() > 1) value /= 100.0f; emit valueChanged(value); - valueBox->setValue(value); }; void SliderGroup::setValue(float value) { - if (valueBox->decimals() > 1) - value *= 100.0f; slider->setValue(value); valueBox->setValue(value); } diff --git a/src/slidergroup.h b/src/slidergroup.h index f5bae60..8972d56 100644 --- a/src/slidergroup.h +++ b/src/slidergroup.h @@ -6,16 +6,15 @@ #include #include -class SliderGroup : public QGroupBox +class SliderGroup : public QWidget { Q_OBJECT public: - SliderGroup(const QString &title, - int min, - int max, - int decimals, - QWidget *parent = nullptr); + SliderGroup(int min, + int max, + int decimals, + QWidget *parent = nullptr); signals: void valueChanged(float value); -- 2.39.5 From 88704cd7269cb6bfe5e377dff44e63fdc0e9b6ec Mon Sep 17 00:00:00 2001 From: snt Date: Sat, 4 May 2024 15:05:45 +0200 Subject: [PATCH 14/49] better ui, change colors and font --- docs/changelog.txt | 52 ++++++++++++++----------- docs/roadmap.txt | 18 ++++----- src/audiolayerwidget.cpp | 50 ++++++++++++++++-------- src/audiowidget.cpp | 2 + src/dmxwidget.cpp | 2 + src/libremediaserver-audio-gui.cpp | 8 ++++ src/libremediaserver-audio-gui.ui | 62 +++++++++--------------------- src/slidergroup.cpp | 29 ++++++++++++-- src/slidergroup.h | 3 +- 9 files changed, 129 insertions(+), 97 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 48b0ddf..22a7e1f 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -4,39 +4,47 @@ Libre Media Server Audio - An Open source Media Server for arts and performing. https://git.criptomart.net/libremediaserver ******************************************************************************* -Lbre Media Server ChangeLog +Libre Media Server ChangeLog -v 0.2.0 Antigona (24/04/2024) -+ change engine to miniaudio because is imposible pan in SFML and it has not access to low API and audio processing. -+ Refactor all audio methods to MiniAudioEngine. + + + + + +v 0.2.0 Antígona (24/04/2024) ++ Change audio engine to miniaudio because is imposible pan in SFML and it has not access to low API and audio processing. ++ Refactor all audio methods to MiniAudioEngine class. + Select sound device output. -+ pan. -+ Show faders values. -+ play offset. ++ Pan. ++ Show faders values. New SliderGroup class. ++ Entry Point 16 bits. + Refactor AudioMasterWidget to AudioDMXReceptionWidget. -+ mp3, flac, wav (mp3 has given some errors seeking cursor...). -+ settings dialog not working, only read the conf file at startup. -+ variable number of layers. -+ olathread, send double channels only once for each dmx frame buffer. ++ Read mp3, flac, wav (mp3 has given some errors seeking cursor...). ++ 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. ++ Terminal mode without graphical interface. All audio methods has been refactorized out of QWidget world. ++ Compilation without GUI (-DNOGUI). ++ 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); -v 0.1.3 Unreleased (19/04/2024) +v 0.1.3 Leúcade (19/04/2024) + Ubuntu 22.04 jammy. -+ Use SFML as audio engine. + Qt 5.15.3. -+ pitch. -+ loop. ++ 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. +- Several bugs tested in real world. +- 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 ++ First Version: 4 layers playing .ogg. ++ Needs Open Lighting Arquitecture => 0.9.0. ++ Pure Data as audio engine. diff --git a/docs/roadmap.txt b/docs/roadmap.txt index 8ff57d7..6b12098 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -20,8 +20,8 @@ v 0.2.2 + hay que empaquetar OLA, incluirlo en el binario, o implementar sACN y linkarlo estáticamente. + https://github.com/ETCLabs/sACN - Qt6. -- audio processing (eq, rev, compresor, ...) por master y capa. -- CIPT/MSex, send icons play-pause-stop. +- Audio processing (eq, rev, compresor, ...) by master and layer. +- CIPT/MSex, send icons play/pause/stop. - Rasp build. - Octopus Sound Card support (6 outputs - 8 inputs). @@ -41,15 +41,13 @@ v 0.2.1 - audio device linked, outputs will be redirected there. - dmx address + universe settings. - Rose noise and sine generator in menu to test system. -- Keyboards strokes, load media files from ui. -- Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante. +- Ui/Ux; Keyboards strokes, load media files from ui. +- Ui/Ux: Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante. - Logs, verbosity, timestamp. -- Bufgix: depurar errores cuando no carga la librería de medias, cambia el númmero de capas, cambia el universo, etc. -- New control mode without pitch control, it saves resources. MA_SOUND_FLAG_NO_PITCH +- New play mode without pitch control, it saves resources. MA_SOUND_FLAG_NO_PITCH - Vumeter or indicator about audio output in layer and master. - SettingsDialog. - Load/save conf file. -- ¿stop offset? is it needed? -- decouple MiniAudioEngine from AudioWidget, starts whith no gui or with audio in a dedicated thread. -- New Status "Iddle" in playbacks if is not loaded. -- check return errors, we are too happy.... +- ¿Exit Point? is it needed? +- Hardening: check return errors, i'm too happy.... +- Tests: errors on wrong conf file. diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index ffb8341..23dcb9a 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -8,9 +8,31 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): { QVBoxLayout *layout = new QVBoxLayout; + QVBoxLayout *playback = new QVBoxLayout; + m_folderValue = new QLabel; + //m_folderValue->setMaximumWidth(160); + m_folderValue->setAlignment(Qt::AlignHCenter); + m_folderValue->setStyleSheet( + "color: white;" + "background-color: black;" + ); + playback->addWidget(m_folderValue); + m_fileValue = new QLabel; + //m_fileValue->setMaximumWidth(160); + m_fileValue->setAlignment(Qt::AlignHCenter); + m_fileValue->setStyleSheet( + "color: white;" + "background-color: black;" + ); + + playback->addWidget(m_fileValue); + playback->setSpacing(0); + playback->setContentsMargins(0, 0, 0, 0); + layout->addLayout(playback); + m_suspendResumeButton = new QPushButton(this); m_suspendResumeButton->setText(StatusStr[Status::Iddle]); - m_suspendResumeButton->setMaximumWidth(200); + //m_suspendResumeButton->setMaximumWidth(180); //connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume())); layout->addWidget(m_suspendResumeButton); @@ -19,7 +41,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_progress->setRange(0, 0); m_progress->setValue(0); m_progress->setFormat("%v / %m"); - m_progress->setMaximumWidth(200); + //m_progress->setMaximumWidth(180); layout->addWidget(m_progress); m_progressTime = new QTimeEdit; @@ -28,7 +50,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_progressTime->setDisplayFormat("h:mm:ss:zzz"); m_progressTime->setReadOnly(true); m_progressTime->setButtonSymbols(QAbstractSpinBox::NoButtons); - m_progressTime->setMaximumWidth(88); + //m_progressTime->setMaximumWidth(80); m_progressTime->setFocusPolicy(Qt::NoFocus); m_totalTimeValue = new QTimeEdit; m_totalTimeValue->setObjectName("Track Length"); @@ -36,32 +58,28 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_totalTimeValue->setDisplayFormat("h:mm:ss:zzz"); m_totalTimeValue->setReadOnly(true); m_totalTimeValue->setButtonSymbols(QAbstractSpinBox::NoButtons); - m_totalTimeValue->setMaximumWidth(88); + //m_totalTimeValue->setMaximumWidth(80); m_totalTimeValue->setFocusPolicy(Qt::NoFocus); QHBoxLayout *status = new QHBoxLayout; status->addWidget(m_progressTime); status->addWidget(m_totalTimeValue); layout->addLayout(status); - QVBoxLayout *playback = new QVBoxLayout; - m_folderValue = new QLabel; - m_folderValue->setMaximumWidth(200); - playback->addWidget(m_folderValue); - m_fileValue = new QLabel; - m_fileValue->setMaximumWidth(200); - playback->addWidget(m_fileValue); - layout->addLayout(playback); - QHBoxLayout *volumeBox = new QHBoxLayout; - m_volume = new SliderGroup(0 , 100, 2, NULL); + m_volume = new SliderGroup("Vol", 0 , 100, 2, NULL); volumeBox->addWidget(m_volume); connect(m_volume, SIGNAL(valueChanged(float)), this, SLOT(volumeChanged(float))); - m_pan = new SliderGroup(0 , 255, 0, NULL); + m_pan = new SliderGroup("Pan", 0 , 255, 0, NULL); volumeBox->addWidget(m_pan); connect(m_pan, SIGNAL(valueChanged(float)), this, SLOT(panChanged(float))); - m_pitch = new SliderGroup(0 , 255, 0, NULL); + m_pitch = new SliderGroup("Pitch", 0 , 255, 0, NULL); volumeBox->addWidget(m_pitch); + volumeBox->setSpacing(0); + volumeBox->setContentsMargins(0, 0, 0, 0); connect(m_pitch, SIGNAL(valueChanged(float)), this, SLOT(pitchChanged(float))); layout->addLayout(volumeBox); + layout->setAlignment(Qt::AlignHCenter); + layout->setSpacing(0); + layout->setContentsMargins(2, 2, 2, 2); this->setLayout(layout); } diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index 69dc60d..316e43a 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -10,6 +10,8 @@ AudioWidget::AudioWidget() : connect(alw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SLOT(uiSliderAction(int, Slider, int))); connect(alw, SIGNAL(uiPlaybackChanged(int, Status)), this, SLOT(uiChangePlaybackStatus(int, Status))); } + m_layout->setSpacing(0); + m_layout->setContentsMargins(0, 0, 0, 0); setLayout(m_layout); } diff --git a/src/dmxwidget.cpp b/src/dmxwidget.cpp index 60d4206..c5b4150 100644 --- a/src/dmxwidget.cpp +++ b/src/dmxwidget.cpp @@ -9,6 +9,8 @@ dmxWidget::dmxWidget(QWidget *parent) : QVBoxLayout *vbox = new QVBoxLayout; m_receiveDMX->setText("DMX Signal"); vbox->addWidget(m_receiveDMX); + vbox->setSpacing(1); + vbox->setContentsMargins(1, 1, 1, 1); this->setLayout(vbox); connect(m_watchDMX, SIGNAL(timeout()), this, SLOT(watchDMXExpired())); diff --git a/src/libremediaserver-audio-gui.cpp b/src/libremediaserver-audio-gui.cpp index a300229..5c366ac 100644 --- a/src/libremediaserver-audio-gui.cpp +++ b/src/libremediaserver-audio-gui.cpp @@ -32,8 +32,16 @@ libreMediaServerAudioUi::libreMediaServerAudioUi(QWidget *parent) QDockWidget *topWidget = new QDockWidget(tr("Master"), this); topWidget->setAllowedAreas(Qt::TopDockWidgetArea); topWidget->setWidget(m_dmxWidget); + topWidget->setContentsMargins(0, 0, 0, 0); addDockWidget(Qt::TopDockWidgetArea, topWidget); connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup())); + this->setContentsMargins(5, 5, 5, 5); + this->setStyleSheet( + "color: white;" + "background-color: gray;" + "selection-color: blue;" + "selection-background-color: green" + ); } libreMediaServerAudioUi::~libreMediaServerAudioUi() diff --git a/src/libremediaserver-audio-gui.ui b/src/libremediaserver-audio-gui.ui index 6ade744..65c83c2 100644 --- a/src/libremediaserver-audio-gui.ui +++ b/src/libremediaserver-audio-gui.ui @@ -1,19 +1,31 @@ - Santi Noreña belfegor@gmail.com + Santi Noreña lms@criptomart.net LibreMediaServerAudio - + 0 0 - 114 - 218 + 800 + 800 + + + Unifont + 12 + 75 + true + + LibreMediaServer + + + ../../../../criptomart/artwork/logo_v2_criptomart.net.png../../../../criptomart/artwork/logo_v2_criptomart.net.png + @@ -21,7 +33,7 @@ 0 0 114 - 22 + 21 @@ -32,47 +44,9 @@ - - - Exit - - - - - Open Configuration... - - - - - Save Configuration... - - - - - Settings... - - - - - false - - - Init - - - - - IP Address - - - - - Make Thumbs - - - OLA Setup... + OLA Setup diff --git a/src/slidergroup.cpp b/src/slidergroup.cpp index 2941bc4..4bef674 100644 --- a/src/slidergroup.cpp +++ b/src/slidergroup.cpp @@ -1,6 +1,7 @@ #include "slidergroup.h" -SliderGroup::SliderGroup(int min, +SliderGroup::SliderGroup(QString name, + int min, int max, int decimals, QWidget *parent) @@ -8,23 +9,43 @@ SliderGroup::SliderGroup(int min, { QVBoxLayout *layout = new QVBoxLayout; layout->setAlignment(Qt::AlignHCenter); - this->setMaximumWidth(65); + 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(100); slider->setSingleStep(1); slider->setRange(min, max); - slider->setMaximumWidth(65); + //slider->setMaximumWidth(40); + slider->setToolTip(name); + slider->setStyleSheet("QSlider {" + "border: 1px solid #999999;" + "margin: 0px;" + "height: 200px;" + "width: 40px;}" + ); + slider->setContentsMargins(0, 0, 0, 0); valueBox = new QDoubleSpinBox(); valueBox->setFocusPolicy(Qt::NoFocus); valueBox->setButtonSymbols(QAbstractSpinBox::NoButtons); - valueBox->setMaximumWidth(65); + //valueBox->setMaximumWidth(40); valueBox->setRange(min, max); 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))); layout->addWidget(slider); layout->addWidget(valueBox); + this->setStyleSheet("border: 1px solid #999999;" + "width: 40px;" + "margin: 0px;" + ); + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); this->setLayout(layout); } diff --git a/src/slidergroup.h b/src/slidergroup.h index 8972d56..1d8cc8c 100644 --- a/src/slidergroup.h +++ b/src/slidergroup.h @@ -11,7 +11,8 @@ class SliderGroup : public QWidget Q_OBJECT public: - SliderGroup(int min, + SliderGroup(QString name, + int min, int max, int decimals, QWidget *parent = nullptr); -- 2.39.5 From 5a7a82736febc489a258d9c53c342f9452781714 Mon Sep 17 00:00:00 2001 From: snt Date: Sat, 4 May 2024 16:45:05 +0200 Subject: [PATCH 15/49] working UI controls --- src/audiolayerwidget.cpp | 25 +++++++++++++------------ src/audiolayerwidget.h | 6 +++--- src/audiowidget.cpp | 29 ++++++++++------------------- src/audiowidget.h | 16 ++++++---------- src/libremediaserver-audio-gui.cpp | 2 +- src/libremediaserver-audio.cpp | 22 ++++++++++++++++++++++ src/libremediaserver-audio.h | 2 ++ src/medialibrary.h | 6 ------ src/slidergroup.cpp | 2 -- src/slidergroup.h | 2 +- 10 files changed, 58 insertions(+), 54 deletions(-) diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 23dcb9a..2dd1d94 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -24,7 +24,6 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): "color: white;" "background-color: black;" ); - playback->addWidget(m_fileValue); playback->setSpacing(0); playback->setContentsMargins(0, 0, 0, 0); @@ -33,7 +32,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_suspendResumeButton = new QPushButton(this); m_suspendResumeButton->setText(StatusStr[Status::Iddle]); //m_suspendResumeButton->setMaximumWidth(180); - //connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume())); + connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume())); layout->addWidget(m_suspendResumeButton); m_progress = new QProgressBar(this); @@ -47,19 +46,21 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_progressTime = new QTimeEdit; m_progressTime->setToolTip("Current Time"); m_progressTime->setObjectName("Current Time"); - m_progressTime->setDisplayFormat("h:mm:ss:zzz"); + m_progressTime->setDisplayFormat("mm:ss:zz"); m_progressTime->setReadOnly(true); m_progressTime->setButtonSymbols(QAbstractSpinBox::NoButtons); - //m_progressTime->setMaximumWidth(80); + m_progressTime->setMaximumWidth(75); m_progressTime->setFocusPolicy(Qt::NoFocus); + m_progressTime->setAlignment(Qt::AlignHCenter); m_totalTimeValue = new QTimeEdit; m_totalTimeValue->setObjectName("Track Length"); m_totalTimeValue->setToolTip("Track Length"); - m_totalTimeValue->setDisplayFormat("h:mm:ss:zzz"); + m_totalTimeValue->setDisplayFormat("mm:ss:zz"); m_totalTimeValue->setReadOnly(true); m_totalTimeValue->setButtonSymbols(QAbstractSpinBox::NoButtons); - //m_totalTimeValue->setMaximumWidth(80); + m_totalTimeValue->setMaximumWidth(75); m_totalTimeValue->setFocusPolicy(Qt::NoFocus); + m_totalTimeValue->setAlignment(Qt::AlignHCenter); QHBoxLayout *status = new QHBoxLayout; status->addWidget(m_progressTime); status->addWidget(m_totalTimeValue); @@ -67,15 +68,15 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): QHBoxLayout *volumeBox = new QHBoxLayout; m_volume = new SliderGroup("Vol", 0 , 100, 2, NULL); volumeBox->addWidget(m_volume); - connect(m_volume, SIGNAL(valueChanged(float)), this, SLOT(volumeChanged(float))); + connect(m_volume, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int))); m_pan = new SliderGroup("Pan", 0 , 255, 0, NULL); volumeBox->addWidget(m_pan); - connect(m_pan, SIGNAL(valueChanged(float)), this, SLOT(panChanged(float))); + connect(m_pan, SIGNAL(valueChanged(int)), this, SLOT(panChanged(int))); m_pitch = new SliderGroup("Pitch", 0 , 255, 0, NULL); volumeBox->addWidget(m_pitch); volumeBox->setSpacing(0); volumeBox->setContentsMargins(0, 0, 0, 0); - connect(m_pitch, SIGNAL(valueChanged(float)), this, SLOT(pitchChanged(float))); + connect(m_pitch, SIGNAL(valueChanged(int)), this, SLOT(pitchChanged(int))); layout->addLayout(volumeBox); layout->setAlignment(Qt::AlignHCenter); layout->setSpacing(0); @@ -89,17 +90,17 @@ AudioLayerWidget::~AudioLayerWidget() } // From UI. -void AudioLayerWidget::volumeChanged(float value) +void AudioLayerWidget::volumeChanged(int value) { emit(uiSliderChanged(m_layer, Slider::Volume, value)); } -void AudioLayerWidget::panChanged(float value) +void AudioLayerWidget::panChanged(int value) { emit(uiSliderChanged(m_layer, Slider::Pan, value)); } -void AudioLayerWidget::pitchChanged(float value) +void AudioLayerWidget::pitchChanged(int value) { emit(uiSliderChanged(m_layer, Slider::Pitch, value)); } diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index df5853a..4f89d17 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -39,9 +39,9 @@ private: public slots: void toggleSuspendResume(); - void volumeChanged(float vol); - void panChanged(float pan); - void pitchChanged(float pitch); + void volumeChanged(int vol); + void panChanged(int pan); + void pitchChanged(int pitch); void fileLoaded(QString file); void durationChanged(float dur); void refreshUi(float progress); diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index 316e43a..58ca7fd 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -1,17 +1,18 @@ #include "audiowidget.h" -AudioWidget::AudioWidget() : - m_layout(new QHBoxLayout()) +AudioWidget::AudioWidget(QWidget *parent) : + QWidget(parent) + , m_layout(new QHBoxLayout()) { for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) { AudioLayerWidget *alw = new AudioLayerWidget(this, i); m_layout->insertWidget(i, alw); - connect(alw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SLOT(uiSliderAction(int, Slider, int))); - connect(alw, SIGNAL(uiPlaybackChanged(int, Status)), this, SLOT(uiChangePlaybackStatus(int, Status))); + connect(alw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SIGNAL(uiSliderChanged(int, Slider, int))); + connect(alw, SIGNAL(uiPlaybackChanged(int, Status)), this, SIGNAL(uiPlaybackChanged(int, Status))); } m_layout->setSpacing(0); - m_layout->setContentsMargins(0, 0, 0, 0); + m_layout->setContentsMargins(1, 1, 1, 1); setLayout(m_layout); } @@ -49,22 +50,12 @@ void AudioWidget::cursorChanged(int layer, float cursor) AudioLayerWidget *alw = dynamic_cast(item->widget()); alw->refreshUi(cursor); } - -void AudioWidget::uiSliderAction(int layer, Slider s, int value) +/* +void AudioWidget::uiSliderAction(int layer, Slider s, float value) { - switch (s){ - case Slider::Volume: - emit uiVolChanged(layer, value); - break; - case Slider::Pan: - emit uiPanChanged(layer, value); - break; - case Slider::Pitch: - emit uiPitchChanged(layer, value); - break; - } + emit uiSliderChanged(layer, s, value); } void AudioWidget::uiChangePlaybackStatus(int layer, Status s) { emit uiPlaybackChanged(layer, s); -} +}*/ diff --git a/src/audiowidget.h b/src/audiowidget.h index 3314127..ff3adea 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -13,7 +13,7 @@ class AudioWidget : public QWidget Q_OBJECT public: - AudioWidget(); + AudioWidget(QWidget *parent = nullptr); void mediaLoaded(int layer, QString media, float duration); void volChanged(int layer, float vol); void panChanged(int layer, int pan); @@ -21,18 +21,14 @@ public: void playbackChanged(int layer, Status status); void cursorChanged(int layer, float cursor); QHBoxLayout *m_layout; - +/* public slots: - void uiSliderAction(int layer, Slider s, int value); + void uiSliderAction(int layer, Slider s, float value); void uiChangePlaybackStatus(int layer, Status s); - +*/ signals: - void uiMediaLoaded(int layer, QString media ); - void uiVolChanged(int layer, float vol); - void uiPanChanged(int layer, int pan); - void uiPitchChanged(int layer, int pitch); - void uiPlaybackChanged(int layer, Status status); - void uiEntryPointChanged(int layer, int cursor); + void uiPlaybackChanged(int layer, Status s); + void uiSliderChanged(int layer, Slider s, int vol); }; #endif // AUDIOWIDGET_H diff --git a/src/libremediaserver-audio-gui.cpp b/src/libremediaserver-audio-gui.cpp index 5c366ac..2d92918 100644 --- a/src/libremediaserver-audio-gui.cpp +++ b/src/libremediaserver-audio-gui.cpp @@ -26,7 +26,7 @@ libreMediaServerAudioUi::libreMediaServerAudioUi(QWidget *parent) { ui.setupUi(this); this->setWindowTitle(VERSION); - m_aw = new AudioWidget; + m_aw = new AudioWidget(this); setCentralWidget(m_aw); m_dmxWidget = new dmxWidget(this); QDockWidget *topWidget = new QDockWidget(tr("Master"), this); diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index d049c44..deb1a7d 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -134,6 +134,28 @@ void libreMediaServerAudio::setUi(libreMediaServerAudioUi *lmsUi) { m_lmsUi = lmsUi; connect(m_ola, SIGNAL(universeReceived(int)), m_lmsUi->m_dmxWidget, SLOT(updateWatchDMX(int))); + connect(m_lmsUi->m_aw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SLOT(uiSliderChanged(int, Slider, int))); + connect(m_lmsUi->m_aw, SIGNAL(uiPlaybackChanged(int, Status)), this, SLOT(uiPlaybackChanged(int, Status))); }; +void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value) +{ + switch (s){ + case Slider::Volume: + m_mae.volChanged(layer, float((value / 100.0f))); + break; + case Slider::Pan: + m_mae.panChanged(layer, value); + break; + case Slider::Pitch: + m_mae.pitchChanged(layer, value); + break; + } +} + +void libreMediaServerAudio::uiPlaybackChanged(int layer, Status s) +{ + m_mae.playbackChanged(layer, s); +} + #endif diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index 923a42b..9c8f152 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -54,6 +54,8 @@ private slots: void dmxInput(int layer, int channel, int value); #ifndef NOGUI void refreshUi(); + void uiSliderChanged(int layer, Slider s, int value); + void uiPlaybackChanged(int layer, Status s); #endif }; diff --git a/src/medialibrary.h b/src/medialibrary.h index 5a0b55b..8c2eb07 100644 --- a/src/medialibrary.h +++ b/src/medialibrary.h @@ -27,12 +27,6 @@ class MediaLibrary : public QObject public: MediaLibrary(QObject *parent = 0); - /** - * @brief request a new file from the media library - * @param int folder - the folder required - * @param int layer - file required - * @return QString the file required with full path - */ QString requestNewFile(int folder, int layer); void initMediaLibrary(); diff --git a/src/slidergroup.cpp b/src/slidergroup.cpp index 4bef674..e58588e 100644 --- a/src/slidergroup.cpp +++ b/src/slidergroup.cpp @@ -52,8 +52,6 @@ SliderGroup::SliderGroup(QString name, void SliderGroup::sliderValueChanged(int value) { valueBox->setValue(value); - if (valueBox->decimals() > 1) - value /= 100.0f; emit valueChanged(value); }; diff --git a/src/slidergroup.h b/src/slidergroup.h index 1d8cc8c..f597a5b 100644 --- a/src/slidergroup.h +++ b/src/slidergroup.h @@ -18,7 +18,7 @@ public: QWidget *parent = nullptr); signals: - void valueChanged(float value); + void valueChanged(int value); public slots: void setValue(float value); -- 2.39.5 From 389966782d739776fe570fdf48a5da1dcb69e6ca Mon Sep 17 00:00:00 2001 From: snt Date: Sat, 4 May 2024 19:35:12 +0200 Subject: [PATCH 16/49] =?UTF-8?q?open=20file=20dialog=20clicking=20on=20fi?= =?UTF-8?q?le/folder=20labels.=20se=20atasca=20y=20se=20pone=20a=20100%,?= =?UTF-8?q?=20los=20faders=20no=20refrescan=20como=20debieran,=20parece=20?= =?UTF-8?q?que=20se=20saturan=20las=20se=C3=B1ales.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libremediaserver-audio.pro | 2 ++ src/audiolayerwidget.cpp | 29 +++++++++++++++++++++++++---- src/audiolayerwidget.h | 13 +++++++++---- src/audiowidget.cpp | 10 +--------- src/audiowidget.h | 7 ++----- src/clickablelabel.cpp | 13 +++++++++++++ src/clickablelabel.h | 22 ++++++++++++++++++++++ src/defines.h | 6 +++--- src/libremediaserver-audio.cpp | 6 ++++++ src/libremediaserver-audio.h | 1 + src/miniaudioengine.cpp | 2 ++ 11 files changed, 86 insertions(+), 25 deletions(-) create mode 100644 src/clickablelabel.cpp create mode 100644 src/clickablelabel.h diff --git a/libremediaserver-audio.pro b/libremediaserver-audio.pro index 154d1fe..42ef0d1 100644 --- a/libremediaserver-audio.pro +++ b/libremediaserver-audio.pro @@ -2,6 +2,7 @@ TEMPLATE = app TARGET = libremediaserver-audio QT += webkitwidgets widgets HEADERS += src/libremediaserver-audio.h \ + src/clickablelabel.h \ src/dmxwidget.h \ src/libremediaserver-audio-gui.h \ src/main.h \ @@ -16,6 +17,7 @@ HEADERS += src/libremediaserver-audio.h \ src/settings.h \ src/slidergroup.h SOURCES += src/main.cpp \ + src/clickablelabel.cpp \ src/dmxwidget.cpp \ src/libremediaserver-audio-gui.cpp \ src/miniaudio.c \ diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 2dd1d94..ee112dd 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -9,7 +9,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): QVBoxLayout *layout = new QVBoxLayout; QVBoxLayout *playback = new QVBoxLayout; - m_folderValue = new QLabel; + m_folderValue = new ClickableLabel; //m_folderValue->setMaximumWidth(160); m_folderValue->setAlignment(Qt::AlignHCenter); m_folderValue->setStyleSheet( @@ -17,7 +17,9 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): "background-color: black;" ); playback->addWidget(m_folderValue); - m_fileValue = new QLabel; + m_fileValue = new ClickableLabel; + connect(m_fileValue, SIGNAL(clicked()), this, SLOT(openMediaDialog())); + connect(m_folderValue, SIGNAL(clicked()), this, SLOT(openMediaDialog())); //m_fileValue->setMaximumWidth(160); m_fileValue->setAlignment(Qt::AlignHCenter); m_fileValue->setStyleSheet( @@ -52,6 +54,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_progressTime->setMaximumWidth(75); m_progressTime->setFocusPolicy(Qt::NoFocus); m_progressTime->setAlignment(Qt::AlignHCenter); + m_progressTime->setContentsMargins(0,0,0,0); m_totalTimeValue = new QTimeEdit; m_totalTimeValue->setObjectName("Track Length"); m_totalTimeValue->setToolTip("Track Length"); @@ -61,6 +64,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_totalTimeValue->setMaximumWidth(75); m_totalTimeValue->setFocusPolicy(Qt::NoFocus); m_totalTimeValue->setAlignment(Qt::AlignHCenter); + m_totalTimeValue->setContentsMargins(0,0,0,0); QHBoxLayout *status = new QHBoxLayout; status->addWidget(m_progressTime); status->addWidget(m_totalTimeValue); @@ -115,13 +119,28 @@ void AudioLayerWidget::toggleSuspendResume() break; case Status::Paused: case Status::Stopped: - this->setPlaybackStatus(Status::PlayingOnce); + //this->setPlaybackStatus(Status::PlayingOnce); emit uiPlaybackChanged(m_layer, Status::PlayingOnce); case Status::Iddle: break; } } +void AudioLayerWidget::openMediaDialog() +{ + QFileDialog dialog(this); + dialog.setFileMode(QFileDialog::ExistingFile); + dialog.setNameFilter(tr("Sound Tracks (*.mp3 *.mp3 *.flac *.wav")); + dialog.setViewMode(QFileDialog::Detail); + dialog.setDirectory(Settings::getInstance()->getPathMedia()); + if (!dialog.exec()) + return; + QStringList fileNames; + fileNames = dialog.selectedFiles(); + emit uiLoadMedia(m_layer, fileNames.at(0)); + this->fileLoaded(fileNames.at(0)); +} + // from DMX signals void AudioLayerWidget::setVol(float vol) { @@ -157,10 +176,12 @@ void AudioLayerWidget::fileLoaded(QString file) void AudioLayerWidget::setPlaybackStatus(Status status) { + if (StatusStr[status] == m_suspendResumeButton->text()) + return; + m_suspendResumeButton->blockSignals(true); m_status = status; if (status == Status::Stopped) m_progress->setValue(0); - m_suspendResumeButton->blockSignals(true); m_suspendResumeButton->setText(StatusStr[status]); m_suspendResumeButton->blockSignals(false); } diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index 4f89d17..c0c6b3b 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -3,11 +3,13 @@ #include #include -#include +#include #include #include "defines.h" #include "slidergroup.h" +#include "clickablelabel.h" +#include "settings.h" class AudioLayerWidget : public QWidget { @@ -28,8 +30,8 @@ private: Status m_status; int m_layer; QPushButton *m_suspendResumeButton; - QLabel *m_fileValue; - QLabel * m_folderValue; + ClickableLabel *m_fileValue; + ClickableLabel * m_folderValue; SliderGroup *m_volume; SliderGroup *m_pan; SliderGroup *m_pitch; @@ -46,10 +48,13 @@ public slots: void durationChanged(float dur); void refreshUi(float progress); +private slots: + void openMediaDialog(); + signals: void uiPlaybackChanged(int layer, Status s); void uiSliderChanged(int layer, Slider s, int value); - + void uiLoadMedia(int layer, QString s); }; #endif // AUDIOLAYERWIDGET_H diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index 58ca7fd..47d7ce5 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -10,6 +10,7 @@ AudioWidget::AudioWidget(QWidget *parent) : m_layout->insertWidget(i, alw); connect(alw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SIGNAL(uiSliderChanged(int, Slider, int))); connect(alw, SIGNAL(uiPlaybackChanged(int, Status)), this, SIGNAL(uiPlaybackChanged(int, Status))); + connect(alw, SIGNAL(uiLoadMedia(int, QString)), this, SIGNAL(uiLoadMedia(int, QString))); } m_layout->setSpacing(0); m_layout->setContentsMargins(1, 1, 1, 1); @@ -50,12 +51,3 @@ void AudioWidget::cursorChanged(int layer, float cursor) AudioLayerWidget *alw = dynamic_cast(item->widget()); alw->refreshUi(cursor); } -/* -void AudioWidget::uiSliderAction(int layer, Slider s, float value) -{ - emit uiSliderChanged(layer, s, value); -} - -void AudioWidget::uiChangePlaybackStatus(int layer, Status s) { - emit uiPlaybackChanged(layer, s); -}*/ diff --git a/src/audiowidget.h b/src/audiowidget.h index ff3adea..a293a0a 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -21,14 +21,11 @@ public: void playbackChanged(int layer, Status status); void cursorChanged(int layer, float cursor); QHBoxLayout *m_layout; -/* -public slots: - void uiSliderAction(int layer, Slider s, float value); - void uiChangePlaybackStatus(int layer, Status s); -*/ + signals: void uiPlaybackChanged(int layer, Status s); void uiSliderChanged(int layer, Slider s, int vol); + void uiLoadMedia(int layer, QString s); }; #endif // AUDIOWIDGET_H diff --git a/src/clickablelabel.cpp b/src/clickablelabel.cpp new file mode 100644 index 0000000..333219b --- /dev/null +++ b/src/clickablelabel.cpp @@ -0,0 +1,13 @@ +#include "clickablelabel.h" + +ClickableLabel::ClickableLabel(QWidget *parent, Qt::WindowFlags f) + : QLabel{parent} +{ + +} + +ClickableLabel::~ClickableLabel() {} + +void ClickableLabel::mousePressEvent(QMouseEvent* event) { + emit clicked(); +} diff --git a/src/clickablelabel.h b/src/clickablelabel.h new file mode 100644 index 0000000..e75aae7 --- /dev/null +++ b/src/clickablelabel.h @@ -0,0 +1,22 @@ +#ifndef CLICKABLELABEL_H +#define CLICKABLELABEL_H + +#include +#include +#include + +class ClickableLabel : public QLabel +{ + Q_OBJECT +public: + explicit ClickableLabel(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()); + ~ClickableLabel(); + +signals: + void clicked(); + +protected: + void mousePressEvent(QMouseEvent* event); +}; + +#endif // CLICKABLELABEL_H diff --git a/src/defines.h b/src/defines.h index dee7850..633b06c 100644 --- a/src/defines.h +++ b/src/defines.h @@ -3,10 +3,10 @@ #define VERSION "LibreMediaServerAudio 0.2.0 Antigona Release" #define COPYRIGHT "(C) 2014-2024 Santi Noreña " -#define LICENSE "GPL 3 Licensed. See LICENSE.txt.\nSound guys are not allowed to use this software." +#define LICENSE "GPL 3 Licensed. See LICENSE.txt." #define DEFAULT_FILE "lms-audio.xlm" -#define MAX_LAYERS 16 -#define UI_REFRESH_TIME 200 +#define MAX_LAYERS 4 +#define UI_REFRESH_TIME 1000 // struct where save the DMX settings for each layer struct dmxSetting { diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index deb1a7d..b59a8f1 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -126,6 +126,7 @@ void libreMediaServerAudio::refreshUi() { Status s = m_mae.getStatus(i); if (s == Status::PlayingOnce || s == Status::PlayingLoop) { m_lmsUi->m_aw->cursorChanged(i, m_mae.getCursor(i)); + //m_lmsUi->m_aw->playbackChanged(i, s); } } } @@ -136,6 +137,7 @@ void libreMediaServerAudio::setUi(libreMediaServerAudioUi *lmsUi) connect(m_ola, SIGNAL(universeReceived(int)), m_lmsUi->m_dmxWidget, SLOT(updateWatchDMX(int))); connect(m_lmsUi->m_aw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SLOT(uiSliderChanged(int, Slider, int))); connect(m_lmsUi->m_aw, SIGNAL(uiPlaybackChanged(int, Status)), this, SLOT(uiPlaybackChanged(int, Status))); + connect(m_lmsUi->m_aw, SIGNAL(uiLoadMedia(int, QString)), this, SLOT(uiLoadMedia(int, QString))); }; void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value) @@ -158,4 +160,8 @@ void libreMediaServerAudio::uiPlaybackChanged(int layer, Status s) m_mae.playbackChanged(layer, s); } +void libreMediaServerAudio::uiLoadMedia(int layer, QString s) +{ + m_mae.loadMedia(layer, s.toLatin1().data()); +} #endif diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index 9c8f152..6b80f97 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -56,6 +56,7 @@ private slots: void refreshUi(); void uiSliderChanged(int layer, Slider s, int value); void uiPlaybackChanged(int layer, Status s); + void uiLoadMedia(int layer, QString s); #endif }; diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 7ec94ba..1f2c0b4 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -122,6 +122,7 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file) MA_SOUND_FLAG_NO_SPATIALIZATION \ /*| MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE \ | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC \ + | MA_SOUND_FLAG_NO_PITCH \ | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM \*/ , NULL, NULL, &m_currentSound[layer]); if (result != MA_SUCCESS) @@ -249,6 +250,7 @@ void MiniAudioEngine::setCursor(int layer, int cursor) ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &f); f = (cursor * f) / 65025; ma_sound_seek_to_pcm_frame(&m_currentSound[layer], f); + // ToDo: change the loop entry point too } Status MiniAudioEngine::getStatus(int layer) -- 2.39.5 From ef653553d9801b495f0d4ab73c05188517718518 Mon Sep 17 00:00:00 2001 From: snt Date: Sat, 4 May 2024 19:38:43 +0200 Subject: [PATCH 17/49] update magicq head qith new personality --- docs/LibreMediaServer_Audio.hed | 146 ++++++++++++++++---------------- 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/docs/LibreMediaServer_Audio.hed b/docs/LibreMediaServer_Audio.hed index 5da3a28..58d0fd5 100644 --- a/docs/LibreMediaServer_Audio.hed +++ b/docs/LibreMediaServer_Audio.hed @@ -1,76 +1,76 @@ ް׆ˌĠ򝤫鿰맫͓Ԕ ҊÅЁ䍡 ӽ -䉭ėĈ -ϛ -Ӧ -ڑ -ė - -ݍ -Ȫ -웣傪Ⓨ֚ -ކՂ -߸“ -Ŷ -ѝ -ωƀ - - - - -ŕ -ʷí -̙ -򴹤 -ԥѼ܅ -𗹣َ -̚ -Რ - -Ņ -⽬ -̫ -喤쏎ʁǏ - -߬ػс -썎ޛ - -쏎 - - - -Ճ - -尨 -ގ - -ލ -ƕ - -ŗ - - - - - -ˤ - - - - - -쏐 - - - -쏎 -󩼿 - - - -ÛƘ - - - - +Ꭸʆ +ɑ +ɬ +򉇁 +Ԑɉ + +ٿդϨ҃ +񀠧ڔ +ڑŌ +򻴧 + + + + + + + + +쏎ބ +힇ݳ + +Ԓlj + +έ +倬쏎 + +޽ڊ + +؛ +ŕ +ðݑ +ȕ +˛ +̽ɧ + +𓎍 + + +ً + +ʐ +ï +뷪 + + +܋ +Ò +뻡 +ǒ + +𓎍 +ʟ + +㍛ + + + + + + +𓎑 + + + +ҟ + + + +ف + + + + -- 2.39.5 From 246a8a2f98a201883d51177c5fb89998282b5976 Mon Sep 17 00:00:00 2001 From: snt Date: Sun, 5 May 2024 14:39:21 +0200 Subject: [PATCH 18/49] =?UTF-8?q?restringe=20las=20se=C3=B1ales=20de=20los?= =?UTF-8?q?=20sliders,=20en=20vez=20de=20actualizar=20en=20directo,=20s?= =?UTF-8?q?=C3=B3lo=20actualiza=20con=20el=20timer=20refreshGui.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/roadmap.txt | 2 +- libremediaserver-audio.pro | 4 +-- src/clickablelabel.cpp | 3 +- src/defines.h | 2 +- src/libremediaserver-audio.cpp | 60 +++++++++++++++++++--------------- src/libremediaserver-audio.h | 2 ++ src/miniaudioengine.cpp | 7 ++-- src/slidergroup.cpp | 7 +++- 8 files changed, 53 insertions(+), 34 deletions(-) diff --git a/docs/roadmap.txt b/docs/roadmap.txt index 6b12098..894c32c 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -49,5 +49,5 @@ v 0.2.1 - SettingsDialog. - Load/save conf file. - ¿Exit Point? is it needed? -- Hardening: check return errors, i'm too happy.... +- Hardening: check return errors, catch execptions, i'm too happy.... - Tests: errors on wrong conf file. diff --git a/libremediaserver-audio.pro b/libremediaserver-audio.pro index 42ef0d1..41d6ecd 100644 --- a/libremediaserver-audio.pro +++ b/libremediaserver-audio.pro @@ -30,9 +30,9 @@ SOURCES += src/main.cpp \ src/settings.cpp \ src/slidergroup.cpp FORMS += src/libremediaserver-audio-gui.ui -CCFLAG += -msse2 -mavx2 #-fsanitize=address -g -O0 +CCFLAG += -msse2 -mavx2 #-fsanitize=address -g3 -O0 QMAKE_CXXFLAGS += $$(CXXFLAG) -#QMAKE_CXXFLAGS += -fsanitize=address -g -O0 +#QMAKE_CXXFLAGS += -fsanitize=address -g3 -O0 QMAKE_CFLAGS += $$(CCFLAG) QMAKE_LFLAGS += $$(LDFLAG) LIBS += -lola -lolacommon -ldl -lpthread -lm diff --git a/src/clickablelabel.cpp b/src/clickablelabel.cpp index 333219b..623493d 100644 --- a/src/clickablelabel.cpp +++ b/src/clickablelabel.cpp @@ -3,11 +3,12 @@ ClickableLabel::ClickableLabel(QWidget *parent, Qt::WindowFlags f) : QLabel{parent} { - + Q_UNUSED(f); } ClickableLabel::~ClickableLabel() {} void ClickableLabel::mousePressEvent(QMouseEvent* event) { + Q_UNUSED(event); emit clicked(); } diff --git a/src/defines.h b/src/defines.h index 633b06c..a4eeea5 100644 --- a/src/defines.h +++ b/src/defines.h @@ -6,7 +6,7 @@ #define LICENSE "GPL 3 Licensed. See LICENSE.txt." #define DEFAULT_FILE "lms-audio.xlm" #define MAX_LAYERS 4 -#define UI_REFRESH_TIME 1000 +#define UI_REFRESH_TIME 200 // struct where save the DMX settings for each layer struct dmxSetting { diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index b59a8f1..d146e10 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -28,6 +28,12 @@ libreMediaServerAudio::libreMediaServerAudio(bool gui) set->readFile(); m_mediaLibrary = new MediaLibrary; m_mediaLibrary->initMediaLibrary(); + for (int i = 0; i < MAX_LAYERS; i++) { + m_currentMedia[i] = Status::Iddle; + m_updateUi[i][0] = -1; + m_updateUi[i][1] = -1; + m_updateUi[i][2] = -1; + } m_ola = new olaThread(this, set->getLayersNumber()); Q_CHECK_PTR(m_ola); m_ola->blockSignals(true); @@ -54,7 +60,7 @@ libreMediaServerAudio::~libreMediaServerAudio() void libreMediaServerAudio::dmxInput(int layer, int channel, int value) { - if (layer > LAYER_CHANNELS) + if (layer >= MAX_LAYERS || channel >= LAYER_CHANNELS) return; QString mediaFile = NULL; int aux; @@ -66,40 +72,32 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) return; if (QFile::exists(mediaFile)){ m_mae.loadMedia(layer, mediaFile.toLatin1().data()); -#ifndef NOGUI + m_currentMedia[layer] = mediaFile; +#ifndef NOGIO if (m_ui) m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); #endif - m_currentMedia[layer] = mediaFile; } + return; } else if (channel == VOLUME_COARSE || channel == VOLUME_FINE) { - m_mae.volChanged(layer, (value / 65025.0f)); -#ifndef NOGUI - if (m_ui) - m_lmsUi->m_aw->volChanged(layer, (value / 650.25f)); -#endif + float tmp = value / 65025.0f; + m_mae.volChanged(layer, tmp); + m_updateUi[layer][0] = tmp * 100; } else if (channel == PAN) { m_mae.panChanged(layer, value); -#ifndef NOGUI - if (m_ui) - m_lmsUi->m_aw->panChanged(layer, value); -#endif + m_updateUi[layer][1] = value; } else if (channel == PITCH) { m_mae.pitchChanged(layer, value); -#ifndef NOGUI - if (m_ui) - m_lmsUi->m_aw->pitchChanged(layer, value); -#endif + m_updateUi[layer][2] = value; } else if (channel == ENTRY_POINT_COARSE || channel == ENTRY_POINT_FINE) { m_mae.setCursor(layer, value); #ifndef NOGUI - if (m_ui) - m_lmsUi->m_aw->cursorChanged(layer, m_mae.getCursor(layer)); + m_lmsUi->m_aw->cursorChanged(layer, m_mae.getCursor(layer)); #endif - + return; } else if (channel == PLAYBACK && value > 0) { - Status s = m_mae.getStatus(layer); aux = value / 25; + Status s = m_currentStatus[layer]; if (s != aux) { if (aux == 0) s = Status::PlayingOnce; @@ -110,9 +108,9 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) else if (aux == 3) s = Status::PlayingLoop; m_mae.playbackChanged(layer, s); + m_currentStatus[layer] = s; #ifndef NOGUI - if (m_ui) - m_lmsUi->m_aw->playbackChanged(layer, s); + if (m_ui) m_lmsUi->m_aw->playbackChanged(layer, s); #endif } } @@ -120,13 +118,23 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) #ifndef NOGUI void libreMediaServerAudio::refreshUi() { - if (!m_ui) - return; + if (!m_ui) return; for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) { - Status s = m_mae.getStatus(i); + Status s = m_currentStatus[i]; if (s == Status::PlayingOnce || s == Status::PlayingLoop) { m_lmsUi->m_aw->cursorChanged(i, m_mae.getCursor(i)); - //m_lmsUi->m_aw->playbackChanged(i, s); + } + if (m_updateUi[i][0] >= 0) { + m_lmsUi->m_aw->volChanged(i, m_updateUi[i][0]); + m_updateUi[i][0] = -1; + } + if (m_updateUi[i][1] >= 0) { + m_lmsUi->m_aw->panChanged(i, m_updateUi[i][1]); + m_updateUi[i][1] = -1; + } + if (m_updateUi[i][2] >= 0) { + m_lmsUi->m_aw->pitchChanged(i, m_updateUi[i][2]); + m_updateUi[i][2] = -1; } } } diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index 6b80f97..9782d88 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -44,10 +44,12 @@ private: MediaLibrary *m_mediaLibrary; MiniAudioEngine m_mae; QString m_currentMedia[MAX_LAYERS]; + Status m_currentStatus[MAX_LAYERS]; #ifndef NOGUI bool m_ui; QTimer *m_refreshUi; libreMediaServerAudioUi *m_lmsUi; + int m_updateUi[MAX_LAYERS][3]; #endif private slots: diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 1f2c0b4..8dc38da 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -2,7 +2,9 @@ MiniAudioEngine::MiniAudioEngine() { - + for (int i =0; i < MAX_LAYERS; i++) { + m_mediaLoaded[i] = false; + } } void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) @@ -194,6 +196,7 @@ void MiniAudioEngine::volChanged(int layer, float vol) if (m_mediaLoaded[layer] == false) return; ma_sound_group_set_volume(&m_currentSound[layer], vol); + qDebug() << "vol: " << vol; } void MiniAudioEngine::panChanged(int layer, float value) @@ -255,7 +258,7 @@ void MiniAudioEngine::setCursor(int layer, int cursor) Status MiniAudioEngine::getStatus(int layer) { - if (m_mediaLoaded[layer] == ma_bool8(false)) + if (m_mediaLoaded[layer] == false) return Status::Iddle; if (ma_sound_is_playing(&m_currentSound[layer])) { if (ma_sound_is_looping(&m_currentSound[layer])) diff --git a/src/slidergroup.cpp b/src/slidergroup.cpp index e58588e..6120093 100644 --- a/src/slidergroup.cpp +++ b/src/slidergroup.cpp @@ -57,6 +57,11 @@ void SliderGroup::sliderValueChanged(int value) void SliderGroup::setValue(float value) { - slider->setValue(value); + slider->blockSignals(true); + valueBox->blockSignals(true); + if (int(value) != slider->value()) + slider->setValue(value); valueBox->setValue(value); + slider->blockSignals(false); + valueBox->blockSignals(false); } -- 2.39.5 From d34b972a549a315b40977766e8f000af375caa4c Mon Sep 17 00:00:00 2001 From: snt Date: Sun, 5 May 2024 17:36:20 +0200 Subject: [PATCH 19/49] mejor rendimiento --- src/audiolayerwidget.cpp | 14 +++++------ src/audiolayerwidget.h | 2 +- src/audiowidget.cpp | 2 +- src/defines.h | 2 +- src/libremediaserver-audio-gui.ui | 8 +++--- src/libremediaserver-audio.cpp | 42 ++++++++++++++----------------- src/libremediaserver-audio.h | 2 +- src/main.cpp | 1 - src/miniaudioengine.cpp | 3 ++- src/miniaudioengine.h | 1 + src/slidergroup.cpp | 18 +++++++------ 11 files changed, 47 insertions(+), 48 deletions(-) diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index ee112dd..563eeb9 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -51,7 +51,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_progressTime->setDisplayFormat("mm:ss:zz"); m_progressTime->setReadOnly(true); m_progressTime->setButtonSymbols(QAbstractSpinBox::NoButtons); - m_progressTime->setMaximumWidth(75); + m_progressTime->setMinimumWidth(80); m_progressTime->setFocusPolicy(Qt::NoFocus); m_progressTime->setAlignment(Qt::AlignHCenter); m_progressTime->setContentsMargins(0,0,0,0); @@ -61,7 +61,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_totalTimeValue->setDisplayFormat("mm:ss:zz"); m_totalTimeValue->setReadOnly(true); m_totalTimeValue->setButtonSymbols(QAbstractSpinBox::NoButtons); - m_totalTimeValue->setMaximumWidth(75); + m_totalTimeValue->setMinimumWidth(80); m_totalTimeValue->setFocusPolicy(Qt::NoFocus); m_totalTimeValue->setAlignment(Qt::AlignHCenter); m_totalTimeValue->setContentsMargins(0,0,0,0); @@ -119,8 +119,8 @@ void AudioLayerWidget::toggleSuspendResume() break; case Status::Paused: case Status::Stopped: - //this->setPlaybackStatus(Status::PlayingOnce); - emit uiPlaybackChanged(m_layer, Status::PlayingOnce); + this->setPlaybackStatus(Status::PlayingLoop); + emit uiPlaybackChanged(m_layer, Status::PlayingLoop); case Status::Iddle: break; } @@ -176,12 +176,12 @@ void AudioLayerWidget::fileLoaded(QString file) void AudioLayerWidget::setPlaybackStatus(Status status) { - if (StatusStr[status] == m_suspendResumeButton->text()) + if (!strcmp(StatusStr[status], m_suspendResumeButton->text().toLatin1().constData())) return; m_suspendResumeButton->blockSignals(true); m_status = status; if (status == Status::Stopped) - m_progress->setValue(0); + refreshCurrentTime(0); m_suspendResumeButton->setText(StatusStr[status]); m_suspendResumeButton->blockSignals(false); } @@ -200,7 +200,7 @@ void AudioLayerWidget::durationChanged(float dur) m_totalTimeValue->blockSignals(false); } -void AudioLayerWidget::refreshUi(float progress) +void AudioLayerWidget::refreshCurrentTime(float progress) { progress *= 1000; m_progress->blockSignals(true); diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index c0c6b3b..1c0ee83 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -46,7 +46,7 @@ public slots: void pitchChanged(int pitch); void fileLoaded(QString file); void durationChanged(float dur); - void refreshUi(float progress); + void refreshCurrentTime(float progress); private slots: void openMediaDialog(); diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index 47d7ce5..3d17c2d 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -49,5 +49,5 @@ void AudioWidget::cursorChanged(int layer, float cursor) { QLayoutItem * const item = m_layout->itemAt(layer); AudioLayerWidget *alw = dynamic_cast(item->widget()); - alw->refreshUi(cursor); + alw->refreshCurrentTime(cursor); } diff --git a/src/defines.h b/src/defines.h index a4eeea5..f8a2312 100644 --- a/src/defines.h +++ b/src/defines.h @@ -6,7 +6,7 @@ #define LICENSE "GPL 3 Licensed. See LICENSE.txt." #define DEFAULT_FILE "lms-audio.xlm" #define MAX_LAYERS 4 -#define UI_REFRESH_TIME 200 +#define UI_REFRESH_TIME 93 // struct where save the DMX settings for each layer struct dmxSetting { diff --git a/src/libremediaserver-audio-gui.ui b/src/libremediaserver-audio-gui.ui index 65c83c2..c0f11ad 100644 --- a/src/libremediaserver-audio-gui.ui +++ b/src/libremediaserver-audio-gui.ui @@ -2,13 +2,13 @@ Santi Noreña lms@criptomart.net LibreMediaServerAudio - + 0 0 - 800 - 800 + 500 + 400 @@ -32,7 +32,7 @@ 0 0 - 114 + 500 21 diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index d146e10..5eb65aa 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -40,16 +40,9 @@ libreMediaServerAudio::libreMediaServerAudio(bool gui) connect(m_ola, SIGNAL(dmxOutput(int, int, int)), this, SLOT(dmxInput(int, int, int))); m_ola->registerUniverse(); m_mae.startEngine(set->getAudioDeviceId()); - qDebug("Init Complete."); + qDebug("Core init Complete. Start reading DMX."); m_ola->blockSignals(false); m_ola->start(QThread::TimeCriticalPriority ); -#ifndef NOGUI - if (m_ui) { - m_refreshUi = new QTimer(this); - connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); - m_refreshUi->start(UI_REFRESH_TIME); - } -#endif } libreMediaServerAudio::~libreMediaServerAudio() @@ -73,7 +66,7 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) if (QFile::exists(mediaFile)){ m_mae.loadMedia(layer, mediaFile.toLatin1().data()); m_currentMedia[layer] = mediaFile; -#ifndef NOGIO +#ifndef NOGUI if (m_ui) m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); #endif @@ -82,7 +75,7 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) } else if (channel == VOLUME_COARSE || channel == VOLUME_FINE) { float tmp = value / 65025.0f; m_mae.volChanged(layer, tmp); - m_updateUi[layer][0] = tmp * 100; + m_updateUi[layer][0] = tmp * 100.0f; } else if (channel == PAN) { m_mae.panChanged(layer, value); m_updateUi[layer][1] = value; @@ -98,21 +91,19 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) } else if (channel == PLAYBACK && value > 0) { aux = value / 25; Status s = m_currentStatus[layer]; - if (s != aux) { - if (aux == 0) - s = Status::PlayingOnce; - else if (aux == 1) - s = Status::Stopped; - else if (aux == 2) - s = Status::Paused; - else if (aux == 3) - s = Status::PlayingLoop; - m_mae.playbackChanged(layer, s); - m_currentStatus[layer] = s; + if (aux == 0) + s = Status::PlayingOnce; + else if (aux == 1) + s = Status::Stopped; + else if (aux == 2) + s = Status::Paused; + else if (aux == 3) + s = Status::PlayingLoop; + m_mae.playbackChanged(layer, s); + m_currentStatus[layer] = s; #ifndef NOGUI - if (m_ui) m_lmsUi->m_aw->playbackChanged(layer, s); + if (m_ui) m_lmsUi->m_aw->playbackChanged(layer, s); #endif - } } } @@ -136,6 +127,7 @@ void libreMediaServerAudio::refreshUi() { m_lmsUi->m_aw->pitchChanged(i, m_updateUi[i][2]); m_updateUi[i][2] = -1; } + //m_lmsUi->m_aw->playbackChanged(i, m_currentStatus[i]); } } @@ -146,6 +138,9 @@ void libreMediaServerAudio::setUi(libreMediaServerAudioUi *lmsUi) connect(m_lmsUi->m_aw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SLOT(uiSliderChanged(int, Slider, int))); connect(m_lmsUi->m_aw, SIGNAL(uiPlaybackChanged(int, Status)), this, SLOT(uiPlaybackChanged(int, Status))); connect(m_lmsUi->m_aw, SIGNAL(uiLoadMedia(int, QString)), this, SLOT(uiLoadMedia(int, QString))); + m_refreshUi = new QTimer(this); + connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); + m_refreshUi->start(UI_REFRESH_TIME); }; void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value) @@ -166,6 +161,7 @@ void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value) void libreMediaServerAudio::uiPlaybackChanged(int layer, Status s) { m_mae.playbackChanged(layer, s); + m_currentStatus[layer] = s; } void libreMediaServerAudio::uiLoadMedia(int layer, QString s) diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index 9782d88..5e956ac 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -49,7 +49,7 @@ private: bool m_ui; QTimer *m_refreshUi; libreMediaServerAudioUi *m_lmsUi; - int m_updateUi[MAX_LAYERS][3]; + float m_updateUi[MAX_LAYERS][3]; #endif private slots: diff --git a/src/main.cpp b/src/main.cpp index 99643b0..eea3c29 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,7 +32,6 @@ bool hasUi(int &argc, char *argv[]) int main(int argc, char *argv[]) { QApplication app(argc, argv); - libreMediaServerAudio lms(hasUi(argc, argv)); #ifndef NOGUI if (hasUi(argc, argv)) diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 8dc38da..59345e9 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -195,8 +195,9 @@ void MiniAudioEngine::volChanged(int layer, float vol) { if (m_mediaLoaded[layer] == false) return; + if (vol > 1) + vol = 1; ma_sound_group_set_volume(&m_currentSound[layer], vol); - qDebug() << "vol: " << vol; } void MiniAudioEngine::panChanged(int layer, float value) diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 2bf224b..169d33b 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -27,6 +27,7 @@ protected: void setCursor(int layer, int cursor); ma_result printFormatInfo(int layer); Status getStatus(int layer); + inline float getVol(int layer) { return ma_sound_get_volume(&m_currentSound[layer]); } private: ma_resource_manager_config resourceManagerConfig; diff --git a/src/slidergroup.cpp b/src/slidergroup.cpp index 6120093..a488560 100644 --- a/src/slidergroup.cpp +++ b/src/slidergroup.cpp @@ -1,5 +1,5 @@ #include "slidergroup.h" - +#include SliderGroup::SliderGroup(QString name, int min, int max, @@ -15,22 +15,22 @@ SliderGroup::SliderGroup(QString name, slider->setFocusPolicy(Qt::StrongFocus); slider->setTickPosition(QSlider::TicksBothSides); slider->setTickInterval((max - min) / 11); - slider->setMinimumHeight(100); + slider->setMinimumHeight(0); slider->setSingleStep(1); slider->setRange(min, max); - //slider->setMaximumWidth(40); + slider->setMinimumWidth(50); slider->setToolTip(name); slider->setStyleSheet("QSlider {" - "border: 1px solid #999999;" + "border: 2px solid #685060;" "margin: 0px;" "height: 200px;" - "width: 40px;}" + "width: 50px;}" ); slider->setContentsMargins(0, 0, 0, 0); valueBox = new QDoubleSpinBox(); valueBox->setFocusPolicy(Qt::NoFocus); valueBox->setButtonSymbols(QAbstractSpinBox::NoButtons); - //valueBox->setMaximumWidth(40); + valueBox->setMinimumWidth(50); valueBox->setRange(min, max); valueBox->setDecimals(decimals); valueBox->setObjectName(name); @@ -40,8 +40,8 @@ SliderGroup::SliderGroup(QString name, connect(slider, SIGNAL(valueChanged(int)), this, SLOT(sliderValueChanged(int))); layout->addWidget(slider); layout->addWidget(valueBox); - this->setStyleSheet("border: 1px solid #999999;" - "width: 40px;" + this->setStyleSheet("border: 2px solid #685060;" + "width: 50px;" "margin: 0px;" ); layout->setSpacing(0); @@ -51,7 +51,9 @@ SliderGroup::SliderGroup(QString name, void SliderGroup::sliderValueChanged(int value) { + valueBox->blockSignals(true); valueBox->setValue(value); + valueBox->blockSignals(false); emit valueChanged(value); }; -- 2.39.5 From 5915d4898e9f85eef11a1a4cf183b44f0251d790 Mon Sep 17 00:00:00 2001 From: snt Date: Sun, 5 May 2024 21:44:21 +0200 Subject: [PATCH 20/49] =?UTF-8?q?cambida=20se=C3=B1al=20dmx=20por=20llamad?= =?UTF-8?q?a=20directa=20al=20m=C3=A9todo,=20reduce=20un=2020%=20de=20cpu?= =?UTF-8?q?=20en=20mi=20ordenador.=20Restringida=20actualizaci=C3=B3n=20de?= =?UTF-8?q?=20entry=20point=20como=20volumen,=20sigue=20cascando=20la=20b?= =?UTF-8?q?=C3=BAsqueda=20en=20mp3,=20wav=20va=20fino.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/audiolayerwidget.cpp | 2 +- src/libremediaserver-audio.cpp | 24 +++++++++++++----------- src/libremediaserver-audio.h | 9 +++++---- src/miniaudioengine.cpp | 7 ++++++- src/olathread.cpp | 21 +++++++++++---------- src/olathread.h | 19 +++++++++---------- 6 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 563eeb9..02da882 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -58,7 +58,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_totalTimeValue = new QTimeEdit; m_totalTimeValue->setObjectName("Track Length"); m_totalTimeValue->setToolTip("Track Length"); - m_totalTimeValue->setDisplayFormat("mm:ss:zz"); + m_totalTimeValue->setDisplayFormat("mm:ss:zzz"); m_totalTimeValue->setReadOnly(true); m_totalTimeValue->setButtonSymbols(QAbstractSpinBox::NoButtons); m_totalTimeValue->setMinimumWidth(80); diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 5eb65aa..589c190 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -29,10 +29,14 @@ libreMediaServerAudio::libreMediaServerAudio(bool gui) m_mediaLibrary = new MediaLibrary; m_mediaLibrary->initMediaLibrary(); for (int i = 0; i < MAX_LAYERS; i++) { - m_currentMedia[i] = Status::Iddle; + m_currentMedia[i] = ""; + m_currentStatus[i] = Status::Iddle; +#ifdef NOGUI m_updateUi[i][0] = -1; m_updateUi[i][1] = -1; m_updateUi[i][2] = -1; + m_updateUi[i][3] = -1; +#endif } m_ola = new olaThread(this, set->getLayersNumber()); Q_CHECK_PTR(m_ola); @@ -42,7 +46,9 @@ libreMediaServerAudio::libreMediaServerAudio(bool gui) m_mae.startEngine(set->getAudioDeviceId()); qDebug("Core init Complete. Start reading DMX."); m_ola->blockSignals(false); +#ifdef NOGUI m_ola->start(QThread::TimeCriticalPriority ); +#endif } libreMediaServerAudio::~libreMediaServerAudio() @@ -71,7 +77,6 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); #endif } - return; } else if (channel == VOLUME_COARSE || channel == VOLUME_FINE) { float tmp = value / 65025.0f; m_mae.volChanged(layer, tmp); @@ -84,10 +89,7 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) m_updateUi[layer][2] = value; } else if (channel == ENTRY_POINT_COARSE || channel == ENTRY_POINT_FINE) { m_mae.setCursor(layer, value); -#ifndef NOGUI - m_lmsUi->m_aw->cursorChanged(layer, m_mae.getCursor(layer)); -#endif - return; + m_updateUi[layer][3] = value; } else if (channel == PLAYBACK && value > 0) { aux = value / 25; Status s = m_currentStatus[layer]; @@ -111,10 +113,6 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) void libreMediaServerAudio::refreshUi() { if (!m_ui) return; for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) { - Status s = m_currentStatus[i]; - if (s == Status::PlayingOnce || s == Status::PlayingLoop) { - m_lmsUi->m_aw->cursorChanged(i, m_mae.getCursor(i)); - } if (m_updateUi[i][0] >= 0) { m_lmsUi->m_aw->volChanged(i, m_updateUi[i][0]); m_updateUi[i][0] = -1; @@ -127,7 +125,10 @@ void libreMediaServerAudio::refreshUi() { m_lmsUi->m_aw->pitchChanged(i, m_updateUi[i][2]); m_updateUi[i][2] = -1; } - //m_lmsUi->m_aw->playbackChanged(i, m_currentStatus[i]); + if (m_updateUi[i][3] >= 0) { + m_lmsUi->m_aw->cursorChanged(i, m_mae.getCursor(i)); + m_updateUi[i][3] = -1; + } } } @@ -141,6 +142,7 @@ void libreMediaServerAudio::setUi(libreMediaServerAudioUi *lmsUi) m_refreshUi = new QTimer(this); connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); m_refreshUi->start(UI_REFRESH_TIME); + m_ola->start(QThread::TimeCriticalPriority ); }; void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value) diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index 5e956ac..665f3e2 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -35,25 +35,26 @@ class libreMediaServerAudio : public QObject public: libreMediaServerAudio(bool gui = false); virtual ~libreMediaServerAudio(); - olaThread *m_ola; + void dmxInput(int layer, int channel, int value); #ifndef NOGUI void setUi(libreMediaServerAudioUi *lmsUi); #endif - + //static void NewDmx(const ola::client::DMXMetadata &data, const ola::DmxBuffer &buffer); private: + olaThread *m_ola; MediaLibrary *m_mediaLibrary; MiniAudioEngine m_mae; QString m_currentMedia[MAX_LAYERS]; Status m_currentStatus[MAX_LAYERS]; + static QList m_dmxSettings; #ifndef NOGUI bool m_ui; QTimer *m_refreshUi; libreMediaServerAudioUi *m_lmsUi; - float m_updateUi[MAX_LAYERS][3]; + float m_updateUi[MAX_LAYERS][4]; #endif private slots: - void dmxInput(int layer, int channel, int value); #ifndef NOGUI void refreshUi(); void uiSliderChanged(int layer, Slider s, int value); diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 59345e9..f65744d 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -114,9 +114,11 @@ ma_result MiniAudioEngine::getAllAudioDevices() ma_result MiniAudioEngine::loadMedia(int layer, char *file) { ma_result result; + float vol = -1; if (m_mediaLoaded[layer] == true) { + vol = ma_sound_get_volume(&m_currentSound[layer]); ma_sound_uninit(&m_currentSound[layer]); m_mediaLoaded[layer] = false; } @@ -131,7 +133,10 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file) qWarning("Failed to load file %s", file); else { m_mediaLoaded[layer] = true; - this->volChanged(layer, 0); + if (vol == -1) + this->volChanged(layer, 0); + else + this->volChanged(layer, vol); } return result; } diff --git a/src/olathread.cpp b/src/olathread.cpp index 471775c..409cf79 100644 --- a/src/olathread.cpp +++ b/src/olathread.cpp @@ -1,11 +1,11 @@ -#include "olathread.h" - +#include "libremediaserver-audio.h" +//#include "olathread.h" olaThread::olaThread(QObject *parent, int layers) : m_counter(0) , m_layers(layers) { - Q_UNUSED(parent); + this->setParent(parent); gettimeofday(&m_last_data, NULL); for (int i=0; i < MAX_LAYERS; i++) { @@ -36,6 +36,7 @@ void olaThread::init() } m_client = m_clientWrapper->GetClient(); m_client->SetDMXCallback(ola::NewCallback(this, &olaThread::NewDmx)); + //m_client->SetDMXCallback(ola::NewCallback((libreMediaServerAudio *)this->parent(), libreMediaServerAudio::NewDmx)); m_clientWrapper->GetSelectServer()->RegisterRepeatingTimeout(4000, ola::NewCallback(this, &olaThread::CheckDataLoss)); m_client->SetCloseHandler(ola::NewSingleCallback(this, &olaThread::socketClosed)); m_dmxSettings = Settings::getInstance()->getDmxSettings(); @@ -76,7 +77,7 @@ void olaThread::NewDmx(const ola::client::DMXMetadata &data, case DMX_FOLDER: value *= 0x100; value += buffer.Get(i.address + DMX_FILE); - emit dmxOutput(i.layer,j,value); + qobject_cast(parent())->dmxInput(i.layer, j, value); m_dmx[i.layer][DMX_FILE] = buffer.Get(i.address + DMX_FILE); fileSent = true; break; @@ -84,13 +85,13 @@ void olaThread::NewDmx(const ola::client::DMXMetadata &data, if (fileSent) break; value += buffer.Get(i.address + DMX_FOLDER) * 0x100; - emit dmxOutput(i.layer,j,value); + qobject_cast(parent())->dmxInput(i.layer, j, value); m_dmx[i.layer][DMX_FOLDER] = buffer.Get(i.address + DMX_FOLDER); fileSent = true; break; case VOLUME_FINE: value = (buffer.Get(i.address + VOLUME_COARSE) * 0x100) + value; - emit dmxOutput(i.layer,j,value); + qobject_cast(parent())->dmxInput(i.layer, j, value); m_dmx[i.layer][VOLUME_COARSE] = buffer.Get(i.address + VOLUME_COARSE); volSent = true; break; @@ -98,13 +99,13 @@ void olaThread::NewDmx(const ola::client::DMXMetadata &data, if (volSent) break; value = (value * 0x100) + buffer.Get(i.address + VOLUME_FINE); - emit dmxOutput(i.layer,j,value); + qobject_cast(parent())->dmxInput(i.layer, j, value); m_dmx[i.layer][VOLUME_FINE] = buffer.Get(i.address + VOLUME_FINE); volSent = true; break; case ENTRY_POINT_FINE: value = (buffer.Get(i.address + ENTRY_POINT_COARSE) * 0x100) + value; - emit dmxOutput(i.layer,j,value); + qobject_cast(parent())->dmxInput(i.layer, j, value); m_dmx[i.layer][ENTRY_POINT_COARSE] = buffer.Get(i.address + ENTRY_POINT_COARSE); entrySent = true; break; @@ -112,12 +113,12 @@ void olaThread::NewDmx(const ola::client::DMXMetadata &data, if (entrySent) break; value = (value * 0x100) + buffer.Get(i.address + ENTRY_POINT_FINE); - emit dmxOutput(i.layer,j,value); + qobject_cast(parent())->dmxInput(i.layer, j, value); m_dmx[i.layer][ENTRY_POINT_FINE] = buffer.Get(i.address + ENTRY_POINT_FINE); entrySent = true; break; default: - emit dmxOutput(i.layer,j,value); + qobject_cast(parent())->dmxInput(i.layer, j, value); break; } } diff --git a/src/olathread.h b/src/olathread.h index dcae35b..ed2735a 100644 --- a/src/olathread.h +++ b/src/olathread.h @@ -20,10 +20,17 @@ class olaThread : public QThread Q_OBJECT public: + QList m_dmxSettings; + int m_dmx[MAX_LAYERS][LAYER_CHANNELS]; + ola::client::OlaClientWrapper *m_clientWrapper; + ola::client::OlaClient *m_client; + unsigned int m_counter; + struct timeval m_last_data; // Last DMX frame received + int m_layers; olaThread(QObject *parent = 0, int layers = 0); virtual ~olaThread(); - + void run (); /** Retorna el valor de un canal *@param int layer the layer for we want the channel *@param int channel the channel for the value wanted @@ -35,14 +42,6 @@ public: void resendDmx(); private: - void run (); - ola::client::OlaClientWrapper *m_clientWrapper; - ola::client::OlaClient *m_client; - unsigned int m_counter; - struct timeval m_last_data; // Last DMX frame received - int m_layers; - int m_dmx[MAX_LAYERS][LAYER_CHANNELS]; - QList m_dmxSettings; /** * @brief Callback from ola. Control de errores en el registro de Universos en OLA * typedef SingleUseCallback1 ola::client::SetCallback @@ -67,7 +66,7 @@ private: * This is called one for second if there is not updated in the DMX frame. * emit only the channels that has been changed. */ - void NewDmx(const ola::client::DMXMetadata &dmx_meta, const ola::DmxBuffer &buffer); // + void NewDmx(const ola::client::DMXMetadata &dmx_meta, const ola::DmxBuffer &buffer); /** * @brief Sometimes the ola server closes the connection. This is a callback to handle this event an reconect to ola */ -- 2.39.5 From 7a9c0cd0ac3d1fd32a47e1779ce053f810b01baf Mon Sep 17 00:00:00 2001 From: snt Date: Tue, 7 May 2024 20:23:09 +0200 Subject: [PATCH 21/49] =?UTF-8?q?libreMediaServer=20no=20refresca=20direct?= =?UTF-8?q?amente=20la=20ui,=20solo=20actualiza=20valores=20en=20=20audiow?= =?UTF-8?q?idget.=20la=20ui=20se=20actualiza=20con=20un=20timer=20en=20aud?= =?UTF-8?q?iowidget.=20Quitadas=20se=C3=B1ales=20en=20todo,=20mejora=20ren?= =?UTF-8?q?dimiento.=20fade=20en=20volumen=20basado=20en=20la=20trama=20dm?= =?UTF-8?q?x=20(25=20ms)=20para=20evitar=20clicks.=20refresca=20los=20valo?= =?UTF-8?q?res=20de=20la=20capa=20cuando=20carga=20un=20media.=20Ui=20Ok.?= =?UTF-8?q?=20nuevo=20formato=20de=20archivo=20de=20configuraci=C3=B3n=20x?= =?UTF-8?q?ml.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/changelog.txt | 2 + docs/lms-audio.xlm | 14 +++--- docs/roadmap.txt | 8 +++- src/audiolayerwidget.cpp | 18 ++++---- src/audiolayerwidget.h | 25 +++++------ src/audiowidget.cpp | 70 +++++++++++++++++++++++------- src/audiowidget.h | 15 +++++-- src/defines.h | 17 ++++++-- src/dmxPersonality.h | 1 - src/libremediaserver-audio-gui.cpp | 2 +- src/libremediaserver-audio.cpp | 67 ++++++++++++++++------------ src/libremediaserver-audio.h | 15 ++++--- src/main.cpp | 4 +- src/miniaudioengine.cpp | 65 +++++++++++++++------------ src/miniaudioengine.h | 2 + src/olathread.cpp | 24 +++++----- src/settings.cpp | 49 +++++++++++---------- src/settings.h | 15 ++++--- src/slidergroup.cpp | 16 ++++++- src/slidergroup.h | 2 + 20 files changed, 271 insertions(+), 160 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 22a7e1f..a69017b 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -27,6 +27,8 @@ v 0.2.0 Antígona (24/04/2024) + Compilation without GUI (-DNOGUI). + 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). v 0.1.3 Leúcade (19/04/2024) diff --git a/docs/lms-audio.xlm b/docs/lms-audio.xlm index cc498ca..4274267 100644 --- a/docs/lms-audio.xlm +++ b/docs/lms-audio.xlm @@ -1,8 +1,8 @@ - - - - - - - + + + + + + + diff --git a/docs/roadmap.txt b/docs/roadmap.txt index 894c32c..bd98089 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -45,9 +45,13 @@ v 0.2.1 - Ui/Ux: Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante. - Logs, verbosity, timestamp. - New play mode without pitch control, it saves resources. MA_SOUND_FLAG_NO_PITCH -- Vumeter or indicator about audio output in layer and master. +- Vumeter or indicator about audio output in layer and master, add to sliderGroup. +- QSlider can not accept floats and it can no manage high frequency updates. - SettingsDialog. - Load/save conf file. - ¿Exit Point? is it needed? -- Hardening: check return errors, catch execptions, i'm too happy.... +- Hardening: check return errors, try/catch exceptions, i'm too happy.... - Tests: errors on wrong conf file. +- BUGFIX: there are some small clicks when changing volume and play/stop/pause. vol 24 bits? microfades in engine? setVol 0 before changing playback state? +- refactorize dmxInput: loadMedia, changePlayBack, +- BUGFIX: in nogui mode we need more info print at terminal (load media, change playback status). diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 02da882..a22b2cc 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -52,6 +52,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_progressTime->setReadOnly(true); m_progressTime->setButtonSymbols(QAbstractSpinBox::NoButtons); m_progressTime->setMinimumWidth(80); + m_progressTime->setMaximumWidth(80); m_progressTime->setFocusPolicy(Qt::NoFocus); m_progressTime->setAlignment(Qt::AlignHCenter); m_progressTime->setContentsMargins(0,0,0,0); @@ -138,7 +139,7 @@ void AudioLayerWidget::openMediaDialog() QStringList fileNames; fileNames = dialog.selectedFiles(); emit uiLoadMedia(m_layer, fileNames.at(0)); - this->fileLoaded(fileNames.at(0)); + this->setMediaFile(fileNames.at(0)); } // from DMX signals @@ -163,7 +164,7 @@ void AudioLayerWidget::setPitch(int pitch) m_pitch->blockSignals(false); } -void AudioLayerWidget::fileLoaded(QString file) +void AudioLayerWidget::setMediaFile(QString file) { QStringList list = file.split("/"); int size = list.size(); @@ -174,19 +175,18 @@ void AudioLayerWidget::fileLoaded(QString file) this->setPlaybackStatus(Status::Stopped); } -void AudioLayerWidget::setPlaybackStatus(Status status) +void AudioLayerWidget::setPlaybackStatus(Status s) { - if (!strcmp(StatusStr[status], m_suspendResumeButton->text().toLatin1().constData())) - return; + Status status = static_cast(s); m_suspendResumeButton->blockSignals(true); m_status = status; - if (status == Status::Stopped) - refreshCurrentTime(0); + //if (status == Status::Stopped) + // refreshCurrentTime(0); m_suspendResumeButton->setText(StatusStr[status]); m_suspendResumeButton->blockSignals(false); } -void AudioLayerWidget::durationChanged(float dur) +void AudioLayerWidget::setDuration(float dur) { m_progress->blockSignals(true); m_progressTime->blockSignals(true); @@ -200,7 +200,7 @@ void AudioLayerWidget::durationChanged(float dur) m_totalTimeValue->blockSignals(false); } -void AudioLayerWidget::refreshCurrentTime(float progress) +void AudioLayerWidget::setCurrentTime(float progress) { progress *= 1000; m_progress->blockSignals(true); diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index 1c0ee83..9380b81 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -18,13 +18,6 @@ class AudioLayerWidget : public QWidget public: explicit AudioLayerWidget(QWidget *parent = 0, int layer = 0); ~AudioLayerWidget(); - void setVol(float vol); - void resume(); - void setPan(int pan); - void setPitch(int pitch); - void setLoop(bool on); - void setPlaybackStatus(Status status); - inline Status getPlaybackStatus() { return m_status; } private: Status m_status; @@ -39,17 +32,23 @@ private: QTimeEdit *m_totalTimeValue; QProgressBar *m_progress; +// From DMX public slots: + void setMediaFile(QString file); + void setDuration(float dur); + void setCurrentTime(float progress); + void setPlaybackStatus(Status status); + void setVol(float vol); + void setPan(int pan); + void setPitch(int pitch); + +// From Ui +private slots: + void openMediaDialog(); void toggleSuspendResume(); void volumeChanged(int vol); void panChanged(int pan); void pitchChanged(int pitch); - void fileLoaded(QString file); - void durationChanged(float dur); - void refreshCurrentTime(float progress); - -private slots: - void openMediaDialog(); signals: void uiPlaybackChanged(int layer, Status s); diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index 3d17c2d..ca2633a 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -1,5 +1,5 @@ #include "audiowidget.h" - +#include AudioWidget::AudioWidget(QWidget *parent) : QWidget(parent) @@ -15,39 +15,79 @@ AudioWidget::AudioWidget(QWidget *parent) : m_layout->setSpacing(0); m_layout->setContentsMargins(1, 1, 1, 1); setLayout(m_layout); + m_refreshUi = new QTimer(this); + connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); + m_refreshUi->start(UI_REFRESH_TIME * 2); } void AudioWidget::mediaLoaded(int layer, QString file, float duration) { - QLayoutItem * const item = m_layout->itemAt(layer); - dynamic_cast(item->widget())->fileLoaded(file); - dynamic_cast(item->widget())->durationChanged(duration); + m_layerUpdate[layer].media = file; + m_layerUpdate[layer].duration = duration; + m_layerUpdate[layer].updated = true; } void AudioWidget::volChanged(int layer, float vol) { - QLayoutItem * const item = m_layout->itemAt(layer); - dynamic_cast(item->widget())->setVol(vol); + m_layerUpdate[layer].vol = vol; + m_layerUpdate[layer].updated = true; } void AudioWidget::panChanged(int layer, int pan) { - QLayoutItem * const item = m_layout->itemAt(layer); - dynamic_cast(item->widget())->setPan(pan); + m_layerUpdate[layer].pan = pan; + m_layerUpdate[layer].updated = true; } void AudioWidget::pitchChanged(int layer, int pitch) { - QLayoutItem * const item = m_layout->itemAt(layer); - dynamic_cast(item->widget())->setPitch(pitch); + + m_layerUpdate[layer].pitch = pitch; + m_layerUpdate[layer].updated = true; } void AudioWidget::playbackChanged(int layer, Status status) { - QLayoutItem * const item = m_layout->itemAt(layer); - dynamic_cast(item->widget())->setPlaybackStatus(status); + m_layerUpdate[layer].status = status; + m_layerUpdate[layer].updated = true; } void AudioWidget::cursorChanged(int layer, float cursor) { - QLayoutItem * const item = m_layout->itemAt(layer); - AudioLayerWidget *alw = dynamic_cast(item->widget()); - alw->refreshCurrentTime(cursor); + m_layerUpdate[layer].cursor = floor(cursor * 1000) / 1000; + m_layerUpdate[layer].updated = true; +} + +void AudioWidget::refreshUi() +{ + for (int i = 0; i < MAX_LAYERS; i++) + { + if (m_layerUpdate[i].updated) { + QLayoutItem * const item = m_layout->itemAt(i); + AudioLayerWidget *alw = dynamic_cast(item->widget()); + if (m_layerUpdate[i].vol > -1) { + alw->setVol(m_layerUpdate[i].vol); + m_layerUpdate[i].vol = -1; + } + if (m_layerUpdate[i].cursor > -1) { + alw->setCurrentTime(m_layerUpdate[i].cursor); + m_layerUpdate[i].cursor = -1; + } + if (m_layerUpdate[i].pan > -1) { + alw->setPan(m_layerUpdate[i].pan); + m_layerUpdate[i].pan = -1; + } + if (m_layerUpdate[i].pitch > -1) { + alw->setPitch(m_layerUpdate[i].pitch); + m_layerUpdate[i].pitch = -1; + } + if (m_layerUpdate[i].status != Status::Iddle) { + alw->setPlaybackStatus(m_layerUpdate[i].status); + m_layerUpdate[i].status = Status::Iddle; + } + if (m_layerUpdate[i].duration > -1) { + alw->setMediaFile(m_layerUpdate[i].media); + alw->setDuration(m_layerUpdate[i].duration); + m_layerUpdate[i].duration = -1; + } + m_layerUpdate[i].updated = false; + } + } } diff --git a/src/audiowidget.h b/src/audiowidget.h index a293a0a..dd9b1f1 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -5,7 +5,6 @@ #include "audiolayerwidget.h" #include "settings.h" -#include "miniaudioengine.h" #include "defines.h" // MAX_LAYERS class AudioWidget : public QWidget @@ -14,14 +13,22 @@ class AudioWidget : public QWidget public: AudioWidget(QWidget *parent = nullptr); - void mediaLoaded(int layer, QString media, float duration); + +private: + QHBoxLayout *m_layout; + layerData m_layerUpdate[MAX_LAYERS]; + QTimer *m_refreshUi; + +public slots: void volChanged(int layer, float vol); void panChanged(int layer, int pan); void pitchChanged(int layer, int pitch); - void playbackChanged(int layer, Status status); void cursorChanged(int layer, float cursor); - QHBoxLayout *m_layout; + void mediaLoaded(int layer, QString media, float duration); + void playbackChanged(int layer, Status status); +private slots: + void refreshUi(); signals: void uiPlaybackChanged(int layer, Status s); void uiSliderChanged(int layer, Slider s, int vol); diff --git a/src/defines.h b/src/defines.h index f8a2312..6552d19 100644 --- a/src/defines.h +++ b/src/defines.h @@ -6,9 +6,10 @@ #define LICENSE "GPL 3 Licensed. See LICENSE.txt." #define DEFAULT_FILE "lms-audio.xlm" #define MAX_LAYERS 4 -#define UI_REFRESH_TIME 93 +#define MAX_AUDIODEVICES 8 +#define UI_REFRESH_TIME 77 +#define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks -// struct where save the DMX settings for each layer struct dmxSetting { int address; unsigned int universe; @@ -41,5 +42,15 @@ enum Slider Pitch, }; +#include +struct layerData { + QString media; + Status status; + bool updated; + float vol; + float cursor; + int pan; + int pitch; + float duration; +}; #endif // DEFINES_H - diff --git a/src/dmxPersonality.h b/src/dmxPersonality.h index c56829e..82f9468 100644 --- a/src/dmxPersonality.h +++ b/src/dmxPersonality.h @@ -10,7 +10,6 @@ #define ENTRY_POINT_COARSE 5 #define ENTRY_POINT_FINE 4 #define PITCH 7 - #define LAYER_CHANNELS 9 #endif // DMXPERSONALITY_H diff --git a/src/libremediaserver-audio-gui.cpp b/src/libremediaserver-audio-gui.cpp index 2d92918..b769679 100644 --- a/src/libremediaserver-audio-gui.cpp +++ b/src/libremediaserver-audio-gui.cpp @@ -38,7 +38,7 @@ libreMediaServerAudioUi::libreMediaServerAudioUi(QWidget *parent) this->setContentsMargins(5, 5, 5, 5); this->setStyleSheet( "color: white;" - "background-color: gray;" + "background-color: #4f4048;" "selection-color: blue;" "selection-background-color: green" ); diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 589c190..cb18dc2 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -21,11 +21,11 @@ #include "libremediaserver-audio.h" -libreMediaServerAudio::libreMediaServerAudio(bool gui) +libreMediaServerAudio::libreMediaServerAudio() { - m_ui = gui; - Settings *set = Settings::getInstance(); - set->readFile(); + m_settings = Settings::getInstance(); + m_settings->readFile(); + m_ui = m_settings->getShowUi(); m_mediaLibrary = new MediaLibrary; m_mediaLibrary->initMediaLibrary(); for (int i = 0; i < MAX_LAYERS; i++) { @@ -38,12 +38,11 @@ libreMediaServerAudio::libreMediaServerAudio(bool gui) m_updateUi[i][3] = -1; #endif } - m_ola = new olaThread(this, set->getLayersNumber()); + m_ola = new olaThread(this, m_settings->getLayersNumber()); Q_CHECK_PTR(m_ola); m_ola->blockSignals(true); - connect(m_ola, SIGNAL(dmxOutput(int, int, int)), this, SLOT(dmxInput(int, int, int))); m_ola->registerUniverse(); - m_mae.startEngine(set->getAudioDeviceId()); + m_mae.startEngine(m_settings->getAudioDeviceId()); qDebug("Core init Complete. Start reading DMX."); m_ola->blockSignals(false); #ifdef NOGUI @@ -57,27 +56,29 @@ libreMediaServerAudio::~libreMediaServerAudio() m_mae.stopEngine(); } +void libreMediaServerAudio::loadMedia(int layer, int folder, int file) +{ + QString mediaFile = m_mediaLibrary->requestNewFile(folder, 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_currentMedia[layer] = mediaFile; +#ifndef NOGUI + if (m_ui) + m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); +#endif + m_mae.printFormatInfo(layer); + } +} + void libreMediaServerAudio::dmxInput(int layer, int channel, int value) { if (layer >= MAX_LAYERS || channel >= LAYER_CHANNELS) return; QString mediaFile = NULL; int aux; - if (channel == DMX_FOLDER || channel == DMX_FILE){ - int folder = (value >> 8) & 0x000000FF; - int file = value & 0x000000FF; - mediaFile = m_mediaLibrary->requestNewFile(folder, 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_currentMedia[layer] = mediaFile; -#ifndef NOGUI - if (m_ui) - m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); -#endif - } - } else if (channel == VOLUME_COARSE || channel == VOLUME_FINE) { + if (channel == VOLUME_COARSE || channel == VOLUME_FINE) { float tmp = value / 65025.0f; m_mae.volChanged(layer, tmp); m_updateUi[layer][0] = tmp * 100.0f; @@ -104,15 +105,17 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) m_mae.playbackChanged(layer, s); m_currentStatus[layer] = s; #ifndef NOGUI - if (m_ui) m_lmsUi->m_aw->playbackChanged(layer, s); + if (m_ui) { + m_lmsUi->m_aw->playbackChanged(layer, s); + m_lmsUi->m_aw->cursorChanged(layer, m_mae.getCursor(layer)); + } #endif } } - #ifndef NOGUI void libreMediaServerAudio::refreshUi() { if (!m_ui) return; - for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) { + for (int i= 0; i < m_settings->getLayersNumber(); i++ ) { if (m_updateUi[i][0] >= 0) { m_lmsUi->m_aw->volChanged(i, m_updateUi[i][0]); m_updateUi[i][0] = -1; @@ -125,7 +128,9 @@ void libreMediaServerAudio::refreshUi() { m_lmsUi->m_aw->pitchChanged(i, m_updateUi[i][2]); m_updateUi[i][2] = -1; } - if (m_updateUi[i][3] >= 0) { + if (m_updateUi[i][3] >= 0 \ + || m_currentStatus[i] == Status::PlayingOnce\ + || m_currentStatus[i] == Status::PlayingLoop) { m_lmsUi->m_aw->cursorChanged(i, m_mae.getCursor(i)); m_updateUi[i][3] = -1; } @@ -135,6 +140,7 @@ void libreMediaServerAudio::refreshUi() { void libreMediaServerAudio::setUi(libreMediaServerAudioUi *lmsUi) { m_lmsUi = lmsUi; + m_ui = true; connect(m_ola, SIGNAL(universeReceived(int)), m_lmsUi->m_dmxWidget, SLOT(updateWatchDMX(int))); connect(m_lmsUi->m_aw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SLOT(uiSliderChanged(int, Slider, int))); connect(m_lmsUi->m_aw, SIGNAL(uiPlaybackChanged(int, Status)), this, SLOT(uiPlaybackChanged(int, Status))); @@ -145,6 +151,7 @@ void libreMediaServerAudio::setUi(libreMediaServerAudioUi *lmsUi) m_ola->start(QThread::TimeCriticalPriority ); }; +// From Ui widgets void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value) { switch (s){ @@ -166,8 +173,12 @@ void libreMediaServerAudio::uiPlaybackChanged(int layer, Status s) m_currentStatus[layer] = s; } -void libreMediaServerAudio::uiLoadMedia(int layer, QString s) +void libreMediaServerAudio::uiLoadMedia(int layer, QString mediaFile) { - m_mae.loadMedia(layer, s.toLatin1().data()); + if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0) + return; + m_mae.loadMedia(layer, mediaFile.toLatin1().data()); + m_currentMedia[layer] = mediaFile; + m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); } #endif diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index 665f3e2..1af37df 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -21,6 +21,7 @@ #define LIBREMEDIASERVERAUDIO_H #include "medialibrary.h" +#include "miniaudioengine.h" #include "olathread.h" #include "settings.h" #include "defines.h" @@ -33,33 +34,35 @@ class libreMediaServerAudio : public QObject Q_OBJECT public: - libreMediaServerAudio(bool gui = false); + libreMediaServerAudio(); virtual ~libreMediaServerAudio(); void dmxInput(int layer, int channel, int value); + void loadMedia(int layer, int folder, int file); #ifndef NOGUI void setUi(libreMediaServerAudioUi *lmsUi); + bool inline getShowUi() { return m_settings->getShowUi(); } #endif - //static void NewDmx(const ola::client::DMXMetadata &data, const ola::DmxBuffer &buffer); + private: olaThread *m_ola; MediaLibrary *m_mediaLibrary; MiniAudioEngine m_mae; + Settings *m_settings; QString m_currentMedia[MAX_LAYERS]; Status m_currentStatus[MAX_LAYERS]; - static QList m_dmxSettings; -#ifndef NOGUI + QList m_dmxSettings; bool m_ui; +#ifndef NOGUI QTimer *m_refreshUi; libreMediaServerAudioUi *m_lmsUi; float m_updateUi[MAX_LAYERS][4]; -#endif private slots: -#ifndef NOGUI void refreshUi(); void uiSliderChanged(int layer, Slider s, int value); void uiPlaybackChanged(int layer, Status s); void uiLoadMedia(int layer, QString s); + #endif }; diff --git a/src/main.cpp b/src/main.cpp index eea3c29..79b7a91 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,9 +32,9 @@ bool hasUi(int &argc, char *argv[]) int main(int argc, char *argv[]) { QApplication app(argc, argv); - libreMediaServerAudio lms(hasUi(argc, argv)); + libreMediaServerAudio lms; #ifndef NOGUI - if (hasUi(argc, argv)) + if (hasUi(argc, argv) || lms.getShowUi()) { libreMediaServerAudioUi *lmsUi = new libreMediaServerAudioUi(); lms.setUi(lmsUi); diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index f65744d..c2d9a6d 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -4,6 +4,11 @@ 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; } } @@ -79,8 +84,8 @@ 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 = 0; - resourceManagerConfig.jobThreadCount = 0; + resourceManagerConfig.decodedSampleRate = ma_standard_sample_rate_48000; + resourceManagerConfig.jobThreadCount = 1; result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager); if (result != MA_SUCCESS) { qCritical("Failed to initialize audio resource manager."); @@ -114,11 +119,9 @@ ma_result MiniAudioEngine::getAllAudioDevices() ma_result MiniAudioEngine::loadMedia(int layer, char *file) { ma_result result; - float vol = -1; if (m_mediaLoaded[layer] == true) { - vol = ma_sound_get_volume(&m_currentSound[layer]); ma_sound_uninit(&m_currentSound[layer]); m_mediaLoaded[layer] = false; } @@ -133,10 +136,8 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file) qWarning("Failed to load file %s", file); else { m_mediaLoaded[layer] = true; - if (vol == -1) - this->volChanged(layer, 0); - else - this->volChanged(layer, vol); + this->refreshValues(layer); + m_currentLayerValues[layer].media = file; } return result; } @@ -191,7 +192,7 @@ ma_result MiniAudioEngine::printFormatInfo(int layer) qWarning("Failed to get data format %i\n", layer); return MA_INVALID_DATA; } - qInfo("samples/sec: %u format: %u channels: %u", sampleRate, format, channels); + qInfo() << "name:" << m_currentLayerValues[layer].media << "samples/sec:" << sampleRate << "format:" << format << "channels:" << channels; return result; } @@ -200,9 +201,10 @@ void MiniAudioEngine::volChanged(int layer, float vol) { if (m_mediaLoaded[layer] == false) return; - if (vol > 1) - vol = 1; - ma_sound_group_set_volume(&m_currentSound[layer], vol); + if (vol >= 1) + vol = 0.99f; + ma_sound_group_set_fade_in_milliseconds(&m_currentSound[layer], -1, vol, FADE_TIME); + m_currentLayerValues[layer].vol = vol; } void MiniAudioEngine::panChanged(int layer, float value) @@ -213,6 +215,7 @@ void MiniAudioEngine::panChanged(int layer, float value) return; result = (value / 128.0) - 1.0; ma_sound_group_set_pan(&m_currentSound[layer], result); + m_currentLayerValues[layer].pan = value; } void MiniAudioEngine::pitchChanged(int layer, float value) @@ -223,6 +226,7 @@ void MiniAudioEngine::pitchChanged(int layer, float value) return; result = value / 128.0; ma_sound_group_set_pitch(&m_currentSound[layer], result); + m_currentLayerValues[layer].pitch = value; } void MiniAudioEngine::playbackChanged(int layer, Status status) @@ -235,7 +239,7 @@ void MiniAudioEngine::playbackChanged(int layer, Status status) break; case Status::Stopped: ma_sound_stop(&m_currentSound[layer]); - ma_sound_seek_to_pcm_frame(&m_currentSound[layer], 0); + this->setCursor(layer, m_currentLayerValues[layer].cursor); break; case Status::PlayingLoop: ma_sound_set_looping(&m_currentSound[layer], true); @@ -248,30 +252,35 @@ void MiniAudioEngine::playbackChanged(int layer, Status status) default: break; } + m_currentLayerValues[layer].status = status; } void MiniAudioEngine::setCursor(int layer, int cursor) { - ma_uint64 f; + ma_uint64 end; + m_currentLayerValues[layer].cursor = cursor; if (m_mediaLoaded[layer] == false) return; - ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &f); - f = (cursor * f) / 65025; - ma_sound_seek_to_pcm_frame(&m_currentSound[layer], f); - // ToDo: change the loop entry point too + ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &end); + ma_uint64 start = (cursor * end) / 65025; + ma_sound_seek_to_pcm_frame(&m_currentSound[layer], start); + ma_result result = ma_data_source_set_loop_point_in_pcm_frames(&m_currentSound[layer], start, end); + if (result != MA_SUCCESS) { + return; // Failed to set the loop point. + } } Status MiniAudioEngine::getStatus(int layer) { - if (m_mediaLoaded[layer] == false) - return Status::Iddle; - if (ma_sound_is_playing(&m_currentSound[layer])) { - if (ma_sound_is_looping(&m_currentSound[layer])) - return Status::PlayingLoop; - return Status::PlayingOnce; - } - if (this->getDuration(layer) > 0) - return Status::Paused; - return Status::Stopped; + return m_currentLayerValues[layer].status; +} + +void MiniAudioEngine::refreshValues(int layer) +{ + this->panChanged(layer, m_currentLayerValues[layer].pan); + this->volChanged(layer, m_currentLayerValues[layer].vol); + this->pitchChanged(layer, m_currentLayerValues[layer].pitch); + this->playbackChanged(layer, m_currentLayerValues[layer].status); + this->setCursor(layer, m_currentLayerValues[layer].cursor); } diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 169d33b..2c3ec5a 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -40,10 +40,12 @@ private: 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(int id); ma_result startContext(); + void refreshValues(int layer); }; #endif // MINIAUDIOENGINE_H diff --git a/src/olathread.cpp b/src/olathread.cpp index 409cf79..6ca9325 100644 --- a/src/olathread.cpp +++ b/src/olathread.cpp @@ -1,5 +1,4 @@ #include "libremediaserver-audio.h" -//#include "olathread.h" olaThread::olaThread(QObject *parent, int layers) : m_counter(0) @@ -36,7 +35,6 @@ void olaThread::init() } m_client = m_clientWrapper->GetClient(); m_client->SetDMXCallback(ola::NewCallback(this, &olaThread::NewDmx)); - //m_client->SetDMXCallback(ola::NewCallback((libreMediaServerAudio *)this->parent(), libreMediaServerAudio::NewDmx)); m_clientWrapper->GetSelectServer()->RegisterRepeatingTimeout(4000, ola::NewCallback(this, &olaThread::CheckDataLoss)); m_client->SetCloseHandler(ola::NewSingleCallback(this, &olaThread::socketClosed)); m_dmxSettings = Settings::getInstance()->getDmxSettings(); @@ -69,30 +67,31 @@ void olaThread::NewDmx(const ola::client::DMXMetadata &data, bool volSent = false; bool entrySent = false; bool fileSent = false; + int aux; for (int j = 0; j < LAYER_CHANNELS; j++){ int value = buffer.Get((i.address) + j); if (m_dmx[i.layer][j] != value) { m_dmx[i.layer][j] = value; switch (j) { case DMX_FOLDER: - value *= 0x100; - value += buffer.Get(i.address + DMX_FILE); - qobject_cast(parent())->dmxInput(i.layer, j, value); - m_dmx[i.layer][DMX_FILE] = buffer.Get(i.address + DMX_FILE); + aux = buffer.Get(i.address + DMX_FILE); + qobject_cast(parent())->loadMedia(i.layer, value, aux); + m_dmx[i.layer][DMX_FILE] = aux; fileSent = true; break; case DMX_FILE: if (fileSent) break; - value += buffer.Get(i.address + DMX_FOLDER) * 0x100; - qobject_cast(parent())->dmxInput(i.layer, j, value); - m_dmx[i.layer][DMX_FOLDER] = buffer.Get(i.address + DMX_FOLDER); + aux = buffer.Get(i.address + DMX_FOLDER); + qobject_cast(parent())->loadMedia(i.layer, aux, value); + m_dmx[i.layer][DMX_FOLDER] = aux; fileSent = true; break; case VOLUME_FINE: - value = (buffer.Get(i.address + VOLUME_COARSE) * 0x100) + value; + aux = buffer.Get(i.address + VOLUME_COARSE); + value += (aux * 0x100); qobject_cast(parent())->dmxInput(i.layer, j, value); - m_dmx[i.layer][VOLUME_COARSE] = buffer.Get(i.address + VOLUME_COARSE); + m_dmx[i.layer][VOLUME_COARSE] = aux; volSent = true; break; case VOLUME_COARSE: @@ -103,6 +102,9 @@ void olaThread::NewDmx(const ola::client::DMXMetadata &data, m_dmx[i.layer][VOLUME_FINE] = buffer.Get(i.address + VOLUME_FINE); volSent = true; break; + case PLAYBACK: + qobject_cast(parent())->dmxInput(i.layer, j, value); + break; case ENTRY_POINT_FINE: value = (buffer.Get(i.address + ENTRY_POINT_COARSE) * 0x100) + value; qobject_cast(parent())->dmxInput(i.layer, j, value); diff --git a/src/settings.cpp b/src/settings.cpp index f664bb0..9e00914 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -15,6 +15,7 @@ Settings::Settings(QObject *parent) : QObject(parent) { m_layersNumber = 0; + m_ui = false; } // Read the dmx settings for dmx.xml At the moment we need: @@ -23,6 +24,7 @@ Settings::Settings(QObject *parent) : // - The first DMX channel of each source/layer // - The universe to bind in OLA // - Audio device id +// - Show the Ui or not void Settings::readFromFile(QString file) { QFile* xmlFile = new QFile(file); if (!xmlFile->open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -34,53 +36,56 @@ void Settings::readFromFile(QString file) { exit(1); } QXmlStreamReader* xmlReader = new QXmlStreamReader(xmlFile); - int counter = 0; - //Parse the XML until we reach end of it - while(!xmlReader->atEnd() && !xmlReader->hasError() && counter < MAX_LAYERS) { - // Read next element + while(!xmlReader->atEnd() && !xmlReader->hasError()) { QXmlStreamReader::TokenType token = xmlReader->readNext(); - //If token is just StartDocument - go to next if(token == QXmlStreamReader::StartDocument) { continue; } - //If token is StartElement - read it if(token == QXmlStreamReader::StartElement) { - if(xmlReader->name() == "dmxSettings") { - int version = xmlReader->attributes().value("fileVersion").toLocal8Bit().toInt(); - if(version == 1) { - m_layersNumber = xmlReader->attributes().value("layersNumber").toLocal8Bit().toInt(); - m_pathmedia = xmlReader->attributes().value("path").toLocal8Bit(); - continue; - } - } - if(xmlReader->name() == "audioDevice") { - m_audioDeviceId = xmlReader->attributes().value("id").toLocal8Bit().toInt(); + if(xmlReader->name() == "lmsAudio") { + m_ui = xmlReader->attributes().value("ui").toLocal8Bit().toInt(); + m_layersNumber = xmlReader->attributes().value("layersNumber").toLocal8Bit().toInt(); + m_pathmedia = xmlReader->attributes().value("path").toLocal8Bit(); continue; } - QString add = "layer"; - add.append(QString("%1").arg(counter)); - if((xmlReader->name() == add)) { + 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 = counter; + temp.layer = xmlReader->attributes().value("id").toLocal8Bit().toInt(); m_settings.append(temp); if (!m_universe.contains(temp.universe)) { m_universe.insert(temp.universe); } - counter++; } } } if(xmlReader->hasError()) { QMessageBox::critical(NULL,"File xml Parse Error ", xmlReader->errorString(), QMessageBox::Ok); qWarning("File xml Parse Error %s", xmlReader->errorString().toLatin1().constData()); - return; + // ToDo: manage this, open a dialog to load a new file. } xmlReader->clear(); xmlFile->close(); delete xmlReader; delete xmlFile; + this->printSettings(); +} + +void Settings::printSettings() { + qInfo() << "Settings read;\nShow Ui:" << m_ui << "Layers:" << m_layersNumber << "Path:" << m_pathmedia <<"Audio Device qty:" << m_audioDeviceQty; + for (uint i = 0; i < m_audioDeviceQty; i++) + qInfo() << "Audio device id:" << m_audioDeviceId[i]; + for (int i = 0; i < m_layersNumber; i++) + qInfo() << "Layer:" << m_settings[i].layer << "Address:" << m_settings[i].address << "Universe:" << m_settings[i].universe; } void Settings::readFile() { diff --git a/src/settings.h b/src/settings.h index 8cd55bb..f27da6a 100644 --- a/src/settings.h +++ b/src/settings.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "medialibrary.h" #include "audiowidget.h" @@ -15,25 +16,27 @@ class Settings : public QObject Q_OBJECT public: + Settings(QObject *parent = 0); static Settings *getInstance(); inline QSet getUniverses() { return m_universe; } 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 bool getShowUi() { return m_ui; } void readFile(); - inline int getAudioDeviceId() { return m_audioDeviceId; } + void readFromFile(QString file); + void printSettings(); private: static Settings *_instance; QList m_settings; QString m_pathmedia; - uint m_audioDeviceId; + uint m_audioDeviceId[MAX_AUDIODEVICES]; + uint m_audioDeviceQty; QSet m_universe; int m_layersNumber; - - explicit Settings(QObject *parent = 0); - void readFromFile(QString file); - + bool m_ui; }; #endif // SETTINGS_H diff --git a/src/slidergroup.cpp b/src/slidergroup.cpp index a488560..9ef9680 100644 --- a/src/slidergroup.cpp +++ b/src/slidergroup.cpp @@ -18,10 +18,11 @@ SliderGroup::SliderGroup(QString name, slider->setMinimumHeight(0); slider->setSingleStep(1); slider->setRange(min, max); + slider->setValue(0); slider->setMinimumWidth(50); slider->setToolTip(name); slider->setStyleSheet("QSlider {" - "border: 2px solid #685060;" + "border: 1px solid #5a4855;" "margin: 0px;" "height: 200px;" "width: 50px;}" @@ -32,17 +33,20 @@ SliderGroup::SliderGroup(QString name, 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); - this->setStyleSheet("border: 2px solid #685060;" + this->setStyleSheet("border: 1px solid #5a4855;" "width: 50px;" "margin: 0px;" + "background-color: #383034;" ); layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); @@ -67,3 +71,11 @@ void SliderGroup::setValue(float 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); +} diff --git a/src/slidergroup.h b/src/slidergroup.h index f597a5b..5bfeeb8 100644 --- a/src/slidergroup.h +++ b/src/slidergroup.h @@ -27,6 +27,8 @@ public slots: private: QSlider *slider; QDoubleSpinBox *valueBox; + + void mousePressEvent(QMouseEvent* event); }; #endif -- 2.39.5 From 0979c3608e3f1d961453fb4f128f2c1c9573d450 Mon Sep 17 00:00:00 2001 From: snt Date: Tue, 7 May 2024 20:57:13 +0200 Subject: [PATCH 22/49] puliendo --- docs/changelog.txt | 8 ++------ docs/roadmap.txt | 6 +----- src/audiolayerwidget.cpp | 3 --- src/libremediaserver-audio.cpp | 1 + src/miniaudioengine.cpp | 2 +- 5 files changed, 5 insertions(+), 15 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index a69017b..5c7e0b6 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -6,12 +6,7 @@ https://git.criptomart.net/libremediaserver Libre Media Server ChangeLog - - - - - -v 0.2.0 Antígona (24/04/2024) +v 0.2.0 Antígona (26/05/2024) + Change audio engine to miniaudio because is imposible pan in SFML and it has not access to low API and audio processing. + Refactor all audio methods to MiniAudioEngine class. + Select sound device output. @@ -29,6 +24,7 @@ v 0.2.0 Antígona (24/04/2024) + 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). ++ Load media files from ui clicking in the media labels. v 0.1.3 Leúcade (19/04/2024) diff --git a/docs/roadmap.txt b/docs/roadmap.txt index bd98089..153c596 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -41,17 +41,13 @@ v 0.2.1 - audio device linked, outputs will be redirected there. - dmx address + universe settings. - Rose noise and sine generator in menu to test system. -- Ui/Ux; Keyboards strokes, load media files from ui. +- Ui/Ux; Keyboards strokes. - Ui/Ux: Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante. - Logs, verbosity, timestamp. - New play mode without pitch control, it saves resources. MA_SOUND_FLAG_NO_PITCH - Vumeter or indicator about audio output in layer and master, add to sliderGroup. -- QSlider can not accept floats and it can no manage high frequency updates. - SettingsDialog. - Load/save conf file. - ¿Exit Point? is it needed? - Hardening: check return errors, try/catch exceptions, i'm too happy.... - Tests: errors on wrong conf file. -- BUGFIX: there are some small clicks when changing volume and play/stop/pause. vol 24 bits? microfades in engine? setVol 0 before changing playback state? -- refactorize dmxInput: loadMedia, changePlayBack, -- BUGFIX: in nogui mode we need more info print at terminal (load media, change playback status). diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index a22b2cc..4a07451 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -172,7 +172,6 @@ void AudioLayerWidget::setMediaFile(QString file) m_folderValue->setText(list.at(size - 2)); m_fileValue->setText(list.at(size - 1)); } - this->setPlaybackStatus(Status::Stopped); } void AudioLayerWidget::setPlaybackStatus(Status s) @@ -180,8 +179,6 @@ void AudioLayerWidget::setPlaybackStatus(Status s) Status status = static_cast(s); m_suspendResumeButton->blockSignals(true); m_status = status; - //if (status == Status::Stopped) - // refreshCurrentTime(0); m_suspendResumeButton->setText(StatusStr[status]); m_suspendResumeButton->blockSignals(false); } diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index cb18dc2..ab12820 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -104,6 +104,7 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) s = Status::PlayingLoop; m_mae.playbackChanged(layer, s); m_currentStatus[layer] = s; + qInfo() << "Layer" << layer << StatusStr[s]; #ifndef NOGUI if (m_ui) { m_lmsUi->m_aw->playbackChanged(layer, s); diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index c2d9a6d..fa58464 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -192,7 +192,7 @@ ma_result MiniAudioEngine::printFormatInfo(int layer) qWarning("Failed to get data format %i\n", layer); return MA_INVALID_DATA; } - qInfo() << "name:" << m_currentLayerValues[layer].media << "samples/sec:" << sampleRate << "format:" << format << "channels:" << channels; + qInfo() << "Layer:" << layer << m_currentLayerValues[layer].media << "samples/sec:" << sampleRate << "format:" << format << "channels:" << channels; return result; } -- 2.39.5 From cd0105c9f9d66173dd8f6d61e5eec3327990b1fb Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 8 May 2024 18:56:16 +0200 Subject: [PATCH 23/49] =?UTF-8?q?quitado=20peque=C3=B1o=20glitch=20cuando?= =?UTF-8?q?=20entry=20point=20no=20es=20cero.=20stop=20con=20fade=20out=20?= =?UTF-8?q?para=20evitar=20click.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/roadmap.txt | 6 +- src/audiolayerwidget.cpp | 10 ++-- src/audiowidget.cpp | 11 +++- src/defines.h | 2 +- src/libremediaserver-audio.cpp | 24 ++++++-- src/miniaudioengine.cpp | 105 ++++++++++++++++++--------------- src/miniaudioengine.h | 14 +++-- src/settings.cpp | 4 +- 8 files changed, 105 insertions(+), 71 deletions(-) diff --git a/docs/roadmap.txt b/docs/roadmap.txt index 153c596..94081f4 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -5,7 +5,6 @@ https://git.criptomart.net/libremediaserver ******************************************************************************* Libre Media Server Roadmap -(en continuo crecimiento...) v 0.2.x - skin, UI/UX @@ -45,9 +44,12 @@ v 0.2.1 - Ui/Ux: Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante. - Logs, verbosity, timestamp. - New play mode without pitch control, it saves resources. MA_SOUND_FLAG_NO_PITCH -- Vumeter or indicator about audio output in layer and master, add to sliderGroup. - SettingsDialog. - Load/save conf file. - ¿Exit Point? is it needed? - Hardening: check return errors, try/catch exceptions, i'm too happy.... - Tests: errors on wrong conf file. + +v0.2.0: +- BUGFIX: crash at startup and no dmx signal. +- Vumeter or indicator about audio output in layer and master, add to sliderGroup. diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 4a07451..e8d22bd 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -10,8 +10,8 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): QVBoxLayout *playback = new QVBoxLayout; m_folderValue = new ClickableLabel; - //m_folderValue->setMaximumWidth(160); - m_folderValue->setAlignment(Qt::AlignHCenter); + m_folderValue->setMaximumWidth(160); + m_folderValue->setAlignment(Qt::AlignLeft); m_folderValue->setStyleSheet( "color: white;" "background-color: black;" @@ -20,8 +20,8 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_fileValue = new ClickableLabel; connect(m_fileValue, SIGNAL(clicked()), this, SLOT(openMediaDialog())); connect(m_folderValue, SIGNAL(clicked()), this, SLOT(openMediaDialog())); - //m_fileValue->setMaximumWidth(160); - m_fileValue->setAlignment(Qt::AlignHCenter); + m_fileValue->setMaximumWidth(160); + m_fileValue->setAlignment(Qt::AlignLeft); m_fileValue->setStyleSheet( "color: white;" "background-color: black;" @@ -33,7 +33,6 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_suspendResumeButton = new QPushButton(this); m_suspendResumeButton->setText(StatusStr[Status::Iddle]); - //m_suspendResumeButton->setMaximumWidth(180); connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume())); layout->addWidget(m_suspendResumeButton); @@ -42,7 +41,6 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_progress->setRange(0, 0); m_progress->setValue(0); m_progress->setFormat("%v / %m"); - //m_progress->setMaximumWidth(180); layout->addWidget(m_progress); m_progressTime = new QTimeEdit; diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index ca2633a..8bd077c 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -11,13 +11,20 @@ AudioWidget::AudioWidget(QWidget *parent) : connect(alw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SIGNAL(uiSliderChanged(int, Slider, int))); connect(alw, SIGNAL(uiPlaybackChanged(int, Status)), this, SIGNAL(uiPlaybackChanged(int, Status))); connect(alw, SIGNAL(uiLoadMedia(int, QString)), this, SIGNAL(uiLoadMedia(int, QString))); + m_layerUpdate[i].status = Status::Iddle; + m_layerUpdate[i].duration = 0; + m_layerUpdate[i].media = ""; + m_layerUpdate[i].vol = 0; + m_layerUpdate[i].pan = 128; + m_layerUpdate[i].pitch = 128; + m_layerUpdate[i].cursor = 0; } m_layout->setSpacing(0); m_layout->setContentsMargins(1, 1, 1, 1); setLayout(m_layout); m_refreshUi = new QTimer(this); connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); - m_refreshUi->start(UI_REFRESH_TIME * 2); + m_refreshUi->start(UI_REFRESH_TIME * 1.5); } void AudioWidget::mediaLoaded(int layer, QString file, float duration) @@ -51,7 +58,7 @@ void AudioWidget::playbackChanged(int layer, Status status) void AudioWidget::cursorChanged(int layer, float cursor) { - m_layerUpdate[layer].cursor = floor(cursor * 1000) / 1000; + m_layerUpdate[layer].cursor = cursor; m_layerUpdate[layer].updated = true; } diff --git a/src/defines.h b/src/defines.h index 6552d19..a9c92b8 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 77 +#define UI_REFRESH_TIME 66 #define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks struct dmxSetting { diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index ab12820..2ea3266 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -108,7 +108,7 @@ 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_lmsUi->m_aw->cursorChanged(layer, m_mae.getCursor(layer)); } #endif } @@ -170,16 +170,28 @@ void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value) void libreMediaServerAudio::uiPlaybackChanged(int layer, Status s) { - m_mae.playbackChanged(layer, s); - m_currentStatus[layer] = s; + ma_result result; + + result = m_mae.playbackChanged(layer, s); + if (result == MA_SUCCESS) { + m_currentStatus[layer] = s; + } else { + qWarning() << "ui playback change error" << result << "status" << s << "layer" << layer; + } } void libreMediaServerAudio::uiLoadMedia(int layer, QString mediaFile) { + ma_result result; + if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0) return; - m_mae.loadMedia(layer, mediaFile.toLatin1().data()); - m_currentMedia[layer] = mediaFile; - m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); + result = m_mae.loadMedia(layer, mediaFile.toLatin1().data()); + if (result == MA_SUCCESS) { + m_currentMedia[layer] = mediaFile; + m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); + } else { + qWarning() << "ui load media error" << result << "file" << mediaFile << "layer" << layer; + } } #endif diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index fa58464..d1040b9 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -1,5 +1,5 @@ #include "miniaudioengine.h" - +#include //enum macro MiniAudioEngine::MiniAudioEngine() { for (int i =0; i < MAX_LAYERS; i++) { @@ -27,25 +27,26 @@ void MiniAudioEngine::stopEngine() ma_resource_manager_uninit(&resourceManager); } -bool MiniAudioEngine::startEngine(int n) +bool MiniAudioEngine::startEngine(uint n) { ma_result result; result = this->startContext(); - if (result != MA_SUCCESS) { - return result; - } - this->getAllAudioDevices(); + 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(int id) +ma_result MiniAudioEngine::startDevice(uint id) { ma_result result; ma_device_config deviceConfig; ma_engine_config engineConfig; + if (id >= playbackDeviceCount) + id = playbackDeviceCount - 1; deviceConfig = ma_device_config_init(ma_device_type_playback); deviceConfig.playback.pDeviceID = &pPlaybackDeviceInfos[id].id; deviceConfig.playback.format = resourceManager.config.decodedFormat; @@ -73,7 +74,7 @@ ma_result MiniAudioEngine::startDevice(int id) return result; } iChosenDevice = id; - qInfo("Initialized audio device %d: %s", id, pPlaybackDeviceInfos[id].name); + qInfo("Initialized audio device %d : %s", id, pPlaybackDeviceInfos[id].name); return result; } @@ -85,7 +86,7 @@ ma_result MiniAudioEngine::startContext() 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.jobThreadCount = 1; + resourceManagerConfig.jobThreadCount = 4; result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager); if (result != MA_SUCCESS) { qCritical("Failed to initialize audio resource manager."); @@ -109,7 +110,7 @@ ma_result MiniAudioEngine::getAllAudioDevices() ma_context_uninit(&context); return result; } - printf("Audio devices detected in system:\n"); + printf("Audio devices available:\n"); for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < playbackDeviceCount; iAvailableDevice += 1) { qInfo("%d: : %s", iAvailableDevice, pPlaybackDeviceInfos[iAvailableDevice].name); } @@ -127,10 +128,8 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file) } result = ma_sound_init_from_file(&engine, file, \ MA_SOUND_FLAG_NO_SPATIALIZATION \ - /*| MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE \ - | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC \ - | MA_SOUND_FLAG_NO_PITCH \ - | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM \*/ + | MA_SOUND_FLAG_DECODE \ + /*| MA_SOUND_FLAG_NO_PITCH \*/ , NULL, NULL, &m_currentSound[layer]); if (result != MA_SUCCESS) qWarning("Failed to load file %s", file); @@ -157,7 +156,7 @@ float MiniAudioEngine::getDuration(int layer) } result = ma_sound_get_data_format(&m_currentSound[layer], NULL, NULL, &sampleRate, NULL, 0); if (result != MA_SUCCESS) { - return result; + return MA_ERROR; } ret = 1000.0f * (lengthInPCMFrames / float(sampleRate)); return ret; @@ -173,8 +172,8 @@ float MiniAudioEngine::getCursor(int layer) result = ma_sound_get_cursor_in_seconds(&m_currentSound[layer], &ret); if (result != MA_SUCCESS) { - qWarning("Can not get cursor %i", layer); - ret = -1; + qWarning("%i can not get cursor error %i", layer, result); + ret = MA_ERROR; } return ret; } @@ -188,11 +187,10 @@ 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("Failed to get data format %i\n", layer); - return MA_INVALID_DATA; - } - qInfo() << "Layer:" << layer << m_currentLayerValues[layer].media << "samples/sec:" << sampleRate << "format:" << format << "channels:" << channels; + 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; return result; } @@ -220,55 +218,70 @@ void MiniAudioEngine::panChanged(int layer, float value) void MiniAudioEngine::pitchChanged(int layer, float value) { - float result; + float pitch; if (m_mediaLoaded[layer] == false) return; - result = value / 128.0; - ma_sound_group_set_pitch(&m_currentSound[layer], result); + pitch = value / 128.0; + ma_sound_group_set_pitch(&m_currentSound[layer], pitch); m_currentLayerValues[layer].pitch = value; } -void MiniAudioEngine::playbackChanged(int layer, Status status) +ma_result MiniAudioEngine::playbackChanged(int layer, Status status) { + ma_result result = MA_SUCCESS; + if (m_mediaLoaded[layer] == false) - return; + return MA_DOES_NOT_EXIST; switch (status) { case Status::Paused: - ma_sound_stop(&m_currentSound[layer]); + result = ma_sound_stop_with_fade_in_milliseconds(&m_currentSound[layer], FADE_TIME); break; case Status::Stopped: - ma_sound_stop(&m_currentSound[layer]); - this->setCursor(layer, m_currentLayerValues[layer].cursor); + result = 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); - ma_sound_start(&m_currentSound[layer]); - break; + result = ma_sound_start(&m_currentSound[layer]); + break; case Status::PlayingOnce: + ma_sound_set_stop_time_in_milliseconds(&m_currentSound[layer], ~(ma_uint64)0); ma_sound_set_looping(&m_currentSound[layer], false); - ma_sound_start(&m_currentSound[layer]); + result = ma_sound_start(&m_currentSound[layer]); break; default: break; } - m_currentLayerValues[layer].status = status; + if (result == MA_SUCCESS) + m_currentLayerValues[layer].status = status; + return result; } -void MiniAudioEngine::setCursor(int layer, int cursor) +ma_result MiniAudioEngine::seekToCursor(int layer, int cursor) { - ma_uint64 end; + ma_result result = MA_SUCCESS; + ma_uint64 end, start; + + if (m_mediaLoaded[layer] == false) + return MA_DOES_NOT_EXIST; + result = ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &end); + 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); + return (result); +} + +ma_result MiniAudioEngine::setCursor(int layer, int cursor) +{ + ma_result result = MA_SUCCESS; m_currentLayerValues[layer].cursor = cursor; - if (m_mediaLoaded[layer] == false) - return; - ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &end); - ma_uint64 start = (cursor * end) / 65025; - ma_sound_seek_to_pcm_frame(&m_currentSound[layer], start); - ma_result result = ma_data_source_set_loop_point_in_pcm_frames(&m_currentSound[layer], start, end); - if (result != MA_SUCCESS) { - return; // Failed to set the loop point. - } + result = this->seekToCursor(layer, cursor); + return (result); } Status MiniAudioEngine::getStatus(int layer) @@ -278,9 +291,9 @@ Status MiniAudioEngine::getStatus(int layer) void MiniAudioEngine::refreshValues(int layer) { + this->seekToCursor(layer, m_currentLayerValues[layer].cursor); this->panChanged(layer, m_currentLayerValues[layer].pan); this->volChanged(layer, m_currentLayerValues[layer].vol); this->pitchChanged(layer, m_currentLayerValues[layer].pitch); this->playbackChanged(layer, m_currentLayerValues[layer].status); - this->setCursor(layer, m_currentLayerValues[layer].cursor); } diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 2c3ec5a..6d0ea19 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -13,7 +13,7 @@ class MiniAudioEngine public: MiniAudioEngine(); void stopEngine(); - bool startEngine(int id); + bool startEngine(uint id); static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); protected: @@ -21,13 +21,14 @@ protected: void volChanged(int layer, float vol); void panChanged(int layer, float pan); void pitchChanged(int layer, float pitch); - void playbackChanged(int layer, Status status); + ma_result playbackChanged(int layer, Status status); + ma_result setCursor(int layer, int cursor); + ma_result printFormatInfo(int layer); float getDuration(int layer); float getCursor(int layer); - void setCursor(int layer, int cursor); - ma_result printFormatInfo(int layer); Status getStatus(int layer); - inline float getVol(int layer) { return ma_sound_get_volume(&m_currentSound[layer]); } + inline float getVol(int layer) { + return ma_sound_get_volume(&m_currentSound[layer]); } private: ma_resource_manager_config resourceManagerConfig; @@ -43,9 +44,10 @@ private: layerData m_currentLayerValues[MAX_LAYERS]; ma_result getAllAudioDevices(); - ma_result startDevice(int id); + ma_result startDevice(uint id); ma_result startContext(); void refreshValues(int layer); + ma_result seekToCursor(int layer, int cursor); }; #endif // MINIAUDIOENGINE_H diff --git a/src/settings.cpp b/src/settings.cpp index 9e00914..9d06394 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -81,9 +81,9 @@ void Settings::readFromFile(QString file) { } void Settings::printSettings() { - qInfo() << "Settings read;\nShow Ui:" << m_ui << "Layers:" << m_layersNumber << "Path:" << m_pathmedia <<"Audio Device qty:" << m_audioDeviceQty; + qInfo() << "Settings readed:\nShow Ui:" << m_ui << "Layers:" << m_layersNumber << "Path:" << m_pathmedia <<"Audio Device qty:" << m_audioDeviceQty; for (uint i = 0; i < m_audioDeviceQty; i++) - qInfo() << "Audio device id:" << m_audioDeviceId[i]; + qInfo() << "Audio device internal id:" << i << "system id:" << m_audioDeviceId[i]; for (int i = 0; i < m_layersNumber; i++) qInfo() << "Layer:" << m_settings[i].layer << "Address:" << m_settings[i].address << "Universe:" << m_settings[i].universe; } -- 2.39.5 From f67ad9b1e1c2b2a98b2f7c6abf5d925a1f35a48b Mon Sep 17 00:00:00 2001 From: snt Date: Thu, 9 May 2024 14:07:24 +0200 Subject: [PATCH 24/49] =?UTF-8?q?nuevos=20modos=20de=20reproducci=C3=B3n:?= =?UTF-8?q?=20Play=20Folder,=20Play=20Folder=20Loop,=20Play=20Folder=20Ran?= =?UTF-8?q?dom.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/roadmap.txt | 1 - src/defines.h | 13 +++++-- src/libremediaserver-audio.cpp | 64 +++++++++++++++++++++++++++++++++- src/libremediaserver-audio.h | 1 + src/medialibrary.h | 3 ++ src/miniaudioengine.cpp | 3 ++ src/miniaudioengine.h | 2 ++ 7 files changed, 83 insertions(+), 4 deletions(-) diff --git a/docs/roadmap.txt b/docs/roadmap.txt index 94081f4..0771257 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -51,5 +51,4 @@ v 0.2.1 - Tests: errors on wrong conf file. v0.2.0: -- BUGFIX: crash at startup and no dmx signal. - Vumeter or indicator about audio output in layer and master, add to sliderGroup. diff --git a/src/defines.h b/src/defines.h index a9c92b8..ff299c1 100644 --- a/src/defines.h +++ b/src/defines.h @@ -22,7 +22,10 @@ enum Status Paused, PlayingOnce, PlayingLoop, - Iddle + Iddle, + PlayingFolder, + PlayingFolderLoop, + PlayingFolderRandom }; static const char* StatusStr[] = @@ -30,8 +33,11 @@ static const char* StatusStr[] = "Stop", "Pause", "Playing One", - "Playing Loop", + "Playing One Loop", "Iddle", + "Playing Folder", + "Playing Folder Loop", + "Playing Folder Random", 0x0 }; @@ -52,5 +58,8 @@ struct layerData { int pan; int pitch; float duration; + int address; + unsigned int universe; + int device; }; #endif // DEFINES_H diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 2ea3266..a9868fd 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -70,6 +70,14 @@ void libreMediaServerAudio::loadMedia(int layer, int folder, int file) #endif m_mae.printFormatInfo(layer); } + if (m_currentStatus[layer] == Status::PlayingFolder \ + || (m_currentStatus[layer] == Status::PlayingFolderLoop)\ + || (m_currentStatus[layer] == Status::PlayingFolderRandom)) { + m_played.append(file); + } else if (m_currentStatus[layer] == Status::PlayingOnce \ + || m_currentStatus[layer] == Status::PlayingLoop) { + m_played.clear(); + } } void libreMediaServerAudio::dmxInput(int layer, int channel, int value) @@ -102,6 +110,12 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) s = Status::Paused; else if (aux == 3) s = Status::PlayingLoop; + else if (aux == 4) + s = Status::PlayingFolder; + else if (aux == 5) + s = Status::PlayingFolderLoop; + else if (aux == 6) + s = Status::PlayingFolderRandom; m_mae.playbackChanged(layer, s); m_currentStatus[layer] = s; qInfo() << "Layer" << layer << StatusStr[s]; @@ -131,10 +145,58 @@ void libreMediaServerAudio::refreshUi() { } if (m_updateUi[i][3] >= 0 \ || m_currentStatus[i] == Status::PlayingOnce\ - || m_currentStatus[i] == Status::PlayingLoop) { + || m_currentStatus[i] == Status::PlayingLoop\ + || m_currentStatus[i] == Status::PlayingFolder\ + || m_currentStatus[i] == Status::PlayingFolderLoop + || m_currentStatus[i] == Status::PlayingFolderRandom) { m_lmsUi->m_aw->cursorChanged(i, m_mae.getCursor(i)); 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; + } + if (m_currentStatus[i] == Status::PlayingFolder) { + uint last = m_played.last(); + int folder = m_ola->getValue(i, DMX_FOLDER); + last++; + if (last < m_mediaLibrary->getMediaFolderCount(folder)) { + this->loadMedia(i, folder, last); + m_mae.playbackChanged(i, Status::PlayingFolder); + } + else { + m_currentStatus[i] = Status::Stopped; + m_lmsUi->m_aw->playbackChanged(i, Status::Stopped); + } + } + if (m_currentStatus[i] == Status::PlayingFolderLoop) { + uint last = m_played.last(); + int folder = m_ola->getValue(i, DMX_FOLDER); + last++; + if (last >= m_mediaLibrary->getMediaFolderCount(folder)) { + this->loadMedia(i, folder, 0); + m_mae.playbackChanged(i, Status::PlayingFolderLoop); + } else { + this->loadMedia(i, folder, last); + m_mae.playbackChanged(i, Status::PlayingFolder); + } + } + if (m_currentStatus[i] == Status::PlayingFolderRandom) { + int last = -1; + int folder = m_ola->getValue(i, DMX_FOLDER); + if (uint(abs(m_played.size())) >= m_mediaLibrary->getMediaFolderCount(folder)) + m_played.clear(); + while (last == -1) { + last = rand() % m_mediaLibrary->getMediaFolderCount(folder); + if (m_played.contains(last)) + last = -1; + } + this->loadMedia(i, folder, last); + m_mae.playbackChanged(i, Status::PlayingFolderRandom); + } + } } } diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index 1af37df..d83446a 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -52,6 +52,7 @@ private: Status m_currentStatus[MAX_LAYERS]; QList m_dmxSettings; bool m_ui; + QList m_played; #ifndef NOGUI QTimer *m_refreshUi; libreMediaServerAudioUi *m_lmsUi; diff --git a/src/medialibrary.h b/src/medialibrary.h index 8c2eb07..ea92bca 100644 --- a/src/medialibrary.h +++ b/src/medialibrary.h @@ -29,6 +29,9 @@ public: MediaLibrary(QObject *parent = 0); QString requestNewFile(int folder, int layer); void initMediaLibrary(); + inline uint getMediaFolderCount(int folder) { + return m_media->at(folder).m_ElementCount; + } private: QList *m_media; diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index d1040b9..9204636 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -247,6 +247,9 @@ ma_result MiniAudioEngine::playbackChanged(int layer, Status status) result = ma_sound_start(&m_currentSound[layer]); break; 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); result = ma_sound_start(&m_currentSound[layer]); diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 6d0ea19..6e1393c 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -5,6 +5,7 @@ #include "miniaudio.h" #include "defines.h" // MAX_LAYERS #include // prints messages +#define MA_DEBUG_OUTPUT class MiniAudioEngine { @@ -29,6 +30,7 @@ protected: Status getStatus(int layer); inline float getVol(int layer) { return ma_sound_get_volume(&m_currentSound[layer]); } + inline bool getAtEnd(int layer) { return m_currentSound[layer].atEnd; } private: ma_resource_manager_config resourceManagerConfig; -- 2.39.5 From 7631e54d51aa2dc2bcb8c6640047cec8272219bc Mon Sep 17 00:00:00 2001 From: snt Date: Thu, 9 May 2024 14:10:46 +0200 Subject: [PATCH 25/49] =?UTF-8?q?nuevos=20modos=20reproducci=C3=B3n=20en?= =?UTF-8?q?=20personalidad?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/LibreMediaServer_Audio.hed | 105 ++++++++++++++++---------------- 1 file changed, 54 insertions(+), 51 deletions(-) diff --git a/docs/LibreMediaServer_Audio.hed b/docs/LibreMediaServer_Audio.hed index 58d0fd5..fda3e2d 100644 --- a/docs/LibreMediaServer_Audio.hed +++ b/docs/LibreMediaServer_Audio.hed @@ -2,7 +2,7 @@ ҊÅЁ䍡 ӽ Ꭸʆ -ɑ +ɑ ɬ 򉇁 Ԑɉ @@ -24,53 +24,56 @@ Ԓlj -έ -倬쏎 - -޽ڊ - -؛ -ŕ -ðݑ -ȕ -˛ -̽ɧ - -𓎍 - - -ً - -ʐ -ï -뷪 - - -܋ -Ò -뻡 -ǒ - -𓎍 -ʟ - -㍛ - - - - - - -𓎑 - - - -ҟ - - - -ف - - - - +Ŷ§ +ÐŽÊ +𡭟Ē + +܊ +񢰽 +зм +񓎍 +ҭ +ܻۏ +ڑן +ޏ + +Ƴ + + + +Ǖ + +𓎍Ԏ + + +Ξ +ֆ + +ց + +ᱯ +݈ + +؈ + +馹 +۴ +𓎍 + + + + + +𓎑 + + + +Ɨ + + + +Ӌ +쏎 + + + -- 2.39.5 From 103a33820ef8c407f6b02519c1e286378d2bd0e3 Mon Sep 17 00:00:00 2001 From: snt Date: Fri, 10 May 2024 20:03:14 +0200 Subject: [PATCH 26/49] 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 -- 2.39.5 From 8c69da5f9d4886e96805e4a8e70f74fd06e762e4 Mon Sep 17 00:00:00 2001 From: snt Date: Fri, 10 May 2024 21:04:26 +0200 Subject: [PATCH 27/49] 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); -- 2.39.5 From 7cd4c8fbd84d917806c4eecf6c3220b5ac4106e2 Mon Sep 17 00:00:00 2001 From: snt Date: Sun, 12 May 2024 23:23:26 +0200 Subject: [PATCH 28/49] 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 -- 2.39.5 From f87c908d300f93ec646a269d712d7fbfb38473f4 Mon Sep 17 00:00:00 2001 From: snt Date: Mon, 13 May 2024 02:22:34 +0200 Subject: [PATCH 29/49] 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(); -- 2.39.5 From 352513328704e4b36e4ab060c9740aa7a18a8648 Mon Sep 17 00:00:00 2001 From: snt Date: Tue, 14 May 2024 20:49:28 +0200 Subject: [PATCH 30/49] 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 -- 2.39.5 From 3244ea2abcee1cb65af7051e29091dd4b804bc92 Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 15 May 2024 00:16:49 +0200 Subject: [PATCH 31/49] =?UTF-8?q?cambio=20la=20configuraci=C3=B3n=20del=20?= =?UTF-8?q?banco=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; -- 2.39.5 From 7bc339dfe334265b87060de00aa296eca249ef97 Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 15 May 2024 01:25:44 +0200 Subject: [PATCH 32/49] =?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 - -Ŷ§ -ÐŽÊ -𡭟Ē - -܊ -񢰽 -зм -񓎍 -ҭ -ܻۏ -ڑן -ޏ - -Ƴ - - - -Ǖ - -𓎍Ԏ - - -Ξ -ֆ - -ց - -ᱯ -݈ - -؈ - -馹 -۴ -𓎍 - - - - - -𓎑 - - - -Ɨ - - - -Ӌ -쏎 - - - +͌وГ +䩴؍ + + +ǁ + +ήƵ +ꂨ⑯ɞɅ +ˆ +㨥 +פ + +Θב +˻ + +ūî +䈍 +п +¥߸ڋ +Ĩ© +勌㊈ +͹ +ˢ݈ +ɢƢ +񍒍Й +˟ + +ǔ +檵 +Ӡ̧׀ +ꗪㄮϞѝ +ᯠ쫶 +ϼȡ嵶 +ᄨڍ֟ + +ڱ +񔸼񣏎 +ڔ + + +֐ + +̽ɤ +甯؞τ + + + + + + +𣇒 +Ԇ + +䷩ +ߍ + + + + + + + + + + +܂ +쏎 +מ + + +Ӽ + + + + + + + + + + +͚ʝǓ + + + +ݽ + + + + -- 2.39.5 From 8f321b9d6949cf111792c95242bbf0aca7fd0c47 Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 15 May 2024 02:21:30 +0200 Subject: [PATCH 33/49] =?UTF-8?q?fix=20sigsev=20cuando=20se=20pincha=20en?= =?UTF-8?q?=20el=20bot=C3=B3n=20de=20play/pause?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/audiolayerwidget.cpp | 5 +++-- src/audiolayerwidget.h | 1 + src/defines.h | 20 ++++++++++++++++++-- src/libremediaserver-audio.cpp | 4 ++-- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 2655938..bd9d371 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -3,6 +3,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): QWidget(parent) + , m_oldStatus(Status::PlayingLoop) , m_layer(layer) , m_suspendResumeButton(0) { @@ -32,7 +33,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): layout->addLayout(playback); m_suspendResumeButton = new QPushButton(this); - m_suspendResumeButton->setText(StatusStr[Status::Iddle]); + m_suspendResumeButton->setText(statusToString(Status::Iddle)); connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume())); layout->addWidget(m_suspendResumeButton); @@ -180,7 +181,7 @@ void AudioLayerWidget::setPlaybackStatus(Status s) { m_suspendResumeButton->blockSignals(true); m_status = s; - m_suspendResumeButton->setText(StatusStr[s]); + m_suspendResumeButton->setText(statusToString(s)); m_suspendResumeButton->blockSignals(false); } diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index cae18d4..51c1203 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -11,6 +11,7 @@ #include "clickablelabel.h" #include "settings.h" + class AudioLayerWidget : public QWidget { Q_OBJECT diff --git a/src/defines.h b/src/defines.h index a885485..b4560a8 100644 --- a/src/defines.h +++ b/src/defines.h @@ -17,7 +17,7 @@ struct dmxSetting { int audioDevice; }; -enum Status +enum class Status { Stopped, Paused, @@ -29,6 +29,22 @@ enum Status PlayingFolderRandom }; +constexpr const char* statusToString(Status e) noexcept +{ + switch (e) + { + case Status::Stopped: return "Stop"; + case Status::Paused: return "Paused"; + case Status::PlayingOnce: return "Play 1"; + case Status::PlayingLoop: return "Play Loop"; + case Status::Iddle: return "Iddle"; + case Status::PlayingFolder: return "Play Folder"; + case Status::PlayingFolderLoop: return "Play Folder Loop"; + case Status::PlayingFolderRandom: return "Playing Folder Random"; + default: return "--++--"; + } +} +/* static const char* StatusStr[] = { "Stop", @@ -40,7 +56,7 @@ static const char* StatusStr[] = "Play Folder Loop", "Play Folder Rand", 0x0 -}; +};*/ enum Slider { diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 07ab9a8..9366935 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -132,7 +132,7 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) s = Status::PlayingFolderRandom; m_mae.playbackChanged(layer, s); m_currentStatus[layer] = s; - qInfo() << "Layer" << layer << StatusStr[s]; + qInfo() << "Layer" << layer << statusToString(s); #ifndef NOGUI if (m_ui) { m_lmsUi->m_aw->playbackChanged(layer, s); @@ -253,7 +253,7 @@ void libreMediaServerAudio::uiPlaybackChanged(int layer, Status s) if (result == MA_SUCCESS) { m_currentStatus[layer] = s; } else { - qWarning() << "ui playback change error" << result << "status" << s << "layer" << layer; + qWarning() << "ui playback change error " << result << " status " << statusToString(s) << "layer" << layer; } } -- 2.39.5 From 86567b8beff47daec58372570773f107b6a4c7ea Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 15 May 2024 17:50:21 +0200 Subject: [PATCH 34/49] =?UTF-8?q?indicadores=20filtros=20Ui=20funcionando,?= =?UTF-8?q?=20sin=20interacci=C3=B3n=20de=20usuario.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libremediaserver-audio.pro | 6 +++ src/audiolayerwidget.cpp | 23 +++++++--- src/audiolayerwidget.h | 24 +++++----- src/audiowidget.cpp | 18 +++++++- src/audiowidget.h | 3 ++ src/clickabledoublespinbox.cpp | 21 +++++++++ src/clickabledoublespinbox.h | 25 ++++++++++ src/clickableslider.cpp | 3 ++ src/clickableslider.h | 30 ++++++++++++ src/defines.h | 1 + src/dmxPersonality.h | 20 ++++++++ src/filterbankwidget.cpp | 82 +++++++++++++++++++++++++++++++++ src/filterbankwidget.h | 22 +++++++++ src/libremediaserver-audio.cpp | 7 +++ src/slidergroup.cpp | 15 ++---- src/slidergroup.h | 83 +++------------------------------- 16 files changed, 275 insertions(+), 108 deletions(-) create mode 100644 src/clickabledoublespinbox.cpp create mode 100644 src/clickabledoublespinbox.h create mode 100644 src/clickableslider.cpp create mode 100644 src/clickableslider.h create mode 100644 src/filterbankwidget.cpp create mode 100644 src/filterbankwidget.h diff --git a/libremediaserver-audio.pro b/libremediaserver-audio.pro index 41d6ecd..0371808 100644 --- a/libremediaserver-audio.pro +++ b/libremediaserver-audio.pro @@ -2,8 +2,11 @@ TEMPLATE = app TARGET = libremediaserver-audio QT += webkitwidgets widgets HEADERS += src/libremediaserver-audio.h \ + src/clickabledoublespinbox.h \ src/clickablelabel.h \ + src/clickableslider.h \ src/dmxwidget.h \ + src/filterbankwidget.h \ src/libremediaserver-audio-gui.h \ src/main.h \ src/miniaudio.h \ @@ -17,8 +20,11 @@ HEADERS += src/libremediaserver-audio.h \ src/settings.h \ src/slidergroup.h SOURCES += src/main.cpp \ + src/clickabledoublespinbox.cpp \ src/clickablelabel.cpp \ + src/clickableslider.cpp \ src/dmxwidget.cpp \ + src/filterbankwidget.cpp \ src/libremediaserver-audio-gui.cpp \ src/miniaudio.c \ src/libremediaserver-audio.cpp \ diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index bd9d371..b2f2782 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -1,5 +1,7 @@ #include "audiolayerwidget.h" -#include + +#include +#include AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): QWidget(parent) @@ -21,7 +23,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_fileValue = new ClickableLabel; connect(m_fileValue, SIGNAL(clicked()), this, SLOT(openMediaDialog())); connect(m_folderValue, SIGNAL(clicked()), this, SLOT(openMediaDialog())); - m_fileValue->setMaximumWidth(160); + m_fileValue->setMaximumWidth(300); m_fileValue->setAlignment(Qt::AlignLeft); m_fileValue->setStyleSheet( "color: white;" @@ -69,6 +71,10 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): status->addWidget(m_progressTime); status->addWidget(m_totalTimeValue); layout->addLayout(status); + + m_filterBank = new FilterBankWidget(this); + layout->addWidget(m_filterBank); + QVBoxLayout *volumeBox = new QVBoxLayout; m_pitch = new SliderGroup("Pitch", 0 , 255, 0, NULL); volumeBox->addWidget(m_pitch); @@ -88,10 +94,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): this->setLayout(layout); } -AudioLayerWidget::~AudioLayerWidget() -{ - -} +AudioLayerWidget::~AudioLayerWidget() {} // From UI. void AudioLayerWidget::volumeChanged(int value) @@ -209,3 +212,11 @@ void AudioLayerWidget::setCurrentTime(float progress) m_progress->blockSignals(false); m_progressTime->blockSignals(false); } + +void AudioLayerWidget::setFilterParam(int channel, int value) +{ + m_filterBank->blockSignals(true); + m_filterBank->setValue(channel, value); + m_filterBank->blockSignals(false); + +} diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index 51c1203..32bd7c7 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -3,14 +3,13 @@ #include #include -#include #include #include "defines.h" #include "slidergroup.h" #include "clickablelabel.h" #include "settings.h" - +#include "filterbankwidget.h" class AudioLayerWidget : public QWidget { @@ -20,6 +19,16 @@ public: explicit AudioLayerWidget(QWidget *parent = 0, int layer = 0); ~AudioLayerWidget(); + // From OLA -> LibreMediaServer -> AudioWidget + void setMediaFile(QString file); + void setDuration(float dur); + void setCurrentTime(float progress); + void setPlaybackStatus(Status status); + void setVol(float vol); + void setPan(int pan); + void setPitch(int pitch); + void setFilterParam(int channel, int value); + private: Status m_status; Status m_oldStatus; @@ -33,16 +42,9 @@ private: QTimeEdit *m_progressTime; QTimeEdit *m_totalTimeValue; QProgressBar *m_progress; + FilterBankWidget *m_filterBank; -// From DMX -public slots: - void setMediaFile(QString file); - void setDuration(float dur); - void setCurrentTime(float progress); - void setPlaybackStatus(Status status); - void setVol(float vol); - void setPan(int pan); - void setPitch(int pitch); +//public slots: // From Ui private slots: diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index e163da3..2f3b634 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -1,5 +1,6 @@ #include "audiowidget.h" -#include + +//#include AudioWidget::AudioWidget(QWidget *parent) : QWidget(parent) @@ -19,6 +20,8 @@ AudioWidget::AudioWidget(QWidget *parent) : m_layerUpdate[i].pan = 128; m_layerUpdate[i].pitch = 128; m_layerUpdate[i].cursor = 0; + for (int j = 0; j < FILTER_CHANNELS; j++) + m_filtersUpdate[i][j] = -1; } m_layout->setSpacing(0); m_layout->setContentsMargins(1, 1, 1, 1); @@ -68,7 +71,7 @@ void AudioWidget::refreshUi() for (uint i = 0; i < m_layers; i++) { if (m_layerUpdate[i].updated) { - QLayoutItem * const item = m_layout->itemAt(i); + QLayoutItem *item = m_layout->itemAt(i); AudioLayerWidget *alw = dynamic_cast(item->widget()); if (m_layerUpdate[i].vol > -1) { alw->setVol(m_layerUpdate[i].vol); @@ -95,7 +98,18 @@ void AudioWidget::refreshUi() alw->setDuration(m_layerUpdate[i].duration); m_layerUpdate[i].duration = -1; } + for (int j = 0; j < FILTER_CHANNELS; j++) { + if (m_filtersUpdate[i][j] > -1) + alw->setFilterParam(j, m_filtersUpdate[i][j]); + m_filtersUpdate[i][j] = -1; + } m_layerUpdate[i].updated = false; } } } + +void AudioWidget::filterParamChanged(int layer, int channel, int value) +{ + m_filtersUpdate[layer][channel - 9] = value; + m_layerUpdate[layer].updated = true; +} diff --git a/src/audiowidget.h b/src/audiowidget.h index c314656..6849f5e 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -2,6 +2,7 @@ #define AUDIOWIDGET_H #include +#include #include "audiolayerwidget.h" #include "settings.h" @@ -13,12 +14,14 @@ class AudioWidget : public QWidget public: AudioWidget(QWidget *parent = nullptr); + void filterParamChanged(int layer, int channel, int value); private: QHBoxLayout *m_layout; layerData m_layerUpdate[MAX_LAYERS]; QTimer *m_refreshUi; uint m_layers; + int m_filtersUpdate[MAX_LAYERS][FILTER_CHANNELS]; public slots: void volChanged(int layer, float vol); diff --git a/src/clickabledoublespinbox.cpp b/src/clickabledoublespinbox.cpp new file mode 100644 index 0000000..b2b9c3a --- /dev/null +++ b/src/clickabledoublespinbox.cpp @@ -0,0 +1,21 @@ +#include "clickabledoublespinbox.h" + +#include + +ClickableDoubleSpinBox::ClickableDoubleSpinBox(QWidget *parent) + : QDoubleSpinBox(parent) +{ + setFocusPolicy(Qt::NoFocus); + setButtonSymbols(QAbstractSpinBox::NoButtons); + setValue(-1); + setDecimals(1); + setAlignment(Qt::AlignHCenter); + setContentsMargins(0, 0, 0, 0); + setMaximumWidth(50); + this->setStyleSheet("border: 0px solid #5a4855;" + "width: 50px;" + "margin: 0px;" + "background-color: #383034;" + ); +} + diff --git a/src/clickabledoublespinbox.h b/src/clickabledoublespinbox.h new file mode 100644 index 0000000..81bcb76 --- /dev/null +++ b/src/clickabledoublespinbox.h @@ -0,0 +1,25 @@ +#ifndef CLICKABLEDOUBLESPINBOX_H +#define CLICKABLEDOUBLESPINBOX_H + +#include +#include +#include +#include + +class ClickableDoubleSpinBox : public QDoubleSpinBox +{ + Q_OBJECT +public: + explicit ClickableDoubleSpinBox(QWidget *parent = nullptr); +protected: + void mousePressEvent ( QMouseEvent * event ) { + if (event->button() == Qt::LeftButton) { + emit click(); + } + event->accept(); + } +signals: + void click(); +}; + +#endif // CLICKABLEDOUBLESPINBOX_H diff --git a/src/clickableslider.cpp b/src/clickableslider.cpp new file mode 100644 index 0000000..2c34478 --- /dev/null +++ b/src/clickableslider.cpp @@ -0,0 +1,3 @@ +#include "clickableslider.h" + +ClickableSlider::ClickableSlider(QWidget *parent) : QSlider{parent} {} diff --git a/src/clickableslider.h b/src/clickableslider.h new file mode 100644 index 0000000..af34c91 --- /dev/null +++ b/src/clickableslider.h @@ -0,0 +1,30 @@ +#ifndef CLICKABLESLIDER_H +#define CLICKABLESLIDER_H + +#include +#include +#include +#include + +class ClickableSlider : public QSlider +{ + Q_OBJECT +public: + ClickableSlider(QWidget *parent = nullptr); + +protected: + void mousePressEvent ( QMouseEvent * event ) + { + if (event->button() == Qt::RightButton) + { + if (this->isEnabled()) { + qDebug() << "disabling slider"; + this->setDisabled(true); + } + event->accept(); + } + QSlider::mousePressEvent(event); + } +}; + +#endif // CLICKABLESLIDER_H diff --git a/src/defines.h b/src/defines.h index b4560a8..68c72f5 100644 --- a/src/defines.h +++ b/src/defines.h @@ -9,6 +9,7 @@ #define MAX_AUDIODEVICES 8 #define UI_REFRESH_TIME 100 #define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks +#define FILTER_CHANNELS 13 // number of dmx channels dedicated to filters by layer struct dmxSetting { int address; diff --git a/src/dmxPersonality.h b/src/dmxPersonality.h index b083ae6..9f965be 100644 --- a/src/dmxPersonality.h +++ b/src/dmxPersonality.h @@ -27,4 +27,24 @@ #define SEND2 23 #define LAYER_CHANNELS 24 +constexpr const char* dmxChannelToString(int e) noexcept +{ + switch (e) { + case HP_FREQ: return "High Pass Cutoff Frec"; + case LOW_FREQ: return "Low Cutoff Frec"; + case LOW_Q: return "Low Slope"; + case LOW_GAIN: return "Low Gain"; + case MIDLOW_FREQ: return "Mid Low Frec"; + case MIDLOW_Q: return "Mid Low Q"; + case MIDLOW_GAIN: return "Mid Low Gain"; + case MIDHIGH_FREQ: return "Mid High Frec"; + case MIDHIGH_Q: return "Mid High Q"; + case MIDHIGH_GAIN: return "Mid High Gain"; + case HIGH_FREQ: return "High Cutoff Frec"; + case HIGH_Q: return "High Slope"; + case HIGH_GAIN: return "High Gain"; + default: return "++--++--++"; + } +} + #endif // DMXPERSONALITY_H diff --git a/src/filterbankwidget.cpp b/src/filterbankwidget.cpp new file mode 100644 index 0000000..276b7f2 --- /dev/null +++ b/src/filterbankwidget.cpp @@ -0,0 +1,82 @@ +#include "filterbankwidget.h" + +#include +#include "dmxPersonality.h" + +FilterBankWidget::FilterBankWidget(QWidget *parent) + : QWidget{parent} +{ + QHBoxLayout *layout = new QHBoxLayout; + layout->setAlignment(Qt::AlignHCenter); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + this->setStyleSheet("border: 1px solid #5a4855;" + "margin: 0px;" + "background-color: #383034;" + ); + for (int i = 0; i < 13; i++) { + fb[i] = new ClickableDoubleSpinBox; + const char *name = dmxChannelToString(i + 9); + fb[i]->setObjectName(name); + fb[i]->setToolTip(name); + } + fb[0]->setRange(0, 500); + layout->insertWidget(0, fb[0]); + for (int i = 1; i < 13;) { + QVBoxLayout *filterLayout= new QVBoxLayout; + for (int j = i; j < i + 3; j++) { + if ((j - 1) % 3 == 0) + fb[j]->setRange(0, 24000); + else if ((i - 1) % 3 == 1) { + fb[j]->setRange(0, 10); + } else { + fb[j]->setRange(-50, 50); + fb[j]->setMinimum(-50); + fb[j]->setValue(-8); + } + filterLayout->insertWidget(j, fb[j]); + } + filterLayout->setSpacing(0); + filterLayout->setAlignment(Qt::AlignHCenter); + filterLayout->setContentsMargins(0, 0, 0, 0); + layout->addLayout(filterLayout); + i += 3; + } + setLayout(layout); +} + +void FilterBankWidget::setValue(int filter, int value) +{ + double result = 0; + int channel = filter + 9; + + if (channel == HP_FREQ) { + result = double((value * 1.31) + 16.0f); // 16 - 350 + } else if (channel == LOW_FREQ) { + result = 30 + (value * 1.647); // 30 - 450 + } else if (channel == LOW_Q) { + result = (double)(value / 32.0f) + 0.1f; // 0.1 - 8 + } else if (channel == LOW_GAIN) { + result = (double)(value / 21.25f) - 6.023528412f; + } else if (channel == MIDLOW_FREQ) { + result = 200 + (value * 9.019607843); // 200 - 450 + } else if (channel == MIDLOW_Q) { + result = (double)( value / 64.0f) + 0.10; // 0.1 - 4 + } else if (channel == MIDLOW_GAIN) { + result = (double)(value / 7.0833333333333f) - 18.0f; + } else if (channel == MIDHIGH_FREQ) { + result = 600 + (value * 25.09803922); // 600 - 7000 + } else if (channel == MIDHIGH_Q) { + result = (double)( value / 64.0f) + 0.10; // 0.1 - 4 + } else if (channel == MIDHIGH_GAIN) { + result = (double)(value / 7.0833333333333f) - 18.0f; + } else if (channel == HIGH_FREQ) { + result = 1500 + (value * 56.8627451); // 1500 - 16000 + } else if (channel == HIGH_Q) { + result = (double)( value / 32.0f) + 0.1f; + } else if (channel == HIGH_GAIN) { + result = (double)(value / 21.25) - 6.023528412f; + } + fb[filter]->setValue(result); + qDebug() << "filter " << filter << " " << result; +} diff --git a/src/filterbankwidget.h b/src/filterbankwidget.h new file mode 100644 index 0000000..07f2e9b --- /dev/null +++ b/src/filterbankwidget.h @@ -0,0 +1,22 @@ +#ifndef FILTERBANKWIDGET_H +#define FILTERBANKWIDGET_H + +#include +#include +#include "clickabledoublespinbox.h" + + +class FilterBankWidget : public QWidget +{ + Q_OBJECT +public: + explicit FilterBankWidget(QWidget *parent = nullptr); + ClickableDoubleSpinBox *fb[13]; + void setValue(int filter, int value); + + +signals: + +}; + +#endif // FILTERBANKWIDGET_H diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 9366935..0c42e86 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -142,6 +142,13 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) #endif } else if (channel >= HP_FREQ && channel <= HIGH_GAIN) { m_mae.filterParamChanged(layer, m_dmxSettings.at(layer).audioDevice, channel, value); +#ifndef NOGUI + if (m_ui) { + m_lmsUi->m_aw->filterParamChanged(layer, channel, value); + m_played.clear(); + m_played.append(m_ola->getValue(layer, DMX_FILE)); + } +#endif } } #ifndef NOGUI diff --git a/src/slidergroup.cpp b/src/slidergroup.cpp index 4395a8d..c8e267d 100644 --- a/src/slidergroup.cpp +++ b/src/slidergroup.cpp @@ -1,16 +1,7 @@ #include "slidergroup.h" -#include -#include -DoubleSpinBoxClickable::DoubleSpinBoxClickable(QWidget *parent) - : QDoubleSpinBox{parent} {} - -DoubleSpinBoxClickable::~DoubleSpinBoxClickable() {} - -SliderClickDisable::SliderClickDisable(QWidget *parent) - : QSlider{parent} {} - -SliderClickDisable::~SliderClickDisable() {} +#include +#include SliderGroup::SliderGroup(QString name, int min, @@ -56,7 +47,7 @@ SliderGroup::SliderGroup(QString 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())); + connect(&valueBox, SIGNAL(click()), this, SLOT(enableSlider())); layout->addWidget(&slider); layout->addWidget(&valueBox); this->setStyleSheet("border: 1px solid #5a4855;" diff --git a/src/slidergroup.h b/src/slidergroup.h index b6940b1..39843bc 100644 --- a/src/slidergroup.h +++ b/src/slidergroup.h @@ -1,87 +1,16 @@ #ifndef SLIDERGROUP_H #define SLIDERGROUP_H -#include -#include -#include -#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); - } -}; +#include "clickabledoublespinbox.h" +#include "clickableslider.h" class SliderGroup : public QWidget { Q_OBJECT - public: SliderGroup(QString name, int min, @@ -97,8 +26,8 @@ public slots: void sliderValueChanged(int value); private: - SliderClickDisable slider; - DoubleSpinBoxClickable valueBox; + ClickableSlider slider; + ClickableDoubleSpinBox valueBox; private slots: void enableSlider() { slider.setEnabled(true); } -- 2.39.5 From 14ac167dfbb869a1527a185c3e6c5eef6954d6c9 Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 15 May 2024 18:30:15 +0200 Subject: [PATCH 35/49] cleaning --- src/audiolayerwidget.cpp | 3 +-- src/filterbankwidget.cpp | 7 +++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index b2f2782..3c81f6c 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -13,7 +13,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): QVBoxLayout *playback = new QVBoxLayout; m_folderValue = new ClickableLabel; - m_folderValue->setMaximumWidth(160); + m_folderValue->setMaximumWidth(300); m_folderValue->setAlignment(Qt::AlignLeft); m_folderValue->setStyleSheet( "color: white;" @@ -53,7 +53,6 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_progressTime->setReadOnly(true); m_progressTime->setButtonSymbols(QAbstractSpinBox::NoButtons); m_progressTime->setMinimumWidth(80); - //m_progressTime->setMaximumWidth(80); m_progressTime->setFocusPolicy(Qt::NoFocus); m_progressTime->setAlignment(Qt::AlignHCenter); m_progressTime->setContentsMargins(0,0,0,0); diff --git a/src/filterbankwidget.cpp b/src/filterbankwidget.cpp index 276b7f2..c07453a 100644 --- a/src/filterbankwidget.cpp +++ b/src/filterbankwidget.cpp @@ -8,10 +8,12 @@ FilterBankWidget::FilterBankWidget(QWidget *parent) { QHBoxLayout *layout = new QHBoxLayout; layout->setAlignment(Qt::AlignHCenter); - layout->setContentsMargins(0, 0, 0, 0); + layout->setContentsMargins(0, 2, 0, 2); layout->setSpacing(0); this->setStyleSheet("border: 1px solid #5a4855;" "margin: 0px;" + "margin-top: 2px;" + "margin-bottom: 2px;" "background-color: #383034;" ); for (int i = 0; i < 13; i++) { @@ -31,8 +33,6 @@ FilterBankWidget::FilterBankWidget(QWidget *parent) fb[j]->setRange(0, 10); } else { fb[j]->setRange(-50, 50); - fb[j]->setMinimum(-50); - fb[j]->setValue(-8); } filterLayout->insertWidget(j, fb[j]); } @@ -78,5 +78,4 @@ void FilterBankWidget::setValue(int filter, int value) result = (double)(value / 21.25) - 6.023528412f; } fb[filter]->setValue(result); - qDebug() << "filter " << filter << " " << result; } -- 2.39.5 From d94f874259cd4a18a6f3e8294f6ff512bd22daf4 Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 15 May 2024 19:28:30 +0200 Subject: [PATCH 36/49] =?UTF-8?q?resuelve=20glitch=20cuando=20no=20empieza?= =?UTF-8?q?=20en=20cero,=20parece=20que=20se=20queda=20en=20alguna=20cach?= =?UTF-8?q?=C3=A9=20intermedia=20unos=20frames=20guardados=20que=20no=20s?= =?UTF-8?q?=C3=A9=20flushear...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/defines.h | 2 +- src/miniaudioengine.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/defines.h b/src/defines.h index 68c72f5..23d3322 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,7 +1,7 @@ #ifndef DEFINES_H #define DEFINES_H -#define VERSION "LibreMediaServerAudio 0.2.0 Antigona Release" +#define VERSION "LibreMediaServerAudio v0.2.0 Antigona" #define COPYRIGHT "(C) 2014-2024 Santi Noreña " #define LICENSE "GPL 3 Licensed. See LICENSE.txt." #define DEFAULT_FILE "lms-audio.xlm" diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 9dbd3c8..6bdeb2d 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -376,7 +376,10 @@ ma_result MiniAudioEngine::playbackChanged(int layer, Status status) ma_sound_set_stop_time_in_milliseconds(&m_currentSound[layer], ~(ma_uint64)0); ma_sound_set_looping(&m_currentSound[layer], loop); result = ma_sound_start(&m_currentSound[layer]); - //this->volChanged(layer, m_currentLayerValues[layer].vol); // glitch when seek to cursor, how flush the audio buffer? + if (m_currentLayerValues[layer].cursor != 0) { + usleep(1000 * 50); // Avoid small glitch at start, how to flush the cached buffers in audio pipe line? + } + this->volChanged(layer, m_currentLayerValues[layer].vol); default: break; } -- 2.39.5 From 27c7969df38cfbc8c46c15fb30c2bff7a9d1b6c7 Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 15 May 2024 20:29:24 +0200 Subject: [PATCH 37/49] true bypass en filterBank --- src/audiolayerwidget.cpp | 7 +++++++ src/audiolayerwidget.h | 1 + src/defines.h | 1 + src/filterbankwidget.cpp | 15 ++++++++++++++- src/filterbankwidget.h | 6 +++++- src/libremediaserver-audio.cpp | 2 ++ src/miniaudioengine.cpp | 35 ++++++++++++++++++++++++++++++++-- src/miniaudioengine.h | 2 ++ 8 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 3c81f6c..c3b1f86 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -72,6 +72,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): layout->addLayout(status); m_filterBank = new FilterBankWidget(this); + connect(m_filterBank, SIGNAL(setBypass(bool)), this, SLOT(setBypass(bool))); layout->addWidget(m_filterBank); QVBoxLayout *volumeBox = new QVBoxLayout; @@ -111,6 +112,12 @@ void AudioLayerWidget::pitchChanged(int value) emit(uiSliderChanged(m_layer, Slider::Pitch, value)); } +void AudioLayerWidget::setBypass(bool value) +{ + emit(uiSliderChanged(m_layer, Slider::Bypass, value)); +} + + void AudioLayerWidget::toggleSuspendResume() { switch (m_status) { diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index 32bd7c7..f3ba1e4 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -53,6 +53,7 @@ private slots: void volumeChanged(int vol); void panChanged(int pan); void pitchChanged(int pitch); + void setBypass(bool value); signals: void uiPlaybackChanged(int layer, Status s); diff --git a/src/defines.h b/src/defines.h index 23d3322..0c78cd9 100644 --- a/src/defines.h +++ b/src/defines.h @@ -64,6 +64,7 @@ enum Slider Volume, Pan, Pitch, + Bypass }; #include diff --git a/src/filterbankwidget.cpp b/src/filterbankwidget.cpp index c07453a..e3e9790 100644 --- a/src/filterbankwidget.cpp +++ b/src/filterbankwidget.cpp @@ -22,8 +22,13 @@ FilterBankWidget::FilterBankWidget(QWidget *parent) fb[i]->setObjectName(name); fb[i]->setToolTip(name); } + QVBoxLayout *master = new QVBoxLayout; fb[0]->setRange(0, 500); - layout->insertWidget(0, fb[0]); + m_bypass = new QCheckBox; + connect(m_bypass, SIGNAL(stateChanged(int)), this, SLOT(bypassChanged(int))); + master->addWidget(m_bypass); + master->addWidget(fb[0]); + layout->addLayout(master); for (int i = 1; i < 13;) { QVBoxLayout *filterLayout= new QVBoxLayout; for (int j = i; j < i + 3; j++) { @@ -79,3 +84,11 @@ void FilterBankWidget::setValue(int filter, int value) } fb[filter]->setValue(result); } + +void FilterBankWidget::bypassChanged(int value) +{ + if (value == 0) + emit setBypass(false); + else + emit setBypass(true); +} diff --git a/src/filterbankwidget.h b/src/filterbankwidget.h index 07f2e9b..bb36ef2 100644 --- a/src/filterbankwidget.h +++ b/src/filterbankwidget.h @@ -3,6 +3,7 @@ #include #include +#include #include "clickabledoublespinbox.h" @@ -12,11 +13,14 @@ class FilterBankWidget : public QWidget public: explicit FilterBankWidget(QWidget *parent = nullptr); ClickableDoubleSpinBox *fb[13]; + QCheckBox *m_bypass; void setValue(int filter, int value); +private slots: + void bypassChanged(int value); signals: - + void setBypass(bool value); }; #endif // FILTERBANKWIDGET_H diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 0c42e86..2916007 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -249,6 +249,8 @@ void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value) case Slider::Pitch: m_mae.pitchChanged(layer, value); break; + case Slider::Bypass: + m_mae.setBypass(m_dmxSettings.at(layer).audioDevice, layer, value); } } diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 6bdeb2d..adce7ac 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -65,6 +65,13 @@ 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_splitter_node_config splitterConfig = ma_splitter_node_config_init(CHANNELS); + result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->input); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to initialize input node." << endl; + return result; + } + 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) { @@ -100,13 +107,23 @@ ma_result MiniAudioEngine::createFilterBank(int id, uint layer) return result; } - 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 initialize output node." << endl; return result; } + result = ma_node_attach_output_bus(&fb->input, 0, &fb->hpf, 0); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach input node." << endl; + return result; + } + result = ma_node_attach_output_bus(&fb->input, 1, &fb->output, 0); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach high pass pass filter node." << endl; + return result; + } + ma_node_set_output_bus_volume(&fb->input, 1, 0.0f); 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; @@ -256,7 +273,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].hpf, 0); + result = ma_node_attach_output_bus(&m_currentSound[layer], 0, &m_filterBank[audioDevice][layer].input, 0); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to attach output bus " << audioDevice << endl; //return result; @@ -526,3 +543,17 @@ ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int ch } return (result); } + +bool MiniAudioEngine::setBypass(int audioDevice, int layer, bool bypass) +{ + filterBank *fb = &m_filterBank[audioDevice][layer]; + + if (bypass) { + ma_node_set_output_bus_volume(&fb->input, 1, 1.0f); + ma_node_set_output_bus_volume(&fb->input, 0, 0.0f); + } else { + ma_node_set_output_bus_volume(&fb->input, 1, 0.0f); + ma_node_set_output_bus_volume(&fb->input, 0, 1.0f); + } + +} diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 332c1bf..b55311b 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -19,6 +19,7 @@ using namespace std; typedef struct { + ma_splitter_node input; ma_hpf_node hpf; ma_hpf_node_config hpfConfig; ma_loshelf_node loshelf; @@ -43,6 +44,7 @@ public: bool startEngine(uint layersQty); bool startDevice(uint *id, uint nb); static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); + bool setBypass(int audioDevice, int layer, bool bypass); protected: ma_result loadMedia(int layer, char *media, uint audioDevice); -- 2.39.5 From 7aced09a0218a6421fa000384e33ae80eb76151c Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 15 May 2024 22:36:46 +0200 Subject: [PATCH 38/49] style bypass checkbox --- src/filterbankwidget.cpp | 23 +++++++++++++++++++---- src/libremediaserver-audio-gui.cpp | 2 +- src/miniaudioengine.cpp | 9 +++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/filterbankwidget.cpp b/src/filterbankwidget.cpp index e3e9790..aafa6fb 100644 --- a/src/filterbankwidget.cpp +++ b/src/filterbankwidget.cpp @@ -10,10 +10,10 @@ FilterBankWidget::FilterBankWidget(QWidget *parent) layout->setAlignment(Qt::AlignHCenter); layout->setContentsMargins(0, 2, 0, 2); layout->setSpacing(0); - this->setStyleSheet("border: 1px solid #5a4855;" + this->setStyleSheet("border: 2px solid #5a4855;" "margin: 0px;" - "margin-top: 2px;" - "margin-bottom: 2px;" + "margin-top: 3px;" + "margin-bottom: 3px;" "background-color: #383034;" ); for (int i = 0; i < 13; i++) { @@ -25,8 +25,23 @@ FilterBankWidget::FilterBankWidget(QWidget *parent) QVBoxLayout *master = new QVBoxLayout; fb[0]->setRange(0, 500); m_bypass = new QCheckBox; - connect(m_bypass, SIGNAL(stateChanged(int)), this, SLOT(bypassChanged(int))); master->addWidget(m_bypass); + m_bypass->setText("Bypass"); + m_bypass->setStyleSheet("QCheckBox { border: 2px solid #2a0825;" + "text-align: left top;" + "margin: 0px;" + "background-color: #885074;" + "font-size: 7px;}" + "QCheckBox::indicator { subcontrol-position: right top;" + "width: 30px;" + "height: 30px;" + "background-color: gray;" + "border-radius: 15px;" + "border-style: solid;" + "border-width: 1px;" + "border-color: white white black black;" + ); + connect(m_bypass, SIGNAL(stateChanged(int)), this, SLOT(bypassChanged(int))); master->addWidget(fb[0]); layout->addLayout(master); for (int i = 1; i < 13;) { diff --git a/src/libremediaserver-audio-gui.cpp b/src/libremediaserver-audio-gui.cpp index b769679..22f673c 100644 --- a/src/libremediaserver-audio-gui.cpp +++ b/src/libremediaserver-audio-gui.cpp @@ -35,7 +35,7 @@ libreMediaServerAudioUi::libreMediaServerAudioUi(QWidget *parent) topWidget->setContentsMargins(0, 0, 0, 0); addDockWidget(Qt::TopDockWidgetArea, topWidget); connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup())); - this->setContentsMargins(5, 5, 5, 5); + this->setContentsMargins(3, 3, 3, 3); this->setStyleSheet( "color: white;" "background-color: #4f4048;" diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index adce7ac..888163b 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -165,6 +165,15 @@ ma_result MiniAudioEngine::setNodeGraph(int id) { result = this->createFilterBank(id, i); i++; } + //ma_node_graph *ng = ma_engine_get_node_graph(&m_engine[id]); + //ma_node *endpoint = ma_engine_get_endpoint(&m_engine[id]); + for (uint i = 0; i < m_layersQty; i++) { + result = ma_node_attach_output_bus(&m_filterBank[0][i].output, 0, &m_filterBank[1][i].output, 0); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach aux send." << endl; + //return result; + } + } return (result); } -- 2.39.5 From fc274179ad4cb6613fac27eb8bd07c95cd5bf020 Mon Sep 17 00:00:00 2001 From: snt Date: Sat, 18 May 2024 22:52:22 +0200 Subject: [PATCH 39/49] =?UTF-8?q?funcionando=20en=20dos=20dispositivos=20m?= =?UTF-8?q?ediante=20ring=20buffer,=20pero=20no=20puedo=20mandar=20a=20dos?= =?UTF-8?q?=20dispositivos,=20si=20lo=20pongo=20con=20ma=5Fsplitter=20repr?= =?UTF-8?q?oduce=20m=C3=A1s=20r=C3=A1pido=20y=20con=20glitches=20mandar=20?= =?UTF-8?q?diferentes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libremediaserver-audio.pro | 7 +- src/defines.h | 54 +++++------- src/dmxPersonality.h | 8 +- src/filterbankwidget.cpp | 12 +-- src/ma_writer_node.c | 175 +++++++++++++++++++++++++++++++++++++ src/ma_writer_node.h | 52 +++++++++++ src/miniaudioengine.cpp | 142 +++++++++++++++++++++++------- src/miniaudioengine.h | 30 +++++-- 8 files changed, 390 insertions(+), 90 deletions(-) create mode 100644 src/ma_writer_node.c create mode 100644 src/ma_writer_node.h diff --git a/libremediaserver-audio.pro b/libremediaserver-audio.pro index 0371808..391f2c9 100644 --- a/libremediaserver-audio.pro +++ b/libremediaserver-audio.pro @@ -8,9 +8,11 @@ HEADERS += src/libremediaserver-audio.h \ src/dmxwidget.h \ src/filterbankwidget.h \ src/libremediaserver-audio-gui.h \ + src/ma_writer_node.h \ src/main.h \ - src/miniaudio.h \ src/medialibrary.h \ + src/miniaudio.h \ + src/ma_writer_node.h \ src/miniaudioengine.h \ src/olathread.h \ src/audiolayerwidget.h \ @@ -26,10 +28,11 @@ SOURCES += src/main.cpp \ src/dmxwidget.cpp \ src/filterbankwidget.cpp \ src/libremediaserver-audio-gui.cpp \ - src/miniaudio.c \ src/libremediaserver-audio.cpp \ src/medialibrary.cpp \ + src/miniaudio.c \ src/miniaudioengine.cpp \ + src/ma_writer_node.c \ src/olathread.cpp \ src/audiolayerwidget.cpp \ src/audiowidget.cpp \ diff --git a/src/defines.h b/src/defines.h index 0c78cd9..5f73abe 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,15 +1,18 @@ #ifndef DEFINES_H #define DEFINES_H -#define VERSION "LibreMediaServerAudio v0.2.0 Antigona" -#define COPYRIGHT "(C) 2014-2024 Santi Noreña " -#define LICENSE "GPL 3 Licensed. See LICENSE.txt." -#define DEFAULT_FILE "lms-audio.xlm" -#define MAX_LAYERS 4 -#define MAX_AUDIODEVICES 8 -#define UI_REFRESH_TIME 100 -#define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks -#define FILTER_CHANNELS 13 // number of dmx channels dedicated to filters by layer +#define VERSION "LibreMediaServerAudio v0.2.0 Antigona" +#define COPYRIGHT "(C) 2014-2024 Santi Noreña " +#define LICENSE "GPL3 Licensed. See LICENSE.txt." +#define DEFAULT_FILE "lms-audio.xlm" +#define MAX_LAYERS 4 +#define MAX_AUDIODEVICES 8 +#define FORMAT ma_format_f32 /* Must always be f32. */ +#define CHANNELS 2 +#define SAMPLE_RATE 48000 +#define UI_REFRESH_TIME 100 +#define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks +#define FILTER_CHANNELS 13 // number of dmx channels dedicated to filters by layer struct dmxSetting { int address; @@ -18,7 +21,7 @@ struct dmxSetting { int audioDevice; }; -enum class Status +enum Status { Stopped, Paused, @@ -30,6 +33,15 @@ enum class Status PlayingFolderRandom }; +enum Slider +{ + Volume, + Pan, + Pitch, + Bypass +}; + +#ifdef __cplusplus constexpr const char* statusToString(Status e) noexcept { switch (e) @@ -45,27 +57,6 @@ constexpr const char* statusToString(Status e) noexcept default: return "--++--"; } } -/* -static const char* StatusStr[] = -{ - "Stop", - "Pause", - "Play One", - "Play One Loop", - "Iddle", - "Play Folder", - "Play Folder Loop", - "Play Folder Rand", - 0x0 -};*/ - -enum Slider -{ - Volume, - Pan, - Pitch, - Bypass -}; #include struct layerData { @@ -81,4 +72,5 @@ struct layerData { unsigned int universe; int device; }; +#endif // __cplusplus #endif // DEFINES_H diff --git a/src/dmxPersonality.h b/src/dmxPersonality.h index 9f965be..1da964a 100644 --- a/src/dmxPersonality.h +++ b/src/dmxPersonality.h @@ -23,9 +23,10 @@ #define HIGH_FREQ 19 #define HIGH_Q 20 #define HIGH_GAIN 21 -#define SEND1 22 -#define SEND2 23 -#define LAYER_CHANNELS 24 +#define FILTER_BANK_GAIN 22 // not implemented yet +#define SEND1 23 +#define SEND2 24 +#define LAYER_CHANNELS 25 constexpr const char* dmxChannelToString(int e) noexcept { @@ -43,6 +44,7 @@ constexpr const char* dmxChannelToString(int e) noexcept case HIGH_FREQ: return "High Cutoff Frec"; case HIGH_Q: return "High Slope"; case HIGH_GAIN: return "High Gain"; + case FILTER_BANK_GAIN: return "Post Filters Gain"; default: return "++--++--++"; } } diff --git a/src/filterbankwidget.cpp b/src/filterbankwidget.cpp index aafa6fb..c9b107d 100644 --- a/src/filterbankwidget.cpp +++ b/src/filterbankwidget.cpp @@ -28,19 +28,9 @@ FilterBankWidget::FilterBankWidget(QWidget *parent) master->addWidget(m_bypass); m_bypass->setText("Bypass"); m_bypass->setStyleSheet("QCheckBox { border: 2px solid #2a0825;" - "text-align: left top;" "margin: 0px;" "background-color: #885074;" - "font-size: 7px;}" - "QCheckBox::indicator { subcontrol-position: right top;" - "width: 30px;" - "height: 30px;" - "background-color: gray;" - "border-radius: 15px;" - "border-style: solid;" - "border-width: 1px;" - "border-color: white white black black;" - ); + "font-size: 7px;}"); connect(m_bypass, SIGNAL(stateChanged(int)), this, SLOT(bypassChanged(int))); master->addWidget(fb[0]); layout->addLayout(master); diff --git a/src/ma_writer_node.c b/src/ma_writer_node.c new file mode 100644 index 0000000..e05d38d --- /dev/null +++ b/src/ma_writer_node.c @@ -0,0 +1,175 @@ +#include "ma_writer_node.h" +#include "miniaudio.c" +MA_API ma_writer_node_config ma_writer_node_config_init(ma_uint32 channels, ma_uint32 bufferSizeInFrames, ma_pcm_rb *rb) +{ + ma_writer_node_config config; + + MA_ZERO_OBJECT(&config); + config.nodeConfig = ma_node_config_init(); + config.channels = channels; + config.bufferSizeInFrames = bufferSizeInFrames; + config.pBuffer = rb; + + return config; +} + +static void ma_writer_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_writer_node* pWriteNode = (ma_writer_node*)pNode; + + MA_ASSERT(pWriteNode != NULL); + MA_ASSERT(ma_node_get_input_bus_count(&pWriteNode->baseNode) == 1); + + if (*pFrameCountIn > 0) { + void *pWriteBuffer = NULL; + ma_pcm_rb_acquire_write(pWriteNode->pBuffer, pFrameCountIn, &pWriteBuffer); + if (pWriteBuffer != NULL) { + ma_copy_pcm_frames(pWriteBuffer, ppFramesIn[0], *pFrameCountIn, ma_format_f32, pWriteNode->channels); + ma_pcm_rb_commit_write(pWriteNode->pBuffer, *pFrameCountIn); + } + //ma_silence_pcm_frames(ppFramesOut[0], *pFrameCountOut, ma_format_f32, pWriteNode->channels); + } + //*pFrameCountOut = 0; + ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, ma_format_f32, pWriteNode->channels); +} + +static ma_node_vtable g_ma_writer_node_vtable = +{ + ma_writer_node_process_pcm_frames, + NULL, + 1, + 1, + 0 +// MA_NODE_FLAG_CONTINUOUS_PROCESSING +// MA_NODE_FLAG_SILENT_OUTPUT +}; + +MA_API ma_result ma_writer_node_init(ma_node_graph* pNodeGraph, const ma_writer_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_writer_node* pWriteNode) +{ + ma_result result; + ma_node_config baseConfig; + + if (pWriteNode == NULL || pConfig == NULL || pConfig->pBuffer == NULL \ + || (pConfig->channels > MA_MAX_NODE_BUS_COUNT) ) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pWriteNode); + + baseConfig = pConfig->nodeConfig; + baseConfig.vtable = &g_ma_writer_node_vtable; + baseConfig.pInputChannels = &pConfig->channels; + baseConfig.pOutputChannels = &pConfig->channels; + + result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pWriteNode->baseNode); + if (result != MA_SUCCESS) { + return result; + } + pWriteNode->bufferSizeInFrames = pConfig->bufferSizeInFrames; + pWriteNode->pBuffer = pConfig->pBuffer; + pWriteNode->channels = pConfig->channels; + return MA_SUCCESS; +} + +MA_API void ma_writer_node_uninit(ma_writer_node* pWriteNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_node_uninit(&pWriteNode->baseNode, pAllocationCallbacks); +} + +/* + * Data Source Ring Buffer + */ + + +ma_result ma_data_source_rb_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +{ + ma_data_source_rb* ds = (ma_data_source_rb*)pDataSource; + + ma_uint32 pcmFramesAvailableInRB = 0; + ma_uint32 pcmFramesProcessed = 0; + // lo mismo que en el callback, va el doble de rápido y con glitches. + while (pcmFramesProcessed < frameCount) { + pcmFramesAvailableInRB = ma_pcm_rb_available_read(ds->rb); + if (pcmFramesAvailableInRB == 0) { + break; + } + ma_uint32 framesToRead = frameCount - pcmFramesProcessed; + if (framesToRead > pcmFramesAvailableInRB) { + framesToRead = pcmFramesAvailableInRB; + } + void* pReadBuffer = NULL; + ma_pcm_rb_acquire_read(ds->rb, &framesToRead, &pReadBuffer); + if (pReadBuffer != NULL) { + ma_copy_pcm_frames(pFramesOut, pReadBuffer, framesToRead, ma_format_f32, 2); + ma_pcm_rb_commit_read(ds->rb, framesToRead); + pcmFramesProcessed += framesToRead; + } + else { + break; + } + } + *pFramesRead += pcmFramesProcessed; + return MA_SUCCESS; +} + +ma_result ma_data_source_rb_seek(ma_data_source* pDataSource, ma_uint64 frameIndex) +{ + (void)pDataSource; + (void)frameIndex; + return MA_NOT_IMPLEMENTED; +} + +ma_result ma_data_source_rb_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) +{ + (void)pDataSource; + *pFormat = ma_format_f32; + *pChannels = 2; + *pSampleRate = ma_standard_sample_rate_48000; + return MA_SUCCESS; +} + +ma_result ma_data_source_rb_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor) +{ + (void)pDataSource; + *pCursor = 0; + return MA_NOT_IMPLEMENTED; +} + +ma_result ma_data_source_rb_get_length(ma_data_source* pDataSource, ma_uint64* pLength) +{ + (void)pDataSource; + *pLength = 0; + return MA_NOT_IMPLEMENTED; +} + +ma_data_source_vtable g_ma_data_source_rb_vtable = +{ + ma_data_source_rb_read, + ma_data_source_rb_seek, + ma_data_source_rb_get_data_format, + ma_data_source_rb_get_cursor, + ma_data_source_rb_get_length +}; + +ma_result ma_data_source_rb_init(ma_data_source_rb* pMyDataSource, ma_pcm_rb *ringBuffer) +{ + ma_result result; + ma_data_source_config baseConfig; + + baseConfig = ma_data_source_config_init(); + baseConfig.vtable = &g_ma_data_source_rb_vtable; + + result = ma_data_source_init(&baseConfig, &pMyDataSource->base); + if (result != MA_SUCCESS) { + return result; + } + + pMyDataSource->rb = ringBuffer; + + return MA_SUCCESS; +} + +void ma_data_source_rb_uninit(ma_data_source_rb* pMyDataSource) +{ + ma_data_source_uninit(&pMyDataSource->base); +} diff --git a/src/ma_writer_node.h b/src/ma_writer_node.h new file mode 100644 index 0000000..1b5d259 --- /dev/null +++ b/src/ma_writer_node.h @@ -0,0 +1,52 @@ +/* Include ma_writer_node.h after miniaudio.h */ +#ifndef ma_writer_node_h +#define ma_writer_node_h + +#ifdef __cplusplus +extern "C" { +#endif + +#include "miniaudio.h" + +typedef struct +{ + ma_node_config nodeConfig; + ma_uint32 channels; + ma_uint32 bufferSizeInFrames; + ma_pcm_rb *pBuffer; +} ma_writer_node_config; + +MA_API ma_writer_node_config ma_writer_node_config_init(ma_uint32 channels, ma_uint32 bufferSizeInFrames, ma_pcm_rb *rb); + +typedef struct +{ + ma_node_base baseNode; + ma_uint32 bufferSizeInFrames; + ma_pcm_rb *pBuffer; + ma_uint32 channels; +} ma_writer_node; + +MA_API ma_result ma_writer_node_init(ma_node_graph* pNodeGraph, const ma_writer_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_writer_node* pWriteNode); +MA_API void ma_writer_node_uninit(ma_writer_node* pWriteNode, const ma_allocation_callbacks* pAllocationCallbacks); +/** + * data source ring buffer + */ + +typedef struct +{ + ma_data_source_base base; + ma_pcm_rb *rb; +} ma_data_source_rb; + +ma_result ma_data_source_rb_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); +ma_result ma_data_source_rb_seek(ma_data_source* pDataSource, ma_uint64 frameIndex); +ma_result ma_data_source_rb_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); +ma_result ma_data_source_rb_get_cursor(ma_data_source* pDataSource, ma_uint64* pCursor); +ma_result ma_data_source_rb_get_length(ma_data_source* pDataSource, ma_uint64* pLength); +ma_result ma_data_source_rb_init(ma_data_source_rb* pMyDataSource, ma_pcm_rb *ringBuffer); +void ma_data_source_rb_uninit(ma_data_source_rb* pMyDataSource); + +#ifdef __cplusplus +} +#endif +#endif /* ma_writer_node_h */ diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 888163b..914708d 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -4,16 +4,48 @@ #define BIAS 0.99f #define FILTER_ORDER 3 +static ma_pcm_rb aux1Buffer; +static ma_data_source_node g_dataSupplyNode; +static ma_data_source_rb g_dataSourceRB; + MiniAudioEngine::MiniAudioEngine() {} void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { - (void)pInput; ma_result result; + result = ma_engine_read_pcm_frames((ma_engine*)pDevice->pUserData, pOutput, frameCount, NULL); if (result != MA_SUCCESS) { cout << "Error " << result << ": error audio callback."; } + (void)pInput; +} + +void MiniAudioEngine::audioDataCallback1(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) +{ + (void)pDevice; + ma_result result; + + ma_uint32 pcmFramesAvailableInRB = 0; + ma_uint32 pcmFramesProcessed = 0; + while (pcmFramesProcessed < frameCount) { + pcmFramesAvailableInRB = ma_pcm_rb_available_read(&aux1Buffer); + if (pcmFramesAvailableInRB == 0) { + break; + } + ma_uint32 framesToRead = frameCount - pcmFramesProcessed; + if (framesToRead > pcmFramesAvailableInRB) { + framesToRead = pcmFramesAvailableInRB; + } + void* pReadBuffer = NULL; + ma_pcm_rb_acquire_read(&aux1Buffer, &framesToRead, &pReadBuffer); + if (pReadBuffer != NULL) { + ma_copy_pcm_frames(pOutput, pReadBuffer, framesToRead, FORMAT, CHANNELS); + ma_pcm_rb_commit_read(&aux1Buffer, framesToRead); + pcmFramesProcessed += framesToRead; + }/* else { break; }*/ + } + (void)pInput; } void MiniAudioEngine::stopEngine() @@ -23,6 +55,7 @@ void MiniAudioEngine::stopEngine() } for (uint i = 0; i < m_devicesSelected; i++) { for (uint j = 0; j < m_layersQty; j++) { + ma_node_uninit(&m_filterBank[i][j].input, NULL); ma_hpf_node_uninit(&m_filterBank[i][j].hpf, NULL); ma_loshelf_node_uninit(&m_filterBank[i][j].loshelf, NULL); ma_peak_node_uninit(&m_filterBank[i][j].mLow, NULL); @@ -30,6 +63,8 @@ void MiniAudioEngine::stopEngine() ma_hishelf_node_uninit(&m_filterBank[i][j].hishelf, NULL); ma_splitter_node_uninit(&m_filterBank[i][j].output, NULL); } + //ma_writer_node_uninit(&m_sendToAux[0], NULL); + //ma_pcm_rb_uninit(&aux1Buffer); ma_engine_uninit(&m_engine[i]); ma_device_uninit(&m_device[i]); } @@ -60,56 +95,55 @@ bool MiniAudioEngine::startEngine(uint layers) ma_result MiniAudioEngine::createFilterBank(int id, uint layer) { ma_result result; - ma_node_graph *ng = ma_engine_get_node_graph(&m_engine[id]); ma_node *endpoint = ma_engine_get_endpoint(&m_engine[id]); - filterBank *fb = &m_filterBank[id][layer]; + filterBank *fb = &m_filterBank[id][layer]; ma_splitter_node_config splitterConfig = ma_splitter_node_config_init(CHANNELS); result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->input); if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to initialize input node." << endl; + cout << "ERROR " << result << ": Failed to init input node." << endl; return result; } 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; + cout << "ERROR " << result << ": Failed to init high pass filter node." << endl; return result; } 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; + cout << "ERROR " << result << ": Failed to init 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; + cout << "ERROR " << result << ": Failed to init peak low filter node." << endl; return result; } 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; + cout << "ERROR " << result << ": Failed to init peak high filter node." << endl; return result; } 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 initialize hi shelf filter node." << endl; + cout << "ERROR " << result << ": Failed to init hi shelf filter node." << endl; return result; } result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->output); if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to initialize output node." << endl; + cout << "ERROR " << result << ": Failed to init output node." << endl; return result; } @@ -120,7 +154,7 @@ ma_result MiniAudioEngine::createFilterBank(int id, uint layer) } result = ma_node_attach_output_bus(&fb->input, 1, &fb->output, 0); if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to attach high pass pass filter node." << endl; + cout << "ERROR " << result << ": Failed to attach bypass connection." << endl; return result; } ma_node_set_output_bus_volume(&fb->input, 1, 0.0f); @@ -149,10 +183,17 @@ ma_result MiniAudioEngine::createFilterBank(int id, uint layer) 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; + if (id == 0) { + //result = ma_node_attach_output_bus(&fb->output, 1, endpoint, 0); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach output node to engine." << endl; + return result; + } + result = ma_node_attach_output_bus(&fb->output, 0, &m_sendToAux[id], 0); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach output node to aux send 1." << endl; + return result; + } } return result; } @@ -161,19 +202,31 @@ ma_result MiniAudioEngine::setNodeGraph(int id) { ma_result result = MA_SUCCESS; uint i = 0; + if (id == 0) { + ma_node_graph *ng = ma_engine_get_node_graph(&m_engine[id]); + size_t sizeInFrames = SAMPLE_RATE / 10; // ma_get_bytes_per_frame(FORMAT, CHANNELS); + result = ma_pcm_rb_init(FORMAT, CHANNELS, sizeInFrames, NULL, NULL, &aux1Buffer); + if (result != MA_SUCCESS) { + printf("Failed to initialize ring buffer.\n"); + return result; + } + ma_silence_pcm_frames(aux1Buffer.rb.pBuffer, sizeInFrames, FORMAT, CHANNELS); + ma_writer_node_config writerConfig = ma_writer_node_config_init(CHANNELS, SAMPLE_RATE * 5, &aux1Buffer); + result = ma_writer_node_init(ng, &writerConfig, NULL, &m_sendToAux[id]); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to init writer node." << endl; + return result; + } + result = ma_node_attach_output_bus(&m_sendToAux[id], 0, ma_engine_get_endpoint(&m_engine[id]), 0); // Pull API + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach writer node." << endl; + return result; + } + } while (result == MA_SUCCESS && i < m_layersQty) { result = this->createFilterBank(id, i); i++; } - //ma_node_graph *ng = ma_engine_get_node_graph(&m_engine[id]); - //ma_node *endpoint = ma_engine_get_endpoint(&m_engine[id]); - for (uint i = 0; i < m_layersQty; i++) { - result = ma_node_attach_output_bus(&m_filterBank[0][i].output, 0, &m_filterBank[1][i].output, 0); - if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to attach aux send." << endl; - //return result; - } - } return (result); } @@ -185,12 +238,19 @@ bool MiniAudioEngine::startDevice(uint *systemId, uint nb) m_devicesSelected = nb; for (uint internalId = 0; internalId < nb; internalId++) { - deviceConfig = ma_device_config_init(ma_device_type_playback); + deviceConfig = ma_device_config_init(ma_device_type_duplex); + deviceConfig.capture.pDeviceID = &m_pPlaybackDeviceInfos[systemId[internalId]].id; + deviceConfig.capture.format = m_resourceManager.config.decodedFormat; + deviceConfig.capture.channels = CHANNELS; + deviceConfig.capture.shareMode = ma_share_mode_shared; deviceConfig.playback.pDeviceID = &m_pPlaybackDeviceInfos[systemId[internalId]].id; deviceConfig.playback.format = m_resourceManager.config.decodedFormat; - deviceConfig.playback.channels = 0; + deviceConfig.playback.channels = CHANNELS; deviceConfig.sampleRate = m_resourceManager.config.decodedSampleRate; - deviceConfig.dataCallback = audioDataCallback; + if (internalId == 0) + deviceConfig.dataCallback = audioDataCallback; + else if (internalId == 1) + deviceConfig.dataCallback = audioDataCallback1; deviceConfig.pUserData = &m_engine[internalId]; result = ma_device_init(&m_context, &deviceConfig, &m_device[internalId]); if (result != MA_SUCCESS) { @@ -200,6 +260,7 @@ bool MiniAudioEngine::startDevice(uint *systemId, uint nb) engineConfig = ma_engine_config_init(); engineConfig.pDevice = &m_device[internalId]; engineConfig.pResourceManager = &m_resourceManager; + engineConfig.gainSmoothTimeInMilliseconds = SAMPLE_RATE / 100; engineConfig.noAutoStart = MA_TRUE; result = ma_engine_init(&engineConfig, &m_engine[internalId]); if (result != MA_SUCCESS) { @@ -218,6 +279,23 @@ bool MiniAudioEngine::startDevice(uint *systemId, uint nb) } cout << "Initialized Audio Device. internalId: " << internalId << " systemId: " << systemId[internalId] << " " << m_pPlaybackDeviceInfos[systemId[internalId]].name << endl; } + //result = ma_data_source_rb_init(&g_dataSourceRB, &aux1Buffer); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to init data source ring buffer" << endl; + return false; + } + ma_data_source_node_config dataSupplyNodeConfig = ma_data_source_node_config_init(&g_dataSourceRB); + //result = ma_data_source_node_init(ma_engine_get_node_graph(&m_engine[1]), &dataSupplyNodeConfig, NULL, &g_dataSupplyNode); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to init data source node" << endl; + return false; + } + //result = ma_node_attach_output_bus(&g_dataSupplyNode, 0, ma_engine_get_endpoint(&m_engine[1]), 0); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to attach data source rb node" << endl; + return false; + } + cout << "data source node state " << ma_node_get_state(&g_dataSupplyNode.base) << endl; return true; } @@ -264,12 +342,8 @@ 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, 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 . + // - writer node y source con el buffer escrito en el otro device if (m_mediaLoaded[layer] == true) { ma_sound_uninit(&m_currentSound[layer]); @@ -284,7 +358,7 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file, uint audioDevice) } result = ma_node_attach_output_bus(&m_currentSound[layer], 0, &m_filterBank[audioDevice][layer].input, 0); if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to attach output bus " << audioDevice << endl; + cout << "Error " << result << ": Failed to attach sound output bus " << audioDevice << endl; //return result; } m_mediaLoaded[layer] = true; @@ -352,7 +426,7 @@ void MiniAudioEngine::volChanged(int layer, float vol) return; if (vol >= 1) vol = 0.99f; - ma_sound_group_set_fade_in_milliseconds(&m_currentSound[layer], -1, vol, FADE_TIME); + ma_sound_group_set_fade_in_milliseconds(&m_currentSound[layer], -1, pow(vol, 3), FADE_TIME); m_currentLayerValues[layer].vol = vol; } diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index b55311b..d908c70 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -1,21 +1,19 @@ #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_ENABLE_ONLY_SPECIFIC_BACKENDS +#define MA_ENABLE_JACK +#define MA_NO_GENERATION +#define MA_DEBUG_OUTPUT #define MA_DISABLE_PULSEAUDIO +#define MA_DEBUG_OUTPUT #define MINIAUDIO_IMPLEMENTATION #include "miniaudio.h" -#include "defines.h" // MAX_LAYERS +#include "ma_writer_node.h" #include using namespace std; +#include "defines.h" -/* Data Format */ -#define FORMAT ma_format_f32 /* Must always be f32. */ -#define CHANNELS 2 -#define SAMPLE_RATE 48000 typedef struct { @@ -31,12 +29,23 @@ typedef struct ma_hishelf_node hishelf; ma_hishelf_node_config hishelfConfig; ma_splitter_node output; + ma_writer_node send1; + ma_data_source_node return1; + ma_audio_buffer_ref supplyReturn1; } filterBank; +typedef struct +{ + ma_engine m_engine[MAX_AUDIODEVICES]; + filterBank m_filterBank[MAX_AUDIODEVICES][MAX_LAYERS]; + ma_writer_node m_sendAux1[MAX_LAYERS]; + ma_pcm_rb *aux1Buffer; +} audioObjects; class MiniAudioEngine { friend class libreMediaServerAudio; + static ma_pcm_rb *rb; public: MiniAudioEngine(); @@ -44,6 +53,7 @@ public: bool startEngine(uint layersQty); bool startDevice(uint *id, uint nb); static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); + static void audioDataCallback1(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); bool setBypass(int audioDevice, int layer, bool bypass); protected: @@ -76,6 +86,8 @@ private: filterBank m_filterBank[MAX_AUDIODEVICES][MAX_LAYERS]; ma_engine m_engine[MAX_AUDIODEVICES]; uint m_layersQty; + ma_writer_node m_sendToAux[MAX_LAYERS]; + audioObjects m_audioObjects; ma_result getAllAudioDevices(); ma_result startContext(); -- 2.39.5 From a935d4e619144c338bd5ec10f73c82a656776dbc Mon Sep 17 00:00:00 2001 From: snt Date: Sun, 19 May 2024 01:36:23 +0200 Subject: [PATCH 40/49] =?UTF-8?q?multi=20dispositivo=20con=20env=C3=ADo=20?= =?UTF-8?q?independientes=20por=20capa.=20est=C3=A1=20sucio=20con=20trozos?= =?UTF-8?q?=20sn=20usar=20y=20statics,=20pero=20funciona.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/LibreMediaServer_Audio.hed | 190 ++++++++++++++++---------------- src/libremediaserver-audio.cpp | 2 +- src/ma_writer_node.c | 17 +-- src/miniaudioengine.cpp | 24 +++- src/miniaudioengine.h | 1 + 5 files changed, 128 insertions(+), 106 deletions(-) diff --git a/docs/LibreMediaServer_Audio.hed b/docs/LibreMediaServer_Audio.hed index 1598cab..90b0781 100644 --- a/docs/LibreMediaServer_Audio.hed +++ b/docs/LibreMediaServer_Audio.hed @@ -1,93 +1,99 @@ ް׆ˌĠ򝤫鿰맫͓Ԕ -ҊÅЁ䍡 -ӽ -͌وГ -䩴؍ - - -ǁ - -ήƵ -ꂨ⑯ɞɅ -ˆ -㨥 -פ - -Θב -˻ - -ūî -䈍 -п -¥߸ڋ -Ĩ© -勌㊈ -͹ -ˢ݈ -ɢƢ -񍒍Й -˟ - -ǔ -檵 -Ӡ̧׀ -ꗪㄮϞѝ -ᯠ쫶 -ϼȡ嵶 -ᄨڍ֟ - -ڱ -񔸼񣏎 -ڔ - - -֐ - -̽ɤ -甯؞τ - - - - - - -𣇒 -Ԇ - -䷩ -ߍ - - - - - - - - - - -܂ -쏎 -מ - - -Ӽ - - - - - - - - - - -͚ʝǓ - - - -ݽ - - - - +ҊÅЁͽ +Щܰ +Χ +쏎՚ +ڥ +з +򗹡 +֐ +ᬡ䨳͘ +۽Ӣ + +ԙ + +ا࠭ +Ϡɮ +򃡺쏎 +Ē + +ջо +󕐙ޗ + +Ѵد߯ +ںԻϩ +񖝋ޕ +㓜 +Ѹڱ +ܯԕ + +ĉ +ⷶ +šҔ +㰽 +С׃ +苩ܑ +ٿ뺻 +ڧӴ̧Ӈ +똫䅭̝ԛʂ +껺 +۾ + +Κ + + +Dž +ꬡ˞“ +̾ +虤刬Ⓨ̀ +㨳 + + + +҂ + + +鱤 + +ً + +ۄ +í + + + + + + + + +𓎍 +̀ + +Řϒ +݁׺ + +րɂÈ +񺥤 +ଛ + +ܕ + + + + + +쏒 + + +稳 + + + + + +ٕ + + + + diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 2916007..76f711d 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -140,7 +140,7 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) m_played.append(m_ola->getValue(layer, DMX_FILE)); } #endif - } else if (channel >= HP_FREQ && channel <= HIGH_GAIN) { + } else if (channel >= HP_FREQ) { m_mae.filterParamChanged(layer, m_dmxSettings.at(layer).audioDevice, channel, value); #ifndef NOGUI if (m_ui) { diff --git a/src/ma_writer_node.c b/src/ma_writer_node.c index e05d38d..f58881d 100644 --- a/src/ma_writer_node.c +++ b/src/ma_writer_node.c @@ -18,16 +18,15 @@ static void ma_writer_node_process_pcm_frames(ma_node* pNode, const float** ppFr ma_writer_node* pWriteNode = (ma_writer_node*)pNode; MA_ASSERT(pWriteNode != NULL); - MA_ASSERT(ma_node_get_input_bus_count(&pWriteNode->baseNode) == 1); + MA_ASSERT(ma_node_get_input_bus_count(&pWriteNode->baseNode) == 2); if (*pFrameCountIn > 0) { void *pWriteBuffer = NULL; ma_pcm_rb_acquire_write(pWriteNode->pBuffer, pFrameCountIn, &pWriteBuffer); if (pWriteBuffer != NULL) { - ma_copy_pcm_frames(pWriteBuffer, ppFramesIn[0], *pFrameCountIn, ma_format_f32, pWriteNode->channels); + ma_copy_pcm_frames(pWriteBuffer, ppFramesIn[1], *pFrameCountIn, ma_format_f32, pWriteNode->channels); ma_pcm_rb_commit_write(pWriteNode->pBuffer, *pFrameCountIn); } - //ma_silence_pcm_frames(ppFramesOut[0], *pFrameCountOut, ma_format_f32, pWriteNode->channels); } //*pFrameCountOut = 0; ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, ma_format_f32, pWriteNode->channels); @@ -37,7 +36,7 @@ static ma_node_vtable g_ma_writer_node_vtable = { ma_writer_node_process_pcm_frames, NULL, - 1, + 2, 1, 0 // MA_NODE_FLAG_CONTINUOUS_PROCESSING @@ -48,6 +47,8 @@ MA_API ma_result ma_writer_node_init(ma_node_graph* pNodeGraph, const ma_writer_ { ma_result result; ma_node_config baseConfig; + ma_uint32 inputChannels[2]; // Equal in size to the number of input channels specified in the vtable. + ma_uint32 outputChannels[1]; if (pWriteNode == NULL || pConfig == NULL || pConfig->pBuffer == NULL \ || (pConfig->channels > MA_MAX_NODE_BUS_COUNT) ) { @@ -55,11 +56,13 @@ MA_API ma_result ma_writer_node_init(ma_node_graph* pNodeGraph, const ma_writer_ } MA_ZERO_OBJECT(pWriteNode); - + inputChannels[0] = pConfig->channels; + inputChannels[1] = pConfig->channels; + outputChannels[0] = pConfig->channels; baseConfig = pConfig->nodeConfig; baseConfig.vtable = &g_ma_writer_node_vtable; - baseConfig.pInputChannels = &pConfig->channels; - baseConfig.pOutputChannels = &pConfig->channels; + baseConfig.pInputChannels = inputChannels; + baseConfig.pOutputChannels = outputChannels; result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pWriteNode->baseNode); if (result != MA_SUCCESS) { diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 914708d..33c7840 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -183,13 +183,13 @@ ma_result MiniAudioEngine::createFilterBank(int id, uint layer) cout << "ERROR " << result << ": Failed to attach high shelf filter node." << endl; return result; } - if (id == 0) { - //result = ma_node_attach_output_bus(&fb->output, 1, endpoint, 0); +if (id == 0) { + result = ma_node_attach_output_bus(&fb->output, 0, &m_sendToAux[id], 0); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to attach output node to engine." << endl; return result; } - result = ma_node_attach_output_bus(&fb->output, 0, &m_sendToAux[id], 0); + result = ma_node_attach_output_bus(&fb->output, 1, &m_sendToAux[id], 1); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to attach output node to aux send 1." << endl; return result; @@ -204,7 +204,7 @@ ma_result MiniAudioEngine::setNodeGraph(int id) { if (id == 0) { ma_node_graph *ng = ma_engine_get_node_graph(&m_engine[id]); - size_t sizeInFrames = SAMPLE_RATE / 10; // ma_get_bytes_per_frame(FORMAT, CHANNELS); + size_t sizeInFrames = SAMPLE_RATE; // ma_get_bytes_per_frame(FORMAT, CHANNELS); result = ma_pcm_rb_init(FORMAT, CHANNELS, sizeInFrames, NULL, NULL, &aux1Buffer); if (result != MA_SUCCESS) { printf("Failed to initialize ring buffer.\n"); @@ -623,8 +623,20 @@ ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int ch cout << "ERROR " << result << ": Failed set gain high shelf filter node." << endl; return result; } - } - return (result); + } else if (channel == SEND1) { + ma_node_set_output_bus_volume(&fb->output, 0, pow((value / 255.0f), 2)); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed set Send 1 Volume." << endl; + return result; + } + } else if (channel == SEND2) { + ma_node_set_output_bus_volume(&fb->output, 1, pow((value / 255.0f), 2)); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed set Send 2 Volume." << endl; + } + return result; + } + return (result); } bool MiniAudioEngine::setBypass(int audioDevice, int layer, bool bypass) diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index d908c70..69147d3 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -7,6 +7,7 @@ #define MA_DEBUG_OUTPUT #define MA_DISABLE_PULSEAUDIO #define MA_DEBUG_OUTPUT +#define MA_LOG_LEVEL_DEBUG DEBUG #define MINIAUDIO_IMPLEMENTATION #include "miniaudio.h" #include "ma_writer_node.h" -- 2.39.5 From 5d56921aeb3a6cfce9ba07b68b36658d95e86571 Mon Sep 17 00:00:00 2001 From: snt Date: Mon, 20 May 2024 19:00:05 +0200 Subject: [PATCH 41/49] =?UTF-8?q?refactorizado=20todo=20a=20una=20struct.?= =?UTF-8?q?=20Maximo=20de=20dispositivos=20MAX=5FAUDIODEVICES,=20sin=20tes?= =?UTF-8?q?tear=20mas=20de=20dos.=20Los=20devices=20auxiliares=20leen=20de?= =?UTF-8?q?=20data=20source=20rb=20en=20vez=20de=20en=20el=20callback.=20l?= =?UTF-8?q?a=20idea=20del=20nodegraph=20funcionando=20en=20una=20engine=20?= =?UTF-8?q?dummy=20no=20ha=20funcionado,=20pero=20puede=20que=20fuera=20po?= =?UTF-8?q?r=20la=20refactorizaci=C3=B3n=20y=20la=20introducci=C3=B3n=20de?= =?UTF-8?q?=20las=20data=20sources=20rb.=20Ahora=20que=20est=C3=A1=20todo?= =?UTF-8?q?=20m=C3=A1s=20ordenado=20se=20puede=20volver=20a=20intentar.=20?= =?UTF-8?q?Pero=20tampoco=20merece=20mucho=20la=20pena,=20la=20principal?= =?UTF-8?q?=20diferencia=20era=20el=20master=20bus,=20pero=20se=20puede=20?= =?UTF-8?q?atacar=20la=20salida=20de=20auxNode[0]=20a=20una=20capa=20de=20?= =?UTF-8?q?master=20en=20vez=20de=20al=20endpoint=20directamente.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libremediaserver-audio.cpp | 7 +- src/ma_writer_node.c | 1 - src/miniaudioengine.cpp | 415 ++++++++++++++++----------------- src/miniaudioengine.h | 61 +++-- 4 files changed, 234 insertions(+), 250 deletions(-) diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 76f711d..72398ee 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -40,15 +40,10 @@ libreMediaServerAudio::libreMediaServerAudio() m_updateUi[i][3] = -1; #endif } - if (!m_mae.startEngine(m_layersQty)) { + if (!m_mae.startEngine(m_layersQty, m_settings->getAudioDeviceId(), m_settings->getAudioDeviceQty())) { cout << "Can not start Audio Engine!" << endl; exit(-1); } - uint *audioDevList = m_settings->getAudioDeviceId(); - if (!m_mae.startDevice(audioDevList, m_settings->getAudioDeviceQty())) { - cout << "Can not start Audio Device!" << audioDevList << endl; - exit(-1); - } m_ola = new olaThread(this, m_layersQty); Q_CHECK_PTR(m_ola); m_ola->blockSignals(true); diff --git a/src/ma_writer_node.c b/src/ma_writer_node.c index f58881d..82e057c 100644 --- a/src/ma_writer_node.c +++ b/src/ma_writer_node.c @@ -28,7 +28,6 @@ static void ma_writer_node_process_pcm_frames(ma_node* pNode, const float** ppFr ma_pcm_rb_commit_write(pWriteNode->pBuffer, *pFrameCountIn); } } - //*pFrameCountOut = 0; ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, ma_format_f32, pWriteNode->channels); } diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 33c7840..9b2f64a 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -4,10 +4,6 @@ #define BIAS 0.99f #define FILTER_ORDER 3 -static ma_pcm_rb aux1Buffer; -static ma_data_source_node g_dataSupplyNode; -static ma_data_source_rb g_dataSourceRB; - MiniAudioEngine::MiniAudioEngine() {} void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) @@ -21,83 +17,78 @@ void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const (void)pInput; } -void MiniAudioEngine::audioDataCallback1(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) -{ - (void)pDevice; - ma_result result; - - ma_uint32 pcmFramesAvailableInRB = 0; - ma_uint32 pcmFramesProcessed = 0; - while (pcmFramesProcessed < frameCount) { - pcmFramesAvailableInRB = ma_pcm_rb_available_read(&aux1Buffer); - if (pcmFramesAvailableInRB == 0) { - break; - } - ma_uint32 framesToRead = frameCount - pcmFramesProcessed; - if (framesToRead > pcmFramesAvailableInRB) { - framesToRead = pcmFramesAvailableInRB; - } - void* pReadBuffer = NULL; - ma_pcm_rb_acquire_read(&aux1Buffer, &framesToRead, &pReadBuffer); - if (pReadBuffer != NULL) { - ma_copy_pcm_frames(pOutput, pReadBuffer, framesToRead, FORMAT, CHANNELS); - ma_pcm_rb_commit_read(&aux1Buffer, framesToRead); - pcmFramesProcessed += framesToRead; - }/* else { break; }*/ - } - (void)pInput; -} - void MiniAudioEngine::stopEngine() { - for (uint i = 0; i < m_layersQty; i++) { - ma_sound_uninit(&m_currentSound[i]); + for (uint i = 0; i < m_mae.layersQty; i++) { + if (m_mae.mediaLoaded[i]) + ma_sound_uninit(&m_mae.sounds[i]); } - for (uint i = 0; i < m_devicesSelected; i++) { - for (uint j = 0; j < m_layersQty; j++) { - ma_node_uninit(&m_filterBank[i][j].input, NULL); - ma_hpf_node_uninit(&m_filterBank[i][j].hpf, 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); + for (uint i = 0; i < m_mae.layersQty; i++) { + ma_node_uninit(&m_mae.filters[i].input, NULL); + ma_hpf_node_uninit(&m_mae.filters[i].hpf, NULL); + ma_loshelf_node_uninit(&m_mae.filters[i].loshelf, NULL); + ma_peak_node_uninit(&m_mae.filters[i].mLow, NULL); + ma_peak_node_uninit(&m_mae.filters[i].mHigh, NULL); + ma_hishelf_node_uninit(&m_mae.filters[i].hishelf, NULL); + ma_splitter_node_uninit(&m_mae.filters[i].output, NULL); + } + for (uint i = 0; i < m_mae.audioDevicesQty; i++) { + if (i > 0) { + ma_writer_node_uninit(&m_mae.sendAuxNode[i], NULL); + ma_pcm_rb_uninit(&m_mae.auxBuffers[i]); } - //ma_writer_node_uninit(&m_sendToAux[0], NULL); - //ma_pcm_rb_uninit(&aux1Buffer); - ma_engine_uninit(&m_engine[i]); - ma_device_uninit(&m_device[i]); + ma_engine_uninit(&m_mae.engines[i]); + ma_device_uninit(&m_mae.devices[i]); } - ma_context_uninit(&m_context); - ma_resource_manager_uninit(&m_resourceManager); + ma_context_uninit(&m_mae.context); + ma_resource_manager_uninit(&m_mae.resourceManager); } -bool MiniAudioEngine::startEngine(uint layers) +bool MiniAudioEngine::startEngine(uint layers, uint* audioDevicesId, uint audioDevicesQty) { 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; + m_mae.layersQty = layers; + m_mae.audioDevicesId = audioDevicesId; + m_mae.audioDevicesQty = audioDevicesQty; + for (uint i =0; i < m_mae.layersQty; i++) { + m_mae.mediaLoaded[i] = false; + m_mae.currentStatus[i].status = Status::Iddle; + m_mae.currentStatus[i].pan = 128; + m_mae.currentStatus[i].pitch = 128; + m_mae.currentStatus[i].vol = 0; + m_mae.currentStatus[i].cursor = 0; } result = this->startContext(); if (result != MA_SUCCESS) return false; result = this->getAllAudioDevices(); if (result != MA_SUCCESS) return false; + result = this->startDevices(); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed start audio devices." << endl; + return false; + } + result = this->setNodeGraph(); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to set node graph." << endl; + return false; + } + for (uint i = 0; i < m_mae.audioDevicesQty; i++) { + result = ma_engine_start(&m_mae.engines[i]); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to start audio device" << m_mae.audioDevicesId[i] << endl; + return false; + } + } return true; } -ma_result MiniAudioEngine::createFilterBank(int id, uint layer) +ma_result MiniAudioEngine::createFilterBank(uint layer) { ma_result result; - ma_node_graph *ng = ma_engine_get_node_graph(&m_engine[id]); - ma_node *endpoint = ma_engine_get_endpoint(&m_engine[id]); - filterBank *fb = &m_filterBank[id][layer]; + ma_node_graph *ng = ma_engine_get_node_graph(&m_mae.engines[0]); + ma_node *endpoint = ma_engine_get_endpoint(&m_mae.engines[0]); + filterBank *fb = &m_mae.filters[layer]; ma_splitter_node_config splitterConfig = ma_splitter_node_config_init(CHANNELS); result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->input); @@ -140,13 +131,12 @@ ma_result MiniAudioEngine::createFilterBank(int id, uint layer) cout << "ERROR " << result << ": Failed to init hi shelf filter node." << endl; return result; } - + splitterConfig.outputBusCount = m_mae.audioDevicesQty; result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->output); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to init output node." << endl; return result; } - result = ma_node_attach_output_bus(&fb->input, 0, &fb->hpf, 0); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to attach input node." << endl; @@ -183,137 +173,143 @@ ma_result MiniAudioEngine::createFilterBank(int id, uint layer) cout << "ERROR " << result << ": Failed to attach high shelf filter node." << endl; return result; } -if (id == 0) { - result = ma_node_attach_output_bus(&fb->output, 0, &m_sendToAux[id], 0); + if (m_mae.audioDevicesQty == 1) { + 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; + cout << "ERROR " << result << ": Failed to attach output to endpoint." << endl; return result; } - result = ma_node_attach_output_bus(&fb->output, 1, &m_sendToAux[id], 1); + } else { + result = ma_node_attach_output_bus(&fb->output, 0, &m_mae.sendAuxNode[1], 0); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to attach output node to aux send 1." << endl; return result; } + result = ma_node_attach_output_bus(&fb->output, 1, &m_mae.sendAuxNode[1], 1); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach output node to aux send 1." << endl; + return result; + } + for (uint i = 2; i < m_mae.audioDevicesQty; i++) { + result = ma_node_attach_output_bus(&fb->output, i, &m_mae.sendAuxNode[i], 1); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach output node to aux send 1." << endl; + return result; + } + } } return result; } -ma_result MiniAudioEngine::setNodeGraph(int id) { +ma_result MiniAudioEngine::setNodeGraph() { ma_result result = MA_SUCCESS; - uint i = 0; - if (id == 0) { - ma_node_graph *ng = ma_engine_get_node_graph(&m_engine[id]); - size_t sizeInFrames = SAMPLE_RATE; // ma_get_bytes_per_frame(FORMAT, CHANNELS); - result = ma_pcm_rb_init(FORMAT, CHANNELS, sizeInFrames, NULL, NULL, &aux1Buffer); - if (result != MA_SUCCESS) { - printf("Failed to initialize ring buffer.\n"); - return result; - } - ma_silence_pcm_frames(aux1Buffer.rb.pBuffer, sizeInFrames, FORMAT, CHANNELS); - ma_writer_node_config writerConfig = ma_writer_node_config_init(CHANNELS, SAMPLE_RATE * 5, &aux1Buffer); - result = ma_writer_node_init(ng, &writerConfig, NULL, &m_sendToAux[id]); - if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to init writer node." << endl; - return result; - } - result = ma_node_attach_output_bus(&m_sendToAux[id], 0, ma_engine_get_endpoint(&m_engine[id]), 0); // Pull API - if (result != MA_SUCCESS) { - cout << "ERROR " << result << ": Failed to attach writer node." << endl; - return result; - } + ma_node_graph *ng = ma_engine_get_node_graph(&m_mae.engines[0]); + for (uint i = 1; i < m_mae.audioDevicesQty; i++) { + size_t sizeInFrames = SAMPLE_RATE; + result = ma_pcm_rb_init(FORMAT, CHANNELS, sizeInFrames, NULL, NULL, &m_mae.auxBuffers[i]); + if (result != MA_SUCCESS) { + printf("Failed to initialize ring buffer.\n"); + return result; + } + ma_silence_pcm_frames(m_mae.auxBuffers[i].rb.pBuffer, sizeInFrames, FORMAT, CHANNELS); + ma_writer_node_config writerConfig = ma_writer_node_config_init(CHANNELS, SAMPLE_RATE * 5, &m_mae.auxBuffers[i]); + result = ma_writer_node_init(ng, &writerConfig, NULL, &m_mae.sendAuxNode[i]); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to init writer node." << endl; + return result; + } + // esto va a dar problemas al sumar en el envío 0 una vez por cad envío extra. + // writer_node puede ser silencioso + // así ya estamos en el caso de disparar varios bang por cada envío en el mismo nodegraph + // es mejor que writer node tenga varias entradas, una por cada envío + // que se dispara con un único engine y proporciona un único stream de audio de vuelta a ese engine + // en vez de un puntero hay que pasarle un array de rb + result = ma_node_attach_output_bus(&m_mae.sendAuxNode[i], 0, ma_engine_get_endpoint(&m_mae.engines[0]), 0); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach writer node." << endl; + return result; + } + result = ma_data_source_rb_init(&m_mae.dataSourceRB[i], &m_mae.auxBuffers[i]); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to init data source ring buffer" << endl; + return result; + } + ma_data_source_node_config dataSupplyNodeConfig = ma_data_source_node_config_init(&m_mae.dataSourceRB[i]); + result = ma_data_source_node_init(ma_engine_get_node_graph(&m_mae.engines[i]), &dataSupplyNodeConfig, NULL, &m_mae.dataSupplyNode[i]); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to init data source node" << endl; + return result; + } + result = ma_node_attach_output_bus(&m_mae.dataSupplyNode[i], 0, ma_engine_get_endpoint(&m_mae.engines[i]), 0); + if (result != MA_SUCCESS) { + cout << "Error " << result << ": Failed to attach data source rb node" << endl; + return result; + } } - while (result == MA_SUCCESS && i < m_layersQty) { - result = this->createFilterBank(id, i); - i++; + for (uint i = 0; i < m_mae.layersQty; i++) { + result = this->createFilterBank(i); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed creating filter bank." << endl; + } } return (result); } -bool MiniAudioEngine::startDevice(uint *systemId, uint nb) +ma_result MiniAudioEngine::startDevices() { ma_result result = MA_SUCCESS; ma_device_config deviceConfig; ma_engine_config engineConfig; - m_devicesSelected = nb; - for (uint internalId = 0; internalId < nb; internalId++) { - deviceConfig = ma_device_config_init(ma_device_type_duplex); - deviceConfig.capture.pDeviceID = &m_pPlaybackDeviceInfos[systemId[internalId]].id; - deviceConfig.capture.format = m_resourceManager.config.decodedFormat; - deviceConfig.capture.channels = CHANNELS; - deviceConfig.capture.shareMode = ma_share_mode_shared; - deviceConfig.playback.pDeviceID = &m_pPlaybackDeviceInfos[systemId[internalId]].id; - deviceConfig.playback.format = m_resourceManager.config.decodedFormat; - deviceConfig.playback.channels = CHANNELS; - deviceConfig.sampleRate = m_resourceManager.config.decodedSampleRate; - if (internalId == 0) - deviceConfig.dataCallback = audioDataCallback; - else if (internalId == 1) - deviceConfig.dataCallback = audioDataCallback1; - deviceConfig.pUserData = &m_engine[internalId]; - result = ma_device_init(&m_context, &deviceConfig, &m_device[internalId]); + deviceConfig = ma_device_config_init(ma_device_type_duplex); + deviceConfig.capture.format = m_mae.resourceManager.config.decodedFormat; + deviceConfig.capture.channels = CHANNELS; + deviceConfig.playback.channels = CHANNELS; + deviceConfig.capture.shareMode = ma_share_mode_shared; + deviceConfig.playback.format = m_mae.resourceManager.config.decodedFormat; + deviceConfig.sampleRate = m_mae.resourceManager.config.decodedSampleRate; + deviceConfig.dataCallback = audioDataCallback; + engineConfig = ma_engine_config_init(); + engineConfig.pResourceManager = &m_mae.resourceManager; + engineConfig.gainSmoothTimeInMilliseconds = SAMPLE_RATE / 25; + engineConfig.noAutoStart = MA_TRUE; + + for (uint internalId = 0; internalId < m_mae.audioDevicesQty; internalId++) { + deviceConfig.capture.pDeviceID = &m_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[internalId]].id; + deviceConfig.playback.pDeviceID = &m_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[internalId]].id; + deviceConfig.pUserData = &m_mae.engines[internalId]; + result = ma_device_init(&m_mae.context, &deviceConfig, &m_mae.devices[internalId]); if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to initialize audio device " << m_pPlaybackDeviceInfos[*systemId].name << endl; - return false; + cout << "Error " << result << ": Failed to initialize audio device " << m_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[internalId]].name << endl; + return result; } - engineConfig = ma_engine_config_init(); - engineConfig.pDevice = &m_device[internalId]; - engineConfig.pResourceManager = &m_resourceManager; - engineConfig.gainSmoothTimeInMilliseconds = SAMPLE_RATE / 100; - engineConfig.noAutoStart = MA_TRUE; - result = ma_engine_init(&engineConfig, &m_engine[internalId]); + engineConfig.pDevice = &m_mae.devices[internalId]; + result = ma_engine_init(&engineConfig, &m_mae.engines[internalId]); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to initialize audio engine" << endl; - return false; + return result; } - 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; + cout << "Initialized Audio Device. internalId: " << internalId << " systemId: " << m_mae.audioDevicesId[internalId] << " " << m_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[internalId]].name << endl; } - //result = ma_data_source_rb_init(&g_dataSourceRB, &aux1Buffer); - if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to init data source ring buffer" << endl; - return false; - } - ma_data_source_node_config dataSupplyNodeConfig = ma_data_source_node_config_init(&g_dataSourceRB); - //result = ma_data_source_node_init(ma_engine_get_node_graph(&m_engine[1]), &dataSupplyNodeConfig, NULL, &g_dataSupplyNode); - if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to init data source node" << endl; - return false; - } - //result = ma_node_attach_output_bus(&g_dataSupplyNode, 0, ma_engine_get_endpoint(&m_engine[1]), 0); - if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to attach data source rb node" << endl; - return false; - } - cout << "data source node state " << ma_node_get_state(&g_dataSupplyNode.base) << endl; - return true; + return result; } ma_result MiniAudioEngine::startContext() { ma_result result; - 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); + ma_resource_manager_config resourceManagerConfig = ma_resource_manager_config_init(); + resourceManagerConfig.decodedFormat = FORMAT; + resourceManagerConfig.decodedChannels = CHANNELS; + resourceManagerConfig.decodedSampleRate = SAMPLE_RATE; + resourceManagerConfig.jobThreadCount = MAX_LAYERS; + result = ma_resource_manager_init(&resourceManagerConfig, &m_mae.resourceManager); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to initialize audio resource manager." << endl; return result; } - result = ma_context_init(NULL, 0, NULL, &m_context); + result = ma_context_init(NULL, 0, NULL, &m_mae.context); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to initialize audio context." << endl; } @@ -325,15 +321,15 @@ ma_result MiniAudioEngine::getAllAudioDevices() { ma_result result; - result = ma_context_get_devices(&m_context, &m_pPlaybackDeviceInfos, &m_playbackDeviceCount, NULL, NULL); + result = ma_context_get_devices(&m_mae.context, &m_mae.pPlaybackDeviceInfos, &m_mae.playbackDeviceCount, NULL, NULL); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to enumerate playback devices." << endl; - ma_context_uninit(&m_context); + ma_context_uninit(&m_mae.context); return result; } cout << "Audio devices available:" << endl; - for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < m_playbackDeviceCount; iAvailableDevice += 1) { - cout << iAvailableDevice << " : " << m_pPlaybackDeviceInfos[iAvailableDevice].name << endl; + for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < m_mae.playbackDeviceCount; iAvailableDevice += 1) { + cout << iAvailableDevice << " : " << m_mae.pPlaybackDeviceInfos[iAvailableDevice].name << endl; } return result; } @@ -342,28 +338,26 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file, uint audioDevice) { ma_result result; - // - iniciar un sonido por cada capa, copiar la capa en otro dispositivo - // - writer node y source con el buffer escrito en el otro device - if (m_mediaLoaded[layer] == true) + if (m_mae.mediaLoaded[layer] == true) { - ma_sound_uninit(&m_currentSound[layer]); - m_mediaLoaded[layer] = false; + ma_sound_uninit(&m_mae.sounds[layer]); + m_mae.mediaLoaded[layer] = false; } - result = ma_sound_init_from_file(&m_engine[audioDevice], file, \ + result = ma_sound_init_from_file(&m_mae.engines[0], file, \ MA_SOUND_FLAG_NO_SPATIALIZATION \ - , NULL, NULL, &m_currentSound[layer]); + , NULL, NULL, &m_mae.sounds[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, &m_filterBank[audioDevice][layer].input, 0); + result = ma_node_attach_output_bus(&m_mae.sounds[layer], 0, &m_mae.filters[layer].input, 0); if (result != MA_SUCCESS) { cout << "Error " << result << ": Failed to attach sound output bus " << audioDevice << endl; - //return result; + return result; } - m_mediaLoaded[layer] = true; + m_mae.mediaLoaded[layer] = true; this->refreshValues(layer); - m_currentLayerValues[layer].media = file; + m_mae.currentStatus[layer].media = file; return result; } @@ -372,9 +366,9 @@ float MiniAudioEngine::getDuration(int layer) ma_result result; float ret; - if (m_mediaLoaded[layer] == false) + if (m_mae.mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; - result = ma_sound_get_length_in_seconds(&m_currentSound[layer], &ret); + result = ma_sound_get_length_in_seconds(&m_mae.sounds[layer], &ret); if (result != MA_SUCCESS) { return result; } @@ -386,9 +380,9 @@ float MiniAudioEngine::getCursor(int layer) ma_result result; float ret = 0; - if (m_mediaLoaded[layer] == false) + if (m_mae.mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; - result = ma_sound_get_cursor_in_seconds(&m_currentSound[layer], &ret); + result = ma_sound_get_cursor_in_seconds(&m_mae.sounds[layer], &ret); if (result != MA_SUCCESS) { cout << "Error" << result << ": Can not get cursor " << layer << endl; @@ -403,16 +397,16 @@ ma_result MiniAudioEngine::printFormatInfo(int layer) ma_uint32 channels; ma_uint32 sampleRate; - if (m_mediaLoaded[layer] == false) + if (m_mae.mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; - ma_result result = ma_sound_get_data_format(&m_currentSound[layer], \ + ma_result result = ma_sound_get_data_format(&m_mae.sounds[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 << m_mae.currentStatus[layer].media.toLatin1().data(); cout << " samples/sec:" << sampleRate << " format:" << format; cout << " channels:" << channels << endl; } @@ -422,50 +416,50 @@ ma_result MiniAudioEngine::printFormatInfo(int layer) // Expects between 0 and 1 vol value void MiniAudioEngine::volChanged(int layer, float vol) { - if (m_mediaLoaded[layer] == false) + if (m_mae.mediaLoaded[layer] == false) return; if (vol >= 1) vol = 0.99f; - ma_sound_group_set_fade_in_milliseconds(&m_currentSound[layer], -1, pow(vol, 3), FADE_TIME); - m_currentLayerValues[layer].vol = vol; + ma_sound_group_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, pow(vol, 3), FADE_TIME); + m_mae.currentStatus[layer].vol = vol; } void MiniAudioEngine::panChanged(int layer, float value) { float result; - if (m_mediaLoaded[layer] == false) + if (m_mae.mediaLoaded[layer] == false) return; result = (value / 128.0) - 1.0; - ma_sound_group_set_pan(&m_currentSound[layer], result); - m_currentLayerValues[layer].pan = value; + ma_sound_group_set_pan(&m_mae.sounds[layer], result); + m_mae.currentStatus[layer].pan = value; } void MiniAudioEngine::pitchChanged(int layer, float value) { float pitch; - if (m_mediaLoaded[layer] == false) + if (m_mae.mediaLoaded[layer] == false) return; pitch = value / 128.0; - ma_sound_group_set_pitch(&m_currentSound[layer], pitch); - m_currentLayerValues[layer].pitch = value; + ma_sound_group_set_pitch(&m_mae.sounds[layer], pitch); + m_mae.currentStatus[layer].pitch = value; } ma_result MiniAudioEngine::playbackChanged(int layer, Status status) { ma_result result = MA_SUCCESS; - if (m_mediaLoaded[layer] == false) + if (m_mae.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); + result = ma_sound_stop_with_fade_in_milliseconds(&m_mae.sounds[layer], FADE_TIME); break; case Status::Stopped: - ma_sound_stop_with_fade_in_milliseconds(&m_currentSound[layer], FADE_TIME); - result = this->seekToCursor(layer, m_currentLayerValues[layer].cursor); + ma_sound_stop_with_fade_in_milliseconds(&m_mae.sounds[layer], FADE_TIME); + result = this->seekToCursor(layer, m_mae.currentStatus[layer].cursor); break; case Status::PlayingLoop: loop = true; @@ -473,18 +467,18 @@ ma_result MiniAudioEngine::playbackChanged(int layer, Status status) 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], loop); - result = ma_sound_start(&m_currentSound[layer]); - if (m_currentLayerValues[layer].cursor != 0) { + ma_sound_set_stop_time_in_milliseconds(&m_mae.sounds[layer], ~(ma_uint64)0); + ma_sound_set_looping(&m_mae.sounds[layer], loop); + result = ma_sound_start(&m_mae.sounds[layer]); + if (m_mae.currentStatus[layer].cursor != 0) { usleep(1000 * 50); // Avoid small glitch at start, how to flush the cached buffers in audio pipe line? } - this->volChanged(layer, m_currentLayerValues[layer].vol); + this->volChanged(layer, m_mae.currentStatus[layer].vol); default: break; } if (result == MA_SUCCESS) - m_currentLayerValues[layer].status = status; + m_mae.currentStatus[layer].status = status; return result; } @@ -493,13 +487,13 @@ ma_result MiniAudioEngine::seekToCursor(int layer, int cursor) ma_result result = MA_SUCCESS; ma_uint64 end, start; - if (m_mediaLoaded[layer] == false) + if (m_mae.mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; - result = ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &end); + result = ma_sound_get_length_in_pcm_frames(&m_mae.sounds[layer], &end); if (result != MA_SUCCESS) { return result; } start = (cursor * end) / 65025; - result = ma_sound_seek_to_pcm_frame(&m_currentSound[layer], start); - //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? + result = ma_sound_seek_to_pcm_frame(&m_mae.sounds[layer], start); + //result = ma_data_source_set_loop_point_in_pcm_frames(&m_mae.sounds[layer], start, end); // this do nothing here, it must be done after set_looping or start? return (result); } @@ -507,30 +501,30 @@ ma_result MiniAudioEngine::setCursor(int layer, int cursor) { ma_result result = MA_SUCCESS; - m_currentLayerValues[layer].cursor = cursor; + m_mae.currentStatus[layer].cursor = cursor; result = this->seekToCursor(layer, cursor); return (result); } Status MiniAudioEngine::getStatus(int layer) { - return m_currentLayerValues[layer].status; + return m_mae.currentStatus[layer].status; } void MiniAudioEngine::refreshValues(int layer) { - this->seekToCursor(layer, m_currentLayerValues[layer].cursor); - this->panChanged(layer, m_currentLayerValues[layer].pan); - this->volChanged(layer, m_currentLayerValues[layer].vol); - this->pitchChanged(layer, m_currentLayerValues[layer].pitch); - this->playbackChanged(layer, m_currentLayerValues[layer].status); + this->seekToCursor(layer, m_mae.currentStatus[layer].cursor); + this->panChanged(layer, m_mae.currentStatus[layer].pan); + this->volChanged(layer, m_mae.currentStatus[layer].vol); + this->pitchChanged(layer, m_mae.currentStatus[layer].pitch); + this->playbackChanged(layer, m_mae.currentStatus[layer].status); } ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int channel, int value) { + (void)audioDevice; ma_result result = MA_SUCCESS; - - filterBank *fb = &m_filterBank[audioDevice][layer]; + filterBank *fb = &m_mae.filters[layer]; if (channel == HP_FREQ) { fb->hpfConfig.hpf.cutoffFrequency = double((value * 1.31) + 16.0f); // 16 - 350 @@ -641,7 +635,8 @@ ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int ch bool MiniAudioEngine::setBypass(int audioDevice, int layer, bool bypass) { - filterBank *fb = &m_filterBank[audioDevice][layer]; + (void)audioDevice; + filterBank *fb = &m_mae.filters[layer]; if (bypass) { ma_node_set_output_bus_volume(&fb->input, 1, 1.0f); diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 69147d3..308706b 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -15,7 +15,6 @@ using namespace std; #include "defines.h" - typedef struct { ma_splitter_node input; @@ -30,32 +29,40 @@ typedef struct ma_hishelf_node hishelf; ma_hishelf_node_config hishelfConfig; ma_splitter_node output; - ma_writer_node send1; - ma_data_source_node return1; - ma_audio_buffer_ref supplyReturn1; } filterBank; typedef struct { - ma_engine m_engine[MAX_AUDIODEVICES]; - filterBank m_filterBank[MAX_AUDIODEVICES][MAX_LAYERS]; - ma_writer_node m_sendAux1[MAX_LAYERS]; - ma_pcm_rb *aux1Buffer; -} audioObjects; + ma_engine engines[MAX_AUDIODEVICES]; + ma_device devices[MAX_AUDIODEVICES]; + filterBank filters[MAX_LAYERS]; + ma_writer_node sendAuxNode[MAX_AUDIODEVICES]; + ma_pcm_rb auxBuffers[MAX_AUDIODEVICES]; + ma_node_graph ng; + layerData currentStatus[MAX_LAYERS]; + ma_sound sounds[MAX_LAYERS]; + ma_resource_manager resourceManager; + ma_context context; + ma_device_info* pPlaybackDeviceInfos; + ma_uint32 playbackDeviceCount; + ma_uint32 devicesSelected; + ma_bool8 mediaLoaded[MAX_LAYERS]; + uint layersQty; + uint *audioDevicesId; + uint audioDevicesQty; + ma_data_source_node dataSupplyNode[MAX_AUDIODEVICES]; + ma_data_source_rb dataSourceRB[MAX_AUDIODEVICES]; +} MAE; class MiniAudioEngine { friend class libreMediaServerAudio; - static ma_pcm_rb *rb; public: MiniAudioEngine(); void stopEngine(); - bool startEngine(uint layersQty); - bool startDevice(uint *id, uint nb); + bool startEngine(uint layersQty, uint* audioDevicesID, uint audioDevicesQty); static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); - static void audioDataCallback1(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); - bool setBypass(int audioDevice, int layer, bool bypass); protected: ma_result loadMedia(int layer, char *media, uint audioDevice); @@ -69,33 +76,21 @@ protected: float getCursor(int layer); Status getStatus(int layer); inline float getVol(int layer) { - return ma_sound_get_volume(&m_currentSound[layer]); } - inline bool getAtEnd(int layer) { return m_currentSound[layer].atEnd; } + return ma_sound_get_volume(&m_mae.sounds[layer]); } + inline bool getAtEnd(int layer) { return m_mae.sounds[layer].atEnd; } ma_result filterParamChanged(int layer, int audioDevice, int channel, int value); + bool setBypass(int audioDevice, int layer, bool bypass); private: - 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; - 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_AUDIODEVICES][MAX_LAYERS]; - ma_engine m_engine[MAX_AUDIODEVICES]; - uint m_layersQty; - ma_writer_node m_sendToAux[MAX_LAYERS]; - audioObjects m_audioObjects; + MAE m_mae; + ma_result startDevices(); 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); + ma_result setNodeGraph(); + ma_result createFilterBank(uint layer); }; #endif // MINIAUDIOENGINE_H -- 2.39.5 From f0f6e595fb0797e7eaa365b486a8ed64fbcc4674 Mon Sep 17 00:00:00 2001 From: snt Date: Mon, 20 May 2024 20:08:26 +0200 Subject: [PATCH 42/49] =?UTF-8?q?cambiada=20curva=20de=20volume=20de=20c?= =?UTF-8?q?=C3=BAbia=20a=20cuadr=C3=A1tica,=20en=20pruebas=20a=20ver=20si?= =?UTF-8?q?=20es=20suficiente.=20valuebox=20de=20volumen=20en=20decibelios?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/audiolayerwidget.cpp | 2 +- src/miniaudioengine.cpp | 2 +- src/slidergroup.cpp | 14 ++++++++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index c3b1f86..3528f50 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -82,7 +82,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_pan = new SliderGroup("Pan", 0 , 255, 0, NULL); volumeBox->addWidget(m_pan); connect(m_pan, SIGNAL(valueChanged(int)), this, SLOT(panChanged(int))); - m_volume = new SliderGroup("Vol", 0 , 100, 2, NULL); + 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); diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 9b2f64a..0599fcc 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -420,7 +420,7 @@ void MiniAudioEngine::volChanged(int layer, float vol) return; if (vol >= 1) vol = 0.99f; - ma_sound_group_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, pow(vol, 3), FADE_TIME); + ma_sound_group_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, pow(vol, 2), FADE_TIME); m_mae.currentStatus[layer].vol = vol; } diff --git a/src/slidergroup.cpp b/src/slidergroup.cpp index c8e267d..55bfcf7 100644 --- a/src/slidergroup.cpp +++ b/src/slidergroup.cpp @@ -1,5 +1,5 @@ #include "slidergroup.h" - +#include #include #include @@ -39,7 +39,10 @@ SliderGroup::SliderGroup(QString name, valueBox.setFocusPolicy(Qt::NoFocus); valueBox.setButtonSymbols(QAbstractSpinBox::NoButtons); valueBox.setMinimumWidth(50); - valueBox.setRange(min, max); + if (decimals) + valueBox.setRange(-100, 100); + else + valueBox.setRange(min, max); valueBox.setValue(0); valueBox.setDecimals(decimals); valueBox.setObjectName(name); @@ -51,7 +54,7 @@ SliderGroup::SliderGroup(QString name, layout->addWidget(&slider); layout->addWidget(&valueBox); this->setStyleSheet("border: 1px solid #5a4855;" - "width: 50px;" + "width: 60px;" "margin: 0px;" "background-color: #383034;" ); @@ -74,7 +77,10 @@ void SliderGroup::setValue(float value) valueBox.blockSignals(true); if (int(value) != slider.value()) slider.setValue(value); - valueBox.setValue(value); + if (valueBox.decimals()) + valueBox.setValue(value - 100.0f); + else + valueBox.setValue(value); slider.blockSignals(false); valueBox.blockSignals(false); } -- 2.39.5 From 200dcf86d45e1d760368ebb9b772975da35cea19 Mon Sep 17 00:00:00 2001 From: snt Date: Tue, 21 May 2024 18:17:55 +0200 Subject: [PATCH 43/49] =?UTF-8?q?volumen=20y=20env=C3=ADos=20en=20logar?= =?UTF-8?q?=C3=ADtmico=20aut=C3=A9ntico,=20entre=20-85dB=20y=200.=20SLider?= =?UTF-8?q?s=20en=20UI=20para=20los=20env=C3=ADos=20(s=C3=B3lo=202,=20est?= =?UTF-8?q?=C3=A1ticos,=20hay=20que=20meter=20un=20bucle=20con=20el=20n?= =?UTF-8?q?=C3=BAmero=20de=20env=C3=ADos).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/roadmap.txt | 4 +++ src/audiolayerwidget.cpp | 58 +++++++++++++++++++++++----------- src/audiolayerwidget.h | 4 +++ src/audiowidget.cpp | 9 +++--- src/defines.h | 10 ++++-- src/dmxPersonality.h | 2 +- src/filterbankwidget.cpp | 3 +- src/libremediaserver-audio.cpp | 14 +++++--- src/miniaudioengine.cpp | 27 ++++++++++++---- src/miniaudioengine.h | 2 +- src/slidergroup.cpp | 22 +++++++++---- 11 files changed, 108 insertions(+), 47 deletions(-) diff --git a/docs/roadmap.txt b/docs/roadmap.txt index 154fd78..9e5ec0c 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -46,6 +46,10 @@ v 0.2.1 - Hardening: check return errors, try/catch exceptions, i'm too happy.... - Tests: errors on wrong conf file. - Ui/Ux: seek cursor playback +- ampliar writer para recibir un número n de entradas y escribirlas cada una en un buffer v0.2.0: - Vumeter or indicator about audio output in layer and master, add to sliderGroup. + --> en master se puede hacer con jack, solo en capas. + --> en las capas, hace falta otro nodo atacado en los buses de input que analice la entrada. +- mostrad información de envíos y dispositivos en ui diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 3528f50..f37b67d 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -1,4 +1,5 @@ #include "audiolayerwidget.h" +#include "dmxPersonality.h" #include #include @@ -11,7 +12,6 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): { QVBoxLayout *layout = new QVBoxLayout; - QVBoxLayout *playback = new QVBoxLayout; m_folderValue = new ClickableLabel; m_folderValue->setMaximumWidth(300); m_folderValue->setAlignment(Qt::AlignLeft); @@ -19,7 +19,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): "color: white;" "background-color: black;" ); - playback->addWidget(m_folderValue); + layout->addWidget(m_folderValue); m_fileValue = new ClickableLabel; connect(m_fileValue, SIGNAL(clicked()), this, SLOT(openMediaDialog())); connect(m_folderValue, SIGNAL(clicked()), this, SLOT(openMediaDialog())); @@ -29,10 +29,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): "color: white;" "background-color: black;" ); - playback->addWidget(m_fileValue); - playback->setSpacing(0); - playback->setContentsMargins(0, 0, 0, 0); - layout->addLayout(playback); + layout->addWidget(m_fileValue); m_suspendResumeButton = new QPushButton(this); m_suspendResumeButton->setText(statusToString(Status::Iddle)); @@ -74,17 +71,23 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_filterBank = new FilterBankWidget(this); connect(m_filterBank, SIGNAL(setBypass(bool)), this, SLOT(setBypass(bool))); layout->addWidget(m_filterBank); - - QVBoxLayout *volumeBox = new QVBoxLayout; m_pitch = new SliderGroup("Pitch", 0 , 255, 0, NULL); - volumeBox->addWidget(m_pitch); + layout->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); + layout->addWidget(m_pan); connect(m_pan, SIGNAL(valueChanged(int)), this, SLOT(panChanged(int))); - m_volume = new SliderGroup("Vol", 0, 100, 2, NULL); + + QHBoxLayout *volumeBox = new QHBoxLayout; + m_volume = new SliderGroup("Vol", 0, 65535, 2, NULL); volumeBox->addWidget(m_volume); connect(m_volume, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int))); + m_bus1 = new SliderGroup("Bus 1", 0, 65535, 2, NULL); + volumeBox->addWidget(m_bus1); + connect(m_bus1, SIGNAL(valueChanged(int)), this, SLOT(bus1VolumeChanged(int))); + m_bus2 = new SliderGroup("Bus 2", 0, 65535, 2, NULL); + volumeBox->addWidget(m_bus2); + connect(m_bus2, SIGNAL(valueChanged(int)), this, SLOT(bus2VolumeChanged(int))); volumeBox->setSpacing(0); volumeBox->setContentsMargins(0, 0, 0, 0); layout->addLayout(volumeBox); @@ -102,6 +105,16 @@ void AudioLayerWidget::volumeChanged(int value) emit(uiSliderChanged(m_layer, Slider::Volume, value)); } +void AudioLayerWidget::bus1VolumeChanged(int value) +{ + emit(uiSliderChanged(m_layer, Slider::Bus1, value)); +} + +void AudioLayerWidget::bus2VolumeChanged(int value) +{ + emit(uiSliderChanged(m_layer, Slider::Bus2, value)); +} + void AudioLayerWidget::panChanged(int value) { emit(uiSliderChanged(m_layer, Slider::Pan, value)); @@ -157,9 +170,9 @@ void AudioLayerWidget::openMediaDialog() // from DMX signals void AudioLayerWidget::setVol(float vol) { - m_volume->blockSignals(true); - m_volume->setValue(vol); - m_volume->blockSignals(false); + m_volume->blockSignals(true); + m_volume->setValue(vol); + m_volume->blockSignals(false); } void AudioLayerWidget::setPan(int pan) @@ -221,8 +234,17 @@ void AudioLayerWidget::setCurrentTime(float progress) void AudioLayerWidget::setFilterParam(int channel, int value) { - m_filterBank->blockSignals(true); - m_filterBank->setValue(channel, value); - m_filterBank->blockSignals(false); - + if (channel <= FILTER_BANK_GAIN - FILTER_CHANNELS){ + m_filterBank->blockSignals(true); + m_filterBank->setValue(channel, value); + m_filterBank->blockSignals(false); + } else if (channel == SEND1 - HP_FREQ) { + m_bus1->blockSignals(false); + m_bus1->setValue((value * 256) + 255); + m_bus1->blockSignals(true); + } else if (channel == SEND2 - HP_FREQ) { + m_bus2->blockSignals(false); + m_bus2->setValue(value * 256 + 255); + m_bus2->blockSignals(true); + } } diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index f3ba1e4..cb446a9 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -39,6 +39,8 @@ private: SliderGroup *m_volume; SliderGroup *m_pan; SliderGroup *m_pitch; + SliderGroup *m_bus1; + SliderGroup *m_bus2; QTimeEdit *m_progressTime; QTimeEdit *m_totalTimeValue; QProgressBar *m_progress; @@ -51,6 +53,8 @@ private slots: void openMediaDialog(); void toggleSuspendResume(); void volumeChanged(int vol); + void bus1VolumeChanged(int vol); + void bus2VolumeChanged(int vol); void panChanged(int pan); void pitchChanged(int pitch); void setBypass(bool value); diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index 2f3b634..da7c33f 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -1,6 +1,5 @@ #include "audiowidget.h" - -//#include +#include "dmxPersonality.h" AudioWidget::AudioWidget(QWidget *parent) : QWidget(parent) @@ -23,8 +22,8 @@ AudioWidget::AudioWidget(QWidget *parent) : for (int j = 0; j < FILTER_CHANNELS; j++) m_filtersUpdate[i][j] = -1; } - m_layout->setSpacing(0); - m_layout->setContentsMargins(1, 1, 1, 1); + m_layout->setSpacing(2); + m_layout->setContentsMargins(2, 2, 2, 2); setLayout(m_layout); m_refreshUi = new QTimer(this); connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); @@ -110,6 +109,6 @@ void AudioWidget::refreshUi() void AudioWidget::filterParamChanged(int layer, int channel, int value) { - m_filtersUpdate[layer][channel - 9] = value; + m_filtersUpdate[layer][channel - HP_FREQ] = value; m_layerUpdate[layer].updated = true; } diff --git a/src/defines.h b/src/defines.h index 5f73abe..8d81a59 100644 --- a/src/defines.h +++ b/src/defines.h @@ -10,9 +10,9 @@ #define FORMAT ma_format_f32 /* Must always be f32. */ #define CHANNELS 2 #define SAMPLE_RATE 48000 -#define UI_REFRESH_TIME 100 +#define UI_REFRESH_TIME 97 #define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks -#define FILTER_CHANNELS 13 // number of dmx channels dedicated to filters by layer +#define FILTER_CHANNELS 16 // number of dmx channels dedicated to filters by layer struct dmxSetting { int address; @@ -38,7 +38,9 @@ enum Slider Volume, Pan, Pitch, - Bypass + Bypass, + Bus1, + Bus2 }; #ifdef __cplusplus @@ -71,6 +73,8 @@ struct layerData { int address; unsigned int universe; int device; + int bus1Vol; + int bus2Vol; }; #endif // __cplusplus #endif // DEFINES_H diff --git a/src/dmxPersonality.h b/src/dmxPersonality.h index 1da964a..d08671a 100644 --- a/src/dmxPersonality.h +++ b/src/dmxPersonality.h @@ -23,7 +23,7 @@ #define HIGH_FREQ 19 #define HIGH_Q 20 #define HIGH_GAIN 21 -#define FILTER_BANK_GAIN 22 // not implemented yet +#define FILTER_BANK_GAIN 22 #define SEND1 23 #define SEND2 24 #define LAYER_CHANNELS 25 diff --git a/src/filterbankwidget.cpp b/src/filterbankwidget.cpp index c9b107d..4742af2 100644 --- a/src/filterbankwidget.cpp +++ b/src/filterbankwidget.cpp @@ -86,7 +86,8 @@ void FilterBankWidget::setValue(int filter, int value) result = (double)( value / 32.0f) + 0.1f; } else if (channel == HIGH_GAIN) { result = (double)(value / 21.25) - 6.023528412f; - } + } else + result = (double)value; fb[filter]->setValue(result); } diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 72398ee..07e3b0e 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -96,9 +96,8 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) QString mediaFile = NULL; int aux; if (channel == VOLUME_COARSE || channel == VOLUME_FINE) { - float tmp = value / 65025.0f; - m_mae.volChanged(layer, tmp); - m_updateUi[layer][0] = tmp * 100.0f; + m_mae.volChanged(layer, value); + m_updateUi[layer][0] = value; } else if (channel == PAN) { m_mae.panChanged(layer, value); m_updateUi[layer][1] = value; @@ -236,7 +235,7 @@ void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value) { switch (s){ case Slider::Volume: - m_mae.volChanged(layer, float((value / 100.0f))); + m_mae.volChanged(layer, value); break; case Slider::Pan: m_mae.panChanged(layer, value); @@ -246,6 +245,13 @@ void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value) break; case Slider::Bypass: m_mae.setBypass(m_dmxSettings.at(layer).audioDevice, layer, value); + break; + case Slider::Bus1: + m_mae.filterParamChanged(layer, m_dmxSettings.at(layer).audioDevice, SEND1, value / 255); + break; + case Slider::Bus2: + m_mae.filterParamChanged(layer, m_dmxSettings.at(layer).audioDevice, SEND2, value / 255); + break; } } diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 0599fcc..328e738 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -413,14 +413,17 @@ ma_result MiniAudioEngine::printFormatInfo(int layer) return result; } -// Expects between 0 and 1 vol value -void MiniAudioEngine::volChanged(int layer, float vol) +// Expects between 0 and 65535 vol value +void MiniAudioEngine::volChanged(int layer, int vol) { if (m_mae.mediaLoaded[layer] == false) return; - if (vol >= 1) - vol = 0.99f; - ma_sound_group_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, pow(vol, 2), FADE_TIME); + float db = ((float)vol / 771.0f) - 85.0f; + if (db <= -85.0f) { + db = 0; + } else + db = ma_volume_db_to_linear(db); + ma_sound_group_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, db, FADE_TIME); m_mae.currentStatus[layer].vol = vol; } @@ -618,13 +621,23 @@ ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int ch return result; } } else if (channel == SEND1) { - ma_node_set_output_bus_volume(&fb->output, 0, pow((value / 255.0f), 2)); + float db = ((float)value / 3.0f) - 85.0f; + if (db <= -85.0f) { + db = 0; + } else + db = ma_volume_db_to_linear(db); + ma_node_set_output_bus_volume(&fb->output, 0, db); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed set Send 1 Volume." << endl; return result; } } else if (channel == SEND2) { - ma_node_set_output_bus_volume(&fb->output, 1, pow((value / 255.0f), 2)); + float db = ((float)value / 3.0f) - 85.0f; + if (db <= -85.0f) { + db = 0; + } else + db = ma_volume_db_to_linear(db); + ma_node_set_output_bus_volume(&fb->output, 1, db); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed set Send 2 Volume." << endl; } diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 308706b..870dc42 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -66,7 +66,7 @@ public: protected: ma_result loadMedia(int layer, char *media, uint audioDevice); - void volChanged(int layer, float vol); + void volChanged(int layer, int vol); void panChanged(int layer, float pan); void pitchChanged(int layer, float pitch); ma_result playbackChanged(int layer, Status status); diff --git a/src/slidergroup.cpp b/src/slidergroup.cpp index 55bfcf7..9eedb70 100644 --- a/src/slidergroup.cpp +++ b/src/slidergroup.cpp @@ -39,9 +39,10 @@ SliderGroup::SliderGroup(QString name, valueBox.setFocusPolicy(Qt::NoFocus); valueBox.setButtonSymbols(QAbstractSpinBox::NoButtons); valueBox.setMinimumWidth(50); - if (decimals) - valueBox.setRange(-100, 100); - else + if (decimals) { + valueBox.setRange(-84.0f, 0.0f); + valueBox.setSpecialValueText("-inf"); + } else valueBox.setRange(min, max); valueBox.setValue(0); valueBox.setDecimals(decimals); @@ -66,20 +67,27 @@ SliderGroup::SliderGroup(QString name, void SliderGroup::sliderValueChanged(int value) { valueBox.blockSignals(true); - valueBox.setValue(value); + float db = ((float)value / 771.0f) - 85.0f; + if (db <= -84.5f) { + valueBox.setSpecialValueText("-inf"); + } else + valueBox.setValue(db); valueBox.blockSignals(false); emit valueChanged(value); }; void SliderGroup::setValue(float value) { + float db; + slider.blockSignals(true); valueBox.blockSignals(true); if (int(value) != slider.value()) slider.setValue(value); - if (valueBox.decimals()) - valueBox.setValue(value - 100.0f); - else + if (valueBox.decimals()) { + db = (float)(value / 771.0f) - 85.0f; + valueBox.setValue(db); + } else valueBox.setValue(value); slider.blockSignals(false); valueBox.blockSignals(false); -- 2.39.5 From 53bcb38455cb9aae86219910cd8b4b7505ebf3b2 Mon Sep 17 00:00:00 2001 From: snt Date: Wed, 22 May 2024 20:52:13 +0200 Subject: [PATCH 44/49] =?UTF-8?q?vumeter=20funcionando,=20hay=20que=20comp?= =?UTF-8?q?arar=20la=20salida=20con=20un=20vumeter=20que=20sepa=20que=20fu?= =?UTF-8?q?nciona=20bien=20y=20definir=20los=20par=C3=A1metros=20de=20vent?= =?UTF-8?q?anas,=20picos=20y=20dem=C3=A1s.=20Se=20insertan=20en=20la=20cad?= =?UTF-8?q?ena=20de=20audio=20porque=20no=20veo=20la=20forma=20de=20hacerl?= =?UTF-8?q?o=20en=20paralelo=20https://github.com/mackron/miniaudio/issues?= =?UTF-8?q?/850?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/changelog.txt | 1 + docs/roadmap.txt | 3 -- src/audiolayerwidget.cpp | 13 ++++++ src/audiolayerwidget.h | 2 + src/audiowidget.cpp | 21 ++++++--- src/audiowidget.h | 1 + src/defines.h | 1 + src/libremediaserver-audio.cpp | 1 + src/ma_writer_node.c | 79 ++++++++++++++++++++++++++++++++-- src/ma_writer_node.h | 31 +++++++++++++ src/miniaudioengine.cpp | 25 +++++++---- src/miniaudioengine.h | 10 +++-- 12 files changed, 165 insertions(+), 23 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index ef76b53..9a2f61b 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -30,6 +30,7 @@ v 0.2.0 Antígona (26/05/2024) - Play all medias in one folder consecutevily. - Play all medias in one folder randomly. + Multi audio devices output. ++ Vumeter for each layer v 0.1.3 Leúcade (19/04/2024) + Ubuntu 22.04 jammy. diff --git a/docs/roadmap.txt b/docs/roadmap.txt index 9e5ec0c..bc06163 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -49,7 +49,4 @@ v 0.2.1 - ampliar writer para recibir un número n de entradas y escribirlas cada una en un buffer v0.2.0: -- Vumeter or indicator about audio output in layer and master, add to sliderGroup. - --> en master se puede hacer con jack, solo en capas. - --> en las capas, hace falta otro nodo atacado en los buses de input que analice la entrada. - mostrad información de envíos y dispositivos en ui diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index f37b67d..646cb96 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -91,6 +91,9 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): volumeBox->setSpacing(0); volumeBox->setContentsMargins(0, 0, 0, 0); layout->addLayout(volumeBox); + m_level = new QLabel(); + m_level->setText("0"); + layout->addWidget(m_level); layout->setAlignment(Qt::AlignHCenter); layout->setSpacing(0); layout->setContentsMargins(1, 1, 1, 1); @@ -248,3 +251,13 @@ void AudioLayerWidget::setFilterParam(int channel, int value) m_bus2->blockSignals(true); } } + +void AudioLayerWidget::setLevel(float db) +{ + m_level->blockSignals(true); + if (db > -200) + m_level->setText(QString::number(db)); + else + m_level->setText("-inf"); + m_level->blockSignals(false); +} diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index cb446a9..0f9517c 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -28,6 +28,7 @@ public: void setPan(int pan); void setPitch(int pitch); void setFilterParam(int channel, int value); + void setLevel(float db); private: Status m_status; @@ -36,6 +37,7 @@ private: QPushButton *m_suspendResumeButton; ClickableLabel *m_fileValue; ClickableLabel * m_folderValue; + QLabel *m_level; SliderGroup *m_volume; SliderGroup *m_pan; SliderGroup *m_pitch; diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index da7c33f..98b3a32 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -13,12 +13,13 @@ AudioWidget::AudioWidget(QWidget *parent) : connect(alw, SIGNAL(uiPlaybackChanged(int, Status)), this, SIGNAL(uiPlaybackChanged(int, Status))); connect(alw, SIGNAL(uiLoadMedia(int, QString)), this, SIGNAL(uiLoadMedia(int, QString))); m_layerUpdate[i].status = Status::Iddle; - m_layerUpdate[i].duration = 0; + m_layerUpdate[i].duration = -1; m_layerUpdate[i].media = ""; - m_layerUpdate[i].vol = 0; - m_layerUpdate[i].pan = 128; - m_layerUpdate[i].pitch = 128; - m_layerUpdate[i].cursor = 0; + m_layerUpdate[i].vol = -1; + m_layerUpdate[i].pan = -1; + m_layerUpdate[i].pitch = -1; + m_layerUpdate[i].cursor = -1; + m_layerUpdate[i].level = 100; for (int j = 0; j < FILTER_CHANNELS; j++) m_filtersUpdate[i][j] = -1; } @@ -102,6 +103,10 @@ void AudioWidget::refreshUi() alw->setFilterParam(j, m_filtersUpdate[i][j]); m_filtersUpdate[i][j] = -1; } + if (m_layerUpdate[i].level < 100) { + alw->setLevel(m_layerUpdate[i].level); + m_layerUpdate[i].level = 100; + } m_layerUpdate[i].updated = false; } } @@ -112,3 +117,9 @@ void AudioWidget::filterParamChanged(int layer, int channel, int value) m_filtersUpdate[layer][channel - HP_FREQ] = value; m_layerUpdate[layer].updated = true; } + +void AudioWidget::levelChanged(int layer, float db) +{ + m_layerUpdate[layer].level = db; + m_layerUpdate[layer].updated = true; +} diff --git a/src/audiowidget.h b/src/audiowidget.h index 6849f5e..ddb5767 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -15,6 +15,7 @@ class AudioWidget : public QWidget public: AudioWidget(QWidget *parent = nullptr); void filterParamChanged(int layer, int channel, int value); + void levelChanged(int layer, float db); private: QHBoxLayout *m_layout; diff --git a/src/defines.h b/src/defines.h index 8d81a59..6751fd0 100644 --- a/src/defines.h +++ b/src/defines.h @@ -75,6 +75,7 @@ struct layerData { int device; int bus1Vol; int bus2Vol; + float level; }; #endif // __cplusplus #endif // DEFINES_H diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 07e3b0e..56b016a 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -170,6 +170,7 @@ void libreMediaServerAudio::refreshUi() { m_lmsUi->m_aw->cursorChanged(i, m_mae.getCursor(i)); m_updateUi[i][3] = -1; } + m_lmsUi->m_aw->levelChanged(i, m_mae.getLevel(i)); if (m_mae.getAtEnd(i)) { if (m_currentStatus[i] == Status::PlayingOnce) { m_currentStatus[i] = Status::Stopped; diff --git a/src/ma_writer_node.c b/src/ma_writer_node.c index 82e057c..2845649 100644 --- a/src/ma_writer_node.c +++ b/src/ma_writer_node.c @@ -46,7 +46,7 @@ MA_API ma_result ma_writer_node_init(ma_node_graph* pNodeGraph, const ma_writer_ { ma_result result; ma_node_config baseConfig; - ma_uint32 inputChannels[2]; // Equal in size to the number of input channels specified in the vtable. + ma_uint32 inputChannels[2]; ma_uint32 outputChannels[1]; if (pWriteNode == NULL || pConfig == NULL || pConfig->pBuffer == NULL \ @@ -82,14 +82,12 @@ MA_API void ma_writer_node_uninit(ma_writer_node* pWriteNode, const ma_allocatio * Data Source Ring Buffer */ - ma_result ma_data_source_rb_read(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { ma_data_source_rb* ds = (ma_data_source_rb*)pDataSource; ma_uint32 pcmFramesAvailableInRB = 0; ma_uint32 pcmFramesProcessed = 0; - // lo mismo que en el callback, va el doble de rápido y con glitches. while (pcmFramesProcessed < frameCount) { pcmFramesAvailableInRB = ma_pcm_rb_available_read(ds->rb); if (pcmFramesAvailableInRB == 0) { @@ -175,3 +173,78 @@ void ma_data_source_rb_uninit(ma_data_source_rb* pMyDataSource) { ma_data_source_uninit(&pMyDataSource->base); } + +/* + * vumeter + */ + +MA_API ma_vumeter_node_config ma_vumeter_node_config_init(ma_uint32 channels, ma_uint32 sampleRate) +{ + ma_vumeter_node_config config; + + MA_ZERO_OBJECT(&config); + config.nodeConfig = ma_node_config_init(); + config.channels = channels; + config.sampleRate = sampleRate; + + return config; +} + +static void ma_vumeter_node_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut) +{ + ma_vumeter_node* pVumeterNode = (ma_vumeter_node*)pNode; + + MA_ASSERT(pVumeterNode != NULL); + MA_ASSERT(ma_node_get_input_bus_count(&pVumeterNode->baseNode) == 1); + + for (uint i = 0; i < *pFrameCountIn; i++) { + float input = fabsf(ppFramesIn[0][i]); + pVumeterNode->level += pVumeterNode->alpha * (input - pVumeterNode->level); + } + ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, ma_format_f32, pVumeterNode->channels); +} + +static ma_node_vtable g_ma_vumeter_node_vtable = +{ + ma_vumeter_node_process_pcm_frames, + NULL, + 1, + 1, + 0 +}; + +MA_API ma_result ma_vumeter_node_init(ma_node_graph* pNodeGraph, const ma_vumeter_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_vumeter_node* pVumeterNode) +{ + ma_result result; + ma_node_config baseConfig; + ma_uint32 inputChannels[1]; + ma_uint32 outputChannels[1]; + + if (pVumeterNode == NULL || pConfig == NULL \ + || (pConfig->channels > MA_MAX_NODE_BUS_COUNT) ) { + return MA_INVALID_ARGS; + } + + MA_ZERO_OBJECT(pVumeterNode); + inputChannels[0] = pConfig->channels; + outputChannels[0] = pConfig->channels; + baseConfig = pConfig->nodeConfig; + baseConfig.vtable = &g_ma_vumeter_node_vtable; + baseConfig.pInputChannels = inputChannels; + baseConfig.pOutputChannels = outputChannels; + + result = ma_node_init(pNodeGraph, &baseConfig, pAllocationCallbacks, &pVumeterNode->baseNode); + if (result != MA_SUCCESS) { return result; + } + pVumeterNode->sampleRate = pConfig->sampleRate; + pVumeterNode->channels = pConfig->channels; + pVumeterNode->level = 0; + pVumeterNode->TC = 10000.0f; + pVumeterNode->alpha = 1.0 - expf( (-2.0 * M_PI) / (pVumeterNode->TC * pConfig->sampleRate)); + return MA_SUCCESS; +} + +MA_API void ma_vumeter_node_uninit(ma_vumeter_node* pVumeterNode, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_node_uninit(&pVumeterNode->baseNode, pAllocationCallbacks); +} diff --git a/src/ma_writer_node.h b/src/ma_writer_node.h index 1b5d259..ac592c7 100644 --- a/src/ma_writer_node.h +++ b/src/ma_writer_node.h @@ -8,6 +8,10 @@ extern "C" { #include "miniaudio.h" +/* + * writer + */ + typedef struct { ma_node_config nodeConfig; @@ -46,6 +50,33 @@ ma_result ma_data_source_rb_get_length(ma_data_source* pDataSource, ma_uint64* p ma_result ma_data_source_rb_init(ma_data_source_rb* pMyDataSource, ma_pcm_rb *ringBuffer); void ma_data_source_rb_uninit(ma_data_source_rb* pMyDataSource); + +/* + * VU meter + */ +typedef struct +{ + ma_node_config nodeConfig; + ma_uint32 channels; + ma_uint32 sampleRate; +} ma_vumeter_node_config; + +MA_API ma_vumeter_node_config ma_vumeter_node_config_init(ma_uint32 channels, ma_uint32 sampleRate); + +typedef struct +{ + ma_node_base baseNode; + ma_uint32 channels; + ma_uint32 sampleRate; + float level; + float TC; + float alpha; +} ma_vumeter_node; + +MA_API ma_result ma_vumeter_node_init(ma_node_graph* pNodeGraph, const ma_vumeter_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_vumeter_node* pVumeterNode); +MA_API void ma_vumeter_node_uninit(ma_vumeter_node* pVumeterNode, const ma_allocation_callbacks* pAllocationCallbacks); +MA_API inline float ma_vumeter_node_get_level(ma_vumeter_node* pVumeterNode) { return 5 * pVumeterNode->level; }; + #ifdef __cplusplus } #endif diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 328e738..3ea5c1b 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -24,7 +24,7 @@ void MiniAudioEngine::stopEngine() ma_sound_uninit(&m_mae.sounds[i]); } for (uint i = 0; i < m_mae.layersQty; i++) { - ma_node_uninit(&m_mae.filters[i].input, NULL); + ma_splitter_node_uninit(&m_mae.filters[i].input, NULL); ma_hpf_node_uninit(&m_mae.filters[i].hpf, NULL); ma_loshelf_node_uninit(&m_mae.filters[i].loshelf, NULL); ma_peak_node_uninit(&m_mae.filters[i].mLow, NULL); @@ -91,6 +91,7 @@ ma_result MiniAudioEngine::createFilterBank(uint layer) filterBank *fb = &m_mae.filters[layer]; ma_splitter_node_config splitterConfig = ma_splitter_node_config_init(CHANNELS); + splitterConfig.outputBusCount= 3; result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->input); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to init input node." << endl; @@ -131,6 +132,12 @@ ma_result MiniAudioEngine::createFilterBank(uint layer) cout << "ERROR " << result << ": Failed to init hi shelf filter node." << endl; return result; } + ma_vumeter_node_config vuc = ma_vumeter_node_config_init(CHANNELS, FORMAT); + ma_vumeter_node_init(ng, &vuc, NULL, &fb->vumeter); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to init vumeter node." << endl; + return result; + } splitterConfig.outputBusCount = m_mae.audioDevicesQty; result = ma_splitter_node_init(ng, &splitterConfig, NULL, &fb->output); if (result != MA_SUCCESS) { @@ -142,7 +149,7 @@ ma_result MiniAudioEngine::createFilterBank(uint layer) cout << "ERROR " << result << ": Failed to attach input node." << endl; return result; } - result = ma_node_attach_output_bus(&fb->input, 1, &fb->output, 0); + result = ma_node_attach_output_bus(&fb->input, 1, &fb->vumeter, 0); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to attach bypass connection." << endl; return result; @@ -168,7 +175,12 @@ ma_result MiniAudioEngine::createFilterBank(uint layer) cout << "ERROR " << result << ": Failed to attach high peaks filter node." << endl; return result; } - result = ma_node_attach_output_bus(&fb->hishelf, 0, &fb->output, 0); + result = ma_node_attach_output_bus(&fb->hishelf, 0, &fb->vumeter, 0); + if (result != MA_SUCCESS) { + cout << "ERROR " << result << ": Failed to attach high shelf filter node." << endl; + return result; + } + result = ma_node_attach_output_bus(&fb->vumeter, 0, &fb->output, 0); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to attach high shelf filter node." << endl; return result; @@ -219,12 +231,6 @@ ma_result MiniAudioEngine::setNodeGraph() { cout << "ERROR " << result << ": Failed to init writer node." << endl; return result; } - // esto va a dar problemas al sumar en el envío 0 una vez por cad envío extra. - // writer_node puede ser silencioso - // así ya estamos en el caso de disparar varios bang por cada envío en el mismo nodegraph - // es mejor que writer node tenga varias entradas, una por cada envío - // que se dispara con un único engine y proporciona un único stream de audio de vuelta a ese engine - // en vez de un puntero hay que pasarle un array de rb result = ma_node_attach_output_bus(&m_mae.sendAuxNode[i], 0, ma_engine_get_endpoint(&m_mae.engines[0]), 0); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to attach writer node." << endl; @@ -495,6 +501,7 @@ ma_result MiniAudioEngine::seekToCursor(int layer, int cursor) result = ma_sound_get_length_in_pcm_frames(&m_mae.sounds[layer], &end); if (result != MA_SUCCESS) { return result; } start = (cursor * end) / 65025; + Status oldStatus = m_mae.currentStatus[layer].status; result = ma_sound_seek_to_pcm_frame(&m_mae.sounds[layer], start); //result = ma_data_source_set_loop_point_in_pcm_frames(&m_mae.sounds[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 870dc42..89095e6 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -5,8 +5,6 @@ #define MA_ENABLE_JACK #define MA_NO_GENERATION #define MA_DEBUG_OUTPUT -#define MA_DISABLE_PULSEAUDIO -#define MA_DEBUG_OUTPUT #define MA_LOG_LEVEL_DEBUG DEBUG #define MINIAUDIO_IMPLEMENTATION #include "miniaudio.h" @@ -28,6 +26,7 @@ typedef struct ma_peak_node_config mHighConfig; ma_hishelf_node hishelf; ma_hishelf_node_config hishelfConfig; + ma_vumeter_node vumeter; ma_splitter_node output; } filterBank; @@ -76,10 +75,15 @@ protected: float getCursor(int layer); Status getStatus(int layer); inline float getVol(int layer) { - return ma_sound_get_volume(&m_mae.sounds[layer]); } + return ma_sound_get_volume(&m_mae.sounds[layer]); + }; inline bool getAtEnd(int layer) { return m_mae.sounds[layer].atEnd; } ma_result filterParamChanged(int layer, int audioDevice, int channel, int value); bool setBypass(int audioDevice, int layer, bool bypass); + inline float getLevel(int layer) { + float level = ma_vumeter_node_get_level(&m_mae.filters[layer].vumeter); + return ma_volume_linear_to_db(level); + }; private: MAE m_mae; -- 2.39.5 From db86987b6ade7d15ee2bafc8cb42caa0be730c62 Mon Sep 17 00:00:00 2001 From: snt Date: Thu, 23 May 2024 15:53:44 +0200 Subject: [PATCH 45/49] muestra nombre de los dispositivos en la UI --- src/audiolayerwidget.cpp | 51 +++++++++++++++++++++++++++++++--- src/audiolayerwidget.h | 7 +++-- src/audiowidget.cpp | 9 ++++++ src/audiowidget.h | 1 + src/libremediaserver-audio.cpp | 4 +++ src/miniaudioengine.cpp | 6 ++++ src/miniaudioengine.h | 8 ++++-- 7 files changed, 76 insertions(+), 10 deletions(-) diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 646cb96..7fc467b 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -91,9 +91,39 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): volumeBox->setSpacing(0); volumeBox->setContentsMargins(0, 0, 0, 0); layout->addLayout(volumeBox); - m_level = new QLabel(); - m_level->setText("0"); - layout->addWidget(m_level); + QHBoxLayout *labelsBox = new QHBoxLayout; + m_level = new QLabel("-inf"); + m_level->setStyleSheet("border: 1px solid #5a4855;" + "margin: 0px;" + "background-color: #180014;" + "color: white;" + "width:70px;" + "text-align: center;" + ); + m_level->setMinimumWidth(70); + m_level->setAlignment(Qt::AlignHCenter); + labelsBox->addWidget(m_level); + m_bus1Label = new QLabel("dummy"); + m_bus1Label->setMinimumWidth(80); + m_bus1Label->setStyleSheet("border: 1px solid #5a4855;" + "margin: 0px;" + "background-color: #383034;" + "width:70px;" + ); + m_bus1Label->setAlignment(Qt::AlignHCenter); + labelsBox->addWidget(m_bus1Label); + m_bus2Label = new QLabel("dummy"); + m_bus2Label->setMinimumWidth(80); + m_bus2Label->setStyleSheet("border: 1px solid #5a4855;" + "margin: 0px;" + "background-color: #383034;" + "width: 70px;" + ); + m_bus2Label->setAlignment(Qt::AlignHCenter); + labelsBox->addWidget(m_bus2Label); + labelsBox->setSpacing(0); + labelsBox->setContentsMargins(0, 0, 0, 0); + layout->addLayout(labelsBox); layout->setAlignment(Qt::AlignHCenter); layout->setSpacing(0); layout->setContentsMargins(1, 1, 1, 1); @@ -255,9 +285,22 @@ void AudioLayerWidget::setFilterParam(int channel, int value) void AudioLayerWidget::setLevel(float db) { m_level->blockSignals(true); - if (db > -200) + if (db > -150) m_level->setText(QString::number(db)); else m_level->setText("-inf"); m_level->blockSignals(false); } + +void AudioLayerWidget::setBusName(uint bus, char *name) +{ + if (bus == 0) { + m_bus1Label->blockSignals(true); + m_bus1Label->setText(name); + m_bus1Label->blockSignals(false); + } else if (bus == 1) { + m_bus2Label->blockSignals(true); + m_bus2Label->setText(name); + m_bus2Label->blockSignals(false); + } +} diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index 0f9517c..bc7010f 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -29,6 +29,7 @@ public: void setPitch(int pitch); void setFilterParam(int channel, int value); void setLevel(float db); + void setBusName(uint bus, char *name); private: Status m_status; @@ -37,7 +38,6 @@ private: QPushButton *m_suspendResumeButton; ClickableLabel *m_fileValue; ClickableLabel * m_folderValue; - QLabel *m_level; SliderGroup *m_volume; SliderGroup *m_pan; SliderGroup *m_pitch; @@ -47,8 +47,9 @@ private: QTimeEdit *m_totalTimeValue; QProgressBar *m_progress; FilterBankWidget *m_filterBank; - -//public slots: + QLabel *m_level; + QLabel *m_bus1Label; + QLabel *m_bus2Label; // From Ui private slots: diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index 98b3a32..8d43127 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -123,3 +123,12 @@ void AudioWidget::levelChanged(int layer, float db) m_layerUpdate[layer].level = db; m_layerUpdate[layer].updated = true; } + +void AudioWidget::busNameChanged(uint bus, char* name) +{ + for (uint i = 0; i < m_layers; i++) { + QLayoutItem *item = m_layout->itemAt(i); + AudioLayerWidget *alw = dynamic_cast(item->widget()); + alw->setBusName(bus, name); + } +} diff --git a/src/audiowidget.h b/src/audiowidget.h index ddb5767..238ead2 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -16,6 +16,7 @@ public: AudioWidget(QWidget *parent = nullptr); void filterParamChanged(int layer, int channel, int value); void levelChanged(int layer, float db); + void busNameChanged(uint bus, char *name); private: QHBoxLayout *m_layout; diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 56b016a..177eec2 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -229,6 +229,10 @@ void libreMediaServerAudio::setUi(libreMediaServerAudioUi *lmsUi) connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); m_refreshUi->start(UI_REFRESH_TIME); m_ola->start(QThread::TimeCriticalPriority ); + for (uint i = 0; i < m_settings->getAudioDeviceQty(); i++) { + char *name = m_mae.getDeviceName(i); + m_lmsUi->m_aw->busNameChanged(i, name); + } }; // From Ui widgets diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 3ea5c1b..292251e 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -340,6 +340,12 @@ ma_result MiniAudioEngine::getAllAudioDevices() return result; } +char* MiniAudioEngine::getDeviceName(uint id) +{ + return m_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[id]].name; + +} + ma_result MiniAudioEngine::loadMedia(int layer, char *file, uint audioDevice) { ma_result result; diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 89095e6..b97a9e9 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -43,6 +43,7 @@ typedef struct ma_resource_manager resourceManager; ma_context context; ma_device_info* pPlaybackDeviceInfos; + ma_device_info pSelectedPlaybackDeviceInfos[MAX_AUDIODEVICES]; ma_uint32 playbackDeviceCount; ma_uint32 devicesSelected; ma_bool8 mediaLoaded[MAX_LAYERS]; @@ -58,12 +59,12 @@ class MiniAudioEngine friend class libreMediaServerAudio; public: - MiniAudioEngine(); - void stopEngine(); - bool startEngine(uint layersQty, uint* audioDevicesID, uint audioDevicesQty); static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount); protected: + MiniAudioEngine(); + void stopEngine(); + bool startEngine(uint layersQty, uint* audioDevicesID, uint audioDevicesQty); ma_result loadMedia(int layer, char *media, uint audioDevice); void volChanged(int layer, int vol); void panChanged(int layer, float pan); @@ -84,6 +85,7 @@ protected: float level = ma_vumeter_node_get_level(&m_mae.filters[layer].vumeter); return ma_volume_linear_to_db(level); }; + char* getDeviceName(uint id); private: MAE m_mae; -- 2.39.5 From 0d29dda4c1e2ea5f4562df282c4ddfa8d6251fb2 Mon Sep 17 00:00:00 2001 From: snt Date: Fri, 24 May 2024 01:49:21 +0200 Subject: [PATCH 46/49] =?UTF-8?q?quita=20el=20glitch=20al=20resproducir=20?= =?UTF-8?q?despu=C3=A9s=20de=20cargar=20un=20fichero.=20varias=20optimizac?= =?UTF-8?q?iones=20y=20comprobaciones?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/changelog.txt | 7 ++--- docs/roadmap.txt | 38 ++++++++++---------------- src/audiolayerwidget.cpp | 11 ++++---- src/libremediaserver-audio.cpp | 11 ++++---- src/ma_writer_node.c | 10 +++---- src/ma_writer_node.h | 4 ++- src/miniaudioengine.cpp | 50 ++++++++++++++++++---------------- src/miniaudioengine.h | 6 ++-- 8 files changed, 66 insertions(+), 71 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 9a2f61b..5cd2ca3 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -1,10 +1,10 @@ ******************************************************************************* -Libre Media Server Audio - An Open source Media Server for arts and performing. +LibreMediaServer Audio - An open source media server for arts and performing. (c) Criptomart - Santiago Noreña 2012-2024 https://git.criptomart.net/libremediaserver ******************************************************************************* -Libre Media Server ChangeLog +LibreMediaServer Changelog v 0.2.0 Antígona (26/05/2024) + Change audio engine to miniaudio because is imposible pan in SFML and it has not access to low API and audio processing. @@ -20,9 +20,7 @@ v 0.2.0 Antígona (26/05/2024) + OlaThread send double channels (volume, entry point, load media) only once for each dmx frame buffer. + Terminal mode without graphical interface. All audio methods has been refactorized out of QWidget world. + Compilation without GUI (-DNOGUI). -+ 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). 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: @@ -31,6 +29,7 @@ v 0.2.0 Antígona (26/05/2024) - Play all medias in one folder randomly. + Multi audio devices output. + Vumeter for each layer ++ Show device name on Ui and ouput bus slider. v 0.1.3 Leúcade (19/04/2024) + Ubuntu 22.04 jammy. diff --git a/docs/roadmap.txt b/docs/roadmap.txt index bc06163..bc786a9 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -6,38 +6,32 @@ https://git.criptomart.net/libremediaserver Libre Media Server Roadmap -v 0.2.x -- skin, UI/UX +v 0.3.0 +- Ui/Ux: skin, style. +- Ui/Ux; Keyboards strokes. +- Ui/Ux: Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante. +- Ui/Ux: seek cursor playback - live input. -- insertar/bypass/eliminar audio procesadores sin reiniciar por capa y master. (compresor, equs). -- FX en capas master para que se puedan usar como envíos de auxiliar. -- Enroutado de masters en otros masters (retorno de efectos). - -v 0.2.2 -- Use sACN directly. +- remove ola and use sACN directly. + la instalación de OLA es mediante compilación, el repo de paquetes no está actualizado, nada user-friendly. + hay que empaquetar OLA, incluirlo en el binario, o implementar sACN y linkarlo estáticamente. + https://github.com/ETCLabs/sACN - Qt6. -- Audio processing (eq, rev, compresor, ...) by master and layer. -- CIPT/MSex, send icons play/pause/stop. +- CIPT/MSex. - Rasp build. - Octopus Sound Card support (6 outputs - 8 inputs). - -v 0.2.1 -- mute/panic on layer. - Master Bus Layer: - - each layer will have one "Gain" prefader that acts in source, "Vol" in v 1.3. - - each layer will have one volume dmx channel for each bus layer. One aux "Send" prefader. - mute/panic. - fader + value - - pan. - - magicq .hed + - pan + - magicq personality .hed - audio device linked, outputs will be redirected there. - dmx address + universe settings. -- Rose noise and sine generator in menu to test system. -- Ui/Ux; Keyboards strokes. -- Ui/Ux: Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante. + - compresor/limiter. +- Layer: + - audio procesadores (compresor, reveb, delay). + - mute/panic. +- Rose noise and sine generator. - Logs, verbosity, timestamp. - New play mode without pitch control, it saves resources. MA_SOUND_FLAG_NO_PITCH - SettingsDialog. @@ -45,8 +39,4 @@ 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 - ampliar writer para recibir un número n de entradas y escribirlas cada una en un buffer - -v0.2.0: -- mostrad información de envíos y dispositivos en ui diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 7fc467b..b1eb8b7 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -198,6 +198,7 @@ void AudioLayerWidget::openMediaDialog() fileNames = dialog.selectedFiles(); emit uiLoadMedia(m_layer, fileNames.at(0)); this->setMediaFile(fileNames.at(0)); + this->setPlaybackStatus(Status::Stopped); } // from DMX signals @@ -267,18 +268,18 @@ void AudioLayerWidget::setCurrentTime(float progress) void AudioLayerWidget::setFilterParam(int channel, int value) { - if (channel <= FILTER_BANK_GAIN - FILTER_CHANNELS){ + if (channel <= FILTER_BANK_GAIN - HP_FREQ){ m_filterBank->blockSignals(true); m_filterBank->setValue(channel, value); m_filterBank->blockSignals(false); } else if (channel == SEND1 - HP_FREQ) { - m_bus1->blockSignals(false); - m_bus1->setValue((value * 256) + 255); m_bus1->blockSignals(true); + m_bus1->setValue((value * 256) + 255); + m_bus1->blockSignals(false); } else if (channel == SEND2 - HP_FREQ) { - m_bus2->blockSignals(false); - m_bus2->setValue(value * 256 + 255); m_bus2->blockSignals(true); + m_bus2->setValue(value * 256 + 255); + m_bus2->blockSignals(false); } } diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 177eec2..dd6cedd 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -70,8 +70,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_dmxSettings.at(layer).audioDevice); + m_mae.loadMedia(layer, mediaFile.toLatin1().data()); m_currentMedia[layer] = mediaFile; #ifndef NOGUI if (m_ui) @@ -135,7 +134,7 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) } #endif } else if (channel >= HP_FREQ) { - m_mae.filterParamChanged(layer, m_dmxSettings.at(layer).audioDevice, channel, value); + m_mae.filterParamChanged(layer, channel, value); #ifndef NOGUI if (m_ui) { m_lmsUi->m_aw->filterParamChanged(layer, channel, value); @@ -252,10 +251,10 @@ void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value) m_mae.setBypass(m_dmxSettings.at(layer).audioDevice, layer, value); break; case Slider::Bus1: - m_mae.filterParamChanged(layer, m_dmxSettings.at(layer).audioDevice, SEND1, value / 255); + m_mae.filterParamChanged(layer, SEND1, value / 255.0f); break; case Slider::Bus2: - m_mae.filterParamChanged(layer, m_dmxSettings.at(layer).audioDevice, SEND2, value / 255); + m_mae.filterParamChanged(layer, SEND2, value / 255.0f); break; } } @@ -278,7 +277,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(), m_dmxSettings[layer].audioDevice); + result = m_mae.loadMedia(layer, mediaFile.toLatin1().data()); if (result == MA_SUCCESS) { m_currentMedia[layer] = mediaFile; m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); diff --git a/src/ma_writer_node.c b/src/ma_writer_node.c index 2845649..5b20f66 100644 --- a/src/ma_writer_node.c +++ b/src/ma_writer_node.c @@ -38,8 +38,6 @@ static ma_node_vtable g_ma_writer_node_vtable = 2, 1, 0 -// MA_NODE_FLAG_CONTINUOUS_PROCESSING -// MA_NODE_FLAG_SILENT_OUTPUT }; MA_API ma_result ma_writer_node_init(ma_node_graph* pNodeGraph, const ma_writer_node_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_writer_node* pWriteNode) @@ -178,7 +176,7 @@ void ma_data_source_rb_uninit(ma_data_source_rb* pMyDataSource) * vumeter */ -MA_API ma_vumeter_node_config ma_vumeter_node_config_init(ma_uint32 channels, ma_uint32 sampleRate) +MA_API ma_vumeter_node_config ma_vumeter_node_config_init(ma_uint32 channels, ma_uint32 format, ma_uint32 sampleRate) { ma_vumeter_node_config config; @@ -186,6 +184,7 @@ MA_API ma_vumeter_node_config ma_vumeter_node_config_init(ma_uint32 channels, ma config.nodeConfig = ma_node_config_init(); config.channels = channels; config.sampleRate = sampleRate; + config.format = format; return config; } @@ -201,7 +200,7 @@ static void ma_vumeter_node_process_pcm_frames(ma_node* pNode, const float** ppF float input = fabsf(ppFramesIn[0][i]); pVumeterNode->level += pVumeterNode->alpha * (input - pVumeterNode->level); } - ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, ma_format_f32, pVumeterNode->channels); + ma_copy_pcm_frames(ppFramesOut[0], ppFramesIn[0], *pFrameCountOut, pVumeterNode->format, pVumeterNode->channels); } static ma_node_vtable g_ma_vumeter_node_vtable = @@ -238,8 +237,9 @@ MA_API ma_result ma_vumeter_node_init(ma_node_graph* pNodeGraph, const ma_vumete } pVumeterNode->sampleRate = pConfig->sampleRate; pVumeterNode->channels = pConfig->channels; + pVumeterNode->format = pConfig->format; pVumeterNode->level = 0; - pVumeterNode->TC = 10000.0f; + pVumeterNode->TC = 0.250f; pVumeterNode->alpha = 1.0 - expf( (-2.0 * M_PI) / (pVumeterNode->TC * pConfig->sampleRate)); return MA_SUCCESS; } diff --git a/src/ma_writer_node.h b/src/ma_writer_node.h index ac592c7..3e03df5 100644 --- a/src/ma_writer_node.h +++ b/src/ma_writer_node.h @@ -59,15 +59,17 @@ typedef struct ma_node_config nodeConfig; ma_uint32 channels; ma_uint32 sampleRate; + ma_uint32 format; } ma_vumeter_node_config; -MA_API ma_vumeter_node_config ma_vumeter_node_config_init(ma_uint32 channels, ma_uint32 sampleRate); +MA_API ma_vumeter_node_config ma_vumeter_node_config_init(ma_uint32 channels, ma_uint32 format, ma_uint32 sampleRate); typedef struct { ma_node_base baseNode; ma_uint32 channels; ma_uint32 sampleRate; + ma_uint32 format; float level; float TC; float alpha; diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 292251e..1d0d5b3 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -132,7 +132,7 @@ ma_result MiniAudioEngine::createFilterBank(uint layer) cout << "ERROR " << result << ": Failed to init hi shelf filter node." << endl; return result; } - ma_vumeter_node_config vuc = ma_vumeter_node_config_init(CHANNELS, FORMAT); + ma_vumeter_node_config vuc = ma_vumeter_node_config_init(CHANNELS, FORMAT, SAMPLE_RATE); ma_vumeter_node_init(ng, &vuc, NULL, &fb->vumeter); if (result != MA_SUCCESS) { cout << "ERROR " << result << ": Failed to init vumeter node." << endl; @@ -278,7 +278,7 @@ ma_result MiniAudioEngine::startDevices() deviceConfig.dataCallback = audioDataCallback; engineConfig = ma_engine_config_init(); engineConfig.pResourceManager = &m_mae.resourceManager; - engineConfig.gainSmoothTimeInMilliseconds = SAMPLE_RATE / 25; + engineConfig.defaultVolumeSmoothTimeInPCMFrames = SAMPLE_RATE / 20; engineConfig.noAutoStart = MA_TRUE; for (uint internalId = 0; internalId < m_mae.audioDevicesQty; internalId++) { @@ -346,25 +346,28 @@ char* MiniAudioEngine::getDeviceName(uint id) } -ma_result MiniAudioEngine::loadMedia(int layer, char *file, uint audioDevice) +ma_result MiniAudioEngine::loadMedia(int layer, char *file) { ma_result result; if (m_mae.mediaLoaded[layer] == true) { + ma_sound_set_volume(&m_mae.sounds[layer], 0.0f); + ma_sound_stop(&m_mae.sounds[layer]); ma_sound_uninit(&m_mae.sounds[layer]); m_mae.mediaLoaded[layer] = false; } - result = ma_sound_init_from_file(&m_mae.engines[0], file, \ - MA_SOUND_FLAG_NO_SPATIALIZATION \ - , NULL, NULL, &m_mae.sounds[layer]); + ma_sound_config soundConfig = ma_sound_config_init(); + soundConfig = ma_sound_config_init(); + soundConfig.pFilePath = file; + soundConfig.pInitialAttachment = &m_mae.filters[layer].input; + soundConfig.initialAttachmentInputBusIndex = 0; + soundConfig.channelsIn = 0; + soundConfig.channelsOut = CHANNELS; + soundConfig.flags = MA_SOUND_FLAG_NO_SPATIALIZATION | MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT | MA_SOUND_FLAG_STREAM; //| MA_SOUND_FLAG_NO_PITCH + result = ma_sound_init_ex(&m_mae.engines[0], &soundConfig, &m_mae.sounds[layer]); if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to load file " << file << endl; - return result; - } - result = ma_node_attach_output_bus(&m_mae.sounds[layer], 0, &m_mae.filters[layer].input, 0); - if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to attach sound output bus " << audioDevice << endl; + cout << "Error" << result << ": Failed to load file " << file << endl; return result; } m_mae.mediaLoaded[layer] = true; @@ -435,7 +438,7 @@ void MiniAudioEngine::volChanged(int layer, int vol) db = 0; } else db = ma_volume_db_to_linear(db); - ma_sound_group_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, db, FADE_TIME); + ma_sound_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, db, FADE_TIME); m_mae.currentStatus[layer].vol = vol; } @@ -485,12 +488,13 @@ ma_result MiniAudioEngine::playbackChanged(int layer, Status status) ma_sound_set_stop_time_in_milliseconds(&m_mae.sounds[layer], ~(ma_uint64)0); ma_sound_set_looping(&m_mae.sounds[layer], loop); result = ma_sound_start(&m_mae.sounds[layer]); - if (m_mae.currentStatus[layer].cursor != 0) { - usleep(1000 * 50); // Avoid small glitch at start, how to flush the cached buffers in audio pipe line? - } - this->volChanged(layer, m_mae.currentStatus[layer].vol); - default: - break; + //this->volChanged(layer, m_mae.currentStatus[layer].vol); + float db = (m_mae.currentStatus[layer].vol / 771.0f) - 85.0f; + if (db <= -85.0f) { + db = 0; + } else + db = ma_volume_db_to_linear(db); + ma_sound_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, db, 0); } if (result == MA_SUCCESS) m_mae.currentStatus[layer].status = status; @@ -506,7 +510,7 @@ ma_result MiniAudioEngine::seekToCursor(int layer, int cursor) return MA_DOES_NOT_EXIST; result = ma_sound_get_length_in_pcm_frames(&m_mae.sounds[layer], &end); if (result != MA_SUCCESS) { return result; } - start = (cursor * end) / 65025; + start = (cursor * end) / 65535; Status oldStatus = m_mae.currentStatus[layer].status; result = ma_sound_seek_to_pcm_frame(&m_mae.sounds[layer], start); //result = ma_data_source_set_loop_point_in_pcm_frames(&m_mae.sounds[layer], start, end); // this do nothing here, it must be done after set_looping or start? @@ -531,14 +535,14 @@ void MiniAudioEngine::refreshValues(int layer) { this->seekToCursor(layer, m_mae.currentStatus[layer].cursor); this->panChanged(layer, m_mae.currentStatus[layer].pan); - this->volChanged(layer, m_mae.currentStatus[layer].vol); this->pitchChanged(layer, m_mae.currentStatus[layer].pitch); + ma_sound_group_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, 0, 0.0f); this->playbackChanged(layer, m_mae.currentStatus[layer].status); + this->volChanged(layer, m_mae.currentStatus[layer].vol); } -ma_result MiniAudioEngine::filterParamChanged(int layer, int audioDevice, int channel, int value) +ma_result MiniAudioEngine::filterParamChanged(int layer, int channel, int value) { - (void)audioDevice; ma_result result = MA_SUCCESS; filterBank *fb = &m_mae.filters[layer]; diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index b97a9e9..38107d8 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -65,7 +65,7 @@ protected: MiniAudioEngine(); void stopEngine(); bool startEngine(uint layersQty, uint* audioDevicesID, uint audioDevicesQty); - ma_result loadMedia(int layer, char *media, uint audioDevice); + ma_result loadMedia(int layer, char *media); void volChanged(int layer, int vol); void panChanged(int layer, float pan); void pitchChanged(int layer, float pitch); @@ -79,11 +79,11 @@ protected: return ma_sound_get_volume(&m_mae.sounds[layer]); }; inline bool getAtEnd(int layer) { return m_mae.sounds[layer].atEnd; } - ma_result filterParamChanged(int layer, int audioDevice, int channel, int value); + ma_result filterParamChanged(int layer, int channel, int value); bool setBypass(int audioDevice, int layer, bool bypass); inline float getLevel(int layer) { float level = ma_vumeter_node_get_level(&m_mae.filters[layer].vumeter); - return ma_volume_linear_to_db(level); + return ma_volume_linear_to_db(level) - 4.0f; }; char* getDeviceName(uint id); -- 2.39.5 From 6a22534686e84215e24aaa24ba6eea54dae349ef Mon Sep 17 00:00:00 2001 From: snt Date: Fri, 24 May 2024 19:48:45 +0200 Subject: [PATCH 47/49] =?UTF-8?q?solucionado=20el=20glich=20de=20verdad...?= =?UTF-8?q?=20los=20loop=20points=20y=20range=20points=20no=20funcionan=20?= =?UTF-8?q?al=20final=20de=20l=20loop,=20es=20igual=20que=20seektoPCMFrame?= =?UTF-8?q?=20en=20su=20estado=20actual.=20cambios=20cosm=C3=A9ticos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/roadmap.txt | 2 + libremediaserver-audio.pro | 3 +- src/audiolayerwidget.cpp | 30 +++++++------- src/defines.h | 4 +- src/libremediaserver-audio.cpp | 6 ++- src/miniaudioengine.cpp | 74 +++++++++++++++++++++++++++------- src/miniaudioengine.h | 3 ++ 7 files changed, 87 insertions(+), 35 deletions(-) diff --git a/docs/roadmap.txt b/docs/roadmap.txt index bc786a9..9e4f017 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -40,3 +40,5 @@ v 0.3.0 - Hardening: check return errors, try/catch exceptions, i'm too happy.... - Tests: errors on wrong conf file. - ampliar writer para recibir un número n de entradas y escribirlas cada una en un buffer +- aislar miniaudio del callback dmx tal como hemos hecho con la Ui, al menos las operaciones lentas como cargar medios. +- en load media usar un fence para actualizar mediaLoaded. diff --git a/libremediaserver-audio.pro b/libremediaserver-audio.pro index 391f2c9..67c50c5 100644 --- a/libremediaserver-audio.pro +++ b/libremediaserver-audio.pro @@ -39,9 +39,8 @@ SOURCES += src/main.cpp \ src/settings.cpp \ src/slidergroup.cpp FORMS += src/libremediaserver-audio-gui.ui -CCFLAG += -msse2 -mavx2 #-fsanitize=address -g3 -O0 +CCFLAG += -msse2 -mavx2 QMAKE_CXXFLAGS += $$(CXXFLAG) -#QMAKE_CXXFLAGS += -fsanitize=address -g3 -O0 QMAKE_CFLAGS += $$(CCFLAG) QMAKE_LFLAGS += $$(LDFLAG) LIBS += -lola -lolacommon -ldl -lpthread -lm diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index b1eb8b7..42c4838 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -93,33 +93,35 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): layout->addLayout(volumeBox); QHBoxLayout *labelsBox = new QHBoxLayout; m_level = new QLabel("-inf"); - m_level->setStyleSheet("border: 1px solid #5a4855;" + m_level->setStyleSheet("border: 1px solid #CFB0C9;" "margin: 0px;" - "background-color: #180014;" + "margin-right: 5px;" + "margin-left: 5px;" + "background-color: black;" "color: white;" - "width:70px;" + "width:80px;" "text-align: center;" ); - m_level->setMinimumWidth(70); + m_level->setMinimumWidth(80); + m_level->setMaximumWidth(80); + m_level->setMinimumHeight(20); m_level->setAlignment(Qt::AlignHCenter); labelsBox->addWidget(m_level); m_bus1Label = new QLabel("dummy"); m_bus1Label->setMinimumWidth(80); - m_bus1Label->setStyleSheet("border: 1px solid #5a4855;" + m_bus1Label->setStyleSheet("border: 1px solid #CFB0C9;" "margin: 0px;" - "background-color: #383034;" - "width:70px;" - ); - m_bus1Label->setAlignment(Qt::AlignHCenter); + "background-color: black;" + "color: white;" + "font-size: 11px;"); labelsBox->addWidget(m_bus1Label); m_bus2Label = new QLabel("dummy"); m_bus2Label->setMinimumWidth(80); - m_bus2Label->setStyleSheet("border: 1px solid #5a4855;" + m_bus2Label->setStyleSheet("border: 1px solid #CFB0C9;" "margin: 0px;" - "background-color: #383034;" - "width: 70px;" - ); - m_bus2Label->setAlignment(Qt::AlignHCenter); + "background-color: black;" + "color: white;" + "font-size: 11px;"); labelsBox->addWidget(m_bus2Label); labelsBox->setSpacing(0); labelsBox->setContentsMargins(0, 0, 0, 0); diff --git a/src/defines.h b/src/defines.h index 6751fd0..e19ecf7 100644 --- a/src/defines.h +++ b/src/defines.h @@ -10,8 +10,8 @@ #define FORMAT ma_format_f32 /* Must always be f32. */ #define CHANNELS 2 #define SAMPLE_RATE 48000 -#define UI_REFRESH_TIME 97 -#define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks +#define UI_REFRESH_TIME 123 +#define FADE_TIME 20 #define FILTER_CHANNELS 16 // number of dmx channels dedicated to filters by layer struct dmxSetting { diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index dd6cedd..c9d2dd3 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -129,6 +129,7 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) #ifndef NOGUI if (m_ui) { m_lmsUi->m_aw->playbackChanged(layer, s); + m_updateUi[layer][3] = 1; m_played.clear(); m_played.append(m_ola->getValue(layer, DMX_FILE)); } @@ -173,6 +174,7 @@ void libreMediaServerAudio::refreshUi() { if (m_mae.getAtEnd(i)) { if (m_currentStatus[i] == Status::PlayingOnce) { m_currentStatus[i] = Status::Stopped; + m_lmsUi->m_aw->playbackChanged(i, Status::Stopped); } if (m_currentStatus[i] == Status::PlayingFolder) { uint last = m_played.last(); @@ -187,7 +189,7 @@ void libreMediaServerAudio::refreshUi() { m_lmsUi->m_aw->playbackChanged(i, Status::Stopped); } } - if (m_currentStatus[i] == Status::PlayingFolderLoop) { + else if (m_currentStatus[i] == Status::PlayingFolderLoop) { uint last = m_played.last(); int folder = m_ola->getValue(i, DMX_FOLDER); last++; @@ -199,7 +201,7 @@ void libreMediaServerAudio::refreshUi() { m_mae.playbackChanged(i, Status::PlayingFolder); } } - if (m_currentStatus[i] == Status::PlayingFolderRandom) { + else if (m_currentStatus[i] == Status::PlayingFolderRandom) { int last = -1; int folder = m_ola->getValue(i, DMX_FOLDER); if (uint(abs(m_played.size())) >= m_mediaLibrary->getMediaFolderCount(folder)) diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index 1d0d5b3..d2ebc17 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -278,7 +278,7 @@ ma_result MiniAudioEngine::startDevices() deviceConfig.dataCallback = audioDataCallback; engineConfig = ma_engine_config_init(); engineConfig.pResourceManager = &m_mae.resourceManager; - engineConfig.defaultVolumeSmoothTimeInPCMFrames = SAMPLE_RATE / 20; + //engineConfig.defaultVolumeSmoothTimeInPCMFrames = SAMPLE_RATE / 20; engineConfig.noAutoStart = MA_TRUE; for (uint internalId = 0; internalId < m_mae.audioDevicesQty; internalId++) { @@ -482,38 +482,85 @@ ma_result MiniAudioEngine::playbackChanged(int layer, Status status) case Status::PlayingLoop: loop = true; case Status::PlayingOnce: + ma_sound_set_looping(&m_mae.sounds[layer], loop); + if (m_mae.currentStatus[layer].cursor > 0) { + this->setRangePoint(layer, m_mae.currentStatus[layer].cursor); + this->setLoopPoint(layer, m_mae.currentStatus[layer].cursor); + } case Status::PlayingFolder: case Status::PlayingFolderLoop: case Status::PlayingFolderRandom: ma_sound_set_stop_time_in_milliseconds(&m_mae.sounds[layer], ~(ma_uint64)0); - ma_sound_set_looping(&m_mae.sounds[layer], loop); - result = ma_sound_start(&m_mae.sounds[layer]); - //this->volChanged(layer, m_mae.currentStatus[layer].vol); float db = (m_mae.currentStatus[layer].vol / 771.0f) - 85.0f; if (db <= -85.0f) { db = 0; } else db = ma_volume_db_to_linear(db); - ma_sound_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, db, 0); + result = ma_sound_start(&m_mae.sounds[layer]); + ma_sound_group_set_volume(&m_mae.sounds[layer], 0.0f); + ma_sound_set_fade_in_milliseconds(&m_mae.sounds[layer], 0, db, FADE_TIME); + ma_sound_group_set_volume(&m_mae.sounds[layer], 1.0f); } if (result == MA_SUCCESS) m_mae.currentStatus[layer].status = status; return result; } -ma_result MiniAudioEngine::seekToCursor(int layer, int cursor) +ma_result MiniAudioEngine::setRangePoint(int layer, int cursor) { ma_result result = MA_SUCCESS; - ma_uint64 end, start; + ma_uint64 end = 0, start; if (m_mae.mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; - result = ma_sound_get_length_in_pcm_frames(&m_mae.sounds[layer], &end); - if (result != MA_SUCCESS) { return result; } - start = (cursor * end) / 65535; - Status oldStatus = m_mae.currentStatus[layer].status; + if (cursor == 0) + start = 0; + else { + result = ma_sound_get_length_in_pcm_frames(&m_mae.sounds[layer], &end); + if (result != MA_SUCCESS) { return result; } + start = (cursor * end) / 65535; + } + result = ma_data_source_set_range_in_pcm_frames(&m_mae.sounds[layer].pDataSource, start, end); + if (result != MA_SUCCESS) + cout << "ERROR " << result << " :set range point" << endl; + return (result); +} + +ma_result MiniAudioEngine::setLoopPoint(int layer, int cursor) +{ + ma_result result = MA_SUCCESS; + ma_uint64 end = 0, start; + + if (m_mae.mediaLoaded[layer] == false) + return MA_DOES_NOT_EXIST; + if (cursor == 0) + start = 0; + else { + result = ma_sound_get_length_in_pcm_frames(&m_mae.sounds[layer], &end); + if (result != MA_SUCCESS) { return result; } + start = (cursor * end) / 65535; + } + result = ma_data_source_set_loop_point_in_pcm_frames(&m_mae.sounds[layer].pDataSource, start + 1, end - 1); + if (result != MA_SUCCESS) + cout << "ERROR " << result << " :set loop point" << endl; + return (result); +} + +ma_result MiniAudioEngine::seekToCursor(int layer, int cursor) +{ + ma_result result = MA_SUCCESS; + ma_uint64 end = 0, start; + + if (m_mae.mediaLoaded[layer] == false) + return MA_DOES_NOT_EXIST; + if (cursor == 0) + start = 0; + else { + result = ma_sound_get_length_in_pcm_frames(&m_mae.sounds[layer], &end); + if (result != MA_SUCCESS) { return result; } + start = (cursor * end) / 65535; + } result = ma_sound_seek_to_pcm_frame(&m_mae.sounds[layer], start); - //result = ma_data_source_set_loop_point_in_pcm_frames(&m_mae.sounds[layer], start, end); // this do nothing here, it must be done after set_looping or start? return (result); } @@ -533,12 +580,9 @@ Status MiniAudioEngine::getStatus(int layer) void MiniAudioEngine::refreshValues(int layer) { - this->seekToCursor(layer, m_mae.currentStatus[layer].cursor); this->panChanged(layer, m_mae.currentStatus[layer].pan); this->pitchChanged(layer, m_mae.currentStatus[layer].pitch); - ma_sound_group_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, 0, 0.0f); this->playbackChanged(layer, m_mae.currentStatus[layer].status); - this->volChanged(layer, m_mae.currentStatus[layer].vol); } ma_result MiniAudioEngine::filterParamChanged(int layer, int channel, int value) diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 38107d8..21deff3 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -3,6 +3,7 @@ #define MA_ENABLE_ONLY_SPECIFIC_BACKENDS #define MA_ENABLE_JACK +#define MA_DISABLE_PULSE #define MA_NO_GENERATION #define MA_DEBUG_OUTPUT #define MA_LOG_LEVEL_DEBUG DEBUG @@ -97,6 +98,8 @@ private: ma_result seekToCursor(int layer, int cursor); ma_result setNodeGraph(); ma_result createFilterBank(uint layer); + ma_result setLoopPoint(int layer, int cursor); + ma_result setRangePoint(int layer, int cursor); }; #endif // MINIAUDIOENGINE_H -- 2.39.5 From 029bcdc47ea8dbd24bb9ef4301e83f69ae4ddd70 Mon Sep 17 00:00:00 2001 From: snt Date: Sat, 25 May 2024 17:35:53 +0200 Subject: [PATCH 48/49] =?UTF-8?q?cambios=20cosm=C3=A9ticos.=20protege=20me?= =?UTF-8?q?jor=20el=20cambio=20de=20medios.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/audiolayerwidget.cpp | 83 ++++++++++++++++++++++-------- src/audiowidget.cpp | 5 +- src/clickabledoublespinbox.cpp | 8 +-- src/defines.h | 4 +- src/filterbankwidget.cpp | 21 ++++---- src/libremediaserver-audio-gui.cpp | 5 +- src/libremediaserver-audio-gui.ui | 4 +- src/miniaudioengine.cpp | 69 +++++++++++++------------ 8 files changed, 123 insertions(+), 76 deletions(-) diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 42c4838..0e9527b 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -13,21 +13,33 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): QVBoxLayout *layout = new QVBoxLayout; m_folderValue = new ClickableLabel; - m_folderValue->setMaximumWidth(300); m_folderValue->setAlignment(Qt::AlignLeft); + m_folderValue->setFocusPolicy(Qt::NoFocus); + m_folderValue->setMinimumWidth(MIN_WIDTH); + m_folderValue->setMaximumWidth(MAX_WIDTH); + m_folderValue->setContentsMargins(3,1,3,1); + m_folderValue->setText("Click to open media file (mp3, wav, flac)"); m_folderValue->setStyleSheet( + "margin: 0px;" "color: white;" "background-color: black;" + "font-size: 12px;" ); layout->addWidget(m_folderValue); m_fileValue = new ClickableLabel; + m_fileValue->setAlignment(Qt::AlignLeft); + m_fileValue->setFocusPolicy(Qt::NoFocus); + m_fileValue->setMinimumWidth(MIN_WIDTH); + m_fileValue->setMaximumWidth(MAX_WIDTH); + m_fileValue->setContentsMargins(3,1,3,1); + m_fileValue->setText("++ empty ++"); connect(m_fileValue, SIGNAL(clicked()), this, SLOT(openMediaDialog())); connect(m_folderValue, SIGNAL(clicked()), this, SLOT(openMediaDialog())); - m_fileValue->setMaximumWidth(300); - m_fileValue->setAlignment(Qt::AlignLeft); m_fileValue->setStyleSheet( + "margin: 0px;" "color: white;" "background-color: black;" + "font-size: 14px;" ); layout->addWidget(m_fileValue); @@ -38,9 +50,20 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_progress = new QProgressBar(this); m_progress->setOrientation(Qt::Horizontal); + m_progress->setFocusPolicy(Qt::NoFocus); + m_progress->setAlignment(Qt::AlignHCenter); + m_progress->setContentsMargins(0, 1, 0, 1); + m_progress->setMinimumWidth(MIN_WIDTH); + m_progress->setMaximumWidth(MAX_WIDTH); + m_progress->setMaximumHeight(15); m_progress->setRange(0, 0); m_progress->setValue(0); m_progress->setFormat("%v / %m"); + m_progress->setStyleSheet( + "margin: 0px;" + "font-size: 13px;" + "background-color: black;" + ); layout->addWidget(m_progress); m_progressTime = new QTimeEdit; @@ -49,26 +72,30 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_progressTime->setDisplayFormat("mm:ss:zzz"); m_progressTime->setReadOnly(true); m_progressTime->setButtonSymbols(QAbstractSpinBox::NoButtons); - m_progressTime->setMinimumWidth(80); m_progressTime->setFocusPolicy(Qt::NoFocus); m_progressTime->setAlignment(Qt::AlignHCenter); m_progressTime->setContentsMargins(0,0,0,0); + m_progressTime->setMinimumWidth(MIN_WIDTH); + m_progressTime->setMaximumWidth(MAX_WIDTH); m_totalTimeValue = new QTimeEdit; m_totalTimeValue->setObjectName("Track Length"); m_totalTimeValue->setToolTip("Track Length"); m_totalTimeValue->setDisplayFormat("mm:ss:zzz"); m_totalTimeValue->setReadOnly(true); m_totalTimeValue->setButtonSymbols(QAbstractSpinBox::NoButtons); - m_totalTimeValue->setMinimumWidth(80); m_totalTimeValue->setFocusPolicy(Qt::NoFocus); m_totalTimeValue->setAlignment(Qt::AlignHCenter); m_totalTimeValue->setContentsMargins(0,0,0,0); + m_totalTimeValue->setMinimumWidth(MIN_WIDTH); + m_totalTimeValue->setMaximumWidth(MAX_WIDTH); QHBoxLayout *status = new QHBoxLayout; status->addWidget(m_progressTime); status->addWidget(m_totalTimeValue); layout->addLayout(status); m_filterBank = new FilterBankWidget(this); + m_filterBank->setMaximumWidth(MAX_WIDTH); + m_filterBank->setMinimumWidth(MIN_WIDTH); connect(m_filterBank, SIGNAL(setBypass(bool)), this, SLOT(setBypass(bool))); layout->addWidget(m_filterBank); m_pitch = new SliderGroup("Pitch", 0 , 255, 0, NULL); @@ -95,40 +122,45 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_level = new QLabel("-inf"); m_level->setStyleSheet("border: 1px solid #CFB0C9;" "margin: 0px;" - "margin-right: 5px;" - "margin-left: 5px;" "background-color: black;" "color: white;" - "width:80px;" "text-align: center;" - ); - m_level->setMinimumWidth(80); - m_level->setMaximumWidth(80); - m_level->setMinimumHeight(20); + "font-size: 15px;"); + m_level->setMinimumWidth(MIN_WIDTH / 2); + m_level->setMaximumWidth(MAX_WIDTH / 3); + m_level->setMinimumHeight(25); m_level->setAlignment(Qt::AlignHCenter); + m_level->setContentsMargins(0, 4, 0, 4); labelsBox->addWidget(m_level); m_bus1Label = new QLabel("dummy"); - m_bus1Label->setMinimumWidth(80); + m_bus1Label->setAlignment(Qt::AlignHCenter); + m_bus1Label->setContentsMargins(0, 6, 0, 6); + m_bus1Label->setMinimumHeight(25); + m_bus1Label->setMinimumWidth(MIN_WIDTH / 4); + m_bus1Label->setMaximumWidth(MAX_WIDTH / 3); m_bus1Label->setStyleSheet("border: 1px solid #CFB0C9;" "margin: 0px;" "background-color: black;" "color: white;" - "font-size: 11px;"); + "font-size: 10px;"); labelsBox->addWidget(m_bus1Label); m_bus2Label = new QLabel("dummy"); - m_bus2Label->setMinimumWidth(80); + m_bus2Label->setAlignment(Qt::AlignHCenter); + m_bus2Label->setMinimumWidth(MIN_WIDTH / 4); + m_bus2Label->setMaximumWidth(MAX_WIDTH / 3); + m_bus2Label->setContentsMargins(0, 6, 0, 6); + m_bus2Label->setMinimumHeight(25); m_bus2Label->setStyleSheet("border: 1px solid #CFB0C9;" "margin: 0px;" "background-color: black;" "color: white;" - "font-size: 11px;"); + "font-size: 10px;"); labelsBox->addWidget(m_bus2Label); labelsBox->setSpacing(0); - labelsBox->setContentsMargins(0, 0, 0, 0); + layout->setContentsMargins(0, 0, 0, 0); layout->addLayout(labelsBox); layout->setAlignment(Qt::AlignHCenter); layout->setSpacing(0); - layout->setContentsMargins(1, 1, 1, 1); this->setLayout(layout); } @@ -230,8 +262,12 @@ void AudioLayerWidget::setMediaFile(QString file) QStringList list = file.split("/"); int size = list.size(); if (size >= 2) { - m_folderValue->setText(list.at(size - 2)); - m_fileValue->setText(list.at(size - 1)); + QString tmp = list.at(size - 2); + tmp.truncate(60); + m_folderValue->setText(tmp); + tmp = list.at(size - 1); + tmp.truncate(40); + m_fileValue->setText(tmp); } } @@ -288,8 +324,9 @@ void AudioLayerWidget::setFilterParam(int channel, int value) void AudioLayerWidget::setLevel(float db) { m_level->blockSignals(true); - if (db > -150) - m_level->setText(QString::number(db)); + if (db > -140) + + m_level->setText(QString::number(db, 'f', 2)); else m_level->setText("-inf"); m_level->blockSignals(false); @@ -297,6 +334,8 @@ void AudioLayerWidget::setLevel(float db) void AudioLayerWidget::setBusName(uint bus, char *name) { + if (name && strlen(name) > 17) + name[16] = '\0'; if (bus == 0) { m_bus1Label->blockSignals(true); m_bus1Label->setText(name); diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index 8d43127..ec96a9e 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -23,8 +23,9 @@ AudioWidget::AudioWidget(QWidget *parent) : for (int j = 0; j < FILTER_CHANNELS; j++) m_filtersUpdate[i][j] = -1; } - m_layout->setSpacing(2); - m_layout->setContentsMargins(2, 2, 2, 2); + m_layout->setSpacing(0); + m_layout->setContentsMargins(0, 0, 0, 0); + this->setStyleSheet("margin: 2px;"); setLayout(m_layout); m_refreshUi = new QTimer(this); connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); diff --git a/src/clickabledoublespinbox.cpp b/src/clickabledoublespinbox.cpp index b2b9c3a..76feb8b 100644 --- a/src/clickabledoublespinbox.cpp +++ b/src/clickabledoublespinbox.cpp @@ -11,11 +11,7 @@ ClickableDoubleSpinBox::ClickableDoubleSpinBox(QWidget *parent) setDecimals(1); setAlignment(Qt::AlignHCenter); setContentsMargins(0, 0, 0, 0); - setMaximumWidth(50); - this->setStyleSheet("border: 0px solid #5a4855;" - "width: 50px;" - "margin: 0px;" - "background-color: #383034;" - ); + setMaximumWidth(66); + setMinimumWidth(25); } diff --git a/src/defines.h b/src/defines.h index e19ecf7..e9d4bf2 100644 --- a/src/defines.h +++ b/src/defines.h @@ -11,8 +11,10 @@ #define CHANNELS 2 #define SAMPLE_RATE 48000 #define UI_REFRESH_TIME 123 -#define FADE_TIME 20 +#define FADE_TIME 25 #define FILTER_CHANNELS 16 // number of dmx channels dedicated to filters by layer +#define MAX_WIDTH 500 +#define MIN_WIDTH 50 struct dmxSetting { int address; diff --git a/src/filterbankwidget.cpp b/src/filterbankwidget.cpp index 4742af2..098e591 100644 --- a/src/filterbankwidget.cpp +++ b/src/filterbankwidget.cpp @@ -2,20 +2,22 @@ #include #include "dmxPersonality.h" +#include "defines.h" + +#define BORDER "#CFB0C9;" +#define BACK "#281024;" FilterBankWidget::FilterBankWidget(QWidget *parent) : QWidget{parent} { QHBoxLayout *layout = new QHBoxLayout; layout->setAlignment(Qt::AlignHCenter); - layout->setContentsMargins(0, 2, 0, 2); layout->setSpacing(0); - this->setStyleSheet("border: 2px solid #5a4855;" + layout->setContentsMargins(0, 0, 0, 0); + this->setStyleSheet("border: 1px solid #CFB0C9;" "margin: 0px;" - "margin-top: 3px;" - "margin-bottom: 3px;" - "background-color: #383034;" - ); + "background-color: #080402;" + "font-size: 13px;"); for (int i = 0; i < 13; i++) { fb[i] = new ClickableDoubleSpinBox; const char *name = dmxChannelToString(i + 9); @@ -27,10 +29,11 @@ FilterBankWidget::FilterBankWidget(QWidget *parent) m_bypass = new QCheckBox; master->addWidget(m_bypass); m_bypass->setText("Bypass"); - m_bypass->setStyleSheet("QCheckBox { border: 2px solid #2a0825;" + m_bypass->setMinimumWidth(MIN_WIDTH / 4); + m_bypass->setStyleSheet("QCheckBox { border: 1px solid #CFB0C9;" "margin: 0px;" - "background-color: #885074;" - "font-size: 7px;}"); + "background-color: #c82840;" + "font-size: 8px;}"); connect(m_bypass, SIGNAL(stateChanged(int)), this, SLOT(bypassChanged(int))); master->addWidget(fb[0]); layout->addLayout(master); diff --git a/src/libremediaserver-audio-gui.cpp b/src/libremediaserver-audio-gui.cpp index 22f673c..62b4544 100644 --- a/src/libremediaserver-audio-gui.cpp +++ b/src/libremediaserver-audio-gui.cpp @@ -35,10 +35,11 @@ libreMediaServerAudioUi::libreMediaServerAudioUi(QWidget *parent) topWidget->setContentsMargins(0, 0, 0, 0); addDockWidget(Qt::TopDockWidgetArea, topWidget); connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup())); - this->setContentsMargins(3, 3, 3, 3); + this->setContentsMargins(0, 0, 0, 0); this->setStyleSheet( + "margin: 0px;" "color: white;" - "background-color: #4f4048;" + "background-color: #3f3038;" "selection-color: blue;" "selection-background-color: green" ); diff --git a/src/libremediaserver-audio-gui.ui b/src/libremediaserver-audio-gui.ui index c0f11ad..ad4c061 100644 --- a/src/libremediaserver-audio-gui.ui +++ b/src/libremediaserver-audio-gui.ui @@ -7,7 +7,7 @@ 0 0 - 500 + 400 400 @@ -32,7 +32,7 @@ 0 0 - 500 + 400 21 diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index d2ebc17..edc5f78 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -1,7 +1,7 @@ #include "miniaudioengine.h" #include "dmxPersonality.h" -#define BIAS 0.99f +#define BIAS 1.0f #define FILTER_ORDER 3 MiniAudioEngine::MiniAudioEngine() {} @@ -52,12 +52,13 @@ bool MiniAudioEngine::startEngine(uint layers, uint* audioDevicesId, uint audioD m_mae.audioDevicesId = audioDevicesId; m_mae.audioDevicesQty = audioDevicesQty; for (uint i =0; i < m_mae.layersQty; i++) { - m_mae.mediaLoaded[i] = false; + m_mae.mediaLoaded[i] = MA_FALSE; m_mae.currentStatus[i].status = Status::Iddle; m_mae.currentStatus[i].pan = 128; m_mae.currentStatus[i].pitch = 128; - m_mae.currentStatus[i].vol = 0; + m_mae.currentStatus[i].vol = 0.0f; m_mae.currentStatus[i].cursor = 0; + m_mae.currentStatus[i].updated = false; } result = this->startContext(); if (result != MA_SUCCESS) return false; @@ -278,7 +279,7 @@ ma_result MiniAudioEngine::startDevices() deviceConfig.dataCallback = audioDataCallback; engineConfig = ma_engine_config_init(); engineConfig.pResourceManager = &m_mae.resourceManager; - //engineConfig.defaultVolumeSmoothTimeInPCMFrames = SAMPLE_RATE / 20; + engineConfig.defaultVolumeSmoothTimeInPCMFrames = SAMPLE_RATE / 500; engineConfig.noAutoStart = MA_TRUE; for (uint internalId = 0; internalId < m_mae.audioDevicesQty; internalId++) { @@ -350,12 +351,12 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file) { ma_result result; - if (m_mae.mediaLoaded[layer] == true) + if (m_mae.mediaLoaded[layer] == MA_TRUE) { + m_mae.mediaLoaded[layer] = MA_FALSE; ma_sound_set_volume(&m_mae.sounds[layer], 0.0f); ma_sound_stop(&m_mae.sounds[layer]); ma_sound_uninit(&m_mae.sounds[layer]); - m_mae.mediaLoaded[layer] = false; } ma_sound_config soundConfig = ma_sound_config_init(); soundConfig = ma_sound_config_init(); @@ -370,9 +371,10 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file) cout << "Error" << result << ": Failed to load file " << file << endl; return result; } - m_mae.mediaLoaded[layer] = true; - this->refreshValues(layer); m_mae.currentStatus[layer].media = file; + m_mae.currentStatus[layer].updated = true; + m_mae.mediaLoaded[layer] = MA_TRUE; + this->refreshValues(layer); return result; } @@ -431,7 +433,8 @@ ma_result MiniAudioEngine::printFormatInfo(int layer) // Expects between 0 and 65535 vol value void MiniAudioEngine::volChanged(int layer, int vol) { - if (m_mae.mediaLoaded[layer] == false) + m_mae.currentStatus[layer].vol = vol; + if (m_mae.mediaLoaded[layer] == MA_FALSE && m_mae.currentStatus[layer].updated) return; float db = ((float)vol / 771.0f) - 85.0f; if (db <= -85.0f) { @@ -439,70 +442,72 @@ void MiniAudioEngine::volChanged(int layer, int vol) } else db = ma_volume_db_to_linear(db); ma_sound_set_fade_in_milliseconds(&m_mae.sounds[layer], -1, db, FADE_TIME); - m_mae.currentStatus[layer].vol = vol; } void MiniAudioEngine::panChanged(int layer, float value) { float result; + m_mae.currentStatus[layer].pan = value; if (m_mae.mediaLoaded[layer] == false) return; result = (value / 128.0) - 1.0; ma_sound_group_set_pan(&m_mae.sounds[layer], result); - m_mae.currentStatus[layer].pan = value; } void MiniAudioEngine::pitchChanged(int layer, float value) { float pitch; + m_mae.currentStatus[layer].pitch = value; if (m_mae.mediaLoaded[layer] == false) return; pitch = value / 128.0; ma_sound_group_set_pitch(&m_mae.sounds[layer], pitch); - m_mae.currentStatus[layer].pitch = value; } ma_result MiniAudioEngine::playbackChanged(int layer, Status status) { ma_result result = MA_SUCCESS; - - if (m_mae.mediaLoaded[layer] == false) - return MA_DOES_NOT_EXIST; + float db = 0; bool loop = false; + + m_mae.currentStatus[layer].status = status; + if (m_mae.mediaLoaded[layer] == MA_FALSE) + return MA_DOES_NOT_EXIST; + m_mae.currentStatus[layer].updated = false; switch (status) { case Status::Paused: result = ma_sound_stop_with_fade_in_milliseconds(&m_mae.sounds[layer], FADE_TIME); break; case Status::Stopped: - ma_sound_stop_with_fade_in_milliseconds(&m_mae.sounds[layer], FADE_TIME); + ma_sound_stop_with_fade_in_milliseconds(&m_mae.sounds[layer], 0.0f); result = this->seekToCursor(layer, m_mae.currentStatus[layer].cursor); break; case Status::PlayingLoop: loop = true; - case Status::PlayingOnce: - ma_sound_set_looping(&m_mae.sounds[layer], loop); - if (m_mae.currentStatus[layer].cursor > 0) { - this->setRangePoint(layer, m_mae.currentStatus[layer].cursor); - this->setLoopPoint(layer, m_mae.currentStatus[layer].cursor); + if (m_mae.currentStatus[layer].cursor > 0) { + result = this->seekToCursor(layer, m_mae.currentStatus[layer].cursor); } + case Status::PlayingOnce: case Status::PlayingFolder: case Status::PlayingFolderLoop: case Status::PlayingFolderRandom: + ma_sound_set_looping(&m_mae.sounds[layer], loop); + if (ma_sound_is_playing(&m_mae.sounds[layer])) break; ma_sound_set_stop_time_in_milliseconds(&m_mae.sounds[layer], ~(ma_uint64)0); - float db = (m_mae.currentStatus[layer].vol / 771.0f) - 85.0f; - if (db <= -85.0f) { - db = 0; - } else - db = ma_volume_db_to_linear(db); + db = (m_mae.currentStatus[layer].vol / 771.0f) - 85.0f; + if (db <= -85.0f) db = 0; + else db = ma_volume_db_to_linear(db); result = ma_sound_start(&m_mae.sounds[layer]); - ma_sound_group_set_volume(&m_mae.sounds[layer], 0.0f); - ma_sound_set_fade_in_milliseconds(&m_mae.sounds[layer], 0, db, FADE_TIME); - ma_sound_group_set_volume(&m_mae.sounds[layer], 1.0f); + ma_sound_set_fade_in_milliseconds(&m_mae.sounds[layer], 0.000001f, 0.000000f, FADE_TIME); + if (m_mae.currentStatus[layer].cursor > 0) + usleep(FADE_TIME * 1500); // avoid glitch when load when seeking + ma_sound_set_fade_in_milliseconds(&m_mae.sounds[layer], 0, db, FADE_TIME * 2); + default: + break; } - if (result == MA_SUCCESS) - m_mae.currentStatus[layer].status = status; + m_mae.currentStatus[layer].updated = true; return result; } @@ -719,5 +724,5 @@ bool MiniAudioEngine::setBypass(int audioDevice, int layer, bool bypass) ma_node_set_output_bus_volume(&fb->input, 1, 0.0f); ma_node_set_output_bus_volume(&fb->input, 0, 1.0f); } - + return true; } -- 2.39.5 From d0f565e1c0b9b8b46265d1785fe2b8377191bb82 Mon Sep 17 00:00:00 2001 From: snt Date: Sun, 26 May 2024 14:40:15 +0200 Subject: [PATCH 49/49] cosmetic, fix pan and pitch spinbox, style slider. --- src/audiolayerwidget.cpp | 16 +++++++++++++-- src/slidergroup.cpp | 43 +++++++++++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 0e9527b..9b6ecf7 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -61,7 +61,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_progress->setFormat("%v / %m"); m_progress->setStyleSheet( "margin: 0px;" - "font-size: 13px;" + "font-size: 10px;" "background-color: black;" ); layout->addWidget(m_progress); @@ -77,6 +77,12 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_progressTime->setContentsMargins(0,0,0,0); m_progressTime->setMinimumWidth(MIN_WIDTH); m_progressTime->setMaximumWidth(MAX_WIDTH); + m_progressTime->setStyleSheet( + "margin: 0px;" + "color: white;" + "background-color: black;" + "font-size: 16px;" + ); m_totalTimeValue = new QTimeEdit; m_totalTimeValue->setObjectName("Track Length"); m_totalTimeValue->setToolTip("Track Length"); @@ -88,6 +94,12 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_totalTimeValue->setContentsMargins(0,0,0,0); m_totalTimeValue->setMinimumWidth(MIN_WIDTH); m_totalTimeValue->setMaximumWidth(MAX_WIDTH); + m_totalTimeValue->setStyleSheet( + "margin: 0px;" + "color: white;" + "background-color: black;" + "font-size: 16px;" + ); QHBoxLayout *status = new QHBoxLayout; status->addWidget(m_progressTime); status->addWidget(m_totalTimeValue); @@ -160,7 +172,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): layout->setContentsMargins(0, 0, 0, 0); layout->addLayout(labelsBox); layout->setAlignment(Qt::AlignHCenter); - layout->setSpacing(0); + layout->setSpacing(1); this->setLayout(layout); } diff --git a/src/slidergroup.cpp b/src/slidergroup.cpp index 9eedb70..481d554 100644 --- a/src/slidergroup.cpp +++ b/src/slidergroup.cpp @@ -18,7 +18,8 @@ SliderGroup::SliderGroup(QString name, else { layout = new QHBoxLayout; slider.setOrientation(Qt::Horizontal); - slider.setMinimumHeight(10); + slider.setMaximumHeight(15); + valueBox.setMaximumHeight(15); } layout->setAlignment(Qt::AlignHCenter); layout->setContentsMargins(0, 0, 0, 0); @@ -32,9 +33,24 @@ SliderGroup::SliderGroup(QString name, slider.setMinimumWidth(50); slider.setToolTip(name); slider.setStyleSheet("QSlider {" - "border: 1px solid #5a4855;" + "border: 1px solid #aa8895;" + "background: #20182d;" "margin: 0px;}" - ); + "QSlider::groove:vertical {" + "border: 1px solid #999999;" + "width: 25px;" + "margin: -4px;}" + "QSlider::handle:vertical {" + "background: white;" + "border: 1px solid #5c5c5c;" + "width: 29px;" + "height: 7px;" + "margin: -2px;" + "border-radius: 2px;}" + "Qslider::tickmarks:vertical {background: white;" + "color: white;}" + "QSlider::add-page:vertical {background: blue;}" + "QSlider::sub-page:vertical {background: #20182d;}"); slider.setContentsMargins(0, 0, 0, 0); valueBox.setFocusPolicy(Qt::NoFocus); valueBox.setButtonSymbols(QAbstractSpinBox::NoButtons); @@ -54,10 +70,9 @@ SliderGroup::SliderGroup(QString name, connect(&valueBox, SIGNAL(click()), this, SLOT(enableSlider())); layout->addWidget(&slider); layout->addWidget(&valueBox); - this->setStyleSheet("border: 1px solid #5a4855;" - "width: 60px;" - "margin: 0px;" - "background-color: #383034;" + this->setStyleSheet("border: 1px solid #aa8895;" + "background-color: black;" + "margin: 1px;" ); layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); @@ -67,11 +82,15 @@ SliderGroup::SliderGroup(QString name, void SliderGroup::sliderValueChanged(int value) { valueBox.blockSignals(true); - float db = ((float)value / 771.0f) - 85.0f; - if (db <= -84.5f) { - valueBox.setSpecialValueText("-inf"); - } else - valueBox.setValue(db); + if (valueBox.decimals()) { + float db = ((float)value / 771.0f) - 85.0f; + if (db <= -84.5f) { + valueBox.setSpecialValueText("-inf"); + } else + valueBox.setValue(db); + } else { + valueBox.setValue(value); + } valueBox.blockSignals(false); emit valueChanged(value); }; -- 2.39.5