diff --git a/docs/changelog.txt b/docs/changelog.txt index 22a7e1f..a69017b 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -27,6 +27,8 @@ v 0.2.0 Antígona (24/04/2024) + Compilation without GUI (-DNOGUI). + New Status "Iddle" in playbacks if is not loaded. + New DMX personality version, better sort for audio needs (first load media, set vol, pan, etc, last playback order); ++ Refresh layer values when it loads a new sound file. ++ No QtSignals for sending data, better performance about 20% in my machine. Now, libremediaserver only updates values in AudioWidget, ui refresh is doing with a timer in audiowidget, so there is not problems between graphical and ola thread (the callback). v 0.1.3 Leúcade (19/04/2024) diff --git a/docs/lms-audio.xlm b/docs/lms-audio.xlm index cc498ca..4274267 100644 --- a/docs/lms-audio.xlm +++ b/docs/lms-audio.xlm @@ -1,8 +1,8 @@ - - - - - - - + + + + + + + diff --git a/docs/roadmap.txt b/docs/roadmap.txt index 894c32c..bd98089 100644 --- a/docs/roadmap.txt +++ b/docs/roadmap.txt @@ -45,9 +45,13 @@ v 0.2.1 - Ui/Ux: Dar la opción clickeando en el widget de tiempo de poner una cuenta atrás en vez de hacia delante. - Logs, verbosity, timestamp. - New play mode without pitch control, it saves resources. MA_SOUND_FLAG_NO_PITCH -- Vumeter or indicator about audio output in layer and master. +- Vumeter or indicator about audio output in layer and master, add to sliderGroup. +- QSlider can not accept floats and it can no manage high frequency updates. - SettingsDialog. - Load/save conf file. - ¿Exit Point? is it needed? -- Hardening: check return errors, catch execptions, i'm too happy.... +- Hardening: check return errors, try/catch exceptions, i'm too happy.... - Tests: errors on wrong conf file. +- BUGFIX: there are some small clicks when changing volume and play/stop/pause. vol 24 bits? microfades in engine? setVol 0 before changing playback state? +- refactorize dmxInput: loadMedia, changePlayBack, +- BUGFIX: in nogui mode we need more info print at terminal (load media, change playback status). diff --git a/src/audiolayerwidget.cpp b/src/audiolayerwidget.cpp index 02da882..a22b2cc 100644 --- a/src/audiolayerwidget.cpp +++ b/src/audiolayerwidget.cpp @@ -52,6 +52,7 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, int layer): m_progressTime->setReadOnly(true); m_progressTime->setButtonSymbols(QAbstractSpinBox::NoButtons); m_progressTime->setMinimumWidth(80); + m_progressTime->setMaximumWidth(80); m_progressTime->setFocusPolicy(Qt::NoFocus); m_progressTime->setAlignment(Qt::AlignHCenter); m_progressTime->setContentsMargins(0,0,0,0); @@ -138,7 +139,7 @@ void AudioLayerWidget::openMediaDialog() QStringList fileNames; fileNames = dialog.selectedFiles(); emit uiLoadMedia(m_layer, fileNames.at(0)); - this->fileLoaded(fileNames.at(0)); + this->setMediaFile(fileNames.at(0)); } // from DMX signals @@ -163,7 +164,7 @@ void AudioLayerWidget::setPitch(int pitch) m_pitch->blockSignals(false); } -void AudioLayerWidget::fileLoaded(QString file) +void AudioLayerWidget::setMediaFile(QString file) { QStringList list = file.split("/"); int size = list.size(); @@ -174,19 +175,18 @@ void AudioLayerWidget::fileLoaded(QString file) this->setPlaybackStatus(Status::Stopped); } -void AudioLayerWidget::setPlaybackStatus(Status status) +void AudioLayerWidget::setPlaybackStatus(Status s) { - if (!strcmp(StatusStr[status], m_suspendResumeButton->text().toLatin1().constData())) - return; + Status status = static_cast(s); m_suspendResumeButton->blockSignals(true); m_status = status; - if (status == Status::Stopped) - refreshCurrentTime(0); + //if (status == Status::Stopped) + // refreshCurrentTime(0); m_suspendResumeButton->setText(StatusStr[status]); m_suspendResumeButton->blockSignals(false); } -void AudioLayerWidget::durationChanged(float dur) +void AudioLayerWidget::setDuration(float dur) { m_progress->blockSignals(true); m_progressTime->blockSignals(true); @@ -200,7 +200,7 @@ void AudioLayerWidget::durationChanged(float dur) m_totalTimeValue->blockSignals(false); } -void AudioLayerWidget::refreshCurrentTime(float progress) +void AudioLayerWidget::setCurrentTime(float progress) { progress *= 1000; m_progress->blockSignals(true); diff --git a/src/audiolayerwidget.h b/src/audiolayerwidget.h index 1c0ee83..9380b81 100644 --- a/src/audiolayerwidget.h +++ b/src/audiolayerwidget.h @@ -18,13 +18,6 @@ class AudioLayerWidget : public QWidget public: explicit AudioLayerWidget(QWidget *parent = 0, int layer = 0); ~AudioLayerWidget(); - void setVol(float vol); - void resume(); - void setPan(int pan); - void setPitch(int pitch); - void setLoop(bool on); - void setPlaybackStatus(Status status); - inline Status getPlaybackStatus() { return m_status; } private: Status m_status; @@ -39,17 +32,23 @@ private: QTimeEdit *m_totalTimeValue; QProgressBar *m_progress; +// From DMX public slots: + void setMediaFile(QString file); + void setDuration(float dur); + void setCurrentTime(float progress); + void setPlaybackStatus(Status status); + void setVol(float vol); + void setPan(int pan); + void setPitch(int pitch); + +// From Ui +private slots: + void openMediaDialog(); void toggleSuspendResume(); void volumeChanged(int vol); void panChanged(int pan); void pitchChanged(int pitch); - void fileLoaded(QString file); - void durationChanged(float dur); - void refreshCurrentTime(float progress); - -private slots: - void openMediaDialog(); signals: void uiPlaybackChanged(int layer, Status s); diff --git a/src/audiowidget.cpp b/src/audiowidget.cpp index 3d17c2d..ca2633a 100644 --- a/src/audiowidget.cpp +++ b/src/audiowidget.cpp @@ -1,5 +1,5 @@ #include "audiowidget.h" - +#include AudioWidget::AudioWidget(QWidget *parent) : QWidget(parent) @@ -15,39 +15,79 @@ AudioWidget::AudioWidget(QWidget *parent) : m_layout->setSpacing(0); m_layout->setContentsMargins(1, 1, 1, 1); setLayout(m_layout); + m_refreshUi = new QTimer(this); + connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); + m_refreshUi->start(UI_REFRESH_TIME * 2); } void AudioWidget::mediaLoaded(int layer, QString file, float duration) { - QLayoutItem * const item = m_layout->itemAt(layer); - dynamic_cast(item->widget())->fileLoaded(file); - dynamic_cast(item->widget())->durationChanged(duration); + m_layerUpdate[layer].media = file; + m_layerUpdate[layer].duration = duration; + m_layerUpdate[layer].updated = true; } void AudioWidget::volChanged(int layer, float vol) { - QLayoutItem * const item = m_layout->itemAt(layer); - dynamic_cast(item->widget())->setVol(vol); + m_layerUpdate[layer].vol = vol; + m_layerUpdate[layer].updated = true; } void AudioWidget::panChanged(int layer, int pan) { - QLayoutItem * const item = m_layout->itemAt(layer); - dynamic_cast(item->widget())->setPan(pan); + m_layerUpdate[layer].pan = pan; + m_layerUpdate[layer].updated = true; } void AudioWidget::pitchChanged(int layer, int pitch) { - QLayoutItem * const item = m_layout->itemAt(layer); - dynamic_cast(item->widget())->setPitch(pitch); + + m_layerUpdate[layer].pitch = pitch; + m_layerUpdate[layer].updated = true; } void AudioWidget::playbackChanged(int layer, Status status) { - QLayoutItem * const item = m_layout->itemAt(layer); - dynamic_cast(item->widget())->setPlaybackStatus(status); + m_layerUpdate[layer].status = status; + m_layerUpdate[layer].updated = true; } void AudioWidget::cursorChanged(int layer, float cursor) { - QLayoutItem * const item = m_layout->itemAt(layer); - AudioLayerWidget *alw = dynamic_cast(item->widget()); - alw->refreshCurrentTime(cursor); + m_layerUpdate[layer].cursor = floor(cursor * 1000) / 1000; + m_layerUpdate[layer].updated = true; +} + +void AudioWidget::refreshUi() +{ + for (int i = 0; i < MAX_LAYERS; i++) + { + if (m_layerUpdate[i].updated) { + QLayoutItem * const item = m_layout->itemAt(i); + AudioLayerWidget *alw = dynamic_cast(item->widget()); + if (m_layerUpdate[i].vol > -1) { + alw->setVol(m_layerUpdate[i].vol); + m_layerUpdate[i].vol = -1; + } + if (m_layerUpdate[i].cursor > -1) { + alw->setCurrentTime(m_layerUpdate[i].cursor); + m_layerUpdate[i].cursor = -1; + } + if (m_layerUpdate[i].pan > -1) { + alw->setPan(m_layerUpdate[i].pan); + m_layerUpdate[i].pan = -1; + } + if (m_layerUpdate[i].pitch > -1) { + alw->setPitch(m_layerUpdate[i].pitch); + m_layerUpdate[i].pitch = -1; + } + if (m_layerUpdate[i].status != Status::Iddle) { + alw->setPlaybackStatus(m_layerUpdate[i].status); + m_layerUpdate[i].status = Status::Iddle; + } + if (m_layerUpdate[i].duration > -1) { + alw->setMediaFile(m_layerUpdate[i].media); + alw->setDuration(m_layerUpdate[i].duration); + m_layerUpdate[i].duration = -1; + } + m_layerUpdate[i].updated = false; + } + } } diff --git a/src/audiowidget.h b/src/audiowidget.h index a293a0a..dd9b1f1 100644 --- a/src/audiowidget.h +++ b/src/audiowidget.h @@ -5,7 +5,6 @@ #include "audiolayerwidget.h" #include "settings.h" -#include "miniaudioengine.h" #include "defines.h" // MAX_LAYERS class AudioWidget : public QWidget @@ -14,14 +13,22 @@ class AudioWidget : public QWidget public: AudioWidget(QWidget *parent = nullptr); - void mediaLoaded(int layer, QString media, float duration); + +private: + QHBoxLayout *m_layout; + layerData m_layerUpdate[MAX_LAYERS]; + QTimer *m_refreshUi; + +public slots: void volChanged(int layer, float vol); void panChanged(int layer, int pan); void pitchChanged(int layer, int pitch); - void playbackChanged(int layer, Status status); void cursorChanged(int layer, float cursor); - QHBoxLayout *m_layout; + void mediaLoaded(int layer, QString media, float duration); + void playbackChanged(int layer, Status status); +private slots: + void refreshUi(); signals: void uiPlaybackChanged(int layer, Status s); void uiSliderChanged(int layer, Slider s, int vol); diff --git a/src/defines.h b/src/defines.h index f8a2312..6552d19 100644 --- a/src/defines.h +++ b/src/defines.h @@ -6,9 +6,10 @@ #define LICENSE "GPL 3 Licensed. See LICENSE.txt." #define DEFAULT_FILE "lms-audio.xlm" #define MAX_LAYERS 4 -#define UI_REFRESH_TIME 93 +#define MAX_AUDIODEVICES 8 +#define UI_REFRESH_TIME 77 +#define FADE_TIME 25 // DMX Frame time, 40 fps, avoid clicks -// struct where save the DMX settings for each layer struct dmxSetting { int address; unsigned int universe; @@ -41,5 +42,15 @@ enum Slider Pitch, }; +#include +struct layerData { + QString media; + Status status; + bool updated; + float vol; + float cursor; + int pan; + int pitch; + float duration; +}; #endif // DEFINES_H - diff --git a/src/dmxPersonality.h b/src/dmxPersonality.h index c56829e..82f9468 100644 --- a/src/dmxPersonality.h +++ b/src/dmxPersonality.h @@ -10,7 +10,6 @@ #define ENTRY_POINT_COARSE 5 #define ENTRY_POINT_FINE 4 #define PITCH 7 - #define LAYER_CHANNELS 9 #endif // DMXPERSONALITY_H diff --git a/src/libremediaserver-audio-gui.cpp b/src/libremediaserver-audio-gui.cpp index 2d92918..b769679 100644 --- a/src/libremediaserver-audio-gui.cpp +++ b/src/libremediaserver-audio-gui.cpp @@ -38,7 +38,7 @@ libreMediaServerAudioUi::libreMediaServerAudioUi(QWidget *parent) this->setContentsMargins(5, 5, 5, 5); this->setStyleSheet( "color: white;" - "background-color: gray;" + "background-color: #4f4048;" "selection-color: blue;" "selection-background-color: green" ); diff --git a/src/libremediaserver-audio.cpp b/src/libremediaserver-audio.cpp index 589c190..cb18dc2 100644 --- a/src/libremediaserver-audio.cpp +++ b/src/libremediaserver-audio.cpp @@ -21,11 +21,11 @@ #include "libremediaserver-audio.h" -libreMediaServerAudio::libreMediaServerAudio(bool gui) +libreMediaServerAudio::libreMediaServerAudio() { - m_ui = gui; - Settings *set = Settings::getInstance(); - set->readFile(); + m_settings = Settings::getInstance(); + m_settings->readFile(); + m_ui = m_settings->getShowUi(); m_mediaLibrary = new MediaLibrary; m_mediaLibrary->initMediaLibrary(); for (int i = 0; i < MAX_LAYERS; i++) { @@ -38,12 +38,11 @@ libreMediaServerAudio::libreMediaServerAudio(bool gui) m_updateUi[i][3] = -1; #endif } - m_ola = new olaThread(this, set->getLayersNumber()); + m_ola = new olaThread(this, m_settings->getLayersNumber()); Q_CHECK_PTR(m_ola); m_ola->blockSignals(true); - connect(m_ola, SIGNAL(dmxOutput(int, int, int)), this, SLOT(dmxInput(int, int, int))); m_ola->registerUniverse(); - m_mae.startEngine(set->getAudioDeviceId()); + m_mae.startEngine(m_settings->getAudioDeviceId()); qDebug("Core init Complete. Start reading DMX."); m_ola->blockSignals(false); #ifdef NOGUI @@ -57,27 +56,29 @@ libreMediaServerAudio::~libreMediaServerAudio() m_mae.stopEngine(); } +void libreMediaServerAudio::loadMedia(int layer, int folder, int file) +{ + QString mediaFile = m_mediaLibrary->requestNewFile(folder, file); + if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0) + return; + if (QFile::exists(mediaFile)){ + m_mae.loadMedia(layer, mediaFile.toLatin1().data()); + m_currentMedia[layer] = mediaFile; +#ifndef NOGUI + if (m_ui) + m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); +#endif + m_mae.printFormatInfo(layer); + } +} + void libreMediaServerAudio::dmxInput(int layer, int channel, int value) { if (layer >= MAX_LAYERS || channel >= LAYER_CHANNELS) return; QString mediaFile = NULL; int aux; - if (channel == DMX_FOLDER || channel == DMX_FILE){ - int folder = (value >> 8) & 0x000000FF; - int file = value & 0x000000FF; - mediaFile = m_mediaLibrary->requestNewFile(folder, file); - if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0) - return; - if (QFile::exists(mediaFile)){ - m_mae.loadMedia(layer, mediaFile.toLatin1().data()); - m_currentMedia[layer] = mediaFile; -#ifndef NOGUI - if (m_ui) - m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); -#endif - } - } else if (channel == VOLUME_COARSE || channel == VOLUME_FINE) { + if (channel == VOLUME_COARSE || channel == VOLUME_FINE) { float tmp = value / 65025.0f; m_mae.volChanged(layer, tmp); m_updateUi[layer][0] = tmp * 100.0f; @@ -104,15 +105,17 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value) m_mae.playbackChanged(layer, s); m_currentStatus[layer] = s; #ifndef NOGUI - if (m_ui) m_lmsUi->m_aw->playbackChanged(layer, s); + if (m_ui) { + m_lmsUi->m_aw->playbackChanged(layer, s); + m_lmsUi->m_aw->cursorChanged(layer, m_mae.getCursor(layer)); + } #endif } } - #ifndef NOGUI void libreMediaServerAudio::refreshUi() { if (!m_ui) return; - for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) { + for (int i= 0; i < m_settings->getLayersNumber(); i++ ) { if (m_updateUi[i][0] >= 0) { m_lmsUi->m_aw->volChanged(i, m_updateUi[i][0]); m_updateUi[i][0] = -1; @@ -125,7 +128,9 @@ void libreMediaServerAudio::refreshUi() { m_lmsUi->m_aw->pitchChanged(i, m_updateUi[i][2]); m_updateUi[i][2] = -1; } - if (m_updateUi[i][3] >= 0) { + if (m_updateUi[i][3] >= 0 \ + || m_currentStatus[i] == Status::PlayingOnce\ + || m_currentStatus[i] == Status::PlayingLoop) { m_lmsUi->m_aw->cursorChanged(i, m_mae.getCursor(i)); m_updateUi[i][3] = -1; } @@ -135,6 +140,7 @@ void libreMediaServerAudio::refreshUi() { void libreMediaServerAudio::setUi(libreMediaServerAudioUi *lmsUi) { m_lmsUi = lmsUi; + m_ui = true; connect(m_ola, SIGNAL(universeReceived(int)), m_lmsUi->m_dmxWidget, SLOT(updateWatchDMX(int))); connect(m_lmsUi->m_aw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SLOT(uiSliderChanged(int, Slider, int))); connect(m_lmsUi->m_aw, SIGNAL(uiPlaybackChanged(int, Status)), this, SLOT(uiPlaybackChanged(int, Status))); @@ -145,6 +151,7 @@ void libreMediaServerAudio::setUi(libreMediaServerAudioUi *lmsUi) m_ola->start(QThread::TimeCriticalPriority ); }; +// From Ui widgets void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value) { switch (s){ @@ -166,8 +173,12 @@ void libreMediaServerAudio::uiPlaybackChanged(int layer, Status s) m_currentStatus[layer] = s; } -void libreMediaServerAudio::uiLoadMedia(int layer, QString s) +void libreMediaServerAudio::uiLoadMedia(int layer, QString mediaFile) { - m_mae.loadMedia(layer, s.toLatin1().data()); + if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0) + return; + m_mae.loadMedia(layer, mediaFile.toLatin1().data()); + m_currentMedia[layer] = mediaFile; + m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); } #endif diff --git a/src/libremediaserver-audio.h b/src/libremediaserver-audio.h index 665f3e2..1af37df 100644 --- a/src/libremediaserver-audio.h +++ b/src/libremediaserver-audio.h @@ -21,6 +21,7 @@ #define LIBREMEDIASERVERAUDIO_H #include "medialibrary.h" +#include "miniaudioengine.h" #include "olathread.h" #include "settings.h" #include "defines.h" @@ -33,33 +34,35 @@ class libreMediaServerAudio : public QObject Q_OBJECT public: - libreMediaServerAudio(bool gui = false); + libreMediaServerAudio(); virtual ~libreMediaServerAudio(); void dmxInput(int layer, int channel, int value); + void loadMedia(int layer, int folder, int file); #ifndef NOGUI void setUi(libreMediaServerAudioUi *lmsUi); + bool inline getShowUi() { return m_settings->getShowUi(); } #endif - //static void NewDmx(const ola::client::DMXMetadata &data, const ola::DmxBuffer &buffer); + private: olaThread *m_ola; MediaLibrary *m_mediaLibrary; MiniAudioEngine m_mae; + Settings *m_settings; QString m_currentMedia[MAX_LAYERS]; Status m_currentStatus[MAX_LAYERS]; - static QList m_dmxSettings; -#ifndef NOGUI + QList m_dmxSettings; bool m_ui; +#ifndef NOGUI QTimer *m_refreshUi; libreMediaServerAudioUi *m_lmsUi; float m_updateUi[MAX_LAYERS][4]; -#endif private slots: -#ifndef NOGUI void refreshUi(); void uiSliderChanged(int layer, Slider s, int value); void uiPlaybackChanged(int layer, Status s); void uiLoadMedia(int layer, QString s); + #endif }; diff --git a/src/main.cpp b/src/main.cpp index eea3c29..79b7a91 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,9 +32,9 @@ bool hasUi(int &argc, char *argv[]) int main(int argc, char *argv[]) { QApplication app(argc, argv); - libreMediaServerAudio lms(hasUi(argc, argv)); + libreMediaServerAudio lms; #ifndef NOGUI - if (hasUi(argc, argv)) + if (hasUi(argc, argv) || lms.getShowUi()) { libreMediaServerAudioUi *lmsUi = new libreMediaServerAudioUi(); lms.setUi(lmsUi); diff --git a/src/miniaudioengine.cpp b/src/miniaudioengine.cpp index f65744d..c2d9a6d 100644 --- a/src/miniaudioengine.cpp +++ b/src/miniaudioengine.cpp @@ -4,6 +4,11 @@ MiniAudioEngine::MiniAudioEngine() { for (int i =0; i < MAX_LAYERS; i++) { m_mediaLoaded[i] = false; + m_currentLayerValues[i].status = Status::Iddle; + m_currentLayerValues[i].pan = 128; + m_currentLayerValues[i].pitch = 128; + m_currentLayerValues[i].vol = 0; + m_currentLayerValues[i].cursor = 0; } } @@ -79,8 +84,8 @@ ma_result MiniAudioEngine::startContext() resourceManagerConfig = ma_resource_manager_config_init(); resourceManagerConfig.decodedFormat = ma_format_f32; /* ma_format_f32 should almost always be used as that's what the engine (and most everything else) uses for mixing. */ resourceManagerConfig.decodedChannels = 0; - resourceManagerConfig.decodedSampleRate = 0; - resourceManagerConfig.jobThreadCount = 0; + resourceManagerConfig.decodedSampleRate = ma_standard_sample_rate_48000; + resourceManagerConfig.jobThreadCount = 1; result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager); if (result != MA_SUCCESS) { qCritical("Failed to initialize audio resource manager."); @@ -114,11 +119,9 @@ ma_result MiniAudioEngine::getAllAudioDevices() ma_result MiniAudioEngine::loadMedia(int layer, char *file) { ma_result result; - float vol = -1; if (m_mediaLoaded[layer] == true) { - vol = ma_sound_get_volume(&m_currentSound[layer]); ma_sound_uninit(&m_currentSound[layer]); m_mediaLoaded[layer] = false; } @@ -133,10 +136,8 @@ ma_result MiniAudioEngine::loadMedia(int layer, char *file) qWarning("Failed to load file %s", file); else { m_mediaLoaded[layer] = true; - if (vol == -1) - this->volChanged(layer, 0); - else - this->volChanged(layer, vol); + this->refreshValues(layer); + m_currentLayerValues[layer].media = file; } return result; } @@ -191,7 +192,7 @@ ma_result MiniAudioEngine::printFormatInfo(int layer) qWarning("Failed to get data format %i\n", layer); return MA_INVALID_DATA; } - qInfo("samples/sec: %u format: %u channels: %u", sampleRate, format, channels); + qInfo() << "name:" << m_currentLayerValues[layer].media << "samples/sec:" << sampleRate << "format:" << format << "channels:" << channels; return result; } @@ -200,9 +201,10 @@ void MiniAudioEngine::volChanged(int layer, float vol) { if (m_mediaLoaded[layer] == false) return; - if (vol > 1) - vol = 1; - ma_sound_group_set_volume(&m_currentSound[layer], vol); + if (vol >= 1) + vol = 0.99f; + ma_sound_group_set_fade_in_milliseconds(&m_currentSound[layer], -1, vol, FADE_TIME); + m_currentLayerValues[layer].vol = vol; } void MiniAudioEngine::panChanged(int layer, float value) @@ -213,6 +215,7 @@ void MiniAudioEngine::panChanged(int layer, float value) return; result = (value / 128.0) - 1.0; ma_sound_group_set_pan(&m_currentSound[layer], result); + m_currentLayerValues[layer].pan = value; } void MiniAudioEngine::pitchChanged(int layer, float value) @@ -223,6 +226,7 @@ void MiniAudioEngine::pitchChanged(int layer, float value) return; result = value / 128.0; ma_sound_group_set_pitch(&m_currentSound[layer], result); + m_currentLayerValues[layer].pitch = value; } void MiniAudioEngine::playbackChanged(int layer, Status status) @@ -235,7 +239,7 @@ void MiniAudioEngine::playbackChanged(int layer, Status status) break; case Status::Stopped: ma_sound_stop(&m_currentSound[layer]); - ma_sound_seek_to_pcm_frame(&m_currentSound[layer], 0); + this->setCursor(layer, m_currentLayerValues[layer].cursor); break; case Status::PlayingLoop: ma_sound_set_looping(&m_currentSound[layer], true); @@ -248,30 +252,35 @@ void MiniAudioEngine::playbackChanged(int layer, Status status) default: break; } + m_currentLayerValues[layer].status = status; } void MiniAudioEngine::setCursor(int layer, int cursor) { - ma_uint64 f; + ma_uint64 end; + m_currentLayerValues[layer].cursor = cursor; if (m_mediaLoaded[layer] == false) return; - ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &f); - f = (cursor * f) / 65025; - ma_sound_seek_to_pcm_frame(&m_currentSound[layer], f); - // ToDo: change the loop entry point too + ma_sound_get_length_in_pcm_frames(&m_currentSound[layer], &end); + ma_uint64 start = (cursor * end) / 65025; + ma_sound_seek_to_pcm_frame(&m_currentSound[layer], start); + ma_result result = ma_data_source_set_loop_point_in_pcm_frames(&m_currentSound[layer], start, end); + if (result != MA_SUCCESS) { + return; // Failed to set the loop point. + } } Status MiniAudioEngine::getStatus(int layer) { - if (m_mediaLoaded[layer] == false) - return Status::Iddle; - if (ma_sound_is_playing(&m_currentSound[layer])) { - if (ma_sound_is_looping(&m_currentSound[layer])) - return Status::PlayingLoop; - return Status::PlayingOnce; - } - if (this->getDuration(layer) > 0) - return Status::Paused; - return Status::Stopped; + return m_currentLayerValues[layer].status; +} + +void MiniAudioEngine::refreshValues(int layer) +{ + this->panChanged(layer, m_currentLayerValues[layer].pan); + this->volChanged(layer, m_currentLayerValues[layer].vol); + this->pitchChanged(layer, m_currentLayerValues[layer].pitch); + this->playbackChanged(layer, m_currentLayerValues[layer].status); + this->setCursor(layer, m_currentLayerValues[layer].cursor); } diff --git a/src/miniaudioengine.h b/src/miniaudioengine.h index 169d33b..2c3ec5a 100644 --- a/src/miniaudioengine.h +++ b/src/miniaudioengine.h @@ -40,10 +40,12 @@ private: ma_context context; ma_sound m_currentSound[MAX_LAYERS]; ma_bool8 m_mediaLoaded[MAX_LAYERS]; + layerData m_currentLayerValues[MAX_LAYERS]; ma_result getAllAudioDevices(); ma_result startDevice(int id); ma_result startContext(); + void refreshValues(int layer); }; #endif // MINIAUDIOENGINE_H diff --git a/src/olathread.cpp b/src/olathread.cpp index 409cf79..6ca9325 100644 --- a/src/olathread.cpp +++ b/src/olathread.cpp @@ -1,5 +1,4 @@ #include "libremediaserver-audio.h" -//#include "olathread.h" olaThread::olaThread(QObject *parent, int layers) : m_counter(0) @@ -36,7 +35,6 @@ void olaThread::init() } m_client = m_clientWrapper->GetClient(); m_client->SetDMXCallback(ola::NewCallback(this, &olaThread::NewDmx)); - //m_client->SetDMXCallback(ola::NewCallback((libreMediaServerAudio *)this->parent(), libreMediaServerAudio::NewDmx)); m_clientWrapper->GetSelectServer()->RegisterRepeatingTimeout(4000, ola::NewCallback(this, &olaThread::CheckDataLoss)); m_client->SetCloseHandler(ola::NewSingleCallback(this, &olaThread::socketClosed)); m_dmxSettings = Settings::getInstance()->getDmxSettings(); @@ -69,30 +67,31 @@ void olaThread::NewDmx(const ola::client::DMXMetadata &data, bool volSent = false; bool entrySent = false; bool fileSent = false; + int aux; for (int j = 0; j < LAYER_CHANNELS; j++){ int value = buffer.Get((i.address) + j); if (m_dmx[i.layer][j] != value) { m_dmx[i.layer][j] = value; switch (j) { case DMX_FOLDER: - value *= 0x100; - value += buffer.Get(i.address + DMX_FILE); - qobject_cast(parent())->dmxInput(i.layer, j, value); - m_dmx[i.layer][DMX_FILE] = buffer.Get(i.address + DMX_FILE); + aux = buffer.Get(i.address + DMX_FILE); + qobject_cast(parent())->loadMedia(i.layer, value, aux); + m_dmx[i.layer][DMX_FILE] = aux; fileSent = true; break; case DMX_FILE: if (fileSent) break; - value += buffer.Get(i.address + DMX_FOLDER) * 0x100; - qobject_cast(parent())->dmxInput(i.layer, j, value); - m_dmx[i.layer][DMX_FOLDER] = buffer.Get(i.address + DMX_FOLDER); + aux = buffer.Get(i.address + DMX_FOLDER); + qobject_cast(parent())->loadMedia(i.layer, aux, value); + m_dmx[i.layer][DMX_FOLDER] = aux; fileSent = true; break; case VOLUME_FINE: - value = (buffer.Get(i.address + VOLUME_COARSE) * 0x100) + value; + aux = buffer.Get(i.address + VOLUME_COARSE); + value += (aux * 0x100); qobject_cast(parent())->dmxInput(i.layer, j, value); - m_dmx[i.layer][VOLUME_COARSE] = buffer.Get(i.address + VOLUME_COARSE); + m_dmx[i.layer][VOLUME_COARSE] = aux; volSent = true; break; case VOLUME_COARSE: @@ -103,6 +102,9 @@ void olaThread::NewDmx(const ola::client::DMXMetadata &data, m_dmx[i.layer][VOLUME_FINE] = buffer.Get(i.address + VOLUME_FINE); volSent = true; break; + case PLAYBACK: + qobject_cast(parent())->dmxInput(i.layer, j, value); + break; case ENTRY_POINT_FINE: value = (buffer.Get(i.address + ENTRY_POINT_COARSE) * 0x100) + value; qobject_cast(parent())->dmxInput(i.layer, j, value); diff --git a/src/settings.cpp b/src/settings.cpp index f664bb0..9e00914 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -15,6 +15,7 @@ Settings::Settings(QObject *parent) : QObject(parent) { m_layersNumber = 0; + m_ui = false; } // Read the dmx settings for dmx.xml At the moment we need: @@ -23,6 +24,7 @@ Settings::Settings(QObject *parent) : // - The first DMX channel of each source/layer // - The universe to bind in OLA // - Audio device id +// - Show the Ui or not void Settings::readFromFile(QString file) { QFile* xmlFile = new QFile(file); if (!xmlFile->open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -34,53 +36,56 @@ void Settings::readFromFile(QString file) { exit(1); } QXmlStreamReader* xmlReader = new QXmlStreamReader(xmlFile); - int counter = 0; - //Parse the XML until we reach end of it - while(!xmlReader->atEnd() && !xmlReader->hasError() && counter < MAX_LAYERS) { - // Read next element + while(!xmlReader->atEnd() && !xmlReader->hasError()) { QXmlStreamReader::TokenType token = xmlReader->readNext(); - //If token is just StartDocument - go to next if(token == QXmlStreamReader::StartDocument) { continue; } - //If token is StartElement - read it if(token == QXmlStreamReader::StartElement) { - if(xmlReader->name() == "dmxSettings") { - int version = xmlReader->attributes().value("fileVersion").toLocal8Bit().toInt(); - if(version == 1) { - m_layersNumber = xmlReader->attributes().value("layersNumber").toLocal8Bit().toInt(); - m_pathmedia = xmlReader->attributes().value("path").toLocal8Bit(); - continue; - } - } - if(xmlReader->name() == "audioDevice") { - m_audioDeviceId = xmlReader->attributes().value("id").toLocal8Bit().toInt(); + if(xmlReader->name() == "lmsAudio") { + m_ui = xmlReader->attributes().value("ui").toLocal8Bit().toInt(); + m_layersNumber = xmlReader->attributes().value("layersNumber").toLocal8Bit().toInt(); + m_pathmedia = xmlReader->attributes().value("path").toLocal8Bit(); continue; } - QString add = "layer"; - add.append(QString("%1").arg(counter)); - if((xmlReader->name() == add)) { + if(xmlReader->name() == "audioDevice") { + m_audioDeviceQty = xmlReader->attributes().value("devicesNumber").toLocal8Bit().toInt(); + for (uint i = 0; i < m_audioDeviceQty; i++) + { + m_audioDeviceId[i] = xmlReader->attributes().value(QString("id%1").arg(i)).toLocal8Bit().toInt(); + } + + } + if(xmlReader->name() == "layer") { dmxSetting temp; temp.address = xmlReader->attributes().value("dmx").toLocal8Bit().toInt() - 1; temp.universe = xmlReader->attributes().value("universe").toLocal8Bit().toInt(); - temp.layer = counter; + temp.layer = xmlReader->attributes().value("id").toLocal8Bit().toInt(); m_settings.append(temp); if (!m_universe.contains(temp.universe)) { m_universe.insert(temp.universe); } - counter++; } } } if(xmlReader->hasError()) { QMessageBox::critical(NULL,"File xml Parse Error ", xmlReader->errorString(), QMessageBox::Ok); qWarning("File xml Parse Error %s", xmlReader->errorString().toLatin1().constData()); - return; + // ToDo: manage this, open a dialog to load a new file. } xmlReader->clear(); xmlFile->close(); delete xmlReader; delete xmlFile; + this->printSettings(); +} + +void Settings::printSettings() { + qInfo() << "Settings read;\nShow Ui:" << m_ui << "Layers:" << m_layersNumber << "Path:" << m_pathmedia <<"Audio Device qty:" << m_audioDeviceQty; + for (uint i = 0; i < m_audioDeviceQty; i++) + qInfo() << "Audio device id:" << m_audioDeviceId[i]; + for (int i = 0; i < m_layersNumber; i++) + qInfo() << "Layer:" << m_settings[i].layer << "Address:" << m_settings[i].address << "Universe:" << m_settings[i].universe; } void Settings::readFile() { diff --git a/src/settings.h b/src/settings.h index 8cd55bb..f27da6a 100644 --- a/src/settings.h +++ b/src/settings.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "medialibrary.h" #include "audiowidget.h" @@ -15,25 +16,27 @@ class Settings : public QObject Q_OBJECT public: + Settings(QObject *parent = 0); static Settings *getInstance(); inline QSet getUniverses() { return m_universe; } inline QString getPathMedia() { return m_pathmedia; } inline QList getDmxSettings() { return m_settings; } inline int getLayersNumber() { return m_layersNumber; } + inline int getAudioDeviceId() { return m_audioDeviceId[0]; } + inline bool getShowUi() { return m_ui; } void readFile(); - inline int getAudioDeviceId() { return m_audioDeviceId; } + void readFromFile(QString file); + void printSettings(); private: static Settings *_instance; QList m_settings; QString m_pathmedia; - uint m_audioDeviceId; + uint m_audioDeviceId[MAX_AUDIODEVICES]; + uint m_audioDeviceQty; QSet m_universe; int m_layersNumber; - - explicit Settings(QObject *parent = 0); - void readFromFile(QString file); - + bool m_ui; }; #endif // SETTINGS_H diff --git a/src/slidergroup.cpp b/src/slidergroup.cpp index a488560..9ef9680 100644 --- a/src/slidergroup.cpp +++ b/src/slidergroup.cpp @@ -18,10 +18,11 @@ SliderGroup::SliderGroup(QString name, slider->setMinimumHeight(0); slider->setSingleStep(1); slider->setRange(min, max); + slider->setValue(0); slider->setMinimumWidth(50); slider->setToolTip(name); slider->setStyleSheet("QSlider {" - "border: 2px solid #685060;" + "border: 1px solid #5a4855;" "margin: 0px;" "height: 200px;" "width: 50px;}" @@ -32,17 +33,20 @@ SliderGroup::SliderGroup(QString name, valueBox->setButtonSymbols(QAbstractSpinBox::NoButtons); valueBox->setMinimumWidth(50); valueBox->setRange(min, max); + valueBox->setValue(0); valueBox->setDecimals(decimals); valueBox->setObjectName(name); valueBox->setToolTip(name); valueBox->setAlignment(Qt::AlignHCenter); valueBox->setContentsMargins(0, 0, 0, 0); connect(slider, SIGNAL(valueChanged(int)), this, SLOT(sliderValueChanged(int))); + //connect(slider, SIGNAL(mousePressEvent(QMouseEvent)), this, SLOT(mousePressEvent(QMouseEvent *))); layout->addWidget(slider); layout->addWidget(valueBox); - this->setStyleSheet("border: 2px solid #685060;" + this->setStyleSheet("border: 1px solid #5a4855;" "width: 50px;" "margin: 0px;" + "background-color: #383034;" ); layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); @@ -67,3 +71,11 @@ void SliderGroup::setValue(float value) slider->blockSignals(false); valueBox->blockSignals(false); } + +void SliderGroup::mousePressEvent(QMouseEvent* event) { + Q_UNUSED(event); + if (slider->isEnabled()) + slider->setDisabled(true); + else + slider->setDisabled(false); +} diff --git a/src/slidergroup.h b/src/slidergroup.h index f597a5b..5bfeeb8 100644 --- a/src/slidergroup.h +++ b/src/slidergroup.h @@ -27,6 +27,8 @@ public slots: private: QSlider *slider; QDoubleSpinBox *valueBox; + + void mousePressEvent(QMouseEvent* event); }; #endif