funcionando con dmx, controles Ui muestran info pero no actúan sobre el
sonido. Refactorizado todos lo métodos que interactúan con el sonido a miniaudioengine
This commit is contained in:
parent
7aea8f6cf1
commit
521f1fc6d7
12 changed files with 516 additions and 501 deletions
|
@ -4,6 +4,7 @@ QT += webkitwidgets widgets
|
|||
HEADERS += src/libremediaserver-audio.h \
|
||||
src/miniaudio.h \
|
||||
src/medialibrary.h \
|
||||
src/miniaudioengine.h \
|
||||
src/olathread.h \
|
||||
src/audiolayerwidget.h \
|
||||
src/dmxPersonality.h \
|
||||
|
@ -17,6 +18,7 @@ SOURCES += src/main.cpp \
|
|||
src/miniaudio.c \
|
||||
src/libremediaserver-audio.cpp \
|
||||
src/medialibrary.cpp \
|
||||
src/miniaudioengine.cpp \
|
||||
src/olathread.cpp \
|
||||
src/audiolayerwidget.cpp \
|
||||
src/audiowidget.cpp \
|
||||
|
|
|
@ -4,59 +4,50 @@
|
|||
AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name):
|
||||
QGroupBox(parent)
|
||||
, m_suspendResumeButton(0)
|
||||
, m_refreshGUI(new QTimer(this))
|
||||
, m_currentMedia("")
|
||||
, m_mediaLoaded(false)
|
||||
, m_volumeIndicator(new QSpinBox)
|
||||
, m_panIndicator(new QSpinBox)
|
||||
, m_pitchIndicator(new QSpinBox)
|
||||
{
|
||||
this->setTitle(name);
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
|
||||
QHBoxLayout *status = new QHBoxLayout;
|
||||
QGridLayout *status = new QGridLayout;
|
||||
m_statusLabel = new QLabel;
|
||||
m_statusLabel->setText(STATUS_LABEL);
|
||||
m_statusValue = new QLabel;
|
||||
status->addWidget(m_statusLabel);
|
||||
status->addWidget(m_statusValue);
|
||||
m_loopCheck = new QCheckBox();
|
||||
m_loopCheckLabel = new QLabel;
|
||||
m_loopCheckLabel->setText("Loop");
|
||||
connect(m_loopCheck, SIGNAL(stateChanged(int)), this, SLOT(loopChanged(int)));
|
||||
status->addWidget(m_loopCheck);
|
||||
status->addWidget(m_loopCheckLabel);
|
||||
layout->addLayout(status);
|
||||
|
||||
QHBoxLayout *folderLoaded = new QHBoxLayout;
|
||||
status->addWidget(m_statusLabel, 0, 0);
|
||||
status->addWidget(m_statusValue, 0, 2);
|
||||
m_folderLabel = new QLabel;
|
||||
m_folderLabel->setText(FOLDER_LABEL);
|
||||
m_folderValue = new QLabel;
|
||||
m_folderValue->setMaximumWidth(200);
|
||||
folderLoaded->addWidget(m_folderLabel);
|
||||
folderLoaded->addWidget(m_folderValue);
|
||||
layout->addLayout(folderLoaded);
|
||||
|
||||
QHBoxLayout *fileLoaded = new QHBoxLayout;
|
||||
status->addWidget(m_folderLabel, 1, 0);
|
||||
status->addWidget(m_folderValue, 1, 1);
|
||||
m_fileLabel = new QLabel;
|
||||
m_fileLabel->setText(FILE_LABEL);
|
||||
m_fileValue = new QLabel;
|
||||
m_fileValue->setMaximumWidth(200);
|
||||
fileLoaded->addWidget(m_fileLabel);
|
||||
fileLoaded->addWidget(m_fileValue);
|
||||
layout->addLayout(fileLoaded);
|
||||
status->addWidget(m_fileLabel, 1, 2);
|
||||
status->addWidget(m_fileValue, 1, 3);
|
||||
layout->addLayout(status);
|
||||
|
||||
QGridLayout *volumeBox = new QGridLayout;
|
||||
m_volumeLabel = new QLabel;
|
||||
m_volumeLabel->setText(tr(VOLUME_LABEL));
|
||||
m_volumeSlider = new QSlider(Qt::Horizontal);
|
||||
m_volumeSlider->setMinimum(-100);
|
||||
m_volumeSlider->setMinimum(0);
|
||||
m_volumeSlider->setMaximum(100);
|
||||
m_volumeSlider->setSingleStep(1);
|
||||
m_volumeIndicator = new QLabel;
|
||||
m_volumeIndicator->setRange(0, 100);
|
||||
m_volumeIndicator->setValue(0);
|
||||
m_volumeIndicator->setMaximumWidth(40);
|
||||
m_volumeIndicator->setButtonSymbols(QAbstractSpinBox::NoButtons);
|
||||
volumeBox->addWidget(m_volumeLabel, 0, 0);
|
||||
volumeBox->addWidget(m_volumeSlider, 0, 1);
|
||||
volumeBox->addWidget(m_volumeIndicator, 0, 2);
|
||||
connect(m_volumeSlider, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int)));
|
||||
connect(m_volumeSlider, &QSlider::valueChanged, this, [=] () {
|
||||
m_volumeIndicator->setText(QString::number(m_volumeSlider->value()));
|
||||
m_volumeIndicator->setValue(m_volumeSlider->value());
|
||||
});
|
||||
m_panLabel = new QLabel;
|
||||
m_panLabel->setText("Pan");
|
||||
|
@ -64,18 +55,34 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name):
|
|||
m_panSlider->setMinimum(0);
|
||||
m_panSlider->setMaximum(255);
|
||||
m_panSlider->setSingleStep(1);
|
||||
m_panIndicator->setRange(0, 255);
|
||||
m_panIndicator->setValue(128);
|
||||
m_panIndicator->setMaximumWidth(40);
|
||||
m_panIndicator->setButtonSymbols(QAbstractSpinBox::NoButtons);
|
||||
connect(m_panSlider, &QSlider::valueChanged, this, [=] () {
|
||||
m_panIndicator->setValue(m_panSlider->value());
|
||||
});
|
||||
connect(m_panSlider, SIGNAL(valueChanged(int)), this, SLOT(panChanged(int)));
|
||||
volumeBox->addWidget(m_panLabel, 1, 0);
|
||||
volumeBox->addWidget(m_panSlider, 1, 1);
|
||||
volumeBox->addWidget(m_panIndicator, 1, 2);
|
||||
m_pitchLabel = new QLabel;
|
||||
m_pitchLabel->setText("Pitch");
|
||||
m_pitchSlider = new QSlider(Qt::Horizontal);
|
||||
m_pitchSlider->setMinimum(0);
|
||||
m_pitchSlider->setMaximum(255);
|
||||
m_pitchSlider->setSingleStep(1);
|
||||
m_pitchIndicator->setRange(0, 255);
|
||||
m_pitchIndicator->setValue(128);
|
||||
m_pitchIndicator->setMaximumWidth(40);
|
||||
m_pitchIndicator->setButtonSymbols(QAbstractSpinBox::NoButtons);
|
||||
connect(m_pitchSlider, &QSlider::valueChanged, this, [=] () {
|
||||
m_pitchIndicator->setValue(m_pitchSlider->value());
|
||||
});
|
||||
connect(m_pitchSlider, SIGNAL(valueChanged(int)), this, SLOT(pitchChanged(int)));
|
||||
volumeBox->addWidget(m_pitchLabel, 2, 0);
|
||||
volumeBox->addWidget(m_pitchSlider, 2, 1);
|
||||
volumeBox->addWidget(m_pitchIndicator, 2, 2);
|
||||
layout->addLayout(volumeBox);
|
||||
|
||||
QHBoxLayout *progressTime = new QHBoxLayout;
|
||||
|
@ -102,15 +109,12 @@ AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name):
|
|||
|
||||
m_progressSlider = new QSlider(Qt::Horizontal);
|
||||
layout->addWidget(m_progressSlider);
|
||||
|
||||
m_suspendResumeButton = new QPushButton(this);
|
||||
m_suspendResumeButton->setText(tr(SUSPEND_LABEL));
|
||||
connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume()));
|
||||
layout->addWidget(m_suspendResumeButton);
|
||||
|
||||
this->setLayout(layout);
|
||||
connect(m_refreshGUI, SIGNAL(timeout()), this, SLOT(refreshGUI()));
|
||||
m_refreshGUI->start(100);
|
||||
}
|
||||
|
||||
AudioLayerWidget::~AudioLayerWidget()
|
||||
|
@ -118,123 +122,69 @@ AudioLayerWidget::~AudioLayerWidget()
|
|||
|
||||
}
|
||||
|
||||
// From UI.
|
||||
void AudioLayerWidget::volumeChanged(int value)
|
||||
{
|
||||
float result;
|
||||
|
||||
if (m_mediaLoaded == false)
|
||||
return;
|
||||
result = ma_volume_linear_to_db(value);
|
||||
ma_sound_group_set_volume(¤tSound, result);
|
||||
(void)value;
|
||||
// ToDo: call the audio engine
|
||||
}
|
||||
|
||||
void AudioLayerWidget::panChanged(int value)
|
||||
{
|
||||
float result;
|
||||
if (m_mediaLoaded == false)
|
||||
return;
|
||||
result = (value / 128.0) - 128;
|
||||
ma_sound_group_set_pan(¤tSound, result);
|
||||
(void)value;
|
||||
// ToDo: call the audio engine
|
||||
}
|
||||
|
||||
void AudioLayerWidget::pitchChanged(int value)
|
||||
{
|
||||
float result;
|
||||
if (m_mediaLoaded == false)
|
||||
return;
|
||||
result = (value / 128.0) - 128;
|
||||
ma_sound_group_set_pitch(¤tSound, result);
|
||||
(void)value;
|
||||
// ToDo: call the audio engine
|
||||
}
|
||||
|
||||
void AudioLayerWidget::loopChanged(int value)
|
||||
{
|
||||
if (m_mediaLoaded == false)
|
||||
return;
|
||||
ma_sound_set_looping(¤tSound, value);
|
||||
(void)value;
|
||||
// ToDo: call the audio engine
|
||||
}
|
||||
|
||||
void AudioLayerWidget::toggleSuspendResume()
|
||||
{
|
||||
switch (m_status) {
|
||||
case Status::PlayingLoop:
|
||||
case Status::PlayingOnce:
|
||||
this->setPlaybackStatus(Status::Paused);
|
||||
case Status::Paused:
|
||||
case Status::Stopped:
|
||||
this->setPlaybackStatus(Status::PlayingOnce);
|
||||
}
|
||||
// ToDo: call the audio engine
|
||||
}
|
||||
|
||||
// from DMX signals
|
||||
void AudioLayerWidget::setVol(qreal vol)
|
||||
{
|
||||
this->volumeChanged(vol);
|
||||
m_volumeSlider->blockSignals(true);
|
||||
m_volumeSlider->setValue(vol);
|
||||
m_volumeIndicator->setText(QString::number(vol));
|
||||
m_volumeIndicator->setValue(vol);
|
||||
m_volumeSlider->blockSignals(false);
|
||||
}
|
||||
|
||||
void AudioLayerWidget::setPan(qreal pan)
|
||||
{
|
||||
this->panChanged(pan);
|
||||
m_panSlider->blockSignals(true);
|
||||
m_panSlider->setValue(pan);
|
||||
m_panIndicator->setValue(pan);
|
||||
m_panSlider->blockSignals(false);
|
||||
}
|
||||
|
||||
void AudioLayerWidget::setPitch(qreal pitch)
|
||||
{
|
||||
this->pitchChanged(pitch);
|
||||
m_pitchSlider->blockSignals(true);
|
||||
m_pitchSlider->setValue(pitch);
|
||||
m_pitchIndicator->setValue(pitch);
|
||||
m_pitchSlider->blockSignals(false);
|
||||
}
|
||||
|
||||
void AudioLayerWidget::loadMedia(QString file)
|
||||
{
|
||||
ma_result result;
|
||||
ma_format *format = 0;
|
||||
ma_uint32 *channels = 0;
|
||||
ma_uint32 *sampleRate = 0;
|
||||
|
||||
|
||||
if (m_currentMedia.compare(file) == 0 ) {
|
||||
return;
|
||||
}
|
||||
if (!QFile::exists(file)) {
|
||||
qWarning("Can not access to file %s", file.toLatin1().constData());
|
||||
return;
|
||||
}
|
||||
ma_engine engine = AudioWidget::getInstance()->getEngine();
|
||||
if (currentSound.ownsDataSource == true)
|
||||
{
|
||||
ma_sound_uninit(¤tSound);
|
||||
}
|
||||
result = ma_sound_init_from_file(&engine, file.toLatin1(), MA_SOUND_FLAG_NO_SPATIALIZATION | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM, NULL, NULL, ¤tSound);
|
||||
if (result != MA_SUCCESS) {
|
||||
qWarning("WARNING: Failed to load sound %s", file.toLatin1().constData());
|
||||
return;
|
||||
}
|
||||
m_currentMedia = file;
|
||||
float pLength = this->getDuration();
|
||||
result = ma_sound_get_data_format(¤tSound, format, channels, sampleRate, NULL, 0);
|
||||
if (result != MA_SUCCESS) {
|
||||
qWarning("WARNING: Failed to get data format %s", file.toLatin1().constData());
|
||||
return;
|
||||
}
|
||||
m_mediaLoaded = true;
|
||||
durationChanged(pLength * 1000);
|
||||
fileLoaded(file);
|
||||
// Display music informations
|
||||
std::cout << "File loaded: " << file.toLatin1().constData() << " : " << std::endl;
|
||||
std::cout << " " << pLength << " seconds";
|
||||
std::cout << " -- " << sampleRate << " samples/sec";
|
||||
std::cout << " -- " << format << " format";
|
||||
std::cout << " -- " << channels << " channels" << std::endl;
|
||||
}
|
||||
|
||||
float AudioLayerWidget::getDuration()
|
||||
{
|
||||
float pLength;
|
||||
|
||||
if (m_mediaLoaded == false)
|
||||
return 0;
|
||||
ma_result result = ma_sound_get_length_in_seconds(¤tSound, &pLength);
|
||||
if (result != MA_SUCCESS) {
|
||||
qWarning("WARNING: Failed to get total duration %s", m_currentMedia.toLatin1().constData());
|
||||
return 0;
|
||||
}
|
||||
return pLength;
|
||||
}
|
||||
|
||||
void AudioLayerWidget::fileLoaded(QString file)
|
||||
{
|
||||
QStringList list = file.split("/");
|
||||
|
@ -245,74 +195,40 @@ void AudioLayerWidget::fileLoaded(QString file)
|
|||
}
|
||||
}
|
||||
|
||||
void AudioLayerWidget::setPlaybackStatus(Status status)
|
||||
{
|
||||
m_status = status;
|
||||
if (status == Status::Stopped)
|
||||
m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(0));
|
||||
QString tmp;
|
||||
switch (status) {
|
||||
case Status::Paused:
|
||||
tmp.append("Paused");
|
||||
break;
|
||||
case Status::PlayingLoop:
|
||||
tmp.append("Playing Loop");
|
||||
break;
|
||||
case Status::PlayingOnce:
|
||||
tmp.append("Playing one");
|
||||
break;
|
||||
case Status::Stopped:
|
||||
tmp.append("Stopped");
|
||||
break;
|
||||
}
|
||||
m_statusValue->setText(tmp);
|
||||
m_suspendResumeButton->setText(tmp);
|
||||
}
|
||||
|
||||
void AudioLayerWidget::durationChanged(qint64 dur)
|
||||
{
|
||||
dur *= 1000;
|
||||
m_progressSlider->setMaximum(dur);
|
||||
m_totalTimeValue->setTime(QTime::fromMSecsSinceStartOfDay(dur));
|
||||
}
|
||||
|
||||
void AudioLayerWidget::play(bool loop)
|
||||
void AudioLayerWidget::refreshUi(float progress)
|
||||
{
|
||||
if (m_mediaLoaded == false)
|
||||
return;
|
||||
ma_sound_set_looping(¤tSound, loop);
|
||||
ma_sound_start(¤tSound);
|
||||
m_loopCheck->blockSignals(true);
|
||||
m_loopCheck->setChecked(loop);
|
||||
m_loopCheck->blockSignals(false);
|
||||
}
|
||||
|
||||
void AudioLayerWidget::pause()
|
||||
{
|
||||
if (m_mediaLoaded == false)
|
||||
return;
|
||||
ma_sound_stop(¤tSound);
|
||||
}
|
||||
|
||||
void AudioLayerWidget::stop()
|
||||
{
|
||||
if (m_mediaLoaded == false)
|
||||
return;
|
||||
ma_sound_stop(¤tSound);
|
||||
ma_sound_seek_to_pcm_frame(¤tSound, 0);
|
||||
m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(0));
|
||||
m_statusValue->setText(STOP_LABEL);
|
||||
m_suspendResumeButton->setText(tr(STOP_LABEL));
|
||||
m_progressSlider->setValue(0);
|
||||
}
|
||||
|
||||
void AudioLayerWidget::refreshGUI() {
|
||||
float progress;
|
||||
|
||||
if (m_mediaLoaded == false)
|
||||
return;
|
||||
if (currentSound.ownsDataSource == 0)
|
||||
return;
|
||||
switch (ma_sound_is_playing(¤tSound)) {
|
||||
case true:
|
||||
ma_sound_get_cursor_in_seconds(¤tSound, &progress);
|
||||
progress *= 1000;
|
||||
m_progressSlider->setValue(progress);
|
||||
m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(progress));
|
||||
m_statusValue->setText(PLAY_LABEL);
|
||||
m_suspendResumeButton->setText(tr(SUSPEND_LABEL));
|
||||
break;
|
||||
case false:
|
||||
m_statusValue->setText(PAUSE_LABEL);
|
||||
m_suspendResumeButton->setText(tr(RESUME_LABEL));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioLayerWidget::toggleSuspendResume()
|
||||
{
|
||||
if (m_mediaLoaded == false)
|
||||
return;
|
||||
if (ma_sound_is_playing(¤tSound)) {
|
||||
this->pause();
|
||||
} else {
|
||||
if (ma_sound_at_end(¤tSound))
|
||||
ma_sound_seek_to_pcm_frame(¤tSound, 0);
|
||||
ma_sound_start(¤tSound);
|
||||
}
|
||||
progress *= 1000;
|
||||
m_progressSlider->setValue(progress);
|
||||
m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(progress));
|
||||
}
|
||||
|
|
|
@ -4,9 +4,7 @@
|
|||
#include <iostream>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QTime>
|
||||
#include <QByteArray>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
|
@ -16,117 +14,63 @@
|
|||
#include <QTimeEdit>
|
||||
#include <QGroupBox>
|
||||
#include <QCheckBox>
|
||||
#include <QSpinBox>
|
||||
|
||||
#include "defines.h"
|
||||
#include "audiowidget.h"
|
||||
#include "miniaudio.h"
|
||||
|
||||
class AudioLayerWidget : public QGroupBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
explicit AudioLayerWidget(QWidget *parent = 0, QString name = "Layer");
|
||||
~AudioLayerWidget();
|
||||
|
||||
/**
|
||||
* @brief load a new media file
|
||||
* @param file name with full path
|
||||
*/
|
||||
void loadMedia(QString file);
|
||||
void play(bool loop);
|
||||
void stop();
|
||||
void pause();
|
||||
|
||||
/**
|
||||
* @brief set the Volume
|
||||
* @param vol volume range 0 -100
|
||||
*/
|
||||
void setVol(qreal vol);
|
||||
void resume();
|
||||
void setPan(qreal pan);
|
||||
void setPitch(qreal pitch);
|
||||
void setLoop(bool on);
|
||||
//void setEntryPoint(qreal entry);
|
||||
//void setEndPoint(qreal end);
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* @brief connected with the button
|
||||
*/
|
||||
void toggleSuspendResume();
|
||||
|
||||
/**
|
||||
* @brief Connected with the slider
|
||||
* @param volume 0 -100 range
|
||||
*/
|
||||
void volumeChanged(int vol);
|
||||
void panChanged(int vol);
|
||||
void pitchChanged(int vol);
|
||||
void loopChanged(int vol);
|
||||
void setPlaybackStatus(Status status);
|
||||
inline Status getPlaybackStatus() { return m_status; }
|
||||
|
||||
private:
|
||||
|
||||
QPushButton *m_suspendResumeButton;
|
||||
|
||||
QLabel *m_statusLabel;
|
||||
QLabel * m_statusValue;
|
||||
|
||||
QLabel *m_volumeLabel;
|
||||
QSlider *m_volumeSlider;
|
||||
QLabel *m_volumeIndicator;
|
||||
|
||||
QLabel *m_panLabel;
|
||||
QSlider *m_panSlider;
|
||||
|
||||
QLabel *m_pitchLabel;
|
||||
QSlider *m_pitchSlider;
|
||||
|
||||
QLabel *m_loopCheckLabel;
|
||||
QCheckBox *m_loopCheck;
|
||||
|
||||
QLabel * m_progressLabel;
|
||||
QSlider *m_progressSlider;
|
||||
|
||||
QLabel *m_progressTimeLabel;
|
||||
QTimeEdit *m_progressTime;
|
||||
|
||||
QLabel *m_totalTimeLabel;
|
||||
QTimeEdit *m_totalTimeValue;
|
||||
|
||||
QLabel *m_fileLabel;
|
||||
QLabel *m_fileValue;
|
||||
|
||||
QLabel * m_folderLabel;
|
||||
QLabel * m_folderValue;
|
||||
|
||||
QTimer *m_refreshGUI;
|
||||
QString m_currentMedia;
|
||||
ma_sound currentSound;
|
||||
ma_bool8 m_mediaLoaded;
|
||||
QLabel *m_volumeLabel;
|
||||
QSlider *m_volumeSlider;
|
||||
QSpinBox *m_volumeIndicator;
|
||||
QLabel *m_panLabel;
|
||||
QSlider *m_panSlider;
|
||||
QSpinBox *m_panIndicator;
|
||||
QLabel *m_pitchLabel;
|
||||
QSlider *m_pitchSlider;
|
||||
QSpinBox *m_pitchIndicator;
|
||||
|
||||
float getDuration();
|
||||
QLabel * m_progressLabel;
|
||||
QSlider *m_progressSlider;
|
||||
QLabel *m_progressTimeLabel;
|
||||
QTimeEdit *m_progressTime;
|
||||
QLabel *m_totalTimeLabel;
|
||||
QTimeEdit *m_totalTimeValue;
|
||||
|
||||
private slots:
|
||||
Status m_status;
|
||||
|
||||
/**
|
||||
* @brief Update the GUI elements with the name of the new file loaded
|
||||
* @param file
|
||||
*/
|
||||
public slots:
|
||||
void toggleSuspendResume();
|
||||
void volumeChanged(int vol);
|
||||
void panChanged(int vol);
|
||||
void pitchChanged(int vol);
|
||||
void loopChanged(int vol);
|
||||
void fileLoaded(QString file);
|
||||
|
||||
/**
|
||||
* @brief Update the GUI elements with the duration of the new file loaded
|
||||
* @param dur The duration of the track in miliseconds
|
||||
*/
|
||||
void durationChanged(qint64 dur);
|
||||
|
||||
/**
|
||||
* @brief Update the variable elements in GUI
|
||||
*/
|
||||
void refreshGUI();
|
||||
void refreshUi(float progress);
|
||||
};
|
||||
|
||||
#endif // AUDIOLAYERWIDGET_H
|
||||
|
|
|
@ -8,14 +8,8 @@
|
|||
#include <QGroupBox>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
//#include "ui_audiomasterwidget.h"
|
||||
|
||||
/*
|
||||
namespace Ui {
|
||||
class AudioMasterWidget;
|
||||
}*/
|
||||
|
||||
class AudioMasterWidget : public QGroupBox //, public Ui::AudioMasterWidget
|
||||
class AudioMasterWidget : public QGroupBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -28,11 +22,6 @@ public slots:
|
|||
void updateWatchDMX();
|
||||
|
||||
private:
|
||||
//QLabel *m_file;
|
||||
//QLabel *m_folder;
|
||||
//QSlider *m_vol;
|
||||
//QCheckBox *m_mute;
|
||||
//QLabel *m_status;
|
||||
QCheckBox *m_receiveDMX;
|
||||
QTimer *m_watchDMX;
|
||||
|
||||
|
|
|
@ -1,172 +1,91 @@
|
|||
#include "audiowidget.h"
|
||||
#include "miniaudio.c"
|
||||
|
||||
AudioWidget *AudioWidget::_instance = 0;
|
||||
|
||||
AudioWidget *AudioWidget::getInstance() {
|
||||
|
||||
if (_instance == 0) {
|
||||
_instance = new AudioWidget();
|
||||
Q_CHECK_PTR(_instance);
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
AudioWidget::AudioWidget() :
|
||||
engineCount(0)
|
||||
m_layout(new QHBoxLayout())
|
||||
, m_refreshUi(new QTimer(this))
|
||||
{
|
||||
this->startEngine();
|
||||
layout = new QHBoxLayout();
|
||||
|
||||
for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) {
|
||||
layout->insertWidget(i, new AudioLayerWidget(this, tr("Layer %1").arg(i + 1)));
|
||||
m_layout->insertWidget(i, new AudioLayerWidget(this, tr("Layer %1").arg(i + 1)));
|
||||
}
|
||||
setLayout(layout);
|
||||
setLayout(m_layout);
|
||||
connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi()));
|
||||
m_refreshUi->start(UI_REFRESH_TIME);
|
||||
}
|
||||
|
||||
void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
|
||||
bool AudioWidget::startEngine(int id)
|
||||
{
|
||||
(void)pInput;
|
||||
//Do master audio processing before sending to device.
|
||||
ma_engine_read_pcm_frames((ma_engine*)pDevice->pUserData, pOutput, frameCount, NULL);
|
||||
return (m_mae.startEngine(id));
|
||||
}
|
||||
|
||||
void AudioWidget::startEngine(int n)
|
||||
bool AudioWidget::startEngine()
|
||||
{
|
||||
this->startContext();
|
||||
this->startDevice(n);
|
||||
}
|
||||
|
||||
void AudioWidget::startDevice(int id)
|
||||
{
|
||||
ma_result result;
|
||||
ma_device_config deviceConfig;
|
||||
ma_engine_config engineConfig;
|
||||
|
||||
deviceConfig = ma_device_config_init(ma_device_type_playback);
|
||||
deviceConfig.playback.pDeviceID = &pPlaybackDeviceInfos[id].id;
|
||||
deviceConfig.playback.format = resourceManager.config.decodedFormat;
|
||||
deviceConfig.playback.channels = 0;
|
||||
deviceConfig.sampleRate = resourceManager.config.decodedSampleRate;
|
||||
deviceConfig.dataCallback = data_callback;
|
||||
deviceConfig.pUserData = &engines[engineCount];
|
||||
result = ma_device_init(&context, &deviceConfig, &devices[engineCount]);
|
||||
if (result != MA_SUCCESS) {
|
||||
qCritical("Failed to initialize audio device %s.", pPlaybackDeviceInfos[id].name);
|
||||
return;
|
||||
}
|
||||
engineConfig = ma_engine_config_init();
|
||||
engineConfig.pDevice = &devices[engineCount];
|
||||
engineConfig.pResourceManager = &resourceManager;
|
||||
engineConfig.noAutoStart = MA_TRUE;
|
||||
result = ma_engine_init(NULL, &engines[engineCount]);
|
||||
if (result != MA_SUCCESS) {
|
||||
qCritical("Failed to initialize audio engine.");
|
||||
return;
|
||||
}
|
||||
result = ma_engine_start(&engines[engineCount]);
|
||||
if (result != MA_SUCCESS) {
|
||||
qCritical("Failed to start audio engine %d.", engineCount);
|
||||
}
|
||||
//engineCount +=1;
|
||||
iChosenDevice = id;
|
||||
qInfo("Initialized audio device %d: %s", id, pPlaybackDeviceInfos[id].name);
|
||||
}
|
||||
|
||||
void AudioWidget::startContext()
|
||||
{
|
||||
ma_result result;
|
||||
|
||||
resourceManagerConfig = ma_resource_manager_config_init();
|
||||
resourceManagerConfig.decodedFormat = ma_format_f32; /* ma_format_f32 should almost always be used as that's what the engine (and most everything else) uses for mixing. */
|
||||
resourceManagerConfig.decodedChannels = 0;
|
||||
resourceManagerConfig.decodedSampleRate = 0;
|
||||
resourceManagerConfig.jobThreadCount = 0;
|
||||
result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager);
|
||||
if (result != MA_SUCCESS) {
|
||||
qCritical("Failed to initialize audio resource manager.");
|
||||
return;
|
||||
}
|
||||
result = ma_context_init(NULL, 0, NULL, &context);
|
||||
if (result != MA_SUCCESS) {
|
||||
qCritical("Failed to initialize audio context.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void AudioWidget::startEngine()
|
||||
{
|
||||
this->startContext();
|
||||
this->getAllAudioDevices();
|
||||
iChosenDevice = Settings::getInstance()->getAudioDeviceId();
|
||||
this->startDevice(iChosenDevice);
|
||||
}
|
||||
|
||||
ma_engine AudioWidget::getEngine()
|
||||
{
|
||||
return(engines[engineCount]);
|
||||
return (m_mae.startEngine(Settings::getInstance()->getAudioDeviceId()));
|
||||
}
|
||||
|
||||
void AudioWidget::stopEngine()
|
||||
{
|
||||
ma_engine_uninit(&engines[engineCount]);
|
||||
ma_device_uninit(&devices[engineCount]);
|
||||
ma_context_uninit(&context);
|
||||
ma_resource_manager_uninit(&resourceManager);
|
||||
m_mae.stopEngine();
|
||||
}
|
||||
|
||||
void AudioWidget::mediaLoaded(int layer, QString media)
|
||||
void AudioWidget::mediaLoaded(int layer, QString file)
|
||||
{
|
||||
QLayoutItem * const item = layout->itemAt(layer);
|
||||
dynamic_cast<AudioLayerWidget *>(item->widget())->loadMedia(media);
|
||||
ma_result result;
|
||||
|
||||
if (m_currentMedia[layer].compare(file) == 0 ) {
|
||||
return;
|
||||
}
|
||||
if (!QFile::exists(file)) {
|
||||
qWarning("Can not access to file %s", file.toLatin1().constData());
|
||||
return;
|
||||
}
|
||||
result = m_mae.loadMedia(layer, file.toLatin1().data());
|
||||
if (result != MA_SUCCESS) {
|
||||
qWarning("can not open file %s", file.toLatin1().constData());
|
||||
return;
|
||||
}
|
||||
m_currentMedia[layer] = file;
|
||||
float pLength = m_mae.getDuration(layer);
|
||||
qInfo("File loaded: %s - Duration: %f secs", file.toLatin1().constData(), pLength);
|
||||
m_mae.printFormatInfo(layer);
|
||||
QLayoutItem * const item = m_layout->itemAt(layer);
|
||||
dynamic_cast<AudioLayerWidget *>(item->widget())->fileLoaded(file);
|
||||
dynamic_cast<AudioLayerWidget *>(item->widget())->durationChanged(pLength);
|
||||
}
|
||||
|
||||
void AudioWidget::volChanged(int layer, qreal vol) {
|
||||
QLayoutItem * const item = layout->itemAt(layer);
|
||||
m_mae.volChanged(layer, vol);
|
||||
QLayoutItem * const item = m_layout->itemAt(layer);
|
||||
dynamic_cast<AudioLayerWidget *>(item->widget())->setVol(vol);
|
||||
}
|
||||
|
||||
void AudioWidget::panChanged(int layer, qreal vol) {
|
||||
QLayoutItem * const item = layout->itemAt(layer);
|
||||
dynamic_cast<AudioLayerWidget *>(item->widget())->setPan(vol);
|
||||
void AudioWidget::panChanged(int layer, qreal pan) {
|
||||
m_mae.panChanged(layer, pan);
|
||||
QLayoutItem * const item = m_layout->itemAt(layer);
|
||||
dynamic_cast<AudioLayerWidget *>(item->widget())->setPan(pan);
|
||||
}
|
||||
|
||||
void AudioWidget::pitchChanged(int layer, qreal vol) {
|
||||
QLayoutItem * const item = layout->itemAt(layer);
|
||||
dynamic_cast<AudioLayerWidget *>(item->widget())->setPitch(vol);
|
||||
void AudioWidget::pitchChanged(int layer, qreal pitch) {
|
||||
m_mae.pitchChanged(layer, pitch);
|
||||
QLayoutItem * const item = m_layout->itemAt(layer);
|
||||
dynamic_cast<AudioLayerWidget *>(item->widget())->setPitch(pitch);
|
||||
}
|
||||
|
||||
void AudioWidget::playbackChanged(int layer, Status status)
|
||||
{
|
||||
QLayoutItem * const item = layout->itemAt(layer);
|
||||
switch (status) {
|
||||
case PlayingOnce:
|
||||
dynamic_cast<AudioLayerWidget *>(item->widget())->play(false);
|
||||
break;
|
||||
case Stopped:
|
||||
dynamic_cast<AudioLayerWidget *>(item->widget())->stop();
|
||||
break;
|
||||
case Paused:
|
||||
dynamic_cast<AudioLayerWidget *>(item->widget())->pause();
|
||||
break;
|
||||
case PlayingLoop:
|
||||
dynamic_cast<AudioLayerWidget *>(item->widget())->play(true);
|
||||
break;
|
||||
}
|
||||
m_mae.playbackChanged(layer, status);
|
||||
QLayoutItem * const item = m_layout->itemAt(layer);
|
||||
dynamic_cast<AudioLayerWidget *>(item->widget())->setPlaybackStatus(status);
|
||||
}
|
||||
|
||||
// enum all audio devices in system
|
||||
void AudioWidget::getAllAudioDevices()
|
||||
{
|
||||
ma_result result;
|
||||
|
||||
result = ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, NULL, NULL);
|
||||
if (result != MA_SUCCESS) {
|
||||
qCritical("Failed to enumerate playback devices.");
|
||||
ma_context_uninit(&context);
|
||||
return;
|
||||
void AudioWidget::refreshUi() {
|
||||
for (int i= 0; i < Settings::getInstance()->getLayersNumber(); i++ ) {
|
||||
QLayoutItem * const item = m_layout->itemAt(i);
|
||||
AudioLayerWidget *aw = dynamic_cast<AudioLayerWidget *>(item->widget());
|
||||
Status s = aw->getPlaybackStatus();
|
||||
if (s == Status::PlayingOnce || s == Status::PlayingLoop) {
|
||||
aw->refreshUi(m_mae.getCursor(i));
|
||||
}
|
||||
}
|
||||
for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < playbackDeviceCount; iAvailableDevice += 1) {
|
||||
qInfo("%d: : %s", iAvailableDevice, pPlaybackDeviceInfos[iAvailableDevice].name);
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "audiomasterwidget.h"
|
||||
#include "audiolayerwidget.h"
|
||||
#include "settings.h"
|
||||
#include "miniaudio.h"
|
||||
#include "miniaudioengine.h"
|
||||
#include "defines.h"
|
||||
|
||||
|
||||
|
@ -20,43 +20,26 @@ class AudioWidget : public QWidget
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
static AudioWidget *getInstance();
|
||||
ma_engine getEngine();
|
||||
AudioWidget();
|
||||
bool startEngine();
|
||||
bool startEngine(int id);
|
||||
void stopEngine();
|
||||
void startEngine(int id);
|
||||
ma_device_info* pPlaybackDeviceInfos;
|
||||
ma_uint32 playbackDeviceCount;
|
||||
ma_uint32 iChosenDevice;
|
||||
|
||||
protected:
|
||||
|
||||
void mediaLoaded(int layer, QString media );
|
||||
void volChanged(int layer, qreal vol);
|
||||
void panChanged(int layer, qreal pan);
|
||||
void pitchChanged(int layer, qreal pitch);
|
||||
void playbackChanged(int layer, Status status);
|
||||
void startEngine();
|
||||
|
||||
private:
|
||||
MiniAudioEngine m_mae;
|
||||
QString m_currentMedia[MAX_LAYERS];
|
||||
QHBoxLayout *m_layout;
|
||||
QTimer *m_refreshUi;
|
||||
|
||||
static AudioWidget *_instance;
|
||||
AudioWidget();
|
||||
QHBoxLayout *layout;
|
||||
ma_engine engines[MAX_DEVICES];
|
||||
ma_uint32 engineCount;
|
||||
ma_device devices[MAX_DEVICES];
|
||||
ma_context context;
|
||||
ma_resource_manager_config resourceManagerConfig;
|
||||
ma_resource_manager resourceManager;
|
||||
void getAllAudioDevices();
|
||||
void startDevice(int id);
|
||||
void startContext();
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
private slots:
|
||||
void refreshUi();
|
||||
};
|
||||
|
||||
#endif // AUDIOWIDGET_H
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
#ifndef DEFINES_H
|
||||
#define DEFINES_H
|
||||
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QtGlobal>
|
||||
|
||||
#define VERSION "LibreMediaServer-Audio 0.1.4"
|
||||
#define COPYRIGHT "(C) 2014-2024 Santi Norena lms@criptomart.net"
|
||||
#define LICENSE "GPL 3 License. See LICENSE.txt and credits.txt for details"
|
||||
|
||||
#define LAYERS_NUMBER 4 // esto tiene que desaparecer
|
||||
|
||||
#define DEFAULT_FILE "lms-audio.xlm"
|
||||
|
||||
#define SUSPEND_LABEL "Pause playback"
|
||||
#define RESUME_LABEL "Resume playback"
|
||||
|
||||
#define PLAY_LABEL "Playing"
|
||||
#define STOP_LABEL "Stopped"
|
||||
#define SUSPEND_LABEL "Pause"
|
||||
#define RESUME_LABEL "Resume"
|
||||
#define PLAY_LABEL "Play"
|
||||
#define STOP_LABEL "Stop"
|
||||
#define PAUSE_LABEL "Pause"
|
||||
#define IDDLE_LABEL "Iddle playback"
|
||||
|
||||
#define VOLUME_LABEL "Volume"
|
||||
#define PROGRESS_LABEL "Progress"
|
||||
#define PROGRESS_TIME_LABEL "Current"
|
||||
#define REMAINING_TIME "Remaining Time: "
|
||||
#define REMAINING_TIME "Remaining"
|
||||
#define TOTAL_TIME_LABEL "Total"
|
||||
#define FILE_LABEL "File:"
|
||||
#define FOLDER_LABEL "Folder:"
|
||||
#define FILE_LABEL "File: "
|
||||
#define FOLDER_LABEL "Folder: "
|
||||
#define STATUS_LABEL "Status: "
|
||||
|
||||
#define NOTIFY_INTERVAL 150
|
||||
#define PULL_TIMER_INTERVAL 10
|
||||
#define MAX_DEVICES 16
|
||||
#define MAX_SOUNDS 4096
|
||||
#define MAX_LAYERS 16
|
||||
#define UI_REFRESH_TIME 100
|
||||
|
||||
// struct where save the DMX settings for each layer
|
||||
struct dmxSetting {
|
||||
int address;
|
||||
uint universe;
|
||||
quint8 universe;
|
||||
bool updated;
|
||||
int layer;
|
||||
};
|
||||
|
|
|
@ -30,6 +30,7 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent)
|
|||
|
||||
Settings *set = Settings::getInstance();
|
||||
set->readFile();
|
||||
connect(set, SIGNAL(audioDeviceChanged(int)), this, SLOT(audioDeviceChanged(int)));
|
||||
/*
|
||||
if (args.contains("-log")) {
|
||||
// Inicia el widget Terminal
|
||||
|
@ -57,7 +58,8 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent)
|
|||
|
||||
// start audio engine
|
||||
MediaLibrary::getInstance()->initMediaLibrary();
|
||||
setCentralWidget(AudioWidget::getInstance());
|
||||
aw = new AudioWidget;
|
||||
setCentralWidget(aw);
|
||||
amw = new AudioMasterWidget(this);
|
||||
QDockWidget *topWidget = new QDockWidget(tr("Master"), this);
|
||||
topWidget->setAllowedAreas(Qt::TopDockWidgetArea);
|
||||
|
@ -66,20 +68,20 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent)
|
|||
// ola setup
|
||||
ola = new olaThread();
|
||||
Q_CHECK_PTR(ola);
|
||||
connect(set, SIGNAL(registerUniverse(int)), ola, SLOT(registerUniverse(int)));
|
||||
ola->registerUniverse(); // register now all the universes
|
||||
ola->blockSignals(true);
|
||||
connect(set, SIGNAL(registerUniverse(int)), ola, SLOT(registerUniverse(int)));
|
||||
connect(ola, SIGNAL (layerReceived()), amw, SLOT(updateWatchDMX()));
|
||||
connect(ola, SIGNAL(dmxOutput(int, int, int)), this, SLOT(dmxInput(int, int, int)));
|
||||
connect(ui.actionLaunch_OLA_Setup, SIGNAL(triggered()), this, SLOT(olasetup()));
|
||||
ola->registerUniverse();
|
||||
ola->start(QThread::TimeCriticalPriority );
|
||||
ola->blockSignals(false);
|
||||
// menus
|
||||
connect(ui.actionOpen_conf, SIGNAL(triggered()), this, SLOT(openFile()));
|
||||
connect(ui.actionSave_conf, SIGNAL(triggered()), this, SLOT(saveFile()));
|
||||
connect(ui.action_Settings, SIGNAL(triggered()), this, SLOT(settings()));
|
||||
connect(set, SIGNAL(audioDeviceChanged(int)), this, SLOT(audioDeviceChanged(int)));
|
||||
qDebug("Init Complete");
|
||||
aw->startEngine();
|
||||
qDebug("Init Complete.");
|
||||
ola->blockSignals(false);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
@ -89,7 +91,7 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent)
|
|||
libreMediaServerAudio::~libreMediaServerAudio()
|
||||
{
|
||||
ola->stop();
|
||||
AudioWidget::getInstance()->stopEngine();
|
||||
aw->stopEngine();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
@ -151,27 +153,27 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value)
|
|||
aux = ola->getValue(layer, DMX_FILE);
|
||||
mediaFile = MediaLibrary::getInstance()->requestNewFile(value, aux);
|
||||
if (QFile::exists(mediaFile))
|
||||
AudioWidget::getInstance()->mediaLoaded(layer, mediaFile);
|
||||
aw->mediaLoaded(layer, mediaFile);
|
||||
break;
|
||||
case DMX_FILE:// File
|
||||
aux = ola->getValue(layer, DMX_FOLDER);
|
||||
mediaFile = MediaLibrary::getInstance()->requestNewFile(aux, value);
|
||||
if (QFile::exists(mediaFile))
|
||||
AudioWidget::getInstance()->mediaLoaded(layer, mediaFile);
|
||||
aw->mediaLoaded(layer, mediaFile);
|
||||
break;
|
||||
case VOLUME_COARSE:
|
||||
f = ( value * 0x100 ) + ola->getValue(layer, VOLUME_FINE);
|
||||
AudioWidget::getInstance()->volChanged(layer, (f / 655.35));
|
||||
aw->volChanged(layer, (f / 655.35));
|
||||
break;
|
||||
case VOLUME_FINE:
|
||||
f = ( ola->getValue(layer, VOLUME_COARSE) * 0x100 ) + value;
|
||||
AudioWidget::getInstance()->volChanged(layer, (f / 655.35));
|
||||
aw->volChanged(layer, (f / 655.35));
|
||||
break;
|
||||
case PAN:
|
||||
AudioWidget::getInstance()->panChanged(layer, value);
|
||||
aw->panChanged(layer, value);
|
||||
break;
|
||||
case PITCH:
|
||||
AudioWidget::getInstance()->pitchChanged(layer, value);
|
||||
aw->pitchChanged(layer, value);
|
||||
break;
|
||||
case PLAYBACK:
|
||||
if (value == 0)
|
||||
|
@ -179,16 +181,16 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value)
|
|||
aux = value / 25;
|
||||
switch (aux) {
|
||||
case 0 :
|
||||
AudioWidget::getInstance()->playbackChanged(layer, PlayingOnce);
|
||||
aw->playbackChanged(layer, PlayingOnce);
|
||||
break;
|
||||
case 1 :
|
||||
AudioWidget::getInstance()->playbackChanged(layer, Stopped);
|
||||
aw->playbackChanged(layer, Stopped);
|
||||
break;
|
||||
case 2 :
|
||||
AudioWidget::getInstance()->playbackChanged(layer, Paused);
|
||||
aw->playbackChanged(layer, Paused);
|
||||
break;
|
||||
case 3 :
|
||||
AudioWidget::getInstance()->playbackChanged(layer, PlayingLoop);
|
||||
aw->playbackChanged(layer, PlayingLoop);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -198,6 +200,6 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value)
|
|||
|
||||
void libreMediaServerAudio::audioDeviceChanged(int id)
|
||||
{
|
||||
AudioWidget::getInstance()->stopEngine();
|
||||
AudioWidget::getInstance()->startEngine(id);
|
||||
aw->stopEngine();
|
||||
aw->startEngine(id);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#ifndef LIBREMEDIASERVERAUDIO_H
|
||||
#define LIBREMEDIASERVERAUDIO_H
|
||||
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QDockWidget>
|
||||
#include <QFile>
|
||||
|
@ -29,7 +30,9 @@
|
|||
#include <QWebView>
|
||||
#include <QApplication>
|
||||
#include <QVBoxLayout>
|
||||
#include <QTextEdit>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QtGlobal>
|
||||
|
||||
#include "audiowidget.h"
|
||||
#include "medialibrary.h"
|
||||
|
@ -48,58 +51,29 @@ class libreMediaServerAudio : public QMainWindow
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
libreMediaServerAudio (QStringList args, QWidget *parent = 0);
|
||||
virtual ~libreMediaServerAudio();
|
||||
|
||||
Ui::LibreMediaServerAudio ui;
|
||||
|
||||
// static QTextEdit *textEdit; // Terminal de feedback
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
||||
// void MessageHandler(QtMsgType type, const QMessageLogContext &logcontext, const QString &msg);
|
||||
AudioMasterWidget *amw;
|
||||
AudioWidget *aw;
|
||||
AudioMasterWidget *amw;
|
||||
olaThread *ola;
|
||||
|
||||
olaThread *ola;
|
||||
|
||||
void open_start();
|
||||
void save_finish();
|
||||
void open(QFile *file);
|
||||
void save(QFile *file);
|
||||
void open_start();
|
||||
void save_finish();
|
||||
void open(QFile *file);
|
||||
void save(QFile *file);
|
||||
|
||||
public slots:
|
||||
void audioDeviceChanged(int id);
|
||||
|
||||
private slots:
|
||||
|
||||
/**
|
||||
* @brief Shows the OLA web setup page
|
||||
*/
|
||||
void olasetup();
|
||||
|
||||
/**
|
||||
* @brief Parser for new dmx data arriving
|
||||
* @param layer
|
||||
* @param channel
|
||||
* @param value
|
||||
*/
|
||||
void dmxInput(int layer, int channel, int value);
|
||||
|
||||
// Menu File
|
||||
/**
|
||||
* @brief REad from dis a configuration file
|
||||
*/
|
||||
void openFile();
|
||||
/**
|
||||
* @brief Write to disk a configuration file
|
||||
*/
|
||||
void saveFile();
|
||||
/**
|
||||
* @brief OPen the settings dialog
|
||||
*/
|
||||
void settings();
|
||||
};
|
||||
|
||||
|
|
238
src/miniaudioengine.cpp
Normal file
238
src/miniaudioengine.cpp
Normal file
|
@ -0,0 +1,238 @@
|
|||
#include "miniaudioengine.h"
|
||||
|
||||
MiniAudioEngine::MiniAudioEngine()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MiniAudioEngine::audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
|
||||
{
|
||||
(void)pInput;
|
||||
//Do master audio processing before sending to device.
|
||||
ma_engine_read_pcm_frames((ma_engine*)pDevice->pUserData, pOutput, frameCount, NULL);
|
||||
}
|
||||
|
||||
void MiniAudioEngine::stopEngine()
|
||||
{
|
||||
ma_engine_uninit(&engine);
|
||||
ma_device_uninit(&device);
|
||||
ma_context_uninit(&context);
|
||||
ma_resource_manager_uninit(&resourceManager);
|
||||
}
|
||||
|
||||
bool MiniAudioEngine::startEngine(int n)
|
||||
{
|
||||
ma_result result;
|
||||
|
||||
result = this->startContext();
|
||||
if (result != MA_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
this->getAllAudioDevices();
|
||||
result = this->startDevice(n);
|
||||
return result;
|
||||
}
|
||||
|
||||
ma_result MiniAudioEngine::startDevice(int id)
|
||||
{
|
||||
ma_result result;
|
||||
ma_device_config deviceConfig;
|
||||
ma_engine_config engineConfig;
|
||||
|
||||
deviceConfig = ma_device_config_init(ma_device_type_playback);
|
||||
deviceConfig.playback.pDeviceID = &pPlaybackDeviceInfos[id].id;
|
||||
deviceConfig.playback.format = resourceManager.config.decodedFormat;
|
||||
deviceConfig.playback.channels = 0;
|
||||
deviceConfig.sampleRate = resourceManager.config.decodedSampleRate;
|
||||
deviceConfig.dataCallback = audioDataCallback;
|
||||
deviceConfig.pUserData = &engine;
|
||||
result = ma_device_init(&context, &deviceConfig, &device);
|
||||
if (result != MA_SUCCESS) {
|
||||
printf("Failed to initialize audio device %s.", pPlaybackDeviceInfos[id].name);
|
||||
return result;
|
||||
}
|
||||
engineConfig = ma_engine_config_init();
|
||||
engineConfig.pDevice = &device;
|
||||
engineConfig.pResourceManager = &resourceManager;
|
||||
engineConfig.noAutoStart = MA_TRUE;
|
||||
result = ma_engine_init(NULL, &engine);
|
||||
if (result != MA_SUCCESS) {
|
||||
printf("Failed to initialize audio engine.");
|
||||
return result;
|
||||
}
|
||||
result = ma_engine_start(&engine);
|
||||
if (result != MA_SUCCESS) {
|
||||
printf("Failed to start audio engine %i.", id);
|
||||
return result;
|
||||
}
|
||||
iChosenDevice = id;
|
||||
printf("Initialized audio device %d: %s", id, pPlaybackDeviceInfos[id].name);
|
||||
return result;
|
||||
}
|
||||
|
||||
ma_result MiniAudioEngine::startContext()
|
||||
{
|
||||
ma_result result;
|
||||
|
||||
resourceManagerConfig = ma_resource_manager_config_init();
|
||||
resourceManagerConfig.decodedFormat = ma_format_f32; /* ma_format_f32 should almost always be used as that's what the engine (and most everything else) uses for mixing. */
|
||||
resourceManagerConfig.decodedChannels = 0;
|
||||
resourceManagerConfig.decodedSampleRate = 0;
|
||||
resourceManagerConfig.jobThreadCount = 0;
|
||||
result = ma_resource_manager_init(&resourceManagerConfig, &resourceManager);
|
||||
if (result != MA_SUCCESS) {
|
||||
printf("Failed to initialize audio resource manager.");
|
||||
return result;
|
||||
}
|
||||
result = ma_context_init(NULL, 0, NULL, &context);
|
||||
if (result != MA_SUCCESS) {
|
||||
printf("Failed to initialize audio context.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// enum all audio devices in system
|
||||
ma_result MiniAudioEngine::getAllAudioDevices()
|
||||
{
|
||||
ma_result result;
|
||||
|
||||
result = ma_context_get_devices(&context, &pPlaybackDeviceInfos, &playbackDeviceCount, NULL, NULL);
|
||||
if (result != MA_SUCCESS) {
|
||||
printf("Failed to enumerate playback devices.\n");
|
||||
ma_context_uninit(&context);
|
||||
return result;
|
||||
}
|
||||
printf("Audio devices detected in system:\n");
|
||||
for (ma_uint32 iAvailableDevice = 0; iAvailableDevice < playbackDeviceCount; iAvailableDevice += 1) {
|
||||
qInfo("%d: : %s", iAvailableDevice, pPlaybackDeviceInfos[iAvailableDevice].name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ma_result MiniAudioEngine::loadMedia(int layer, char *file)
|
||||
{
|
||||
ma_result result;
|
||||
|
||||
if (m_mediaLoaded[layer] == true)
|
||||
{
|
||||
qInfo("removing sound %i", layer);
|
||||
ma_sound_uninit(&m_currentSound[layer]);
|
||||
m_mediaLoaded[layer] = false;
|
||||
}
|
||||
result = ma_sound_init_from_file(&engine, file, \
|
||||
MA_SOUND_FLAG_NO_SPATIALIZATION \
|
||||
/*| MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE \
|
||||
| MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC \
|
||||
| MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM \*/
|
||||
, NULL, NULL, &m_currentSound[layer]);
|
||||
if (result != MA_SUCCESS)
|
||||
qWarning("Failed to load file %s", file);
|
||||
else {
|
||||
m_mediaLoaded[layer] = true;
|
||||
this->volChanged(layer, 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
float MiniAudioEngine::getDuration(int layer)
|
||||
{
|
||||
ma_result result;
|
||||
float ret = 0;
|
||||
|
||||
if (m_mediaLoaded[layer] == false)
|
||||
return MA_DOES_NOT_EXIST;
|
||||
result = ma_sound_get_length_in_seconds(&m_currentSound[layer], &ret);
|
||||
if (result != MA_SUCCESS)
|
||||
{
|
||||
qWarning("Can not get duration %i", layer);
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
float MiniAudioEngine::getCursor(int layer)
|
||||
{
|
||||
ma_result result;
|
||||
float ret = 0;
|
||||
|
||||
if (m_mediaLoaded[layer] == false)
|
||||
return MA_DOES_NOT_EXIST;
|
||||
result = ma_sound_get_cursor_in_seconds(&m_currentSound[layer], &ret);
|
||||
if (result != MA_SUCCESS)
|
||||
{
|
||||
qWarning("Can not get cursor %i", layer);
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ma_result MiniAudioEngine::printFormatInfo(int layer)
|
||||
{
|
||||
ma_format format;
|
||||
ma_uint32 channels;
|
||||
ma_uint32 sampleRate;
|
||||
|
||||
if (m_mediaLoaded[layer] == false)
|
||||
return MA_DOES_NOT_EXIST;
|
||||
ma_result result = ma_sound_get_data_format(&m_currentSound[layer], &format, &channels, &sampleRate, NULL, 0);
|
||||
if (result != MA_SUCCESS) {
|
||||
qWarning("Failed to get data format %i\n", layer);
|
||||
return MA_INVALID_DATA;
|
||||
}
|
||||
qInfo("samples/sec: %u format: %u channels: %u", sampleRate, format, channels);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Expects between 0 and 100 vol value in db
|
||||
void MiniAudioEngine::volChanged(int layer, float vol)
|
||||
{
|
||||
float result;
|
||||
|
||||
if (m_mediaLoaded[layer] == false)
|
||||
return;
|
||||
result = ma_volume_linear_to_db(1.00000000 + (vol / 800.0));
|
||||
ma_sound_group_set_volume(&m_currentSound[layer], result);
|
||||
}
|
||||
|
||||
void MiniAudioEngine::panChanged(int layer, float value)
|
||||
{
|
||||
float result;
|
||||
|
||||
if (m_mediaLoaded[layer] == false)
|
||||
return;
|
||||
result = (value / 128.0) - 1.0;
|
||||
ma_sound_group_set_pan(&m_currentSound[layer], result);
|
||||
}
|
||||
|
||||
void MiniAudioEngine::pitchChanged(int layer, float value)
|
||||
{
|
||||
float result;
|
||||
|
||||
if (m_mediaLoaded[layer] == false)
|
||||
return;
|
||||
result = value / 128.0;
|
||||
ma_sound_group_set_pitch(&m_currentSound[layer], result);
|
||||
}
|
||||
|
||||
void MiniAudioEngine::playbackChanged(int layer, Status status)
|
||||
{
|
||||
if (m_mediaLoaded[layer] == false)
|
||||
return;
|
||||
switch (status) {
|
||||
case Status::Paused:
|
||||
ma_sound_stop(&m_currentSound[layer]);
|
||||
break;
|
||||
case Status::Stopped:
|
||||
ma_sound_stop(&m_currentSound[layer]);
|
||||
ma_sound_seek_to_pcm_frame(&m_currentSound[layer], 0);
|
||||
break;
|
||||
case Status::PlayingLoop:
|
||||
ma_sound_set_looping(&m_currentSound[layer], true);
|
||||
ma_sound_start(&m_currentSound[layer]);
|
||||
break;
|
||||
case Status::PlayingOnce:
|
||||
ma_sound_set_looping(&m_currentSound[layer], false);
|
||||
ma_sound_start(&m_currentSound[layer]);
|
||||
break;
|
||||
}
|
||||
}
|
48
src/miniaudioengine.h
Normal file
48
src/miniaudioengine.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifndef MINIAUDIOENGINE_H
|
||||
#define MINIAUDIOENGINE_H
|
||||
|
||||
#define MINIAUDIO_IMPLEMENTATION
|
||||
#include "miniaudio.h"
|
||||
|
||||
#include "defines.h" //MAX_LAYERS
|
||||
#include <stdio.h> // for printf
|
||||
|
||||
class MiniAudioEngine
|
||||
{
|
||||
friend class AudioWidget;
|
||||
|
||||
public:
|
||||
MiniAudioEngine();
|
||||
void stopEngine();
|
||||
bool startEngine(int id);
|
||||
static void audioDataCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
|
||||
|
||||
protected:
|
||||
// slots for DMX input
|
||||
ma_result loadMedia(int layer, char *media );
|
||||
void volChanged(int layer, float vol);
|
||||
void panChanged(int layer, float pan);
|
||||
void pitchChanged(int layer, float pitch);
|
||||
void playbackChanged(int layer, Status status);
|
||||
float getDuration(int layer);
|
||||
float getCursor(int layer);
|
||||
ma_result printFormatInfo(int layer);
|
||||
|
||||
private:
|
||||
ma_resource_manager_config resourceManagerConfig;
|
||||
ma_resource_manager resourceManager;
|
||||
ma_device_info* pPlaybackDeviceInfos;
|
||||
ma_uint32 playbackDeviceCount;
|
||||
ma_uint32 iChosenDevice;
|
||||
ma_engine engine;
|
||||
ma_device device;
|
||||
ma_context context;
|
||||
ma_sound m_currentSound[MAX_LAYERS];
|
||||
ma_bool8 m_mediaLoaded[MAX_LAYERS];
|
||||
|
||||
ma_result getAllAudioDevices();
|
||||
ma_result startDevice(int id);
|
||||
ma_result startContext();
|
||||
};
|
||||
|
||||
#endif // MINIAUDIOENGINE_H
|
|
@ -53,7 +53,7 @@ void SettingsDialog::changeAudioDevice()
|
|||
{
|
||||
m_deviceDialog = new QDialog( this );
|
||||
}
|
||||
QLabel *msgLabel = new QLabel;
|
||||
/* QLabel *msgLabel = new QLabel;
|
||||
AudioWidget *aw = AudioWidget::getInstance();
|
||||
QString *msg = new QString;
|
||||
for (uint iAvailableDevice = 0; iAvailableDevice < aw->playbackDeviceCount; iAvailableDevice += 1) {
|
||||
|
@ -72,7 +72,7 @@ void SettingsDialog::changeAudioDevice()
|
|||
layout->addWidget(closeButton);
|
||||
m_deviceDialog->setLayout(layout);
|
||||
m_deviceDialog->setModal(true);
|
||||
m_deviceDialog->show();
|
||||
m_deviceDialog->show();*/
|
||||
}
|
||||
|
||||
void SettingsDialog::closeAudioDeviceDialog()
|
||||
|
|
Loading…
Add table
Reference in a new issue