This commit is contained in:
Santi Noreña 2014-07-13 17:11:00 +02:00
commit 50106dfc7c
21 changed files with 975 additions and 843 deletions

46
.gitignore vendored Normal file
View file

@ -0,0 +1,46 @@
# C++ objects and libs
*.slo
*.lo
*.o
*.a
*.la
*.lai
*.so
*.dll
*.dylib
# Qt-es
/.qmake.cache
/.qmake.stash
*.pro.user
*.pro.user.*
*.moc
moc_*.cpp
qrc_*.cpp
ui_*.h
Makefile*
*-build-*
# QtCreator
*.autosave
# binarios
puredata/pd
puredata/externals/**
# Folders
bin/**
tcl/**
src/debug/**
src/release/**
log/**
# Backups
*~
*.autosave

167
src/audiodecoder.cpp Normal file
View file

@ -0,0 +1,167 @@
#include "audiodecoder.h"
#include <QFile>
#include <qmath.h>
#include <qendian.h>
AudioDecoder::AudioDecoder(const QAudioFormat &format,
qint64 durationUs,
int sampleRate,
QObject *parent)
: QIODevice(parent)
, m_pos(0)
{
m_decoder = new QAudioDecoder();
m_decoder->setAudioFormat(format);
connect(m_decoder, SIGNAL(error(QAudioDecoder::Error)),
this, SLOT(errorDecoding(QAudioDecoder::Error)));
connect(m_decoder, SIGNAL(bufferReady()),
this, SLOT(readBuffer()));
generateData(format, durationUs, sampleRate);
}
AudioDecoder::AudioDecoder(const QAudioFormat &format,
QObject *parent)
: QIODevice(parent)
, m_pos(0)
{
m_decoder = new QAudioDecoder();
m_decoder->setAudioFormat(format);
connect(m_decoder, SIGNAL(error(QAudioDecoder::Error)),
this, SLOT(errorDecoding(QAudioDecoder::Error)));
connect(m_decoder, SIGNAL(bufferReady()),
this, SLOT(readBuffer()));
connect(m_decoder, SIGNAL(finished()),
this, SLOT(decoderFinished()));
connect(m_decoder, SIGNAL(durationChanged(qint64)),
this, SLOT(trackTimeChanged(qint64)));
}
AudioDecoder::~AudioDecoder()
{
}
void AudioDecoder::start()
{
open(QIODevice::ReadOnly);
}
void AudioDecoder::stop()
{
m_pos = 0;
close();
}
void AudioDecoder::loadMedia(QString file)
{
m_buffer.clear();
m_decoder->setSourceFilename(file);
m_decoder->start();
}
void AudioDecoder::generateData(const QAudioFormat &format, qint64 durationUs, int sampleRate)
{
const int channelBytes = format.sampleSize() / 8;
const int sampleBytes = format.channelCount() * channelBytes;
qint64 length = (format.sampleRate() * format.channelCount() * (format.sampleSize() / 8))
* durationUs / 100000;
Q_ASSERT(length % sampleBytes == 0);
Q_UNUSED(sampleBytes) // suppress warning in release builds
m_buffer.resize(length);
unsigned char *ptr = reinterpret_cast<unsigned char *>(m_buffer.data());
int sampleIndex = 0;
while (length) {
const qreal x = qSin(2 * M_PI * sampleRate * qreal(sampleIndex % format.sampleRate()) / format.sampleRate());
for (int i=0; i<format.channelCount(); ++i) {
qint16 value = static_cast<qint16>(x * 32767);
if (format.byteOrder() == QAudioFormat::LittleEndian)
qToLittleEndian<qint16>(value, ptr);
ptr += channelBytes;
length -= channelBytes;
}
++sampleIndex;
}
}
void AudioDecoder::readBuffer()
{
// Extract all samples avalaible
while(m_decoder->bufferAvailable())
{
QAudioBuffer qbuf = m_decoder->read();
QByteArray ba((const char*)qbuf.data(), qbuf.byteCount());
m_buffer.append(ba);
}
}
void AudioDecoder::errorDecoding(QAudioDecoder::Error msg)
{
// qWarning("Error Decoding ");
switch (msg) {
case QAudioDecoder::NoError:
break;
case QAudioDecoder::ResourceError:
qWarning("A media resource couldn't be resolved: %s", m_decoder->sourceFilename().toLatin1().constData());
break;
case QAudioDecoder::FormatError:
qWarning("The format of a media resource isn't supported: %s", m_decoder->sourceFilename().toLatin1().constData());
break;
case QAudioDecoder::AccessDeniedError:
qWarning("There are not the appropriate permissions to play a media resource %s", m_decoder->sourceFilename().toLatin1().constData());
break;
case QAudioDecoder::ServiceMissingError:
qWarning("A valid playback service was not found, playback cannot proceed");
break;
}
}
qint64 AudioDecoder::readData(char *data, qint64 len)
{
if (m_buffer.size() == 0)
return 0;
qint64 total = 0;
while (len - total > 0) {
const qint64 chunk = qMin((m_buffer.size() - m_pos), len - total);
memcpy(data + total, m_buffer.constData() + m_pos, chunk);
// Controla Final del track
if ( (m_pos + chunk ) >= ( m_buffer.size() )
&& m_decoder->state() != QAudioDecoder::DecodingState )
return (-1);
m_pos = (m_pos + chunk) % m_buffer.size(); // Esto reseta a 0 si alcanza el final y hace loop
total += chunk;
}
return total;
}
qint64 AudioDecoder::writeData(const char *data, qint64 len)
{
Q_UNUSED(data);
Q_UNUSED(len);
return 0;
}
qint64 AudioDecoder::bytesAvailable() const
{
return m_buffer.size() + QIODevice::bytesAvailable();
}
void AudioDecoder::decoderFinished()
{
qDebug("Decoding file finished %s ", m_decoder->sourceFilename().toLatin1().constData());
emit fileLoaded(m_decoder->sourceFilename());
}
void AudioDecoder::trackTimeChanged(qint64 dur)
{
emit totalTimeChanged(dur);
}
void AudioDecoder::setPos(qint64 pos)
{
m_pos = pos;
}

45
src/audiodecoder.h Normal file
View file

@ -0,0 +1,45 @@
#ifndef AUDIODECODER_H
#define AUDIODECODER_H
#include <QIODevice>
#include <QAudioFormat>
#include <QAudioDecoder>
class AudioDecoder : public QIODevice
{
Q_OBJECT
public:
AudioDecoder(const QAudioFormat &format, qint64 durationUs, int sampleRate, QObject *parent);
AudioDecoder(const QAudioFormat &format, QObject *parent);
~AudioDecoder();
void start();
void stop();
qint64 readData(char *data, qint64 maxlen);
qint64 writeData(const char *data, qint64 len);
qint64 bytesAvailable() const;
void loadMedia(QString file);
void setPos(qint64 pos);
private:
void generateData(const QAudioFormat &format, qint64 durationUs, int sampleRate);
qint64 m_pos;
QByteArray m_buffer;
QAudioDecoder *m_decoder;
private slots:
void readBuffer();
void errorDecoding(QAudioDecoder::Error msg);
void decoderFinished();
void trackTimeChanged(qint64 dur);
signals:
void totalTimeChanged(qint64 dur);
void fileLoaded(QString file);
};
#endif // AUDIODECODER_H

View file

@ -1,22 +1,145 @@
#include "audiolayerwidget.h" #include "audiolayerwidget.h"
#include <QDebug>
#include <QVBoxLayout>
#include <QFile>
#include <QTime>
AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name): AudioLayerWidget::AudioLayerWidget(QWidget *parent, QString name):
QGroupBox(parent) QGroupBox(parent)
{ , m_suspendResumeButton(0)
folder = new QLabel(this); , m_deviceBox(0)
file = new QLabel(this); , m_watchDMX(new QTimer(this))
status = new QLabel(this); , m_pullTimer(new QTimer(this))
vol = new QSlider(this); , m_device(QAudioDeviceInfo::defaultOutputDevice())
vol->setMaximum(99); , m_audioOutput(0)
mute = new QCheckBox(this); , m_output(0)
, m_buffer(BufferSize, 0)
, m_decoder(0)
, m_progressCounter(new QTime(0,0,0,1))
, m_progressMs(0)
, m_currentMedia(" ")
QVBoxLayout *vbox = new QVBoxLayout; {
vbox->addWidget(folder); this->setTitle(name);
vbox->addWidget(file);
vbox->addWidget(status); QVBoxLayout *layout = new QVBoxLayout;
vbox->addWidget(vol);
vbox->addWidget(mute); m_deviceBox = new QComboBox(this);
this->setLayout(vbox); const QAudioDeviceInfo &defaultDeviceInfo = QAudioDeviceInfo::defaultOutputDevice();
m_deviceBox->addItem(defaultDeviceInfo.deviceName(), qVariantFromValue(defaultDeviceInfo));
foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) {
if (deviceInfo != defaultDeviceInfo)
m_deviceBox->addItem(deviceInfo.deviceName(), qVariantFromValue(deviceInfo));
}
m_deviceBox->setMaximumWidth(250);
connect(m_deviceBox,SIGNAL(activated(int)),
this, SLOT(deviceChanged(int)));
layout->addWidget(m_deviceBox);
QHBoxLayout *status = new QHBoxLayout;
m_statusLabel = new QLabel;
m_statusLabel->setText(STATUS_LABEL);
m_statusValue = new QLabel;
m_receiveDMX = new QCheckBox("Receiving DMX", this);
// m_receiveDMX->setCheckable(false);
m_receiveDMX->setChecked(false);
status->addWidget(m_receiveDMX);
status->addWidget(m_statusLabel);
status->addWidget(m_statusValue);
layout->addLayout(status);
QHBoxLayout *folderLoaded = new QHBoxLayout;
m_folderLabel = new QLabel;
m_folderLabel->setText(FOLDER_LABEL);
m_folderValue = new QLabel;
folderLoaded->addWidget(m_folderLabel);
folderLoaded->addWidget(m_folderValue);
layout->addLayout(folderLoaded);
QHBoxLayout *fileLoaded = new QHBoxLayout;
m_fileLabel = new QLabel;
m_fileLabel->setText(FILE_LABEL);
m_fileValue = new QLabel;
fileLoaded->addWidget(m_fileLabel);
fileLoaded->addWidget(m_fileValue);
layout->addLayout(fileLoaded);
QHBoxLayout *volumeBox = new QHBoxLayout;
m_volumeLabel = new QLabel;
m_volumeLabel->setText(tr(VOLUME_LABEL));
m_volumeSlider = new QSlider(Qt::Horizontal);
m_volumeSlider->setMinimum(0);
m_volumeSlider->setMaximum(80);
m_volumeSlider->setSingleStep(1);
connect(m_volumeSlider, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int)));
volumeBox->addWidget(m_volumeLabel);
volumeBox->addWidget(m_volumeSlider);
layout->addLayout(volumeBox);
QHBoxLayout *progressTime = new QHBoxLayout;
m_progressTimeLabel = new QLabel;
m_progressTimeLabel->setText(PROGRESS_TIME_LABEL);
m_progressTime = new QTimeEdit;
m_progressTime->setDisplayFormat("h:mm:ss:zzz");
m_progressTime->setReadOnly(true);
m_progressTime->setButtonSymbols(QAbstractSpinBox::NoButtons);
m_progressTime->setMaximumWidth(90);
progressTime->addWidget(m_progressTimeLabel);
progressTime->addWidget(m_progressTime);
// QHBoxLayout *totalTime = new QHBoxLayout;
m_totalTimeLabel = new QLabel;
m_totalTimeLabel->setText(TOTAL_TIME_LABEL);
m_totalTimeValue = new QTimeEdit;
m_totalTimeValue->setDisplayFormat("h:mm:ss:zzz");
m_totalTimeValue->setReadOnly(true);
m_totalTimeValue->setButtonSymbols(QAbstractSpinBox::NoButtons);
m_totalTimeValue->setMaximumWidth(90);
progressTime->addWidget(m_totalTimeLabel);
progressTime->addWidget(m_totalTimeValue);
// layout->addLayout(totalTime);
layout->addLayout(progressTime);
QHBoxLayout *progressSlider = new QHBoxLayout;
m_progressLabel = new QLabel;
m_progressLabel->setText(PROGRESS_LABEL);
m_progressSlider = new QSlider(Qt::Horizontal);
progressSlider->addWidget(m_progressLabel);
progressSlider->addWidget(m_progressSlider);
layout->addLayout(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);
m_format.setSampleRate(DataSampleRateHz);
m_format.setChannelCount(2);
m_format.setSampleSize(16);
m_format.setCodec("audio/pcm");
m_format.setByteOrder(QAudioFormat::LittleEndian);
m_format.setSampleType(QAudioFormat::SignedInt);
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
if (!info.isFormatSupported(m_format)) {
qWarning("Default format not supported - trying to use nearest");
m_format = info.nearestFormat(m_format);
}
m_decoder = new AudioDecoder(m_format, this);
m_decoder->start();
connect(m_decoder, SIGNAL(totalTimeChanged(qint64)),
this, SLOT(durationChanged(qint64)));
connect(m_pullTimer, SIGNAL(timeout()),
this, SLOT(pullTimerExpired()));
connect(m_watchDMX, SIGNAL(timeout()),
this, SLOT(watchDMXExpired()));
m_watchDMX->start(1000);
createAudioOutput();
} }
AudioLayerWidget::~AudioLayerWidget() AudioLayerWidget::~AudioLayerWidget()
@ -24,3 +147,184 @@ AudioLayerWidget::~AudioLayerWidget()
} }
void AudioLayerWidget::createAudioOutput()
{
m_audioOutput = new QAudioOutput(m_device, m_format, this);
Q_CHECK_PTR(m_audioOutput);
m_audioOutput->setNotifyInterval(NOTIFY_INTERVAL);
connect(m_audioOutput, SIGNAL(notify()), SLOT(notified()));
reset();
m_statusValue->setText(PAUSE_LABEL);
connect(m_audioOutput, SIGNAL(stateChanged(QAudio::State)), SLOT(handleStateChanged(QAudio::State)));
}
void AudioLayerWidget::deviceChanged(int index)
{
m_pullTimer->stop();
m_audioOutput->stop();
m_audioOutput->disconnect(this);
m_device = m_deviceBox->itemData(index).value<QAudioDeviceInfo>();
createAudioOutput();
}
void AudioLayerWidget::volumeChanged(int value)
{
if (m_audioOutput)
m_audioOutput->setVolume(qreal(value/100.0f));
}
void AudioLayerWidget::setVol(qreal vol)
{
m_audioOutput->setVolume(vol);
m_volumeSlider->blockSignals(true);
int volume = vol * 100;
m_volumeSlider->setValue(volume);
m_volumeSlider->blockSignals(false);
}
void AudioLayerWidget::loadMedia(QString file)
{
if (m_currentMedia == file)
return;
reset();
if (QFile::exists(file)){
m_decoder->loadMedia(file);
m_currentMedia = file;
fileLoaded(file);
}
}
void AudioLayerWidget::fileLoaded(QString file)
{
QStringList list = file.split("/");
int size = list.size();
if (size >= 2) {
m_folderValue->setText(list.at(size - 2));
m_fileValue->setText(list.at(size - 1));
}
}
void AudioLayerWidget::notified()
{
m_progressMs += m_progressCounter->restart();
m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(m_progressMs));
m_progressSlider->setValue(m_progressMs);
/* qDebug() << "bytesFree = " << m_audioOutput->bytesFree()
<< ", " << "elapsedUSecs = " << m_audioOutput->elapsedUSecs()
<< ", " << "processedUSecs = " << m_audioOutput->processedUSecs();
*/
}
void AudioLayerWidget::pullTimerExpired()
{
if (m_audioOutput && m_audioOutput->state() != QAudio::StoppedState) {
int chunks = m_audioOutput->bytesFree()/m_audioOutput->periodSize();
while (chunks) {
const qint64 len = m_decoder->read(m_buffer.data(), m_audioOutput->periodSize());
if ( len == -1) {
stop();
qDebug("End of file %s", this->title().toLatin1().constData());
break;
}
if (len) {
m_output->write(m_buffer.data(), len);
}
if (len != m_audioOutput->periodSize())
break;
--chunks;
}
}
}
void AudioLayerWidget::toggleSuspendResume()
{
if (m_audioOutput->state() == QAudio::SuspendedState) {
resume();
} else if (m_audioOutput->state() == QAudio::ActiveState) {
pause();
} else if (m_audioOutput->state() == QAudio::StoppedState) {
play();
} else if (m_audioOutput->state() == QAudio::IdleState) {
qWarning("%s: IdleState", this->title().toLatin1().constData());
play();
}
}
void AudioLayerWidget::handleStateChanged(QAudio::State state)
{
if (state == QAudio::SuspendedState) {
m_statusValue->setText(PAUSE_LABEL);
} else if (state == QAudio::ActiveState) {
m_statusValue->setText(PLAY_LABEL);
} else if (m_audioOutput->state() == QAudio::StoppedState) {
m_statusValue->setText(STOP_LABEL);
} else if (state == QAudio::IdleState) {
m_statusValue->setText(IDDLE_LABEL);
}
}
void AudioLayerWidget::durationChanged(qint64 dur)
{
if (dur == -1)
return;
m_totalTimeValue->setTime(QTime::fromMSecsSinceStartOfDay(dur));
m_progressSlider->setMaximum(dur);
}
void AudioLayerWidget::play()
{
setInitPosition();
m_pullTimer->start(PULL_TIMER_INTERVAL);
m_audioOutput->resume();
pullTimerExpired();
m_progressCounter->start();
m_suspendResumeButton->setText(tr(SUSPEND_LABEL));
}
void AudioLayerWidget::pause()
{
m_audioOutput->suspend();
m_pullTimer->stop();
m_suspendResumeButton->setText(tr(RESUME_LABEL));
}
void AudioLayerWidget::resume()
{
m_pullTimer->start(PULL_TIMER_INTERVAL);
m_audioOutput->resume();
pullTimerExpired();
m_progressCounter->start();
m_suspendResumeButton->setText(tr(SUSPEND_LABEL));
}
void AudioLayerWidget::stop()
{
reset();
setInitPosition();
}
void AudioLayerWidget::reset()
{
m_pullTimer->stop();
m_audioOutput->reset();
m_output = m_audioOutput->start();
Q_CHECK_PTR(m_output);
pause();
}
void AudioLayerWidget::setInitPosition()
{
m_decoder->setPos(0);
m_progressMs = 0;
m_progressTime->setTime(QTime::fromMSecsSinceStartOfDay(m_progressMs));
m_progressSlider->setValue(m_progressMs);
}
void AudioLayerWidget::watchDMXExpired() {
m_receiveDMX->setChecked(false);
}
void AudioLayerWidget::updateWatchDMX(bool b)
{
m_receiveDMX->setChecked(b);
}

View file

@ -1,13 +1,20 @@
#ifndef AUDIOLAYERWIDGET_H #ifndef AUDIOLAYERWIDGET_H
#define AUDIOLAYERWIDGET_H #define AUDIOLAYERWIDGET_H
#include <QtGui> #include <QAudioOutput>
#include <QByteArray>
#include <QComboBox>
#include <QLabel>
#include <QPushButton>
#include <QSlider>
#include <QTimer>
#include <QTime>
#include <QTimeEdit>
#include <QGroupBox>
#include <QCheckBox>
//#include "ui_audiolayerwidget.h" #include "audiodecoder.h"
/* #include "defines.h"
namespace Ui {
class AudioLayerWidget;
}*/
class AudioLayerWidget : public QGroupBox class AudioLayerWidget : public QGroupBox
{ {
@ -15,31 +22,78 @@ class AudioLayerWidget : public QGroupBox
public: public:
AudioLayerWidget(QWidget *parent, QString name); explicit AudioLayerWidget(QWidget *parent = 0, QString name = "Layer");
~AudioLayerWidget(); ~AudioLayerWidget();
inline void setFile(QString file) const void loadMedia(QString file);
{ void play();
this->file->setText(file); void stop();
} void pause();
void setVol(qreal vol);
void resume();
inline void setFolder(QString folder) const void updateWatchDMX(bool b);
{ public slots:
this->folder->setText(folder);
}
inline void setVol(float vol) const void toggleSuspendResume();
{ void volumeChanged(int vol);
this->vol->setValue(vol);
}
private: private:
QLabel *file; QPushButton *m_suspendResumeButton;
QLabel *folder; QComboBox *m_deviceBox;
QSlider *vol;
QCheckBox *mute; QLabel *m_statusLabel;
QLabel *status; QLabel * m_statusValue;
QLabel *m_volumeLabel;
QSlider *m_volumeSlider;
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;
QCheckBox *m_receiveDMX;
QTimer *m_watchDMX;
QTimer *m_pullTimer;
QAudioDeviceInfo m_device;
QAudioOutput *m_audioOutput;
QIODevice *m_output; // not owned
QAudioFormat m_format;
QByteArray m_buffer;
AudioDecoder *m_decoder;
QTime *m_progressCounter;
quint64 m_progressMs;
QString m_currentMedia;
void createAudioOutput();
void reset();
void setInitPosition();
private slots:
void notified();
void pullTimerExpired();
void fileLoaded(QString file);
void handleStateChanged(QAudio::State state);
void deviceChanged(int index);
void durationChanged(qint64 dur);
void watchDMXExpired();
}; };
#endif // AUDIOLAYERWIDGET_H #endif // AUDIOLAYERWIDGET_H

View file

@ -3,6 +3,10 @@
#include <QLabel> #include <QLabel>
#include <QtGui> #include <QtGui>
#include <QGroupBox>
#include <QSlider>
#include <QCheckBox>
#include <QVBoxLayout>
//#include "ui_audiomasterwidget.h" //#include "ui_audiomasterwidget.h"

View file

@ -1,382 +0,0 @@
#include "audiomotor.h"
#define PAUSE 2
#define PLAY 0
#define STOP 1
#define MAX_DATA = 1024;
AudioMotor *AudioMotor::_instance = 0;
AudioMotor *AudioMotor::getInstance() {
if (_instance == 0) {
_instance = new AudioMotor();
Q_CHECK_PTR(_instance);
}
return _instance;
}
AudioMotor::AudioMotor(QObject *parent) :
QObject(parent),
m_startaudio(0),
m_writePD(NULL),
m_readPD(NULL),
m_pd_audio(NULL),
m_connectedSocket(NULL),
m_gui(true)
{
qsrand(qrand());
qDebug() << "Init MotorAudio";
}
AudioMotor::~AudioMotor()
{
close();
}
/** Init the engine
*/
bool AudioMotor::init()
{
/* Sets the socket an connections for the comunication with PD
QFile socket(SOCKET);
if (socket.exists())
{
socket.remove();
}*/
// Socket para mandar órdenes a Pure Data
m_writePD = new QTcpSocket(this);
Q_CHECK_PTR(m_writePD);
connect(m_writePD, SIGNAL(connected()),this, SLOT(newConexion()));
connect(m_writePD, SIGNAL(error(QAbstractSocket::SocketError)) , this, SLOT(errorWrite(QAbstractSocket::SocketError)));
// Servidor para recibir feedback de Pure Data
m_readPD = new QTcpServer(this);
Q_CHECK_PTR(m_readPD);
connect(m_readPD, SIGNAL(newConnection()),this, SLOT(newPeer()));
if (m_readPD->listen(QHostAddress::LocalHost, PDPORT)) {
qDebug(QString("AudioMotor| Listening to PD on TCP port %1").arg(PDPORT).toLatin1());
} else {
qErrnoWarning(QString("AudioMotor::init() can not init TCP Server on port %1").arg(PDPORT).toLatin1());
emit toTerminal(QString("AudioMotor::init() can not init TCP Server on port)" + PDPORT));
}
// Start the pd process an set up PD
m_pd_audio = new QProcess(this);
connect(m_pd_audio, SIGNAL(readyReadStandardError()), this, SLOT(stdout()));
connect(m_pd_audio, SIGNAL(finished(int)), this, SLOT(restartAudio()));
QString arguments;
// arguments.append("./puredata/pd -alsa -channels 2 -audiodev 1 -stderr -nostdpath -path ./puredata/externals/ -open ./puredata/lms-audio.pd ");
arguments.append("./puredata/pd -channels 2 -stderr -nostdpath -path ./puredata/externals/ -open ./puredata/lms-audio.pd ");
if (!m_gui)
arguments.append("-nogui");
m_pd_audio->start(arguments);
if (m_pd_audio->waitForStarted(3000)){
qDebug("AudioMotor| PD started");
emit toTerminal(QString("AudioMotor| PD started"));
}
else
{
emit toTerminal("AudioMotor| Can not init PD");
qErrnoWarning("AudioMotor| Can not init PD");
return false;
}
m_startaudio++;
return true;
}
/** Close the engine
*/
bool AudioMotor::close()
{
disconnect(m_pd_audio, SIGNAL(readyReadStandardError()), this, SLOT(stdout()));
disconnect(m_pd_audio, SIGNAL(finished(int)), this, SLOT(restartAudio()));
m_pd_audio->terminate();
m_pd_audio->waitForFinished(1000);
delete m_pd_audio;
m_pd_audio = NULL;
if (m_writePD != NULL)
{
disconnect(m_writePD, SIGNAL(connected()),this, SLOT(newConexion()));
m_writePD->close();
delete m_writePD;
m_writePD = NULL;
}
if (m_readPD != NULL)
{
disconnect(m_readPD, SIGNAL(newConnection()),this, SLOT(newPeer()));
m_readPD->close();
delete m_readPD;
m_readPD = NULL;
}
/*
QFile socket(SOCKET);
if (socket.exists())
{
socket.remove();
}*/
}
/** Set the numbers of layers
*/
void AudioMotor::setLayers (int layers){
}
/** Get the number of layers
*/
int AudioMotor::getlayers(){
}
/** Load a file in memory
*
*/
bool AudioMotor::load(int layer, QString file)
{
if (!QFile::exists(file))
return false;
QString message = tr("%1 ").arg(layer +201);
message.append("open ");
message.append(file);
message.append(";");
qDebug() << "AudioMotor::load " << message;
if (QAbstractSocket::ConnectedState != m_writePD->state())
{
qErrnoWarning("AudioMotor::load(): Socket not conected: ");
emit toTerminal("AudioMotor::load(): Socket not connectedt");
return false;
}
if (message.size() != m_writePD->write(message.toAscii().constData(), message.size()))
{
qErrnoWarning("AudioMotor::load(): Can not write to socket");
emit toTerminal("AudioMotor::load(): Can not write to socket");
return false;
}
return true;
}
/** Starts the playback at start position
*
*/
bool AudioMotor::play(int layer)
{
QString buffer = tr("%1 %2 %3;").arg(layer).arg(PLAYBACK).arg(PLAY);
if (!sendPacket(buffer.toAscii().constData(), buffer.size()))
{
errorSending();
return false;
}
return true;
}
/** Unpause the playback
*/
bool AudioMotor::pause(int layer)
{
QString buffer = tr("%1 %2 %3;").arg(layer).arg(PLAYBACK).arg(PAUSE);
if (!sendPacket(buffer.toAscii().constData(), buffer.size()))
{
errorSending();
return false;
}
return true;
}
/** Stops/pause the playback
*
*/
bool AudioMotor::stop(int layer)
{
QString buffer = tr("%1 %2 %3;").arg(layer).arg(PLAYBACK).arg(STOP);
if (!sendPacket(buffer.toAscii().constData(), buffer.size()))
{
errorSending();
return false;
}
return true;
}
/** Sets the start playback position
*
*/
void AudioMotor::setEntryPoint(int layer, int entry)
{
}
/** Sets the final playback position
*
*/
void AudioMotor::setExitPoint(int layer, int exit)
{
}
/** Set the volumen in one layer
* @param int vol Normalized 0 to 1
@param int layer the layer which applied
*/
void AudioMotor::setLayerVolume(int layer, float vol)
{
QString buffer = tr("%1 %2 %3;").arg(layer).arg(VOLUME_COARSE).arg(vol);
if (!sendPacket(buffer.toAscii().constData(), buffer.size()))
{
errorSending();
}
}
/** Set pan in one layer
*
* @param int vol Normalized 0 (Left) to 1 (Right)
@param int layer the layer which applied
*/
void AudioMotor::setLayerPan(int layer, float pan)
{
QString buffer = tr("%1 %2 %3;").arg(layer).arg(PAN).arg(pan);
if (!sendPacket(buffer.toAscii().constData(), buffer.size()))
{
errorSending();
}
}
/** Set Volumen master.
* All layers are limited by this master
* 0 will mute all the outputs
*/
void AudioMotor::setMasterVolume(int vol){
}
/** Set pan master
* Will pan the master output of sound
*/
void AudioMotor::setMasterPan(int pan){
}
/** Restart the audio process
*
*/
void AudioMotor::restartAudio()
{
close();
init();
}
/** New conexion on TCP Server
*
*/
void AudioMotor::newPeer()
{
m_connectedSocket = m_readPD->nextPendingConnection();
connect(m_connectedSocket, SIGNAL(readyRead()),this, SLOT(newMessage()));
}
/** New message in a TCP socket stablished connection
*
*/
void AudioMotor::newMessage()
{
if (m_connectedSocket == NULL)
{
qDebug()<<("AudioMotor::newMessage() Socket not connected. Trying open it...");
emit toTerminal("AudioMotor::newMessage() Socket not connected. Trying open it...");
newPeer();
return;
}
QString message = m_connectedSocket->readAll();
parse(message);
}
void AudioMotor::parse(QString message)
{
QStringList list = message.split("\n", QString::SkipEmptyParts);
for (int i = 0; i < list.size(); i ++) {
if (list.at(i).size() > 0) {
qDebug() << "AudioMotor::newMessage() message received: " << list.at(i);
QChar val = list.at(i).at(0);
switch (val.digitValue()) {
case 0:
qDebug() << "AudioMotor::newMessage() Loadbang from PD Audio received";
emit toTerminal("AudioMotor::newMessage() Loadbang from PD Audio received");
// Conectamos a Pure Data para escribir
m_writePD->connectToHost(QHostAddress::LocalHost, SOCKET, QIODevice::WriteOnly);
if (m_writePD->waitForConnected(30000))
emit loadbang();
break;
case 9:
if (list.at(i).at(2).digitValue() == 0) {
if (list.at(i).at(7).isDigit() )
emit (volChanged(list.at(i).at(4).digitValue(), ( ( list.at(i).at(6).digitValue() * 10 ) + list.at(i).at(7).digitValue() ) ) );
else
emit (volChanged(list.at(i).at(4).digitValue(), ( ( list.at(i).at(6).digitValue() ) ) ) );
}
break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
QStringList folders = list.at(i).split("/", QString::SkipEmptyParts);
if (folders.size() >= 2)
emit (mediaLoaded(val.digitValue(), folders.at(folders.size() -2), folders.at(folders.size() -1)));
break;
}
}
}
}
/** Error writing to PD
*
*/
void AudioMotor::errorWrite(QAbstractSocket::SocketError error)
{
// QString error = m_writePD->errorString();
qErrnoWarning(QString("AudioMotor::errorWrite() %1").arg(error).toLatin1());
emit toTerminal(QString("AudioMotor::errorWrite() ") + error);
}
/** Sends packets to Pure Data audio
*
*/
bool AudioMotor::sendPacket(const char *buffer, int bufferLen)
{
if (m_writePD == NULL) {
return false;
}
if (QAbstractSocket::ConnectedState != m_writePD->state())
{
return false;
}
if (bufferLen != m_writePD->write((const char*)buffer, bufferLen))
{
return false;
}
return true;
}
// Function error sending packets to PD audio
void AudioMotor::errorSending() {
qDebug() << "AudioMotor| Can not send packets to PD";
emit toTerminal("AudioMotor| Can not send packets to PD");
}

View file

@ -1,143 +0,0 @@
#ifndef AUDIOMOTOR_H
#define AUDIOMOTOR_H
#include <QObject>
#include <QtDebug>
#include <QtNetwork>
#include <QTcpServer>
#include <QLocalSocket>
#include <QTcpSocket>
#include <QChar>
#include "dmxPersonality.h"
#define PDPORT 9198
#define SOCKET 9197 // "/tmp/socket"
class AudioMotor : public QObject
{
Q_OBJECT
public:
static AudioMotor *getInstance();
/** Init the engine
*/
bool init();
/** Close the engine
*/
bool close();
/** Set the numbers of layers
*/
void setLayers (int layers);
/** Get the number of layers
*/
int getlayers();
/** Load a file in memory
*
*/
bool load(int layer, QString file);
/** Starts the playback at start position
*
*/
bool play(int layer);
/** Pause/unpause the playback
*/
bool pause(int layer);
/** Stops the playback and reset the media to the start position
*
*/
bool stop(int layer);
/** Sets the start playback position
*
*/
void setEntryPoint(int layer, int entry);
/** Sets the final playback position
*
*/
void setExitPoint(int layer, int exit);
/** Set the volumen in one layer
*
*/
void setLayerVolume(int layer, float vol);
/** Set pan in one layer
*/
void setLayerPan(int layer, float pan);
/** Set Volumen master.
* All layers are limited by this master
* 0 will mute all the outputs
*/
void setMasterVolume(int vol);
/** Set pan master
* Will pan the master output of sound
*/
void setMasterPan(int pan);
inline void setGui(bool gui) { m_gui = gui; }
private:
AudioMotor(QObject *parent = 0);
virtual ~AudioMotor();
static AudioMotor *_instance;
bool m_gui;
int m_layersNumber;
QProcess *m_pd_audio; // Pure Data process for audio
// Audio TCP Sockets
QTcpSocket *m_writePD;
QTcpServer *m_readPD;
QTcpSocket *m_connectedSocket; // connected socket to server
int m_startaudio; // Counter starts audio engine. Debugging purpose
bool sendPacket(const char *buffer, int bufferLen);
void errorSending();
void parse(QString message);
signals:
void loadbang();
void newConnection();
void mediaLoaded(int layer, QString folder, QString file);
void volChanged(int layer, int vol);
void toTerminal(QString message);
private slots:
void newPeer();
inline void newConexion() { qDebug() << "AudioMotor write socket connected to PD"; }
void restartAudio();
void newMessage();
void errorWrite(QAbstractSocket::SocketError error);
/**
*
* Listen the terminal exit of PD
*
*/
// Sacamos la salida de Pure Data Audio en la terminal
inline void stdout() {
QString out = m_pd_audio->readAllStandardError();
out.chop(1);
if (!out.isEmpty())
{
qDebug() << "AudioMotor from PD: " << out;
}
}
};
#endif // AUDIOMOTOR_H

View file

@ -12,20 +12,40 @@ AudioWidget::AudioWidget(QWidget *parent) :
qDebug( "Init AudioWidget"); qDebug( "Init AudioWidget");
} }
void AudioWidget::mediaLoaded(int layer, QString folder, QString file) void AudioWidget::mediaLoaded(int layer, QString media)
{ {
QLayoutItem * const item = layout->itemAt(layer - 1); QLayoutItem * const item = layout->itemAt(layer);
qDebug() << "AudioWidget::mediaLoaded Received layer: " << layer dynamic_cast<AudioLayerWidget *>(item->widget())->loadMedia(media);
<< "Folder: " << folder /* qDebug() << "AudioWidget::mediaLoaded Received layer: " << layer
<<"File : " << file; << "Media: " << media; */
dynamic_cast<AudioLayerWidget *>(item->widget())->setFolder(folder);
dynamic_cast<AudioLayerWidget *>(item->widget())->setFile(file);
} }
void AudioWidget::volChanged(int layer, int vol) { void AudioWidget::volChanged(int layer, qreal vol) {
QLayoutItem * const item = layout->itemAt(layer - 1); QLayoutItem * const item = layout->itemAt(layer);
qDebug() << "AudioWidget::volChanged Received layer: " << layer /* qDebug() << "AudioWidget::volChanged Received layer: " << layer
<< "Vol : " << vol; << "Vol : " << vol; */
dynamic_cast<AudioLayerWidget *>(item->widget())->setVol(vol); dynamic_cast<AudioLayerWidget *>(item->widget())->setVol(vol);
} }
void AudioWidget::playbackChanged(int layer, QAudio::State state)
{
QLayoutItem * const item = layout->itemAt(layer);
switch (state) {
case QAudio::ActiveState:
dynamic_cast<AudioLayerWidget *>(item->widget())->play();
break;
case QAudio::StoppedState:
dynamic_cast<AudioLayerWidget *>(item->widget())->pause();
break;
case QAudio::SuspendedState:
dynamic_cast<AudioLayerWidget *>(item->widget())->resume();
case QAudio::IdleState:
break;
}
}
void AudioWidget::layerReceived(int layer)
{
QLayoutItem * const item = layout->itemAt(layer);
dynamic_cast<AudioLayerWidget *>(item->widget())->updateWatchDMX(true);
}

View file

@ -10,25 +10,21 @@
class AudioWidget : public QWidget class AudioWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
AudioWidget(QWidget *parent); AudioWidget(QWidget *parent);
private: private:
// QList<AudioLayerWidget*> *list;
QHBoxLayout *layout; QHBoxLayout *layout;
signals: signals:
public slots: public slots:
void mediaLoaded(int layer, QString folder, QString file); void mediaLoaded(int layer, QString media);
void volChanged(int layer, int vol); void volChanged(int layer, qreal vol);
void playbackChanged(int layer, QAudio::State state);
void layerReceived(int layer);
}; };
#endif // AUDIOWIDGET_H #endif // AUDIOWIDGET_H

View file

@ -1,8 +1,61 @@
#ifndef DEFINES_H #ifndef DEFINES_H
#define DEFINES_H #define DEFINES_H
#define VERSION "Libre Media Server Audio 0.1.0"
#define COPYRIGHT "(C) 2014 Santi Norena libremediaserver@gmail.com"
#define LICENSE "GPL 3 License. See LICENSE.txt and credits.txt for details"
#define LAYERS_NUMBER 4 #define LAYERS_NUMBER 4
#define DEFAULT_FILE "lms-audio.xlm"
const int DurationSeconds = 1;
const int ToneSampleRateHz = 600;
const int DataSampleRateHz = 44100;
const int BufferSize = 262144;
#define SUSPEND_LABEL "Pause playback"
#define RESUME_LABEL "Resume playback"
#define PLAY_LABEL "Playing"
#define STOP_LABEL "Stopped"
#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 TOTAL_TIME_LABEL "Total"
#define FILE_LABEL "File: "
#define FOLDER_LABEL "Folder: "
#define STATUS_LABEL " Status: "
#define NOTIFY_INTERVAL 150
#define PULL_TIMER_INTERVAL 10
// struct where save the DMX settings for each layer
struct dmxSetting {
int address;
uint universe;
bool updated;
int layer;
};
// Media Information for MELIn packages. v1.0
struct MediaFile {
quint8 Number; // 0-based contiguous index of the media.
QString MediaName;// Media name.
quint32 MediaLength;// Media length (in frames).
};
// Media Library for ELin packages v1.0
struct MediaFolder {
quint8 m_Id; // Library id.
QString m_Name;// Library name.
quint8 m_ElementCount;// Number of elements in the library.
QList<MediaFile> m_MediaInformation; // Pointer to the Medias Information List of this Library
};
#endif // DEFINES_H #endif // DEFINES_H

View file

@ -18,6 +18,11 @@
*/ */
#include "libremediaserver-audio.h" #include "libremediaserver-audio.h"
QTextEdit * libreMediaServerAudio::textEdit = 0;
/** /**
/ Constructor / Constructor
*/ */
@ -25,39 +30,45 @@
libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent) libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent)
: QMainWindow(parent) : QMainWindow(parent)
{ {
qDebug() << "********************************************************************************"; Q_UNUSED(args);
qDebug() << QDate::currentDate() << QTime::currentTime();
qDebug() << VERSION;
qDebug() << COPYRIGHT;
qDebug() << LICENSE;
// Inicia el User Interface
ui.setupUi(this); ui.setupUi(this);
// Inicia el widget Terminal
textEdit = new QTextEdit(this);
textEdit->append(QString::fromAscii(VERSION));
textEdit->append(QString::fromAscii(LICENSE));
textEdit->append(QString::fromAscii(COPYRIGHT));
QDockWidget *bottomWidget = new QDockWidget(tr("Terminal"), this);
bottomWidget->setAllowedAreas(Qt::BottomDockWidgetArea);
bottomWidget->setWidget(textEdit);
addDockWidget(Qt::BottomDockWidgetArea, bottomWidget);
// Inicia la lectura de dmx a través de ola // Inicia la lectura de dmx a través de ola
ola = new olaThread(); ola = new olaThread();
Q_CHECK_PTR(ola); Q_CHECK_PTR(ola);
connect(ola, SIGNAL(toTerminal(QString)),
this, SLOT(toTerminal(QString))); if (args.contains("-log")) {
ola->start(QThread::TimeCriticalPriority ); // Inicia el widget Terminal
ola->blockSignals(true); textEdit = new QTextEdit;
textEdit->setReadOnly(true);
QDockWidget *bottomWidget = new QDockWidget(tr("Terminal"), this);
bottomWidget->setAllowedAreas(Qt::BottomDockWidgetArea);
bottomWidget->setWidget(textEdit);
addDockWidget(Qt::BottomDockWidgetArea, bottomWidget);
connect(ola, SIGNAL(toTerminal(QString)),
textEdit, SLOT(append(QString)), Qt::QueuedConnection);
}
this->setWindowTitle(VERSION);
// qDebug() << QDate::currentDate().toString() << " "<< QTime::currentTime().toString();
qDebug() << VERSION;
qDebug() << COPYRIGHT;
qDebug() << LICENSE;
// Inicia el widget central de audio // Inicia el widget central de audio
aw = new AudioWidget(this); aw = new AudioWidget(this);
setCentralWidget(aw); setCentralWidget(aw);
// Inicia la lectur de datos DMX
ola->blockSignals(true);
ola->start(QThread::TimeCriticalPriority );
/* connect(MediaLibrary::getInstance(), SIGNAL(debug(QString)),
textEdit, SLOT(append(QString)), Qt::QueuedConnection);
connect(MediaLibrary::getInstance(), SIGNAL(warning(QString)),
textEdit, SLOT(append(QString)), Qt::QueuedConnection);
*/
// Inicia el widget Master. No implementado todavía // Inicia el widget Master. No implementado todavía
/* /*
amw = new AudioMasterWidget(this); amw = new AudioMasterWidget(this);
@ -66,22 +77,6 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent)
topWidget->setWidget(amw); topWidget->setWidget(amw);
addDockWidget(Qt::TopDockWidgetArea, topWidget); addDockWidget(Qt::TopDockWidgetArea, topWidget);
*/ */
// Parse the command line options
if (args.contains("-gui"))
{
qDebug()<< "libremediaserver Constructor option GUI detected";
AudioMotor::getInstance()->setGui(true);
textEdit->append("Pure Data GUI's will be shown");
} else { AudioMotor::getInstance()->setGui(false); }
connect(AudioMotor::getInstance(), SIGNAL(toTerminal(QString)),
this, SLOT(toTerminal(QString)));
if (args.contains("-log"))
{
textEdit->append("Log to file");
}
// Conectamos los menus // Conectamos los menus
connect(ui.actionOpen_conf, SIGNAL(triggered()), this, SLOT(openFile())); connect(ui.actionOpen_conf, SIGNAL(triggered()), this, SLOT(openFile()));
connect(ui.actionSave_conf, SIGNAL(triggered()), this, SLOT(saveFile())); connect(ui.actionSave_conf, SIGNAL(triggered()), this, SLOT(saveFile()));
@ -90,30 +85,19 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent)
Settings *set = new Settings(); Settings *set = new Settings();
// Iniciamos Pure Data
AudioMotor::getInstance()->init();
connect(set, SIGNAL( layersNumber(int)), connect(set, SIGNAL( layersNumber(int)),
ola, SLOT( setLayersNumber(int))); ola, SLOT( setLayersNumber(int)));
connect(set, SIGNAL( DMXConf(dmxSetting ) ), connect(set, SIGNAL( DMXConf(dmxSetting ) ),
ola, SLOT( setDMXConf(dmxSetting) ) ); ola, SLOT( setDMXConf(dmxSetting) ) );
connect(ola, SIGNAL (layerReceived(int)),
connect(AudioMotor::getInstance(), SIGNAL(mediaLoaded(int, QString, QString)), aw, SLOT(layerReceived(int)));
aw, SLOT(mediaLoaded(int, QString, QString)));
connect(AudioMotor::getInstance(), SIGNAL(volChanged(int, int)),
aw, SLOT(volChanged(int, int)));
connect(AudioMotor::getInstance(), SIGNAL(loadbang()),
this, SLOT (loadbang()));
connect(ola, SIGNAL( dmxOutput(int, int, int) ),
this, SLOT( dmxInput(int, int, int) ) );
// Lee la configuración por defecto // Lee la configuración por defecto
set->readDefaultFile(); set->readDefaultFile();
ola->blockSignals(false); ola->blockSignals(false);
connect(ola, SIGNAL( dmxOutput(int, int, int) ),
this, SLOT( dmxInput(int, int, int) ) );
ola->resendDmx();
} }
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
@ -123,13 +107,11 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent)
libreMediaServerAudio::~libreMediaServerAudio() libreMediaServerAudio::~libreMediaServerAudio()
{ {
// save_finish(); // save_finish();
delete MediaLibrary::getInstance(); // delete MediaLibrary::getInstance();
ola->stop(); // ola->stop();
AudioMotor::getInstance()->close(); // qDebug() << QDate::currentDate().toString() << " " << QTime::currentTime().toString();
// qDebug() << "PD Audio restarts: " << m_startaudio; // qDebug() << "********************************************************************************";
qDebug() << QDate::currentDate() << QTime::currentTime(); // return;
qDebug() << "********************************************************************************";
return;
} }
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
@ -171,7 +153,7 @@ void libreMediaServerAudio::ChangeMediaPath()
QString file = fileNames.at(0); QString file = fileNames.at(0);
MediaLibrary::getInstance()->setPath(file); MediaLibrary::getInstance()->setPath(file);
QString desc = tr("Media Path Changed to: %1").arg(m_pathmedia); QString desc = tr("Media Path Changed to: %1").arg(m_pathmedia);
textEdit->append(desc.toAscii()); textEdit->append(desc);
} }
@ -193,49 +175,51 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value)
{ {
// This qDebug slows all the program. Uncomment only for debugging purpouse and comment again in normal use // This qDebug slows all the program. Uncomment only for debugging purpouse and comment again in normal use
// qDebug() << tr("olaInterface|") << "newdmx layer" << layer << "channel" << channel << "value" << value; // qDebug() << tr("olaInterface|") << "newdmx layer" << layer << "channel" << channel << "value" << value;
if (layer > LAYER_CHANNELS)
return;
QString mediaFile = NULL; QString mediaFile = NULL;
int aux; int aux;
float f; qreal f;
switch(channel){ switch(channel){
case DMX_FOLDER:// Folder case DMX_FOLDER:// Folder
aux = ola->getValue(layer, DMX_FILE); aux = ola->getValue(layer, DMX_FILE);
mediaFile = MediaLibrary::getInstance()->requestNewFile(value, aux); mediaFile = MediaLibrary::getInstance()->requestNewFile(value, aux);
if (QFile::exists(mediaFile)) if (QFile::exists(mediaFile))
AudioMotor::getInstance()->load(layer, mediaFile); aw->mediaLoaded(layer, mediaFile);
break; break;
case DMX_FILE:// File case DMX_FILE:// File
aux = ola->getValue(layer, DMX_FOLDER); aux = ola->getValue(layer, DMX_FOLDER);
mediaFile = MediaLibrary::getInstance()->requestNewFile(aux, value); mediaFile = MediaLibrary::getInstance()->requestNewFile(aux, value);
if (QFile::exists(mediaFile)) if (QFile::exists(mediaFile))
AudioMotor::getInstance()->load(layer, mediaFile); aw->mediaLoaded(layer, mediaFile);
break; break;
case VOLUME_COARSE: case VOLUME_COARSE:
f = ( value * 0x100 ) + ola->getValue(layer, VOLUME_FINE); f = ( value * 0x100 ) + ola->getValue(layer, VOLUME_FINE);
AudioMotor::getInstance()->setLayerVolume(layer, f/65535); aw->volChanged(layer, f / 65535);
break; break;
case VOLUME_FINE: case VOLUME_FINE:
f = ( ola->getValue(layer, VOLUME_COARSE) * 0x100 ) + value; f = ( ola->getValue(layer, VOLUME_COARSE) * 0x100 ) + value;
AudioMotor::getInstance()->setLayerVolume(layer, f/65535); aw->volChanged(layer, f / 655.35);
break; break;
case PAN: case PAN:
f = (float)value / 255; f = (float)value / 255;
AudioMotor::getInstance()->setLayerPan(layer, f );
break; break;
case PLAYBACK: case PLAYBACK:
if (value == 0)
break;
aux = value / 25; aux = value / 25;
switch (aux) { switch (aux) {
case 0 : case 0 :
AudioMotor::getInstance()->play(layer); aw->playbackChanged(layer, QAudio::ActiveState);
break; break;
case 1 : case 1 :
AudioMotor::getInstance()->stop(layer); aw->playbackChanged(layer, QAudio::StoppedState);
break; break;
case 2 : case 2 :
AudioMotor::getInstance()->pause(layer); aw->playbackChanged(layer, QAudio::SuspendedState);
break; break;
} }
default: default:
// emit dmxInput(layer, channel, value);
break; break;
} }
} }

View file

@ -16,15 +16,11 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef LIBREMEDIASERVER_H #ifndef LIBREMEDIASERVERAUDIO_H
#define LIBREMEDIASERVER_H #define LIBREMEDIASERVERAUDIO_H
#include <QMainWindow> #include <QMainWindow>
//#include <QApplication> #include <QDockWidget>
#include <QObject>
#include <QDesktopWidget>
#include <QtGui>
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
#include <QFileDialog> #include <QFileDialog>
@ -35,20 +31,14 @@
#include <QTextEdit> #include <QTextEdit>
#include "settings.h" #include "settings.h"
#include "audiomotor.h"
#include "olathread.h" #include "olathread.h"
#include "audiolayerwidget.h"
#include "audiomasterwidget.h" #include "audiomasterwidget.h"
#include "audiowidget.h" #include "audiowidget.h"
#include "defines.h"
#include "ui_libremediaserver-audio.h" #include "ui_libremediaserver-audio.h"
#define VERSION "LibreMediaServer-Audio Version 0.1.0"
#define COPYRIGHT "(C) 2014 Santi Norena libremediaserver@gmail.com"
#define LICENSE "GPL 3 License. See LICENSE.txt and credits.txt for details"
class QMenu; class QMenu;
//class QProcess;
class libreMediaServerAudio : public QMainWindow class libreMediaServerAudio : public QMainWindow
{ {
@ -61,35 +51,26 @@ public:
Ui::LibreMediaServerAudio ui; Ui::LibreMediaServerAudio ui;
static QTextEdit *textEdit; // Terminal de feedback
protected: protected:
QString m_pathmedia; // Path to Medias QString m_pathmedia; // Path to Medias
QProcess *m_ola; // OLA daemon process
bool m_gui;
private: private:
QTextEdit *textEdit; // Terminal de feedback // void MessageHandler(QtMsgType type, const QMessageLogContext &logcontext, const QString &msg);
AudioMasterWidget *amw; AudioMasterWidget *amw;
// AudioLayerWidget *alw;
AudioWidget *aw; AudioWidget *aw;
olaThread *ola; olaThread *ola;
void open_start(); void open_start();
void save_finish(); void save_finish();
void open(QFile *file); void open(QFile *file);
void save(QFile *file); void save(QFile *file);
// void MessageHandler(QtMsgType type, const char *msg);
public slots: public slots:
// inline void toTerminal(QString msg) { textEdit->append(msg); }
inline void toTerminal (QString message)
{
textEdit->append(message);
}
private slots: private slots:
@ -98,16 +79,13 @@ private slots:
*/ */
void loadbang(); void loadbang();
void olasetup(); void olasetup();
void dmxInput(int layer, int channel, int value); void dmxInput(int layer, int channel, int value);
// Menu File // Menu File
void openFile(); void openFile();
void saveFile(); void saveFile();
void ChangeMediaPath();// Change the path to medias void ChangeMediaPath();// Change the path to medias
}; };
#endif // LIBREMEDIASERVER_H #endif // LIBREMEDIASERVERAUDIO_H

View file

@ -1,36 +1,39 @@
TEMPLATE = app TEMPLATE = app
TARGET = libremediaserver-audio TARGET = libremediaserver-audio
QT += network script webkit
QT += network script webkitwidgets widgets multimedia
CONFIG += debug CONFIG += debug
DESTDIR = ./debug DESTDIR = ./debug
HEADERS += libremediaserver-audio.h \ HEADERS += libremediaserver-audio.h \
medialibrary.h \ medialibrary.h \
audiomotor.h \
olathread.h \ olathread.h \
audiolayerwidget.h \ audiolayerwidget.h \
dmxPersonality.h \ dmxPersonality.h \
audiowidget.h \ audiowidget.h \
audiomasterwidget.h \ audiomasterwidget.h \
defines.h \ defines.h \
settings.h settings.h \
audiodecoder.h
SOURCES += main.cpp \ SOURCES += main.cpp \
libremediaserver-audio.cpp \ libremediaserver-audio.cpp \
medialibrary.cpp \ medialibrary.cpp \
audiomotor.cpp \
olathread.cpp \ olathread.cpp \
audiolayerwidget.cpp \ audiolayerwidget.cpp \
audiowidget.cpp \ audiowidget.cpp \
audiomasterwidget.cpp \ audiomasterwidget.cpp \
settings.cpp settings.cpp \
audiodecoder.cpp
FORMS += \ FORMS += \
libremediaserver-audio.ui libremediaserver-audio.ui
#INCLUDEPATH += ./ #INCLUDEPATH += ./
LIBS += -L./debug -lola -lolacommon LIBS += -lola -lolacommon
# -L./debug
#win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../debug/release/ -lcitp #win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../debug/release/ -lcitp
#else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../debug/debug/ -lcitp #else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../debug/debug/ -lcitp
@ -41,7 +44,6 @@ LIBS += -L./debug -lola -lolacommon
RESOURCES = RESOURCES =
OTHER_FILES += \ OTHER_FILES += \
../LICENSE.txt \ ../LICENSE.txt \
../instalacion.txt \ ../instalacion.txt \

View file

@ -19,38 +19,25 @@
*/ */
#include <QApplication> #include <QApplication>
#include <QMutex>
#include <QMutexLocker>
#include "libremediaserver-audio.h" #include "libremediaserver-audio.h"
// Handler for pipe the stderr to a log file // Handler for pipe the stderr to a log file and texEdit
bool initMessageHandler = false; bool initMessageHandler = false;
QFile outFile; QFile outFile;
QMutex mutex;
//QMutexLocker mutexLocker(mutex);
void MessageHandler(QtMsgType type, const char *msg) void MessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{ {
QString txt; Q_UNUSED(context);
switch (type) { // mutex.lock();
case QtDebugMsg:
txt = QString("Debug: %1").arg(msg);
break;
case QtWarningMsg:
txt = QString("Warning: %1").arg(msg);
break;
case QtCriticalMsg:
txt = QString("Critical: %1").arg(msg);
break;
case QtFatalMsg:
txt = QString("Fatal: %1").arg(msg);
abort();
}
// Create the log dir and log file // Create the log dir and log file
if (!initMessageHandler) /* if (!initMessageHandler) {
{
QDir dir; QDir dir;
if (!dir.exists("log")) if (!dir.exists("log")) {
{ if (!dir.mkdir("log")) {
if (!dir.mkdir("log"))
{
qDebug()<<"MessageHandler: Can not create log folder"; qDebug()<<"MessageHandler: Can not create log folder";
return; return;
} }
@ -62,57 +49,127 @@ void MessageHandler(QtMsgType type, const char *msg)
filename.append(date.toString("ddMMyy-")); filename.append(date.toString("ddMMyy-"));
filename.append(time.toString("hhmmss.txt")); filename.append(time.toString("hhmmss.txt"));
outFile.setFileName(filename); outFile.setFileName(filename);
if (!outFile.open(QIODevice::WriteOnly | QIODevice::Append)) if (!outFile.open(QIODevice::WriteOnly | QIODevice::Append)) {
{ qWarning("main/MessageHandler/Qfile::open: can not open log file");
qDebug()<<"main/MessageHandler/Qfile::open: can not open log file";
return; return;
} }
initMessageHandler = true; initMessageHandler = true;
} }
QTextStream ts(&outFile); QTextStream ts(&outFile);*/
ts << txt << endl; if (libreMediaServerAudio::textEdit == 0)
{
QByteArray localMsg = msg.toLocal8Bit();
switch (type) {
case QtDebugMsg:
fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
break;
case QtWarningMsg:
fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
break;
case QtCriticalMsg:
fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
break;
case QtFatalMsg:
fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), context.file, context.line, context.function);
abort();
}
}
else
{
QString txt;
switch (type) {
case QtDebugMsg:
txt.append("Debug from File: ");
txt.append(context.file);
txt.append(" Line: ");
txt.append(QString::number(context.line));
txt.append(" Function: ");
txt.append(context.function);
txt.append(" Message: ");
txt.append(msg);
// libreMediaServerAudio::textEdit->append(msg);, context.file, context.line, context.function);
libreMediaServerAudio::textEdit->append(txt);
break;
case QtWarningMsg:
txt.append("Warning from File: ");
txt.append(context.file);
txt.append(" Line: ");
txt.append(QString::number(context.line));
txt.append(" Function: ");
txt.append(context.function);
txt.append(" Message: ");
txt.append(msg);
// libreMediaServerAudio::textEdit->append(msg);, context.file, context.line, context.function);
libreMediaServerAudio::textEdit->append(txt);
abort();
break;
case QtCriticalMsg:
// txt.append("Critical from File: ");
txt.append(context.file);
txt.append(" Line: ");
txt.append(QString::number(context.line));
txt.append(" Function: ");
txt.append(context.function);
txt.append(" Message ");
txt.append(msg);
// libreMediaServerAudio::textEdit->append(msg);, context.file, context.line, context.function);
libreMediaServerAudio::textEdit->append(txt);
abort();
break;
case QtFatalMsg:
// txt.append("Fatal from File: ");
txt.append(context.file);
txt.append(" Line: ");
txt.append(QString::number(context.line));
txt.append(" Function: ");
txt.append(context.function);
txt.append(" Message: ");
txt.append(msg);
// libreMediaServerAudio::textEdit->append(msg);, context.file, context.line, context.function);
libreMediaServerAudio::textEdit->append(txt);// ts << txt << endl;
abort();
}
// outFile.write(txt.toLatin1().constData(), txt.size());
// ts << txt << endl;
// libreMediaServerAudio::textEdit->append(txt);
}
// mutex.unlock();
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
// ToDo: discriminar niveles de log y log a fichero segúna argumentos
/*
if (args.contains("-log"))
{
qInstallMessageHandler(MessageHandler);
}*/
qInstallMessageHandler(MessageHandler);
QApplication app(argc, argv); QApplication app(argc, argv);
QStringList args = app.arguments(); QStringList args = app.arguments();
// parse the command line // parse the command line
if (args.size() > 1) if (args.size() > 1)
{ {
if (args.contains("-v") > 0) if (args.contains("-v"))
{ {
qDebug() << VERSION; qDebug() << VERSION;
qDebug() << COPYRIGHT; qDebug() << COPYRIGHT;
qDebug() << LICENSE; qDebug() << LICENSE;
return 0; return 0;
} }
if (args.contains("-h") > 0) if (args.contains("-h"))
{ {
qDebug() << VERSION; qDebug() << VERSION;
qDebug() << COPYRIGHT; qDebug() << COPYRIGHT;
qDebug() << LICENSE; qDebug() << LICENSE;
qDebug() << "Help for command line options:"; qDebug() << "Help for command line options:";
qDebug() << "-v show the version and exits"; qDebug() << "-v show the version and exits";
qDebug() << "-gui show the Pure Data GUI's";
qDebug() << "-log write the debug information to a log file instead stderr"; qDebug() << "-log write the debug information to a log file instead stderr";
qDebug() << "-h this help"; qDebug() << "-h this help";
return 0; return 0;
} }
if (args.contains("-log"))
{
qInstallMsgHandler(MessageHandler);
}
if (!args.contains("-gui"))
{
for (int i=1; i<args.size();i++)
{
qDebug() << "Option not known: " << args.at(i);
}
qDebug() <<"Write ./libremediaserver-audio -h for help in command line arguments";
return 0;
}
} }
libreMediaServerAudio libreMediaServerAudio(args); libreMediaServerAudio libreMediaServerAudio(args);
libreMediaServerAudio.show(); libreMediaServerAudio.show();

View file

@ -1,5 +1,6 @@
#include "medialibrary.h" #include "medialibrary.h"
#include <QDebug>
MediaLibrary *MediaLibrary::_instance = 0; MediaLibrary *MediaLibrary::_instance = 0;
@ -26,8 +27,7 @@ MediaLibrary::MediaLibrary(QObject *parent) :
void MediaLibrary::initMediaLibrary() { void MediaLibrary::initMediaLibrary() {
QDir dir; QDir dir;
if (!dir.cd(m_pathmedia)) { if (!dir.cd(m_pathmedia)) {
qWarning("olaInterface::initMediaLibrary| Can not cd to the path: "); qWarning("Can not cd to the path: %s", m_pathmedia.toLatin1().constData());
qWarning(m_pathmedia.toAscii().constData());
return; return;
} }
m_media = new QList<MediaFolder>; m_media = new QList<MediaFolder>;
@ -88,5 +88,3 @@ QString MediaLibrary::requestNewFile(int folder, int file){
} }
return newfile; return newfile;
} }

View file

@ -4,21 +4,7 @@
#include <QObject> #include <QObject>
#include <QDir> #include <QDir>
// Media Information for MELIn packages. v1.0 #include "defines.h"
struct MediaFile {
quint8 Number; // 0-based contiguous index of the media.
QString MediaName;// Media name.
quint32 MediaLength;// Media length (in frames).
};
// Media Library for ELin packages v1.0
struct MediaFolder {
quint8 m_Id; // Library id.
QString m_Name;// Library name.
quint8 m_ElementCount;// Number of elements in the library.
QList<MediaFile> m_MediaInformation; // Pointer to the Medias Information List of this Library
};
class MediaLibrary : public QObject class MediaLibrary : public QObject
{ {
@ -28,7 +14,6 @@ public:
static MediaLibrary *getInstance(); static MediaLibrary *getInstance();
inline void setPath(QString path) { m_pathmedia = path; rescanMediaLibrary();} inline void setPath(QString path) { m_pathmedia = path; rescanMediaLibrary();}
QString requestNewFile(int folder, int layer); QString requestNewFile(int folder, int layer);
private: private:
@ -36,13 +21,11 @@ private:
explicit MediaLibrary(QObject *parent = 0); explicit MediaLibrary(QObject *parent = 0);
static MediaLibrary *_instance; static MediaLibrary *_instance;
inline QString getPath () { return m_pathmedia; } // Get the path to the medias folder tree. inline QString getPath () { return m_pathmedia; } // Get the path to the medias folder tree.
inline void deleteMediaLibrary() { delete m_media; m_media = NULL; } inline void deleteMediaLibrary() { delete m_media; m_media = NULL; }
/** /**
* Change library/path * Change library/path
*/ */
inline void rescanMediaLibrary() inline void rescanMediaLibrary() {
{
deleteMediaLibrary(); deleteMediaLibrary();
initMediaLibrary(); initMediaLibrary();
} }
@ -54,8 +37,6 @@ private:
/** Called when there is a change in the channels folder or file /** Called when there is a change in the channels folder or file
* this is called. Creates a new source. * this is called. Creates a new source.
*/ */
QList<MediaFile> getMediaInformation(QDir dir); // Get all the information of each media file in a dir QList<MediaFile> getMediaInformation(QDir dir); // Get all the information of each media file in a dir
signals: signals:

View file

@ -1,9 +1,8 @@
#include "olathread.h" #include "olathread.h"
olaThread::olaThread(QObject *parent) olaThread::olaThread(QObject *parent)
// : QObject(parent)
{ {
Q_UNUSED(parent);
m_universe = new QList<int>(); m_universe = new QList<int>();
m_counter = 0; m_counter = 0;
gettimeofday(&m_last_data, NULL); gettimeofday(&m_last_data, NULL);
@ -21,11 +20,6 @@ olaThread::olaThread(QObject *parent)
m_dmx[i][j] = 0; m_dmx[i][j] = 0;
} }
} }
/* int argc = 1;
char argv[] = "-l 3";
if (!ola::AppInit (&argc, &argv,"LMS", "DMX sound media server"))
qCritical("Can not init ola");*/
// set up ola connection // set up ola connection
m_clientWrapper = new ola::client::OlaClientWrapper; m_clientWrapper = new ola::client::OlaClientWrapper;
Q_CHECK_PTR(m_clientWrapper); Q_CHECK_PTR(m_clientWrapper);
@ -34,7 +28,7 @@ olaThread::olaThread(QObject *parent)
ola::InitLogging(ola::OLA_LOG_INFO , ola::OLA_LOG_STDERR); ola::InitLogging(ola::OLA_LOG_INFO , ola::OLA_LOG_STDERR);
m_client->SetDMXCallback(ola::NewCallback(this, &olaThread::NewDmx)); m_client->SetDMXCallback(ola::NewCallback(this, &olaThread::NewDmx));
m_clientWrapper->GetSelectServer()->RegisterRepeatingTimeout(4000, ola::NewCallback(this, &olaThread::CheckDataLoss)); m_clientWrapper->GetSelectServer()->RegisterRepeatingTimeout(4000, ola::NewCallback(this, &olaThread::CheckDataLoss));
qDebug() << "Init olaThread"; // qDebug() << "Init olaThread";
} }
// --- DECONSTRUCTOR --- // --- DECONSTRUCTOR ---
@ -45,13 +39,9 @@ olaThread::~olaThread() {
/** Open the connection with olad and start processing data. /** Open the connection with olad and start processing data.
*/ */
void olaThread::run() { void olaThread::run()
{
/* register the universe // qDebug() << tr("olaThread| Running");
if (!m_client->RegisterUniverse(m_universe, ola::REGISTER,ola::NewSingleCallback(&RegisterComplete))) {
qDebug() << "Can not register universe %1".arg(m_universe);
}*/
qDebug() << tr("olaThread| Running");
emit toTerminal("Reading DMX"); emit toTerminal("Reading DMX");
m_clientWrapper->GetSelectServer()->Run(); m_clientWrapper->GetSelectServer()->Run();
} }
@ -77,27 +67,27 @@ void olaThread::stop()
*/ */
// ToDo: It can be more efficient making the dmx buffer a DmxBuffer class instead a int array and compare with the new if there is changes at start. Also all access to the buffer it should be get/set. I should profile this // ToDo: It can be more efficient making the dmx buffer a DmxBuffer class instead a int array and compare with the new if there is changes at start. Also all access to the buffer it should be get/set. I should profile this
// typedef Callback2<void, const DMXMetadata&, const DmxBuffer&> ola::client::RepeatableDMXCallback // typedef Callback2<void, const DMXMetadata&, const DmxBuffer&> ola::client::RepeatableDMXCallback
void olaThread::NewDmx(const ola::client::DMXMetadata &data, void olaThread::NewDmx(const ola::client::DMXMetadata &data,
const ola::DmxBuffer &buffer) const ola::DmxBuffer &buffer)
{ {
m_counter++; m_counter++;
gettimeofday(&m_last_data, NULL); gettimeofday(&m_last_data, NULL);
int universe = data.universe; uint universe = data.universe;
for (int i = 0; i < m_layersNumber; i++) { // loop for reading the channels by layer. for (int i = 0; i < m_layersNumber; i++) { // loop for reading the channels by layer.
if((m_settings.at(i).universe == universe) if(m_settings.at(i).universe == universe) { // Compare if the layer is from this universe
&& ( m_settings.at(i).address > -1 )) { // Compare if the layer is from this universe if ( m_settings.at(i).address > -1 ) { // AND if the DMX address is 0 or greater, process this layer.
// AND if the DMX address is 0 or greater, process this layer. emit layerReceived(i);
for (int j = 0; j < LAYER_CHANNELS; j++){ for (int j = 0; j < LAYER_CHANNELS; j++){
int value = buffer.Get((m_settings.at(i).address) + j); // Get the value for this channel. int value = buffer.Get((m_settings.at(i).address) + j); // Get the value for this channel.
if (m_dmx[i][j] != value) { // Compare the new value with the old value. if (m_dmx[i][j] != value) { // Compare the new value with the old value.
emit dmxOutput(i,j,value); // Connected with dmx slot in olaInterface. emit dmxOutput(i,j,value);
m_dmx[i][j] = value; m_dmx[i][j] = value;
}
} }
}
} }
} }
}
} }
/** /**
@ -111,19 +101,25 @@ bool olaThread::CheckDataLoss() {
timersub(&now, &m_last_data, &diff); timersub(&now, &m_last_data, &diff);
if (diff.tv_sec > 4 || (diff.tv_sec == 4 && diff.tv_usec > 4000000)) { if (diff.tv_sec > 4 || (diff.tv_sec == 4 && diff.tv_usec > 4000000)) {
// loss of data // loss of data
qDebug()<< "olaThread| Can not read one or several universes"; // qDebug()<< "olaThread| Can not read one or several universes";
emit toTerminal("Can not read one universe"); emit toTerminal("olaThread: Can not read one universe");
// return false; // Retorna false para deshabilitar el callback // return false; // Retorna false para deshabilitar el callback
} }
} }
return true; return true;
} }
void olaThread::setLayersNumber(int layersNumber) { m_layersNumber = layersNumber; } void olaThread::setLayersNumber(int layersNumber)
{
if (layersNumber <= LAYERS_NUMBER)
m_layersNumber = layersNumber;
else
m_layersNumber = LAYERS_NUMBER;
}
void olaThread::resendDmx() void olaThread::resendDmx()
{ {
emit toTerminal("Resending DMX info"); // qDebug() << "Resending DMX info";
for (int i = 0; i < m_layersNumber; i++) { // loop for reading the channels by layer. for (int i = 0; i < m_layersNumber; i++) { // loop for reading the channels by layer.
for (int j = 0; j < LAYER_CHANNELS; j++){ for (int j = 0; j < LAYER_CHANNELS; j++){
emit dmxOutput(i, j, m_dmx[i][j]); // Connected with dmx slot in olaInterface. emit dmxOutput(i, j, m_dmx[i][j]); // Connected with dmx slot in olaInterface.
@ -131,6 +127,16 @@ void olaThread::resendDmx()
} }
} }
void olaThread::setDMXConf(dmxSetting set)
{
if (set.layer >= m_layersNumber) { return; }
m_settings.replace(set.layer, set);
// ToDo: registro del nuevo universo si no está registrado ya
if (!m_universe->contains(set.universe)) {
registerUniverse(set.universe);
m_universe->append(set.universe);
}
}
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////

View file

@ -17,14 +17,6 @@
#include "defines.h" #include "defines.h"
#include "dmxPersonality.h" #include "dmxPersonality.h"
// struct where save the DMX settings for each layer
struct dmxSetting {
int address;
uint universe;
bool updated;
int layer;
};
class olaThread : public QThread class olaThread : public QThread
{ {
Q_OBJECT Q_OBJECT
@ -53,24 +45,18 @@ public:
private: private:
void run (); void run ();
ola::client::OlaClientWrapper *m_clientWrapper; ola::client::OlaClientWrapper *m_clientWrapper;
ola::client::OlaClient *m_client; ola::client::OlaClient *m_client;
unsigned int m_counter; unsigned int m_counter;
struct timeval m_last_data; // Last DMX frame received struct timeval m_last_data; // Last DMX frame received
// DMX Conf // DMX Conf
// Cambiar para múltiples universos. Array? método de de ola::client?
QList<int> *m_universe; // Registered universes. QList<int> *m_universe; // Registered universes.
int m_layersNumber; // Number of layers in wich divide the dmx frame. Each layer, one source. int m_layersNumber; // Number of layers in wich divide the dmx frame. Each layer, one source.
int m_dmx[LAYERS_NUMBER][LAYER_CHANNELS]; // DMX Buffer. Habría que cambiarlo si queremos hacer las capas dinámicas int m_dmx[LAYERS_NUMBER][LAYER_CHANNELS]; // DMX Buffer. Habría que cambiarlo si queremos hacer las capas dinámicas
QList<dmxSetting> m_settings; QList<dmxSetting> m_settings;
inline void registerUniverse(int universe) inline void registerUniverse(int universe) {
{
// void ola::client::OlaClient::RegisterUniverse(unsigned int universe,RegisterAction register_action,SetCallback * callback // void ola::client::OlaClient::RegisterUniverse(unsigned int universe,RegisterAction register_action,SetCallback * callback
m_client->RegisterUniverse(universe, ola::client::REGISTER,ola::NewSingleCallback(this, &olaThread::RegisterComplete)); m_client->RegisterUniverse(universe, ola::client::REGISTER,ola::NewSingleCallback(this, &olaThread::RegisterComplete));
} }
@ -78,15 +64,13 @@ private:
/** /**
* Control de errores en el registro de Universos en OLA * Control de errores en el registro de Universos en OLA
*/ */
// typedef SingleUseCallback1<void, const Result&> ola::client::SetCallback // typedef SingleUseCallback1<void, const Result&> ola::client::SetCallback
inline void RegisterComplete(const ola::client::Result &error) { inline void RegisterComplete(const ola::client::Result &error) {
if (error.Success()) { if (error.Success()) {
qDebug() << "Register Universe success"; // qDebug("Register Universe success");
emit toTerminal("Register Universe success"); emit toTerminal("Register Universe success");
} else { } else {
qWarning() << "olaThread|" << "Register command failed" << QString::fromStdString(error.Error()); // qWarning("Register command failed: %s", error.Error().c_str());
emit toTerminal("olaThread| Register command failed " + QString::fromStdString(error.Error())); emit toTerminal("olaThread| Register command failed " + QString::fromStdString(error.Error()));
} }
} }
@ -100,19 +84,7 @@ public slots:
void stop(); // Close the connection with olad. void stop(); // Close the connection with olad.
void setLayersNumber(int layersNumber); void setLayersNumber(int layersNumber);
void setDMXConf(dmxSetting set);
inline void setDMXConf(dmxSetting set)
{
if (set.layer >= m_layersNumber) { return; }
m_settings.replace(set.layer, set);
// ToDo: registro del nuevo universo si no está registrado ya
if (!m_universe->contains(set.universe)) {
registerUniverse(set.universe);
m_universe->append(set.universe);
}
}
protected slots: protected slots:
@ -121,6 +93,7 @@ signals:
void finished(); // Signal for closing. Not used now. void finished(); // Signal for closing. Not used now.
void dmxOutput(int layer, int channel, int value); // Signal when a channel has changed void dmxOutput(int layer, int channel, int value); // Signal when a channel has changed
void toTerminal(QString message); void toTerminal(QString message);
void layerReceived(int i);
}; };
#endif // OLATHREAD_H #endif // OLATHREAD_H

View file

@ -11,8 +11,6 @@ Settings::Settings(QObject *parent) :
// - The number of sources/layers controlled by DMX // - The number of sources/layers controlled by DMX
// - The first DMX channel of each source/layer // - The first DMX channel of each source/layer
// - The universe to bind in OLA // - The universe to bind in OLA
// All this is being moved to settingsDialog Class
void Settings::readFromFile(QString file) { void Settings::readFromFile(QString file) {
QFile* xmlFile = new QFile(file); QFile* xmlFile = new QFile(file);
@ -25,7 +23,7 @@ void Settings::readFromFile(QString file) {
QXmlStreamReader* xmlReader = new QXmlStreamReader(xmlFile); QXmlStreamReader* xmlReader = new QXmlStreamReader(xmlFile);
int counter = 0; int counter = 0;
//Parse the XML until we reach end of it //Parse the XML until we reach end of it
while(!xmlReader->atEnd() && !xmlReader->hasError()) { while(!xmlReader->atEnd() && !xmlReader->hasError() && counter < LAYERS_NUMBER) {
// Read next element // Read next element
QXmlStreamReader::TokenType token = xmlReader->readNext(); QXmlStreamReader::TokenType token = xmlReader->readNext();
//If token is just StartDocument - go to next //If token is just StartDocument - go to next
@ -43,9 +41,6 @@ void Settings::readFromFile(QString file) {
continue; continue;
} }
} }
/* if (worker->m_layersNumber > MAX_SOURCE_DMX) {
worker->m_layersNumber = MAX_SOURCE_DMX;
}*/
QString add = "layer"; QString add = "layer";
add.append(QString("%1").arg(counter)); add.append(QString("%1").arg(counter));
if((xmlReader->name() == add)) { if((xmlReader->name() == add)) {
@ -54,10 +49,6 @@ void Settings::readFromFile(QString file) {
temp.universe = xmlReader->attributes().value("universe").toLocal8Bit().toInt(); temp.universe = xmlReader->attributes().value("universe").toLocal8Bit().toInt();
temp.layer = counter; temp.layer = counter;
emit DMXConf(temp); emit DMXConf(temp);
// If the universe is not in the list, append it.
// if(!worker->m_universe.contains(temp.universe)) {
// worker->m_universe.append(temp.universe);
// }
} }
counter++; counter++;
} }

View file

@ -7,10 +7,8 @@
#include <QMessageBox> #include <QMessageBox>
#include "olathread.h" #include "olathread.h"
#include "audiomotor.h"
#include "medialibrary.h" #include "medialibrary.h"
#include "defines.h"
#define DEFAULT_FILE "lms-audio.xlm"
class Settings : public QObject class Settings : public QObject
{ {