#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) { 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"); }