Antigona Release #1

Merged
snt merged 49 commits from filters into main 2024-05-26 12:42:53 +00:00
20 changed files with 271 additions and 160 deletions
Showing only changes of commit 7a9c0cd0ac - Show all commits

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

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

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) {
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() {

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