diff --git a/docs/LibreMediaServer_Audio.hed b/docs/LibreMediaServer_Audio.hed index 90b0781..fda3e2d 100644 --- a/docs/LibreMediaServer_Audio.hed +++ b/docs/LibreMediaServer_Audio.hed @@ -1,99 +1,79 @@ ް׆ˌĠ򝤫鿰맫͓Ԕ -ҊÅЁͽ -Щܰ -Χ -쏎՚ -ڥ -з -򗹡 -֐ -ᬡ䨳͘ -۽Ӣ - -ԙ - -ا࠭ -Ϡɮ -򃡺쏎 -Ē - -ջо -󕐙ޗ - -Ѵد߯ -ںԻϩ -񖝋ޕ -㓜 -Ѹڱ -ܯԕ - -ĉ -ⷶ -šҔ -㰽 -С׃ -苩ܑ -ٿ뺻 -ڧӴ̧Ӈ -똫䅭̝ԛʂ -껺 -۾ - -Κ - - -Dž -ꬡ˞“ -̾ -虤刬Ⓨ̀ -㨳 - - - -҂ - - -鱤 - -ً - -ۄ -í - - - - - - - - -𓎍 -̀ - -Řϒ -݁׺ - -րɂÈ -񺥤 -ଛ - -ܕ - - - - - -쏒 - - -稳 - - - - - -ٕ - - - - +ҊÅЁ䍡 +ӽ +Ꭸʆ +ɑ +ɬ +򉇁 +Ԑɉ + +ٿդϨ҃ +񀠧ڔ +ڑŌ +򻴧 + + + + + + + + +쏎ބ +힇ݳ + +Ԓlj + +Ŷ§ +ÐŽÊ +𡭟Ē + +܊ +񢰽 +зм +񓎍 +ҭ +ܻۏ +ڑן +ޏ + +Ƴ + + + +Ǖ + +𓎍Ԏ + + +Ξ +ֆ + +ց + +ᱯ +݈ + +؈ + +馹 +۴ +𓎍 + + + + + +𓎑 + + + +Ɨ + + + +Ӌ +쏎 + + + diff --git a/docs/changelog.txt b/docs/changelog.txt index ac07acf..5c7e0b6 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -1,10 +1,10 @@ ******************************************************************************* -LibreMediaServer Audio - An open source media server for arts and performing. +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 ******************************************************************************* -LibreMediaServer Changelog +Libre Media Server 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. @@ -13,38 +13,36 @@ v 0.2.0 Antígona (26/05/2024) + Pan. + Show faders values. New SliderGroup class. + Entry Point 16 bits. -+ 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. ++ Refactor AudioMasterWidget to AudioDMXReceptionWidget. ++ 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); -+ 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. ++ 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. -+ New Play Modes: - - 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. -+ Vumeter for each layer -+ Show device name on Ui and ouput bus slider. -+ 84dae057dbf7c0 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. -+ 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. -+ Qt4 + diff --git a/docs/lms-audio.xlm b/docs/lms-audio.xlm index b2ea7ed..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 9e4f017..0771257 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -6,32 +6,42 @@ https://git.criptomart.net/libremediaserver Libre Media Server Roadmap -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 +v 0.2.x +- skin, UI/UX - live input. -- remove ola and use sACN directly. +- 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. + 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. -- CIPT/MSex. +- 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). + +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. + - each layer will have one volume dmx channel for each bus layer. One aux "Send" prefader. - mute/panic. - fader + value - - pan - - magicq personality .hed + - pan. + - magicq .hed - audio device linked, outputs will be redirected there. - dmx address + universe settings. - - compresor/limiter. -- Layer: - - audio procesadores (compresor, reveb, delay). - - mute/panic. -- Rose noise and sine generator. +- 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. - Logs, verbosity, timestamp. - New play mode without pitch control, it saves resources. MA_SOUND_FLAG_NO_PITCH - SettingsDialog. @@ -39,6 +49,6 @@ v 0.3.0 - ¿Exit Point? is it needed? - 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. + +v0.2.0: +- Vumeter or indicator about audio output in layer and master, add to sliderGroup. diff --git a/libremediaserver-audio.pro b/libremediaserver-audio.pro index 67c50c5..41d6ecd 100644 --- a/libremediaserver-audio.pro +++ b/libremediaserver-audio.pro @@ -2,17 +2,12 @@ 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/ma_writer_node.h \ src/main.h \ - src/medialibrary.h \ src/miniaudio.h \ - src/ma_writer_node.h \ + src/medialibrary.h \ src/miniaudioengine.h \ src/olathread.h \ src/audiolayerwidget.h \ @@ -22,25 +17,22 @@ 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 \ src/medialibrary.cpp \ - src/miniaudio.c \ src/miniaudioengine.cpp \ - src/ma_writer_node.c \ src/olathread.cpp \ src/audiolayerwidget.cpp \ src/audiowidget.cpp \ src/settings.cpp \ src/slidergroup.cpp FORMS += src/libremediaserver-audio-gui.ui -CCFLAG += -msse2 -mavx2 +CCFLAG += -msse2 -mavx2 #-fsanitize=address -g3 -O0 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 9b6ecf7..e8d22bd 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -1,182 +1,96 @@ #include "audiolayerwidget.h" -#include "dmxPersonality.h" - -#include -#include +#include AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): QWidget(parent) - , m_oldStatus(Status::PlayingLoop) , m_layer(layer) , m_suspendResumeButton(0) { QVBoxLayout *layout = new QVBoxLayout; + QVBoxLayout *playback = new QVBoxLayout; m_folderValue = new ClickableLabel; + m_folderValue->setMaximumWidth(160); 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); + playback->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(160); + m_fileValue->setAlignment(Qt::AlignLeft); m_fileValue->setStyleSheet( - "margin: 0px;" "color: white;" "background-color: black;" - "font-size: 14px;" ); - layout->addWidget(m_fileValue); + playback->addWidget(m_fileValue); + playback->setSpacing(0); + playback->setContentsMargins(0, 0, 0, 0); + layout->addLayout(playback); m_suspendResumeButton = new QPushButton(this); - m_suspendResumeButton->setText(statusToString(Status::Iddle)); + m_suspendResumeButton->setText(StatusStr[Status::Iddle]); connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume())); layout->addWidget(m_suspendResumeButton); 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: 10px;" - "background-color: black;" - ); layout->addWidget(m_progress); m_progressTime = new QTimeEdit; m_progressTime->setToolTip("Current Time"); m_progressTime->setObjectName("Current Time"); - m_progressTime->setDisplayFormat("mm:ss:zzz"); + m_progressTime->setDisplayFormat("mm:ss:zz"); 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); - 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"); 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); - 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); 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); - layout->addWidget(m_pitch); - connect(m_pitch, SIGNAL(valueChanged(int)), this, SLOT(pitchChanged(int))); - m_pan = new SliderGroup("Pan", 0 , 255, 0, NULL); - layout->addWidget(m_pan); - connect(m_pan, SIGNAL(valueChanged(int)), this, SLOT(panChanged(int))); - QHBoxLayout *volumeBox = new QHBoxLayout; - m_volume = new SliderGroup("Vol", 0, 65535, 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))); - 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))); + 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); volumeBox->setSpacing(0); volumeBox->setContentsMargins(0, 0, 0, 0); + connect(m_pitch, SIGNAL(valueChanged(int)), this, SLOT(pitchChanged(int))); layout->addLayout(volumeBox); - QHBoxLayout *labelsBox = new QHBoxLayout; - m_level = new QLabel("-inf"); - m_level->setStyleSheet("border: 1px solid #CFB0C9;" - "margin: 0px;" - "background-color: black;" - "color: white;" - "text-align: center;" - "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->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: 10px;"); - labelsBox->addWidget(m_bus1Label); - m_bus2Label = new QLabel("dummy"); - 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: 10px;"); - labelsBox->addWidget(m_bus2Label); - labelsBox->setSpacing(0); - layout->setContentsMargins(0, 0, 0, 0); - layout->addLayout(labelsBox); layout->setAlignment(Qt::AlignHCenter); - layout->setSpacing(1); + layout->setSpacing(0); + layout->setContentsMargins(2, 2, 2, 2); this->setLayout(layout); } -AudioLayerWidget::~AudioLayerWidget() {} +AudioLayerWidget::~AudioLayerWidget() +{ + +} // From UI. void AudioLayerWidget::volumeChanged(int value) @@ -184,16 +98,6 @@ 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)); @@ -204,28 +108,18 @@ 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) { 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(m_oldStatus); - emit uiPlaybackChanged(m_layer, m_oldStatus); + this->setPlaybackStatus(Status::PlayingLoop); + emit uiPlaybackChanged(m_layer, Status::PlayingLoop); case Status::Iddle: break; } @@ -244,15 +138,14 @@ 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 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) @@ -274,20 +167,17 @@ void AudioLayerWidget::setMediaFile(QString file) QStringList list = file.split("/"); int size = list.size(); if (size >= 2) { - 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); + m_folderValue->setText(list.at(size - 2)); + m_fileValue->setText(list.at(size - 1)); } } void AudioLayerWidget::setPlaybackStatus(Status s) { + Status status = static_cast(s); m_suspendResumeButton->blockSignals(true); - m_status = s; - m_suspendResumeButton->setText(statusToString(s)); + m_status = status; + m_suspendResumeButton->setText(StatusStr[status]); m_suspendResumeButton->blockSignals(false); } @@ -315,46 +205,3 @@ void AudioLayerWidget::setCurrentTime(float progress) m_progress->blockSignals(false); m_progressTime->blockSignals(false); } - -void AudioLayerWidget::setFilterParam(int channel, int value) -{ - 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(true); - m_bus1->setValue((value * 256) + 255); - m_bus1->blockSignals(false); - } else if (channel == SEND2 - HP_FREQ) { - m_bus2->blockSignals(true); - m_bus2->setValue(value * 256 + 255); - m_bus2->blockSignals(false); - } -} - -void AudioLayerWidget::setLevel(float db) -{ - m_level->blockSignals(true); - if (db > -140) - - m_level->setText(QString::number(db, 'f', 2)); - else - m_level->setText("-inf"); - m_level->blockSignals(false); -} - -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); - 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 bc7010f..9380b81 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -3,13 +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 { @@ -19,21 +19,8 @@ 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); - void setLevel(float db); - void setBusName(uint bus, char *name); - private: Status m_status; - Status m_oldStatus; int m_layer; QPushButton *m_suspendResumeButton; ClickableLabel *m_fileValue; @@ -41,26 +28,27 @@ 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; - FilterBankWidget *m_filterBank; - QLabel *m_level; - QLabel *m_bus1Label; - QLabel *m_bus2Label; + +// 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 bus1VolumeChanged(int vol); - void bus2VolumeChanged(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/audiowidget.cpp b/src/audiowidget.cpp index ec96a9e..8bd077c 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -1,31 +1,26 @@ #include "audiowidget.h" -#include "dmxPersonality.h" +#include AudioWidget::AudioWidget(QWidget *parent) : QWidget(parent) , m_layout(new QHBoxLayout()) { - m_layers = Settings::getInstance()->getLayersNumber(); - for (uint i= 0; i < m_layers; i++ ) { + 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, 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 = -1; + m_layerUpdate[i].duration = 0; m_layerUpdate[i].media = ""; - 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; + 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(0, 0, 0, 0); - this->setStyleSheet("margin: 2px;"); + m_layout->setContentsMargins(1, 1, 1, 1); setLayout(m_layout); m_refreshUi = new QTimer(this); connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); @@ -69,10 +64,10 @@ void AudioWidget::cursorChanged(int layer, float cursor) void AudioWidget::refreshUi() { - for (uint i = 0; i < m_layers; i++) + for (int i = 0; i < MAX_LAYERS; i++) { if (m_layerUpdate[i].updated) { - QLayoutItem *item = m_layout->itemAt(i); + 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); @@ -99,37 +94,7 @@ 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; - } - if (m_layerUpdate[i].level < 100) { - alw->setLevel(m_layerUpdate[i].level); - m_layerUpdate[i].level = 100; - } m_layerUpdate[i].updated = false; } } } - -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; -} - -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 238ead2..dd9b1f1 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -2,7 +2,6 @@ #define AUDIOWIDGET_H #include -#include #include "audiolayerwidget.h" #include "settings.h" @@ -14,16 +13,11 @@ class AudioWidget : public QWidget 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; 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 deleted file mode 100644 index 76feb8b..0000000 --- a/src/clickabledoublespinbox.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#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(66); - setMinimumWidth(25); -} - diff --git a/src/clickabledoublespinbox.h b/src/clickabledoublespinbox.h deleted file mode 100644 index 81bcb76..0000000 --- a/src/clickabledoublespinbox.h +++ /dev/null @@ -1,25 +0,0 @@ -#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 deleted file mode 100644 index 2c34478..0000000 --- a/src/clickableslider.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "clickableslider.h" - -ClickableSlider::ClickableSlider(QWidget *parent) : QSlider{parent} {} diff --git a/src/clickableslider.h b/src/clickableslider.h deleted file mode 100644 index af34c91..0000000 --- a/src/clickableslider.h +++ /dev/null @@ -1,30 +0,0 @@ -#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 e9d4bf2..ff299c1 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,26 +1,19 @@ #ifndef DEFINES_H #define DEFINES_H -#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 123 -#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 +#define VERSION "LibreMediaServerAudio 0.2.0 Antigona Release" +#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 66 +#define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks struct dmxSetting { int address; unsigned int universe; int layer; - int audioDevice; }; enum Status @@ -35,33 +28,26 @@ enum Status PlayingFolderRandom }; +static const char* StatusStr[] = +{ + "Stop", + "Pause", + "Playing One", + "Playing One Loop", + "Iddle", + "Playing Folder", + "Playing Folder Loop", + "Playing Folder Random", + 0x0 +}; + enum Slider { Volume, Pan, Pitch, - Bypass, - Bus1, - Bus2 }; -#ifdef __cplusplus -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 "--++--"; - } -} - #include struct layerData { QString media; @@ -75,9 +61,5 @@ struct layerData { int address; unsigned int universe; int device; - int bus1Vol; - int bus2Vol; - float level; }; -#endif // __cplusplus #endif // DEFINES_H diff --git a/src/dmxPersonality.h b/src/dmxPersonality.h index d08671a..82f9468 100644 --- a/src/dmxPersonality.h +++ b/src/dmxPersonality.h @@ -1,52 +1,15 @@ #ifndef DMXPERSONALITY_H #define DMXPERSONALITY_H +#define VOLUME_COARSE 3 +#define PAN 6 #define DMX_FOLDER 0 #define DMX_FILE 1 -#define VOLUME_FINE 2 -#define VOLUME_COARSE 3 -#define ENTRY_POINT_FINE 4 -#define ENTRY_POINT_COARSE 5 -#define PAN 6 -#define PITCH 7 #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 -#define MIDHIGH_FREQ 16 -#define MIDHIGH_Q 17 -#define MIDHIGH_GAIN 18 -#define HIGH_FREQ 19 -#define HIGH_Q 20 -#define HIGH_GAIN 21 -#define FILTER_BANK_GAIN 22 -#define SEND1 23 -#define SEND2 24 -#define LAYER_CHANNELS 25 - -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"; - case FILTER_BANK_GAIN: return "Post Filters Gain"; - default: return "++--++--++"; - } -} +#define VOLUME_FINE 2 +#define ENTRY_POINT_COARSE 5 +#define ENTRY_POINT_FINE 4 +#define PITCH 7 +#define LAYER_CHANNELS 9 #endif // DMXPERSONALITY_H diff --git a/src/filterbankwidget.cpp b/src/filterbankwidget.cpp deleted file mode 100644 index 098e591..0000000 --- a/src/filterbankwidget.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "filterbankwidget.h" - -#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->setSpacing(0); - layout->setContentsMargins(0, 0, 0, 0); - this->setStyleSheet("border: 1px solid #CFB0C9;" - "margin: 0px;" - "background-color: #080402;" - "font-size: 13px;"); - 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); - } - QVBoxLayout *master = new QVBoxLayout; - fb[0]->setRange(0, 500); - m_bypass = new QCheckBox; - master->addWidget(m_bypass); - m_bypass->setText("Bypass"); - m_bypass->setMinimumWidth(MIN_WIDTH / 4); - m_bypass->setStyleSheet("QCheckBox { border: 1px solid #CFB0C9;" - "margin: 0px;" - "background-color: #c82840;" - "font-size: 8px;}"); - connect(m_bypass, SIGNAL(stateChanged(int)), this, SLOT(bypassChanged(int))); - 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++) { - 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); - } - 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; - } else - result = (double)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 deleted file mode 100644 index bb36ef2..0000000 --- a/src/filterbankwidget.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef FILTERBANKWIDGET_H -#define FILTERBANKWIDGET_H - -#include -#include -#include -#include "clickabledoublespinbox.h" - - -class FilterBankWidget : public QWidget -{ - Q_OBJECT -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-gui.cpp b/src/libremediaserver-audio-gui.cpp index 62b4544..b769679 100644 --- a/src/libremediaserver-audio-gui.cpp +++ b/src/libremediaserver-audio-gui.cpp @@ -35,11 +35,10 @@ 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(0, 0, 0, 0); + this->setContentsMargins(5, 5, 5, 5); this->setStyleSheet( - "margin: 0px;" "color: white;" - "background-color: #3f3038;" + "background-color: #4f4048;" "selection-color: blue;" "selection-background-color: green" ); diff --git a/src/libremediaserver-audio-gui.ui b/src/libremediaserver-audio-gui.ui index ad4c061..c0f11ad 100644 --- a/src/libremediaserver-audio-gui.ui +++ b/src/libremediaserver-audio-gui.ui @@ -7,7 +7,7 @@ 0 0 - 400 + 500 400 @@ -32,7 +32,7 @@ 0 0 - 400 + 500 21 diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index c9d2dd3..a9868fd 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -26,11 +26,9 @@ 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 (uint i = 0; i < m_layersQty; i++) { + for (int i = 0; i < MAX_LAYERS; i++) { m_currentMedia[i] = ""; m_currentStatus[i] = Status::Iddle; #ifdef NOGUI @@ -40,28 +38,22 @@ libreMediaServerAudio::libreMediaServerAudio() m_updateUi[i][3] = -1; #endif } - if (!m_mae.startEngine(m_layersQty, m_settings->getAudioDeviceId(), m_settings->getAudioDeviceQty())) { - cout << "Can not start Audio Engine!" << endl; - exit(-1); - } - m_ola = new olaThread(this, m_layersQty); + m_ola = new olaThread(this, m_settings->getLayersNumber()); Q_CHECK_PTR(m_ola); m_ola->blockSignals(true); m_ola->registerUniverse(); + m_mae.startEngine(m_settings->getAudioDeviceId()); + qDebug("Core init Complete. Start reading DMX."); + m_ola->blockSignals(false); #ifdef NOGUI m_ola->start(QThread::TimeCriticalPriority ); #endif - m_ola->blockSignals(false); - cout << "Core init Complete." << endl; } libreMediaServerAudio::~libreMediaServerAudio() { m_ola->stop(); m_mae.stopEngine(); - sleep(1); - cout << "bye!" << endl; - exit(0); } void libreMediaServerAudio::loadMedia(int layer, int folder, int file) @@ -95,8 +87,9 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) QString mediaFile = NULL; int aux; if (channel == VOLUME_COARSE || channel == VOLUME_FINE) { - m_mae.volChanged(layer, value); - m_updateUi[layer][0] = value; + float tmp = value / 65025.0f; + m_mae.volChanged(layer, tmp); + m_updateUi[layer][0] = tmp * 100.0f; } else if (channel == PAN) { m_mae.panChanged(layer, value); m_updateUi[layer][1] = value; @@ -125,22 +118,11 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) s = Status::PlayingFolderRandom; m_mae.playbackChanged(layer, s); m_currentStatus[layer] = s; - qInfo() << "Layer" << layer << statusToString(s); + qInfo() << "Layer" << layer << StatusStr[s]; #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)); - } -#endif - } else if (channel >= HP_FREQ) { - m_mae.filterParamChanged(layer, 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)); + //m_lmsUi->m_aw->cursorChanged(layer, m_mae.getCursor(layer)); } #endif } @@ -170,11 +152,11 @@ 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_played.isEmpty()) + m_played.append(m_ola->getValue(i, DMX_FILE)); 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(); @@ -189,7 +171,7 @@ void libreMediaServerAudio::refreshUi() { m_lmsUi->m_aw->playbackChanged(i, Status::Stopped); } } - else if (m_currentStatus[i] == Status::PlayingFolderLoop) { + if (m_currentStatus[i] == Status::PlayingFolderLoop) { uint last = m_played.last(); int folder = m_ola->getValue(i, DMX_FOLDER); last++; @@ -201,7 +183,7 @@ void libreMediaServerAudio::refreshUi() { m_mae.playbackChanged(i, Status::PlayingFolder); } } - else if (m_currentStatus[i] == Status::PlayingFolderRandom) { + 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)) @@ -230,10 +212,6 @@ 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 @@ -241,7 +219,7 @@ void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value) { switch (s){ case Slider::Volume: - m_mae.volChanged(layer, value); + m_mae.volChanged(layer, float((value / 100.0f))); break; case Slider::Pan: m_mae.panChanged(layer, value); @@ -249,15 +227,6 @@ 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); - break; - case Slider::Bus1: - m_mae.filterParamChanged(layer, SEND1, value / 255.0f); - break; - case Slider::Bus2: - m_mae.filterParamChanged(layer, SEND2, value / 255.0f); - break; } } @@ -269,7 +238,7 @@ void libreMediaServerAudio::uiPlaybackChanged(int layer, Status s) if (result == MA_SUCCESS) { m_currentStatus[layer] = s; } else { - qWarning() << "ui playback change error " << result << " status " << statusToString(s) << "layer" << layer; + qWarning() << "ui playback change error" << result << "status" << s << "layer" << layer; } } diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index 898d408..d83446a 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -20,10 +20,6 @@ #ifndef LIBREMEDIASERVERAUDIO_H #define LIBREMEDIASERVERAUDIO_H - -#include -using namespace std; - #include "medialibrary.h" #include "miniaudioengine.h" #include "olathread.h" @@ -57,7 +53,6 @@ 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/ma_writer_node.c b/src/ma_writer_node.c deleted file mode 100644 index 5b20f66..0000000 --- a/src/ma_writer_node.c +++ /dev/null @@ -1,250 +0,0 @@ -#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) == 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[1], *pFrameCountIn, ma_format_f32, pWriteNode->channels); - ma_pcm_rb_commit_write(pWriteNode->pBuffer, *pFrameCountIn); - } - } - 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, - 2, - 1, - 0 -}; - -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; - ma_uint32 inputChannels[2]; - ma_uint32 outputChannels[1]; - - if (pWriteNode == NULL || pConfig == NULL || pConfig->pBuffer == NULL \ - || (pConfig->channels > MA_MAX_NODE_BUS_COUNT) ) { - return MA_INVALID_ARGS; - } - - 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 = inputChannels; - baseConfig.pOutputChannels = outputChannels; - - 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; - 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); -} - -/* - * vumeter - */ - -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; - - MA_ZERO_OBJECT(&config); - config.nodeConfig = ma_node_config_init(); - config.channels = channels; - config.sampleRate = sampleRate; - config.format = format; - - 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, pVumeterNode->format, 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->format = pConfig->format; - pVumeterNode->level = 0; - pVumeterNode->TC = 0.250f; - 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 deleted file mode 100644 index 3e03df5..0000000 --- a/src/ma_writer_node.h +++ /dev/null @@ -1,85 +0,0 @@ -/* 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" - -/* - * writer - */ - -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); - - -/* - * VU meter - */ -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 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; -} 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 -#endif /* ma_writer_node_h */ diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index edc5f78..9204636 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -1,304 +1,80 @@ #include "miniaudioengine.h" -#include "dmxPersonality.h" - -#define BIAS 1.0f -#define FILTER_ORDER 3 - -MiniAudioEngine::MiniAudioEngine() {} +#include //enum macro +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; + } +} void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) { - 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; + //Do master audio processing before sending to device. + ma_engine_read_pcm_frames((ma_engine*)pDevice->pUserData, pOutput, frameCount, NULL); } void MiniAudioEngine::stopEngine() { - 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_mae.layersQty; i++) { - 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); - 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_engine_uninit(&m_mae.engines[i]); - ma_device_uninit(&m_mae.devices[i]); - } - ma_context_uninit(&m_mae.context); - ma_resource_manager_uninit(&m_mae.resourceManager); + ma_engine_uninit(&engine); + ma_device_uninit(&device); + ma_context_uninit(&context); + ma_resource_manager_uninit(&resourceManager); } -bool MiniAudioEngine::startEngine(uint layers, uint* audioDevicesId, uint audioDevicesQty) +bool MiniAudioEngine::startEngine(uint n) { ma_result result; - 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] = 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.0f; - m_mae.currentStatus[i].cursor = 0; - m_mae.currentStatus[i].updated = false; - } result = this->startContext(); - if (result != MA_SUCCESS) return false; + if (result != MA_SUCCESS) return result; 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(uint layer) -{ - ma_result result; - 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); - 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; - 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 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 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 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 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 init hi shelf filter node." << endl; - return result; - } - 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; - 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; - return result; - } - 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; - } - 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; - 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->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; - } - 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 to endpoint." << endl; - return result; - } - } 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; - } - } - } + if (result != MA_SUCCESS) return result; + result = this->startDevice(n); return result; } -ma_result MiniAudioEngine::setNodeGraph() { - ma_result result = MA_SUCCESS; - - 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; - } - 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; - } - } - 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); -} - -ma_result MiniAudioEngine::startDevices() +ma_result MiniAudioEngine::startDevice(uint id) { - ma_result result = MA_SUCCESS; + ma_result result; ma_device_config deviceConfig; ma_engine_config engineConfig; - 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; + 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; + deviceConfig.playback.channels = 0; + deviceConfig.sampleRate = resourceManager.config.decodedSampleRate; deviceConfig.dataCallback = audioDataCallback; - engineConfig = ma_engine_config_init(); - engineConfig.pResourceManager = &m_mae.resourceManager; - engineConfig.defaultVolumeSmoothTimeInPCMFrames = SAMPLE_RATE / 500; - 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_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[internalId]].name << endl; - return result; - } - 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 result; - } - cout << "Initialized Audio Device. internalId: " << internalId << " systemId: " << m_mae.audioDevicesId[internalId] << " " << m_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[internalId]].name << endl; + deviceConfig.pUserData = &engine; + result = ma_device_init(&context, &deviceConfig, &device); + if (result != MA_SUCCESS) { + qCritical("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) { + qCritical("Failed to initialize audio engine."); + return result; + } + result = ma_engine_start(&engine); + if (result != MA_SUCCESS) { + qCritical("Failed to start audio engine %i.", id); + return result; + } + iChosenDevice = id; + qInfo("Initialized audio device %d : %s", id, pPlaybackDeviceInfos[id].name); return result; } @@ -306,19 +82,19 @@ ma_result MiniAudioEngine::startContext() { ma_result result; - 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); + 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.jobThreadCount = 4; + result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager); if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to initialize audio resource manager." << endl; + qCritical("Failed to initialize audio resource manager."); return result; } - result = ma_context_init(NULL, 0, NULL, &m_mae.context); + result = ma_context_init(NULL, 0, NULL, &context); if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to initialize audio context." << endl; + qCritical("Failed to initialize audio context."); } return result; } @@ -328,68 +104,62 @@ ma_result MiniAudioEngine::getAllAudioDevices() { ma_result result; - result = ma_context_get_devices(&m_mae.context, &m_mae.pPlaybackDeviceInfos, &m_mae.playbackDeviceCount, NULL, NULL); + result = ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, NULL, NULL); if (result != MA_SUCCESS) { - cout << "Error " << result << ": Failed to enumerate playback devices." << endl; - ma_context_uninit(&m_mae.context); + qWarning("Failed to enumerate playback devices.\n"); + ma_context_uninit(&context); return result; } - cout << "Audio devices available:" << endl; - for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < m_mae.playbackDeviceCount; iAvailableDevice += 1) { - cout << iAvailableDevice << " : " << m_mae.pPlaybackDeviceInfos[iAvailableDevice].name << endl; + printf("Audio devices available:\n"); + for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < playbackDeviceCount; iAvailableDevice += 1) { + qInfo("%d: : %s", iAvailableDevice, pPlaybackDeviceInfos[iAvailableDevice].name); } return result; } -char* MiniAudioEngine::getDeviceName(uint id) -{ - return m_mae.pPlaybackDeviceInfos[m_mae.audioDevicesId[id]].name; - -} - ma_result MiniAudioEngine::loadMedia(int layer, char *file) { ma_result result; - if (m_mae.mediaLoaded[layer] == MA_TRUE) + if (m_mediaLoaded[layer] == 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]); + 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_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_sound_init_from_file(&engine, file, \ + MA_SOUND_FLAG_NO_SPATIALIZATION \ + | 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); + else { + m_mediaLoaded[layer] = true; + this->refreshValues(layer); + m_currentLayerValues[layer].media = file; } - m_mae.currentStatus[layer].media = file; - m_mae.currentStatus[layer].updated = true; - m_mae.mediaLoaded[layer] = MA_TRUE; - this->refreshValues(layer); return result; } float MiniAudioEngine::getDuration(int layer) { ma_result result; + ma_uint64 lengthInPCMFrames; + ma_uint32 sampleRate; float ret; - if (m_mae.mediaLoaded[layer] == false) + if (m_mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; - result = ma_sound_get_length_in_seconds(&m_mae.sounds[layer], &ret); + result = ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &lengthInPCMFrames); if (result != MA_SUCCESS) { return result; } - return (ret * 1000); + 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; } float MiniAudioEngine::getCursor(int layer) @@ -397,12 +167,12 @@ float MiniAudioEngine::getCursor(int layer) ma_result result; float ret = 0; - if (m_mae.mediaLoaded[layer] == false) + if (m_mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; - result = ma_sound_get_cursor_in_seconds(&m_mae.sounds[layer], &ret); + result = ma_sound_get_cursor_in_seconds(&m_currentSound[layer], &ret); if (result != MA_SUCCESS) { - cout << "Error" << result << ": Can not get cursor " << layer << endl; + qWarning("%i can not get cursor error %i", layer, result); ret = MA_ERROR; } return ret; @@ -414,158 +184,97 @@ ma_result MiniAudioEngine::printFormatInfo(int layer) ma_uint32 channels; ma_uint32 sampleRate; - if (m_mae.mediaLoaded[layer] == false) + if (m_mediaLoaded[layer] == false) return MA_DOES_NOT_EXIST; - 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_mae.currentStatus[layer].media.toLatin1().data(); - cout << " samples/sec:" << sampleRate << " format:" << format; - cout << " channels:" << channels << endl; - } + 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; return result; } -// Expects between 0 and 65535 vol value -void MiniAudioEngine::volChanged(int layer, int vol) +// Expects between 0 and 1 vol value +void MiniAudioEngine::volChanged(int layer, float vol) { - m_mae.currentStatus[layer].vol = vol; - if (m_mae.mediaLoaded[layer] == MA_FALSE && m_mae.currentStatus[layer].updated) + if (m_mediaLoaded[layer] == false) return; - float db = ((float)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, FADE_TIME); + 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) { float result; - m_mae.currentStatus[layer].pan = value; - if (m_mae.mediaLoaded[layer] == false) + if (m_mediaLoaded[layer] == false) return; result = (value / 128.0) - 1.0; - ma_sound_group_set_pan(&m_mae.sounds[layer], result); + ma_sound_group_set_pan(&m_currentSound[layer], result); + m_currentLayerValues[layer].pan = value; } void MiniAudioEngine::pitchChanged(int layer, float value) { float pitch; - m_mae.currentStatus[layer].pitch = value; - if (m_mae.mediaLoaded[layer] == false) + if (m_mediaLoaded[layer] == false) return; pitch = value / 128.0; - ma_sound_group_set_pitch(&m_mae.sounds[layer], pitch); + ma_sound_group_set_pitch(&m_currentSound[layer], pitch); + m_currentLayerValues[layer].pitch = value; } ma_result MiniAudioEngine::playbackChanged(int layer, Status status) { ma_result result = MA_SUCCESS; - float db = 0; - bool loop = false; - m_mae.currentStatus[layer].status = status; - if (m_mae.mediaLoaded[layer] == MA_FALSE) + if (m_mediaLoaded[layer] == 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); + result = ma_sound_stop_with_fade_in_milliseconds(&m_currentSound[layer], FADE_TIME); break; case Status::Stopped: - ma_sound_stop_with_fade_in_milliseconds(&m_mae.sounds[layer], 0.0f); - result = this->seekToCursor(layer, m_mae.currentStatus[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: - loop = true; - if (m_mae.currentStatus[layer].cursor > 0) { - result = this->seekToCursor(layer, m_mae.currentStatus[layer].cursor); - } + 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; 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); - 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_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); + 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]); + break; default: break; } - m_mae.currentStatus[layer].updated = true; + if (result == MA_SUCCESS) + m_currentLayerValues[layer].status = status; return result; } -ma_result MiniAudioEngine::setRangePoint(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_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; + ma_uint64 end, start; - if (m_mae.mediaLoaded[layer] == false) + if (m_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_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); } @@ -573,156 +282,21 @@ ma_result MiniAudioEngine::setCursor(int layer, int cursor) { ma_result result = MA_SUCCESS; - m_mae.currentStatus[layer].cursor = cursor; + m_currentLayerValues[layer].cursor = cursor; result = this->seekToCursor(layer, cursor); return (result); } Status MiniAudioEngine::getStatus(int layer) { - return m_mae.currentStatus[layer].status; + return m_currentLayerValues[layer].status; } void MiniAudioEngine::refreshValues(int layer) { - this->panChanged(layer, m_mae.currentStatus[layer].pan); - this->pitchChanged(layer, m_mae.currentStatus[layer].pitch); - this->playbackChanged(layer, m_mae.currentStatus[layer].status); -} - -ma_result MiniAudioEngine::filterParamChanged(int layer, int channel, int value) -{ - ma_result result = MA_SUCCESS; - filterBank *fb = &m_mae.filters[layer]; - - 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 high pass filter node." << endl; - return result; - } - } 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 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.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; - } - } else if (channel == MIDLOW_Q) { - 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; - } - } else if (channel == MIDLOW_GAIN) { - 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.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.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.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; - } - } else if (channel == SEND1) { - 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) { - 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; - } - return result; - } - return (result); -} - -bool MiniAudioEngine::setBypass(int audioDevice, int layer, bool bypass) -{ - (void)audioDevice; - filterBank *fb = &m_mae.filters[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); - } - return true; + 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); } diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 21deff3..6e1393c 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -1,73 +1,25 @@ #ifndef MINIAUDIOENGINE_H #define MINIAUDIOENGINE_H -#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 #define MINIAUDIO_IMPLEMENTATION #include "miniaudio.h" -#include "ma_writer_node.h" -#include -using namespace std; -#include "defines.h" - -typedef struct -{ - ma_splitter_node input; - ma_hpf_node hpf; - ma_hpf_node_config hpfConfig; - ma_loshelf_node loshelf; - ma_loshelf_node_config loshelfConfig; - ma_peak_node mLow; - ma_peak_node_config mLowConfig; - ma_peak_node mHigh; - ma_peak_node_config mHighConfig; - ma_hishelf_node hishelf; - ma_hishelf_node_config hishelfConfig; - ma_vumeter_node vumeter; - ma_splitter_node output; -} filterBank; - -typedef struct -{ - 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_device_info pSelectedPlaybackDeviceInfos[MAX_AUDIODEVICES]; - 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; +#include "defines.h" // MAX_LAYERS +#include // prints messages +#define MA_DEBUG_OUTPUT class MiniAudioEngine { friend class libreMediaServerAudio; public: + MiniAudioEngine(); + void stopEngine(); + bool startEngine(uint id); 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); - void volChanged(int layer, int vol); + 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); ma_result playbackChanged(int layer, Status status); @@ -77,29 +29,27 @@ protected: float getCursor(int layer); Status getStatus(int layer); inline float getVol(int 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 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) - 4.0f; - }; - char* getDeviceName(uint id); + return ma_sound_get_volume(&m_currentSound[layer]); } + inline bool getAtEnd(int layer) { return m_currentSound[layer].atEnd; } private: - MAE m_mae; + 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]; + layerData m_currentLayerValues[MAX_LAYERS]; - ma_result startDevices(); ma_result getAllAudioDevices(); + ma_result startDevice(uint id); ma_result startContext(); void refreshValues(int layer); 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 diff --git a/src/settings.cpp b/src/settings.cpp index 6527bcb..9d06394 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -51,14 +51,16 @@ 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 6e51d14..f27da6a 100644 --- a/src/settings.h +++ b/src/settings.h @@ -22,8 +22,7 @@ public: inline QString getPathMedia() { return m_pathmedia; } inline QList getDmxSettings() { return m_settings; } inline int getLayersNumber() { return m_layersNumber; } - inline uint *getAudioDeviceId() { return m_audioDeviceId; } - inline uint getAudioDeviceQty() { return m_audioDeviceQty; } + inline int getAudioDeviceId() { return m_audioDeviceId[0]; } inline bool getShowUi() { return m_ui; } void readFile(); void readFromFile(QString file); diff --git a/src/slidergroup.cpp b/src/slidergroup.cpp index 481d554..9ef9680 100644 --- a/src/slidergroup.cpp +++ b/src/slidergroup.cpp @@ -1,8 +1,5 @@ #include "slidergroup.h" -#include -#include -#include - +#include SliderGroup::SliderGroup(QString name, int min, int max, @@ -10,69 +7,46 @@ SliderGroup::SliderGroup(QString name, QWidget *parent) : QWidget(parent) { - QBoxLayout *layout; - if (decimals) { - layout = new QVBoxLayout; - slider.setOrientation(Qt::Vertical); - } - else { - layout = new QHBoxLayout; - slider.setOrientation(Qt::Horizontal); - slider.setMaximumHeight(15); - valueBox.setMaximumHeight(15); - } + QVBoxLayout *layout = new QVBoxLayout; layout->setAlignment(Qt::AlignHCenter); layout->setContentsMargins(0, 0, 0, 0); - 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 #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); - valueBox.setMinimumWidth(50); - if (decimals) { - valueBox.setRange(-84.0f, 0.0f); - valueBox.setSpecialValueText("-inf"); - } else - 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(click()), this, SLOT(enableSlider())); - layout->addWidget(&slider); - layout->addWidget(&valueBox); - this->setStyleSheet("border: 1px solid #aa8895;" - "background-color: black;" - "margin: 1px;" + //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 {" + "border: 1px solid #5a4855;" + "margin: 0px;" + "height: 200px;" + "width: 50px;}" + ); + 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); + this->setStyleSheet("border: 1px solid #5a4855;" + "width: 50px;" + "margin: 0px;" + "background-color: #383034;" ); layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); @@ -81,33 +55,27 @@ SliderGroup::SliderGroup(QString name, void SliderGroup::sliderValueChanged(int value) { - valueBox.blockSignals(true); - 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); + valueBox->blockSignals(true); + valueBox->setValue(value); + 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()) { - db = (float)(value / 771.0f) - 85.0f; - valueBox.setValue(db); - } else - valueBox.setValue(value); - slider.blockSignals(false); - valueBox.blockSignals(false); + 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); } diff --git a/src/slidergroup.h b/src/slidergroup.h index 39843bc..5bfeeb8 100644 --- a/src/slidergroup.h +++ b/src/slidergroup.h @@ -1,16 +1,15 @@ #ifndef SLIDERGROUP_H #define SLIDERGROUP_H -#include -#include -#include - -#include "clickabledoublespinbox.h" -#include "clickableslider.h" +#include +#include +#include +#include class SliderGroup : public QWidget { Q_OBJECT + public: SliderGroup(QString name, int min, @@ -26,12 +25,10 @@ public slots: void sliderValueChanged(int value); private: - ClickableSlider slider; - ClickableDoubleSpinBox valueBox; - -private slots: - void enableSlider() { slider.setEnabled(true); } + QSlider *slider; + QDoubleSpinBox *valueBox; + void mousePressEvent(QMouseEvent* event); }; #endif