Qt5 upgrade and new audio engine based in QtMultimedia.
New GUI.
This commit is contained in:
parent
6e268323d2
commit
cccd987bdd
23 changed files with 724 additions and 983 deletions
46
.gitignore
vendored
Normal file
46
.gitignore
vendored
Normal 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
|
|
@ -1,84 +0,0 @@
|
||||||
#N canvas 70 180 904 466 10;
|
|
||||||
#N canvas 1132 494 547 527 audio_player 1;
|
|
||||||
#X msg 203 93 start;
|
|
||||||
#X msg 259 95 stop;
|
|
||||||
#X obj 119 140 oggread~;
|
|
||||||
#X msg 301 92 resume;
|
|
||||||
#X obj 22 9 inlet;
|
|
||||||
#X obj 219 10 r \$0-c5;
|
|
||||||
#X obj 77 213 *~ 0;
|
|
||||||
#X obj 136 213 *~ 0;
|
|
||||||
#X obj 158 450 dac~;
|
|
||||||
#X obj 210 172 r \$0-c1;
|
|
||||||
#X obj 211 234 r \$0-c2;
|
|
||||||
#X text 208 155 Volumen;
|
|
||||||
#X text 266 233 Pan;
|
|
||||||
#X obj 219 71 select 0 1 2;
|
|
||||||
#X msg 119 101 seek \$1;
|
|
||||||
#X obj 119 36 r \$0-c8;
|
|
||||||
#X obj 119 67 * 0.01;
|
|
||||||
#X obj 210 358 line~;
|
|
||||||
#X msg 210 337 \$1 1;
|
|
||||||
#X obj 117 350 line~;
|
|
||||||
#X msg 117 329 \$1 1;
|
|
||||||
#X obj 194 378 *~;
|
|
||||||
#X obj 101 375 *~;
|
|
||||||
#X floatatom 309 148 5 0 0 0 - - -;
|
|
||||||
#X obj 333 386 outlet;
|
|
||||||
#X obj 333 347 int;
|
|
||||||
#X obj 335 305 * 100;
|
|
||||||
#X obj 117 297 1 - \$1;
|
|
||||||
#X connect 0 0 2 0;
|
|
||||||
#X connect 1 0 2 0;
|
|
||||||
#X connect 2 0 6 0;
|
|
||||||
#X connect 2 1 7 0;
|
|
||||||
#X connect 2 2 23 0;
|
|
||||||
#X connect 3 0 2 0;
|
|
||||||
#X connect 4 0 2 0;
|
|
||||||
#X connect 5 0 13 0;
|
|
||||||
#X connect 6 0 22 0;
|
|
||||||
#X connect 7 0 21 0;
|
|
||||||
#X connect 9 0 7 1;
|
|
||||||
#X connect 9 0 6 1;
|
|
||||||
#X connect 9 0 26 0;
|
|
||||||
#X connect 10 0 18 0;
|
|
||||||
#X connect 10 0 27 0;
|
|
||||||
#X connect 13 0 0 0;
|
|
||||||
#X connect 13 1 1 0;
|
|
||||||
#X connect 13 2 3 0;
|
|
||||||
#X connect 14 0 2 0;
|
|
||||||
#X connect 15 0 16 0;
|
|
||||||
#X connect 16 0 14 0;
|
|
||||||
#X connect 17 0 21 1;
|
|
||||||
#X connect 18 0 17 0;
|
|
||||||
#X connect 19 0 22 1;
|
|
||||||
#X connect 20 0 19 0;
|
|
||||||
#X connect 21 0 8 1;
|
|
||||||
#X connect 22 0 8 0;
|
|
||||||
#X connect 25 0 24 0;
|
|
||||||
#X connect 26 0 25 0;
|
|
||||||
#X connect 27 0 20 0;
|
|
||||||
#X restore 219 -234 pd audio_player;
|
|
||||||
#X obj 19 -18 s \$0-c1;
|
|
||||||
#X obj 79 -19 s \$0-c2;
|
|
||||||
#X obj 135 -18 s \$0-c3;
|
|
||||||
#X obj 197 -16 s \$0-c4;
|
|
||||||
#X obj 268 -15 s \$0-c5;
|
|
||||||
#X obj 335 -234 outlet;
|
|
||||||
#X text 465 -274 c1 Vol Coarse c2 pan c3 folder c4 file c5 playback
|
|
||||||
c6 Control c7 Volumen fino 8 Entry point Coarse 9 Entry point fine
|
|
||||||
;
|
|
||||||
#X obj 106 -273 inlet;
|
|
||||||
#X obj 219 -270 inlet;
|
|
||||||
#X obj 106 -160 route 0 1 2 3 4;
|
|
||||||
#X obj 619 -56 outlet;
|
|
||||||
#X connect 0 0 11 0;
|
|
||||||
#X connect 8 0 10 0;
|
|
||||||
#X connect 9 0 0 0;
|
|
||||||
#X connect 9 0 6 0;
|
|
||||||
#X connect 10 0 1 0;
|
|
||||||
#X connect 10 1 2 0;
|
|
||||||
#X connect 10 2 3 0;
|
|
||||||
#X connect 10 3 4 0;
|
|
||||||
#X connect 10 4 5 0;
|
|
||||||
#X coords 0 466 1 465 0 0 0;
|
|
|
@ -1,134 +0,0 @@
|
||||||
#N canvas 1 460 1700 561 10;
|
|
||||||
#X obj -297 249 layer_audio;
|
|
||||||
#X msg -673 125 \; pd dsp 1;
|
|
||||||
#X obj -400 57 loadbang;
|
|
||||||
#X msg -297 279 send 1 \$1;
|
|
||||||
#X obj -260 502 netsend;
|
|
||||||
#X msg -149 270 send 2 \$1;
|
|
||||||
#X msg -5 272 send 3 \$1;
|
|
||||||
#X msg 140 270 send 4 \$1;
|
|
||||||
#X msg 279 269 send 5 \$1;
|
|
||||||
#X msg 429 273 send 6 \$1;
|
|
||||||
#X msg 571 272 send 7 \$1;
|
|
||||||
#X msg 732 266 send 8 \$1;
|
|
||||||
#X obj -539 202 delay 50;
|
|
||||||
#X msg -539 224 send 0;
|
|
||||||
#X msg -704 203 connect localhost 9198;
|
|
||||||
#N canvas 1 110 1192 300 receive 0;
|
|
||||||
#X floatatom 380 -469 5 0 0 0 - - -;
|
|
||||||
#X obj 412 -371 route 201 202 203 204 205 206 207 208;
|
|
||||||
#X obj -197 -369 send dmx1;
|
|
||||||
#X obj 332 -369 send dmx8;
|
|
||||||
#X obj 259 -369 send dmx7;
|
|
||||||
#X obj 183 -369 send dmx6;
|
|
||||||
#X obj 110 -369 send dmx5;
|
|
||||||
#X obj 25 -369 send dmx4;
|
|
||||||
#X obj -48 -369 send dmx3;
|
|
||||||
#X obj -124 -369 send dmx2;
|
|
||||||
#X obj 118 -280 s file1;
|
|
||||||
#X obj 178 -280 s file2;
|
|
||||||
#X obj 240 -280 s file3;
|
|
||||||
#X obj 300 -280 s file4;
|
|
||||||
#X obj 358 -281 s file5;
|
|
||||||
#X obj 418 -281 s file6;
|
|
||||||
#X obj 480 -281 s file7;
|
|
||||||
#X obj 540 -281 s file8;
|
|
||||||
#X obj 207 -451 route 0 1 2 3 4 5 6 7;
|
|
||||||
#X obj 207 -486 netreceive 9197;
|
|
||||||
#X connect 1 0 10 0;
|
|
||||||
#X connect 1 1 11 0;
|
|
||||||
#X connect 1 2 12 0;
|
|
||||||
#X connect 1 3 13 0;
|
|
||||||
#X connect 1 4 14 0;
|
|
||||||
#X connect 1 5 15 0;
|
|
||||||
#X connect 1 6 16 0;
|
|
||||||
#X connect 1 7 17 0;
|
|
||||||
#X connect 18 0 2 0;
|
|
||||||
#X connect 18 1 9 0;
|
|
||||||
#X connect 18 2 8 0;
|
|
||||||
#X connect 18 3 7 0;
|
|
||||||
#X connect 18 4 6 0;
|
|
||||||
#X connect 18 5 5 0;
|
|
||||||
#X connect 18 6 4 0;
|
|
||||||
#X connect 18 7 3 0;
|
|
||||||
#X connect 18 8 1 0;
|
|
||||||
#X connect 19 0 18 0;
|
|
||||||
#X connect 19 1 0 0;
|
|
||||||
#X restore -156 105 pd receive;
|
|
||||||
#X obj -297 227 r dmx1;
|
|
||||||
#X obj -261 192 r file1;
|
|
||||||
#X obj -149 228 r dmx2;
|
|
||||||
#X obj -5 229 r dmx3;
|
|
||||||
#X obj 29 180 r file3;
|
|
||||||
#X obj 140 229 r dmx4;
|
|
||||||
#X obj 170 179 r file4;
|
|
||||||
#X obj 279 226 r dmx5;
|
|
||||||
#X obj 353 226 r file 5;
|
|
||||||
#X obj 429 230 r dmx6;
|
|
||||||
#X obj 503 228 r file6;
|
|
||||||
#X obj 571 227 r dmx7;
|
|
||||||
#X obj 645 226 r file 7;
|
|
||||||
#X obj 730 224 r dmx8;
|
|
||||||
#X obj 804 224 r file8;
|
|
||||||
#X obj -111 199 r file2;
|
|
||||||
#X msg -784 99 \; pd dsp 0;
|
|
||||||
#X obj -673 103 delay 100;
|
|
||||||
#X obj -5 251 layer_audio;
|
|
||||||
#X obj 140 250 layer_audio;
|
|
||||||
#X obj 279 249 layer_audio;
|
|
||||||
#X obj -149 251 layer_audio;
|
|
||||||
#X obj 429 253 layer_audio;
|
|
||||||
#X obj 571 250 layer_audio;
|
|
||||||
#X obj 730 246 layer_audio;
|
|
||||||
#X msg -269 326 send 9 0 1 \$1;
|
|
||||||
#X msg -126 337 send 9 0 2 \$1;
|
|
||||||
#X msg 4 318 send 9 0 3 \$1;
|
|
||||||
#X msg 147 323 send 9 0 4 \$1;
|
|
||||||
#X connect 0 0 3 0;
|
|
||||||
#X connect 0 1 41 0;
|
|
||||||
#X connect 2 0 14 0;
|
|
||||||
#X connect 2 0 12 0;
|
|
||||||
#X connect 2 0 32 0;
|
|
||||||
#X connect 2 0 33 0;
|
|
||||||
#X connect 3 0 4 0;
|
|
||||||
#X connect 5 0 4 0;
|
|
||||||
#X connect 6 0 4 0;
|
|
||||||
#X connect 7 0 4 0;
|
|
||||||
#X connect 8 0 4 0;
|
|
||||||
#X connect 9 0 4 0;
|
|
||||||
#X connect 10 0 4 0;
|
|
||||||
#X connect 11 0 4 0;
|
|
||||||
#X connect 12 0 13 0;
|
|
||||||
#X connect 13 0 4 0;
|
|
||||||
#X connect 14 0 4 0;
|
|
||||||
#X connect 16 0 0 0;
|
|
||||||
#X connect 17 0 0 1;
|
|
||||||
#X connect 18 0 37 0;
|
|
||||||
#X connect 19 0 34 0;
|
|
||||||
#X connect 20 0 34 1;
|
|
||||||
#X connect 21 0 35 0;
|
|
||||||
#X connect 22 0 35 1;
|
|
||||||
#X connect 23 0 36 0;
|
|
||||||
#X connect 24 0 36 1;
|
|
||||||
#X connect 25 0 38 0;
|
|
||||||
#X connect 26 0 38 1;
|
|
||||||
#X connect 27 0 39 0;
|
|
||||||
#X connect 28 0 39 1;
|
|
||||||
#X connect 29 0 40 0;
|
|
||||||
#X connect 30 0 40 1;
|
|
||||||
#X connect 31 0 37 1;
|
|
||||||
#X connect 33 0 1 0;
|
|
||||||
#X connect 34 0 6 0;
|
|
||||||
#X connect 34 1 43 0;
|
|
||||||
#X connect 35 0 7 0;
|
|
||||||
#X connect 35 1 44 0;
|
|
||||||
#X connect 36 0 8 0;
|
|
||||||
#X connect 37 0 5 0;
|
|
||||||
#X connect 37 1 42 0;
|
|
||||||
#X connect 38 0 9 0;
|
|
||||||
#X connect 39 0 10 0;
|
|
||||||
#X connect 40 0 11 0;
|
|
||||||
#X connect 41 0 4 0;
|
|
||||||
#X connect 42 0 4 0;
|
|
||||||
#X connect 43 0 4 0;
|
|
||||||
#X connect 44 0 4 0;
|
|
168
src/audiodecoder.cpp
Normal file
168
src/audiodecoder.cpp
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
#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: " << m_decoder->sourceFilename();
|
||||||
|
break;
|
||||||
|
case QAudioDecoder::FormatError:
|
||||||
|
qWarning() << "The format of a media resource isn't supported: " << m_decoder->sourceFilename();;
|
||||||
|
break;
|
||||||
|
case QAudioDecoder::AccessDeniedError:
|
||||||
|
qWarning() << "There are not the appropriate permissions to play a media resource" << m_decoder->sourceFilename();;
|
||||||
|
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);
|
||||||
|
// qWarning() << "Buffer Size: " << m_buffer.size() << "m_pos: " << m_pos;
|
||||||
|
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() << "AudioDecoder: Decoding file finished; " << m_decoder->sourceFilename();
|
||||||
|
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
45
src/audiodecoder.h
Normal 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
|
|
@ -1,22 +1,120 @@
|
||||||
#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_pullTimer(new QTimer(this))
|
||||||
|
, m_suspendResumeButton(0)
|
||||||
|
, m_deviceBox(0)
|
||||||
|
, m_output(0)
|
||||||
|
, m_device(QAudioDeviceInfo::defaultOutputDevice())
|
||||||
|
, m_audioOutput(0)
|
||||||
|
, m_buffer(BufferSize, 0)
|
||||||
{
|
{
|
||||||
folder = new QLabel(this);
|
this->setTitle(name);
|
||||||
file = new QLabel(this);
|
|
||||||
status = new QLabel(this);
|
|
||||||
vol = new QSlider(this);
|
|
||||||
vol->setMaximum(99);
|
|
||||||
mute = new QCheckBox(this);
|
|
||||||
|
|
||||||
QVBoxLayout *vbox = new QVBoxLayout;
|
QVBoxLayout *layout = new QVBoxLayout;
|
||||||
vbox->addWidget(folder);
|
m_deviceBox = new QComboBox(this);
|
||||||
vbox->addWidget(file);
|
const QAudioDeviceInfo &defaultDeviceInfo = QAudioDeviceInfo::defaultOutputDevice();
|
||||||
vbox->addWidget(status);
|
m_deviceBox->addItem(defaultDeviceInfo.deviceName(), qVariantFromValue(defaultDeviceInfo));
|
||||||
vbox->addWidget(vol);
|
foreach (const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices(QAudio::AudioOutput)) {
|
||||||
vbox->addWidget(mute);
|
if (deviceInfo != defaultDeviceInfo)
|
||||||
this->setLayout(vbox);
|
m_deviceBox->addItem(deviceInfo.deviceName(), qVariantFromValue(deviceInfo));
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
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);
|
||||||
|
|
||||||
|
m_suspendResumeButton = new QPushButton(this);
|
||||||
|
m_suspendResumeButton->setText(tr(SUSPEND_LABEL));
|
||||||
|
connect(m_suspendResumeButton, SIGNAL(clicked()), SLOT(toggleSuspendResume()));
|
||||||
|
layout->addWidget(m_suspendResumeButton);
|
||||||
|
|
||||||
|
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(100);
|
||||||
|
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 *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);
|
||||||
|
|
||||||
|
QHBoxLayout *progressTime = new QHBoxLayout;
|
||||||
|
m_progressTimeLabel = new QLabel;
|
||||||
|
m_progressTimeLabel->setText(PROGRESS_TIME_LABEL);
|
||||||
|
m_progressTimeValue = new QLabel;
|
||||||
|
m_progressTimeValue->setText("0:00:00:000");
|
||||||
|
progressTime->addWidget(m_progressTimeLabel);
|
||||||
|
progressTime->addWidget(m_progressTimeValue);
|
||||||
|
layout->addLayout(progressTime);
|
||||||
|
|
||||||
|
QHBoxLayout *totalTime = new QHBoxLayout;
|
||||||
|
m_totalTimeLabel = new QLabel;
|
||||||
|
m_totalTimeLabel->setText(TOTAL_TIME_LABEL);
|
||||||
|
m_totalTimeValue = new QLabel;
|
||||||
|
totalTime->addWidget(m_totalTimeLabel);
|
||||||
|
totalTime->addWidget(m_totalTimeValue);
|
||||||
|
layout->addLayout(totalTime);
|
||||||
|
|
||||||
|
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);
|
||||||
|
connect(m_decoder, SIGNAL(totalTimeChanged(qint64)),
|
||||||
|
this, SLOT(durationChanged(qint64)));
|
||||||
|
connect(m_pullTimer, SIGNAL(timeout()),
|
||||||
|
this, SLOT(pullTimerExpired()));
|
||||||
|
createAudioOutput();
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioLayerWidget::~AudioLayerWidget()
|
AudioLayerWidget::~AudioLayerWidget()
|
||||||
|
@ -24,3 +122,152 @@ AudioLayerWidget::~AudioLayerWidget()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioLayerWidget::createAudioOutput()
|
||||||
|
{
|
||||||
|
m_audioOutput = new QAudioOutput(m_device, m_format, this);
|
||||||
|
m_audioOutput->setNotifyInterval(100);
|
||||||
|
connect(m_audioOutput, SIGNAL(notify()), SLOT(notified()));
|
||||||
|
connect(m_audioOutput, SIGNAL(stateChanged(QAudio::State)), SLOT(handleStateChanged(QAudio::State)));
|
||||||
|
m_decoder->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioLayerWidget::deviceChanged(int index)
|
||||||
|
{
|
||||||
|
m_pullTimer->stop();
|
||||||
|
m_decoder->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)
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
if (QFile::exists(file)){
|
||||||
|
m_decoder->loadMedia(file);
|
||||||
|
fileLoaded(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioLayerWidget::notified()
|
||||||
|
{
|
||||||
|
QTime real(0,0,0,0);
|
||||||
|
qint64 ms = m_audioOutput->processedUSecs() / 1000 ;
|
||||||
|
real = real.addMSecs(ms);
|
||||||
|
m_progressTimeValue->setText(real.toString("h:mm:ss:zzz"));
|
||||||
|
m_progressSlider->setValue(ms);
|
||||||
|
/* 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) {
|
||||||
|
qDebug() << "End of file";
|
||||||
|
stop();
|
||||||
|
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) {
|
||||||
|
// qDebug() << "status: Suspended, resume()";
|
||||||
|
m_audioOutput->resume();
|
||||||
|
m_pullTimer->start(20);
|
||||||
|
m_suspendResumeButton->setText(tr(SUSPEND_LABEL));
|
||||||
|
m_statusValue->setText(PLAY_LABEL);
|
||||||
|
} else if (m_audioOutput->state() == QAudio::ActiveState) {
|
||||||
|
// qDebug() << "status: Active, suspend()";
|
||||||
|
m_audioOutput->suspend();
|
||||||
|
m_pullTimer->stop();
|
||||||
|
m_suspendResumeButton->setText(tr(RESUME_LABEL));
|
||||||
|
m_statusValue->setText(PAUSE_LABEL);
|
||||||
|
} else if (m_audioOutput->state() == QAudio::StoppedState) {
|
||||||
|
// qDebug() << "status: Stopped, resume()";
|
||||||
|
play();
|
||||||
|
} else if (m_audioOutput->state() == QAudio::IdleState) {
|
||||||
|
// qDebug() << "status: IdleState";
|
||||||
|
m_statusValue->setText(IDDLE_LABEL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioLayerWidget::handleStateChanged(QAudio::State state)
|
||||||
|
{
|
||||||
|
qDebug() << this->title() << " state = " << state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioLayerWidget::durationChanged(qint64 dur)
|
||||||
|
{
|
||||||
|
if (dur == -1)
|
||||||
|
return;
|
||||||
|
QTime temp(0,0,0,0);
|
||||||
|
QTime real = temp.addMSecs(dur);
|
||||||
|
m_totalTimeValue->setText(real.toString("h:mm:ss:zzz"));
|
||||||
|
m_progressSlider->setMaximum(dur);
|
||||||
|
qDebug() << this->title() << " Duration Changed: " << dur;
|
||||||
|
}
|
||||||
|
|
||||||
|
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::play()
|
||||||
|
{
|
||||||
|
m_decoder->setPos(0);
|
||||||
|
m_output = m_audioOutput->start();
|
||||||
|
m_pullTimer->start(20);
|
||||||
|
m_statusValue->setText(PLAY_LABEL);
|
||||||
|
m_suspendResumeButton->setText(tr(SUSPEND_LABEL));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioLayerWidget::pause()
|
||||||
|
{
|
||||||
|
toggleSuspendResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioLayerWidget::stop()
|
||||||
|
{
|
||||||
|
m_pullTimer->stop();
|
||||||
|
m_audioOutput->suspend();
|
||||||
|
m_audioOutput->reset();
|
||||||
|
m_decoder->setPos(0);
|
||||||
|
m_statusValue->setText(STOP_LABEL);
|
||||||
|
m_suspendResumeButton->setText(tr(RESUME_LABEL));
|
||||||
|
}
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
#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 <QGroupBox>
|
||||||
|
|
||||||
//#include "ui_audiolayerwidget.h"
|
#include "audiodecoder.h"
|
||||||
/*
|
#include "defines.h"
|
||||||
namespace Ui {
|
|
||||||
class AudioLayerWidget;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
class AudioLayerWidget : public QGroupBox
|
class AudioLayerWidget : public QGroupBox
|
||||||
{
|
{
|
||||||
|
@ -15,31 +19,65 @@ 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);
|
||||||
|
|
||||||
inline void setFolder(QString folder) const
|
public slots:
|
||||||
{
|
|
||||||
this->folder->setText(folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setVol(float vol) const
|
|
||||||
{
|
|
||||||
this->vol->setValue(vol);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void toggleSuspendResume();
|
||||||
|
void volumeChanged(int 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;
|
||||||
|
QLabel *m_progressTimeValue;
|
||||||
|
|
||||||
|
QLabel *m_totalTimeLabel;
|
||||||
|
QLabel *m_totalTimeValue;
|
||||||
|
|
||||||
|
QLabel *m_fileLabel;
|
||||||
|
QLabel *m_fileValue;
|
||||||
|
|
||||||
|
QLabel * m_folderLabel;
|
||||||
|
QLabel * m_folderValue;
|
||||||
|
|
||||||
|
QTimer *m_pullTimer;
|
||||||
|
QAudioDeviceInfo m_device;
|
||||||
|
QAudioOutput *m_audioOutput;
|
||||||
|
QIODevice *m_output; // not owned
|
||||||
|
QAudioFormat m_format;
|
||||||
|
QByteArray m_buffer;
|
||||||
|
AudioDecoder *m_decoder;
|
||||||
|
|
||||||
|
void createAudioOutput();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void notified();
|
||||||
|
void pullTimerExpired();
|
||||||
|
void fileLoaded(QString file);
|
||||||
|
void handleStateChanged(QAudio::State state);
|
||||||
|
void deviceChanged(int index);
|
||||||
|
void durationChanged(qint64 dur);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // AUDIOLAYERWIDGET_H
|
#endif // AUDIOLAYERWIDGET_H
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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");
|
|
||||||
}
|
|
||||||
|
|
143
src/audiomotor.h
143
src/audiomotor.h
|
@ -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
|
|
|
@ -12,20 +12,34 @@ 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())->stop();
|
||||||
|
break;
|
||||||
|
case QAudio::SuspendedState:
|
||||||
|
dynamic_cast<AudioLayerWidget *>(item->widget())->toggleSuspendResume();
|
||||||
|
case QAudio::IdleState:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,25 +10,20 @@
|
||||||
|
|
||||||
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AUDIOWIDGET_H
|
#endif // AUDIOWIDGET_H
|
||||||
|
|
|
@ -1,8 +1,57 @@
|
||||||
#ifndef DEFINES_H
|
#ifndef DEFINES_H
|
||||||
#define DEFINES_H
|
#define DEFINES_H
|
||||||
|
|
||||||
|
|
||||||
|
#define VERSION "LibreMediaServer-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 = 32768;
|
||||||
|
|
||||||
|
#define SUSPEND_LABEL "Suspend 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 Time: "
|
||||||
|
#define REMAINING_TIME "Remaining Time: "
|
||||||
|
#define TOTAL_TIME_LABEL "Track Time: "
|
||||||
|
#define FILE_LABEL "File: "
|
||||||
|
#define FOLDER_LABEL "Folder: "
|
||||||
|
#define STATUS_LABEL "Status: "
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
|
|
@ -26,25 +26,28 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent)
|
||||||
: QMainWindow(parent)
|
: QMainWindow(parent)
|
||||||
{
|
{
|
||||||
qDebug() << "********************************************************************************";
|
qDebug() << "********************************************************************************";
|
||||||
qDebug() << QDate::currentDate() << QTime::currentTime();
|
qDebug() << QDate::currentDate().toString() << " "<< QTime::currentTime().toString();
|
||||||
qDebug() << VERSION;
|
qDebug() << VERSION;
|
||||||
qDebug() << COPYRIGHT;
|
qDebug() << COPYRIGHT;
|
||||||
qDebug() << LICENSE;
|
qDebug() << LICENSE;
|
||||||
|
|
||||||
// Inicia el User Interface
|
|
||||||
ui.setupUi(this);
|
ui.setupUi(this);
|
||||||
|
|
||||||
|
this->setWindowTitle(VERSION);
|
||||||
// Inicia el widget Terminal
|
// Inicia el widget Terminal
|
||||||
textEdit = new QTextEdit(this);
|
textEdit = new QTextEdit(this);
|
||||||
textEdit->append(QString::fromAscii(VERSION));
|
textEdit->append(QString::fromLatin1(VERSION));
|
||||||
textEdit->append(QString::fromAscii(LICENSE));
|
textEdit->append(QString::fromLatin1(LICENSE));
|
||||||
textEdit->append(QString::fromAscii(COPYRIGHT));
|
textEdit->append(QString::fromLatin1(COPYRIGHT));
|
||||||
|
|
||||||
QDockWidget *bottomWidget = new QDockWidget(tr("Terminal"), this);
|
QDockWidget *bottomWidget = new QDockWidget(tr("Terminal"), this);
|
||||||
bottomWidget->setAllowedAreas(Qt::BottomDockWidgetArea);
|
bottomWidget->setAllowedAreas(Qt::BottomDockWidgetArea);
|
||||||
bottomWidget->setWidget(textEdit);
|
bottomWidget->setWidget(textEdit);
|
||||||
addDockWidget(Qt::BottomDockWidgetArea, bottomWidget);
|
addDockWidget(Qt::BottomDockWidgetArea, bottomWidget);
|
||||||
|
|
||||||
|
// Inicia el widget central de audio
|
||||||
|
aw = new AudioWidget(this);
|
||||||
|
setCentralWidget(aw);
|
||||||
|
|
||||||
// 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);
|
||||||
|
@ -53,11 +56,6 @@ libreMediaServerAudio::libreMediaServerAudio(QStringList args, QWidget *parent)
|
||||||
ola->start(QThread::TimeCriticalPriority );
|
ola->start(QThread::TimeCriticalPriority );
|
||||||
ola->blockSignals(true);
|
ola->blockSignals(true);
|
||||||
|
|
||||||
// Inicia el widget central de audio
|
|
||||||
|
|
||||||
aw = new AudioWidget(this);
|
|
||||||
setCentralWidget(aw);
|
|
||||||
|
|
||||||
// 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,17 +64,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"))
|
if (args.contains("-log"))
|
||||||
{
|
{
|
||||||
textEdit->append("Log to file");
|
textEdit->append("Log to file");
|
||||||
|
@ -90,30 +77,18 @@ 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(AudioMotor::getInstance(), SIGNAL(mediaLoaded(int, QString, QString)),
|
|
||||||
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) ),
|
connect(ola, SIGNAL( dmxOutput(int, int, int) ),
|
||||||
this, SLOT( dmxInput(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);
|
||||||
|
ola->resendDmx();
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
|
@ -125,9 +100,7 @@ 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() << QDate::currentDate() << QTime::currentTime();
|
|
||||||
qDebug() << "********************************************************************************";
|
qDebug() << "********************************************************************************";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -171,7 +144,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -195,47 +168,45 @@ void libreMediaServerAudio::dmxInput(int layer, int channel, int value)
|
||||||
// qDebug() << tr("olaInterface|") << "newdmx layer" << layer << "channel" << channel << "value" << value;
|
// qDebug() << tr("olaInterface|") << "newdmx layer" << layer << "channel" << channel << "value" << value;
|
||||||
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:
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,7 @@
|
||||||
#define LIBREMEDIASERVER_H
|
#define LIBREMEDIASERVER_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
|
||||||
{
|
{
|
||||||
|
@ -64,17 +54,12 @@ public:
|
||||||
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
|
QTextEdit *textEdit; // Terminal de feedback
|
||||||
AudioMasterWidget *amw;
|
AudioMasterWidget *amw;
|
||||||
// AudioLayerWidget *alw;
|
|
||||||
AudioWidget *aw;
|
AudioWidget *aw;
|
||||||
|
|
||||||
olaThread *ola;
|
olaThread *ola;
|
||||||
|
|
||||||
void open_start();
|
void open_start();
|
||||||
|
@ -82,8 +67,6 @@ private:
|
||||||
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 message)
|
inline void toTerminal (QString message)
|
||||||
|
@ -98,16 +81,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 // LIBREMEDIASERVER_H
|
||||||
|
|
|
@ -1,29 +1,31 @@
|
||||||
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
|
||||||
|
|
47
src/main.cpp
47
src/main.cpp
|
@ -22,35 +22,36 @@
|
||||||
#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
|
||||||
|
|
||||||
bool initMessageHandler = false;
|
bool initMessageHandler = false;
|
||||||
QFile outFile;
|
QFile outFile;
|
||||||
|
|
||||||
void MessageHandler(QtMsgType type, const char *msg)
|
void MessageHandler(QtMsgType type, const QMessageLogContext &logcontext, const QString &msg)
|
||||||
{
|
{
|
||||||
|
Q_UNUSED(logcontext);
|
||||||
QString txt;
|
QString txt;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case QtDebugMsg:
|
case QtDebugMsg:
|
||||||
txt = QString("Debug: %1").arg(msg);
|
txt.append("Debug: ");
|
||||||
|
txt.append(msg);
|
||||||
break;
|
break;
|
||||||
case QtWarningMsg:
|
case QtWarningMsg:
|
||||||
txt = QString("Warning: %1").arg(msg);
|
txt.append("Warning: ");
|
||||||
|
txt.append(msg);
|
||||||
break;
|
break;
|
||||||
case QtCriticalMsg:
|
case QtCriticalMsg:
|
||||||
txt = QString("Critical: %1").arg(msg);
|
txt.append("Critical: ");
|
||||||
|
txt.append(msg);
|
||||||
break;
|
break;
|
||||||
case QtFatalMsg:
|
case QtFatalMsg:
|
||||||
txt = QString("Fatal: %1").arg(msg);
|
txt.append("Fatal: ");
|
||||||
|
txt.append(msg);
|
||||||
abort();
|
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,9 +63,8 @@ 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;
|
||||||
|
@ -76,42 +76,31 @@ void MessageHandler(QtMsgType type, const char *msg)
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
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"))
|
if (args.contains("-log"))
|
||||||
{
|
{
|
||||||
qInstallMsgHandler(MessageHandler);
|
qInstallMessageHandler(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);
|
||||||
|
|
|
@ -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() << "olaInterface::initMediaLibrary| Can not cd to the path: " << 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
#include "olathread.h"
|
#include "olathread.h"
|
||||||
|
|
||||||
|
|
||||||
olaThread::olaThread(QObject *parent)
|
olaThread::olaThread(QObject *parent)
|
||||||
// : QObject(parent)
|
|
||||||
{
|
{
|
||||||
m_universe = new QList<int>();
|
m_universe = new QList<int>();
|
||||||
m_counter = 0;
|
m_counter = 0;
|
||||||
|
@ -21,11 +19,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);
|
||||||
|
@ -45,12 +38,8 @@ 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
|
|
||||||
if (!m_client->RegisterUniverse(m_universe, ola::REGISTER,ola::NewSingleCallback(&RegisterComplete))) {
|
|
||||||
qDebug() << "Can not register universe %1".arg(m_universe);
|
|
||||||
}*/
|
|
||||||
qDebug() << tr("olaThread| Running");
|
qDebug() << tr("olaThread| Running");
|
||||||
emit toTerminal("Reading DMX");
|
emit toTerminal("Reading DMX");
|
||||||
m_clientWrapper->GetSelectServer()->Run();
|
m_clientWrapper->GetSelectServer()->Run();
|
||||||
|
@ -77,7 +66,6 @@ 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)
|
||||||
|
|
|
@ -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,9 +64,7 @@ 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";
|
||||||
|
@ -100,13 +84,9 @@ public slots:
|
||||||
|
|
||||||
void stop(); // Close the connection with olad.
|
void stop(); // Close the connection with olad.
|
||||||
void setLayersNumber(int layersNumber);
|
void setLayersNumber(int layersNumber);
|
||||||
|
inline void setDMXConf(dmxSetting set) {
|
||||||
inline void setDMXConf(dmxSetting set)
|
|
||||||
{
|
|
||||||
if (set.layer >= m_layersNumber) { return; }
|
if (set.layer >= m_layersNumber) { return; }
|
||||||
|
|
||||||
m_settings.replace(set.layer, set);
|
m_settings.replace(set.layer, set);
|
||||||
|
|
||||||
// ToDo: registro del nuevo universo si no está registrado ya
|
// ToDo: registro del nuevo universo si no está registrado ya
|
||||||
if (!m_universe->contains(set.universe)) {
|
if (!m_universe->contains(set.universe)) {
|
||||||
registerUniverse(set.universe);
|
registerUniverse(set.universe);
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Reference in a new issue