libreMediaServer no refresca directamente la ui, solo actualiza

valores en  audiowidget. la ui se actualiza con un timer en audiowidget.
Quitadas señales en todo, mejora rendimiento. fade en volumen basado en
la trama dmx (25 ms) para evitar clicks. refresca los valores de la capa
cuando carga un media. Ui Ok. nuevo formato de archivo de configuración
xml.
This commit is contained in:
snt 2024-05-07 20:23:09 +02:00
parent 5915d4898e
commit 7a9c0cd0ac
20 changed files with 271 additions and 160 deletions

View file

@ -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)

View file

@ -1,8 +1,8 @@
<?xml version='1.0' encoding='UTF-8'?>
<dmxSettings fileVersion="1" layersNumber="4" path="/home/snt/Documentos/lab/lms/media/sound">
<audioDevice id="3" />
<layer0 dmx="1" universe="1" />
<layer1 dmx="17" universe="1" />
<layer2 dmx="33" universe="1" />
<layer3 dmx="49" universe="1" />
</dmxSettings>
<lmsAudio ui="1" layersNumber="4" path="../media/sound" >
<audioDevice devicesNumber="2" id0="3" id1="4" />
<layer id="0" dmx="1" universe="1" />
<layer id="1" dmx="17" universe="1" />
<layer id="2" dmx="33" universe="1" />
<layer id="3" dmx="49" universe="1" />
</lmsAudio>

View file

@ -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).

View file

@ -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<Status>(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);

View file

@ -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);

View file

@ -1,5 +1,5 @@
#include "audiowidget.h"
#include <cmath>
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<AudioLayerWidget *>(item->widget())->fileLoaded(file);
dynamic_cast<AudioLayerWidget *>(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<AudioLayerWidget *>(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<AudioLayerWidget *>(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<AudioLayerWidget *>(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<AudioLayerWidget *>(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<AudioLayerWidget *>(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<AudioLayerWidget *>(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;
}
}
}

View file

@ -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);

View file

@ -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 <QString>
struct layerData {
QString media;
Status status;
bool updated;
float vol;
float cursor;
int pan;
int pitch;
float duration;
};
#endif // DEFINES_H

View file

@ -10,7 +10,6 @@
#define ENTRY_POINT_COARSE 5
#define ENTRY_POINT_FINE 4
#define PITCH 7
#define LAYER_CHANNELS 9
#endif // DMXPERSONALITY_H

View file

@ -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"
);

View file

@ -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,16 +56,9 @@ libreMediaServerAudio::~libreMediaServerAudio()
m_mae.stopEngine();
}
void libreMediaServerAudio::dmxInput(int layer, int channel, int value)
void libreMediaServerAudio::loadMedia(int layer, int folder, int file)
{
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);
QString mediaFile = m_mediaLibrary->requestNewFile(folder, file);
if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0)
return;
if (QFile::exists(mediaFile)){
@ -76,8 +68,17 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value)
if (m_ui)
m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer));
#endif
m_mae.printFormatInfo(layer);
}
} else if (channel == VOLUME_COARSE || channel == VOLUME_FINE) {
}
void libreMediaServerAudio::dmxInput(int layer, int channel, int value)
{
if (layer >= MAX_LAYERS || channel >= LAYER_CHANNELS)
return;
QString mediaFile = NULL;
int aux;
if (channel == VOLUME_COARSE || channel == VOLUME_FINE) {
float tmp = value / 65025.0f;
m_mae.volChanged(layer, tmp);
m_updateUi[layer][0] = tmp * 100.0f;
@ -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

View file

@ -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<dmxSetting> m_dmxSettings;
#ifndef NOGUI
QList<dmxSetting> 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
};

View file

@ -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);

View file

@ -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;
return m_currentLayerValues[layer].status;
}
if (this->getDuration(layer) > 0)
return Status::Paused;
return Status::Stopped;
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);
}

View file

@ -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

View file

@ -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<libreMediaServerAudio *>(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<libreMediaServerAudio *>(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<libreMediaServerAudio *>(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<libreMediaServerAudio *>(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<libreMediaServerAudio *>(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<libreMediaServerAudio *>(parent())->dmxInput(i.layer, j, value);
break;
case ENTRY_POINT_FINE:
value = (buffer.Get(i.address + ENTRY_POINT_COARSE) * 0x100) + value;
qobject_cast<libreMediaServerAudio *>(parent())->dmxInput(i.layer, j, value);

View file

@ -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) {
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;
}
}
if(xmlReader->name() == "audioDevice") {
m_audioDeviceId = xmlReader->attributes().value("id").toLocal8Bit().toInt();
continue;
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();
}
QString add = "layer";
add.append(QString("%1").arg(counter));
if((xmlReader->name() == add)) {
}
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() {

View file

@ -5,6 +5,7 @@
#include <QFile>
#include <QMessageBox>
#include <QSet>
#include <QDebug>
#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<int> getUniverses() { return m_universe; }
inline QString getPathMedia() { return m_pathmedia; }
inline QList<dmxSetting> 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<dmxSetting> m_settings;
QString m_pathmedia;
uint m_audioDeviceId;
uint m_audioDeviceId[MAX_AUDIODEVICES];
uint m_audioDeviceQty;
QSet<int> m_universe;
int m_layersNumber;
explicit Settings(QObject *parent = 0);
void readFromFile(QString file);
bool m_ui;
};
#endif // SETTINGS_H

View file

@ -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);
}

View file

@ -27,6 +27,8 @@ public slots:
private:
QSlider *slider;
QDoubleSpinBox *valueBox;
void mousePressEvent(QMouseEvent* event);
};
#endif