/* Libre Media Server Audio - An Open source Media Server for arts and performing. (c) Criptomart - Santiago NoreƱa 2012-2024 https://git.criptomart.net/libremediaserver This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "libremediaserver-audio.h" libreMediaServerAudio::libreMediaServerAudio() { m_settings = Settings::getInstance(this); //m_settings->readFile(); m_ui = m_settings->getShowUi(); m_layersQty = m_settings->getLayersNumber(); for (uint i = 0; i < m_layersQty; i++) { m_currentMedia[i] = ""; m_currentStatus[i] = Status::Iddle; #ifdef NOGUI m_updateUi[i][0] = -1; m_updateUi[i][1] = -1; m_updateUi[i][2] = -1; m_updateUi[i][3] = -1; #endif } if (!m_mae.startEngine(m_layersQty, m_settings->getAudioDeviceId(), m_settings->getAudioDeviceQty())) { cout << "Can not start Audio Engine!" << endl; exit(-1); } if (m_settings->getDmxActive()) { m_dmxSettings = m_settings->getDmxSettings(); m_mediaLibrary = new MediaLibrary; m_mediaLibrary->initMediaLibrary(); m_ola = new olaThread(this, m_layersQty); Q_CHECK_PTR(m_ola); m_ola->blockSignals(true); m_ola->registerUniverse(); #ifdef NOGUI m_ola->start(QThread::TimeCriticalPriority ); #endif m_ola->blockSignals(false); } else { qDebug() << "DMX inactive"; } if (!m_settings->getShowPlayerActive()) qDebug() << "ShowPlayer inactive"; cout << "Core init Complete." << endl; } libreMediaServerAudio::~libreMediaServerAudio() { if (m_settings->getDmxActive()) m_ola->stop(); m_mae.stopEngine(); delete m_lmsUi; delete m_settings; sleep(1); cout << "bye!" << endl; exit(0); } void libreMediaServerAudio::loadMedia(int layer, int folder, int file) { QString mediaFile = m_mediaLibrary->requestNewFile(folder, file); if (strcmp(mediaFile.toLatin1().constData(), m_currentMedia[layer].toLatin1().constData()) == 0) return; if (QFile::exists(mediaFile)){ m_mae.loadMedia(layer, mediaFile.toLatin1().data()); m_currentMedia[layer] = mediaFile; #ifndef NOGUI if (m_ui) m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); #endif m_mae.printFormatInfo(layer); } if (m_currentStatus[layer] == Status::PlayingFolder \ || (m_currentStatus[layer] == Status::PlayingFolderLoop)\ || (m_currentStatus[layer] == Status::PlayingFolderRandom)) { m_played.append(file); } else if (m_currentStatus[layer] == Status::PlayingOnce \ || m_currentStatus[layer] == Status::PlayingLoop) { m_played.clear(); } } void libreMediaServerAudio::dmxInput(int layer, int channel, int value) { if (layer >= MAX_LAYERS || channel >= LAYER_CHANNELS) return; QString mediaFile = NULL; int aux; if (channel == VOLUME_COARSE || channel == VOLUME_FINE) { m_mae.volChanged(layer, value); m_updateUi[layer][0] = value; } else if (channel == PAN) { m_mae.panChanged(layer, value); m_updateUi[layer][1] = value; } else if (channel == PITCH) { m_mae.pitchChanged(layer, value); m_updateUi[layer][2] = value; } else if (channel == ENTRY_POINT_COARSE || channel == ENTRY_POINT_FINE) { m_mae.setCursor(layer, value); m_updateUi[layer][3] = value; } else if (channel == PLAYBACK && value > 0) { aux = value / 25; Status s = m_currentStatus[layer]; if (aux == 0) s = Status::PlayingOnce; else if (aux == 1) s = Status::Stopped; else if (aux == 2) s = Status::Paused; else if (aux == 3) s = Status::PlayingLoop; else if (aux == 4) s = Status::PlayingFolder; else if (aux == 5) s = Status::PlayingFolderLoop; else if (aux == 6) s = Status::PlayingFolderRandom; m_mae.playbackChanged(layer, s); m_currentStatus[layer] = s; qInfo() << "Layer" << layer << statusToString(s); #ifndef NOGUI if (m_ui) { m_lmsUi->m_aw->playbackChanged(layer, s); m_updateUi[layer][3] = 1; m_played.clear(); m_played.append(m_ola->getValue(layer, DMX_FILE)); } #endif } else if (channel >= HP_FREQ) { m_mae.filterParamChanged(layer, channel, value); #ifndef NOGUI if (m_ui) { m_lmsUi->m_aw->filterParamChanged(layer, channel, value); } #endif } } #ifndef NOGUI void libreMediaServerAudio::refreshUi() { if (!m_ui) return; for (int i= 0; i < m_settings->getLayersNumber(); i++ ) { if (m_updateUi[i][0] >= 0) { m_lmsUi->m_aw->volChanged(i, m_updateUi[i][0]); m_updateUi[i][0] = -1; } if (m_updateUi[i][1] >= 0) { m_lmsUi->m_aw->panChanged(i, m_updateUi[i][1]); m_updateUi[i][1] = -1; } if (m_updateUi[i][2] >= 0) { m_lmsUi->m_aw->pitchChanged(i, m_updateUi[i][2]); m_updateUi[i][2] = -1; } if (m_updateUi[i][3] >= 0 \ || m_currentStatus[i] == Status::PlayingOnce\ || m_currentStatus[i] == Status::PlayingLoop\ || m_currentStatus[i] == Status::PlayingFolder\ || m_currentStatus[i] == Status::PlayingFolderLoop || m_currentStatus[i] == Status::PlayingFolderRandom) { m_lmsUi->m_aw->cursorChanged(i, m_mae.getCursor(i)); m_updateUi[i][3] = -1; } m_lmsUi->m_aw->levelChanged(i, m_mae.getLevel(i)); if (m_mae.getAtEnd(i)) { if (m_settings->getDmxActive()) endMediaDMX(i); else endMediaUi(i); } } } int libreMediaServerAudio::getFileIndexInFolder(const QString& currentFilePath) { QDir directory = QFileInfo(currentFilePath).absoluteDir(); QStringList filters; filters << "*.mp3" << "*.wav" << "*.flac"; QStringList fileList = directory.entryList(filters, QDir::Files, QDir::Name); m_folderSize = fileList.size(); return fileList.indexOf(QFileInfo(currentFilePath).fileName()); } QString libreMediaServerAudio::getNextFile(const QString& currentFilePath, bool loop, bool random) { QDir directory = QFileInfo(currentFilePath).absoluteDir(); QStringList filters; filters << "*.mp3" << "*.wav" << "*.flac"; QStringList fileList = directory.entryList(filters, QDir::Files, QDir::Name); m_folderSize = fileList.size(); int currentIndex = fileList.indexOf(QFileInfo(currentFilePath).fileName()); if (currentIndex >= 0 && currentIndex < m_folderSize - 1 && !random) { return directory.absoluteFilePath(fileList.at(currentIndex + 1)); } else if (loop && fileList.size() > 0 && !random) { return directory.absoluteFilePath(fileList.at(0)); } else if (random && m_folderSize > 0) { if (m_played.size() >= m_folderSize ) m_played.clear(); int r = rand() % fileList.size(); while (m_played.contains(r)) { r = rand() % fileList.size(); } return directory.absoluteFilePath(fileList.at(r)); } return QString(); } void libreMediaServerAudio::endMediaUi(int i) { QString nextFile; if (m_currentStatus[i] == Status::PlayingOnce || m_currentStatus[i] == Status::Stopped) { m_currentStatus[i] = Status::Stopped; m_lmsUi->m_aw->playbackChanged(i, Status::Stopped); m_lmsUi->m_showPlayer->cueTrackAtEnd(i); } else if (m_currentStatus[i] == Status::PlayingFolder) { nextFile = getNextFile(m_currentMedia[i], false, false); } else if (m_currentStatus[i] == Status::PlayingFolderLoop) { nextFile = getNextFile(m_currentMedia[i], true, false); } else if (m_currentStatus[i] == Status::PlayingFolderRandom) { nextFile = getNextFile(m_currentMedia[i], false, true); } if (!nextFile.isEmpty()) { this->uiLoadMedia(i, nextFile); m_mae.playbackChanged(i, m_currentStatus[i]); } else { m_currentStatus[i] = Status::Stopped; m_lmsUi->m_aw->playbackChanged(i, Status::Stopped); m_lmsUi->m_showPlayer->cueTrackAtEnd(i); m_played.clear(); } } void libreMediaServerAudio::endMediaDMX(int i) { if (m_currentStatus[i] == Status::PlayingOnce || m_currentStatus[i] == Status::Stopped) { m_currentStatus[i] = Status::Stopped; m_lmsUi->m_aw->playbackChanged(i, Status::Stopped); m_lmsUi->m_showPlayer->cueTrackAtEnd(i); } else if (m_currentStatus[i] == Status::PlayingFolder) { uint last = 0; if (!m_played.isEmpty()) last = m_played.last() + 1; int folder = m_ola->getValue(i, DMX_FOLDER); QString nextFile = getNextFile(m_currentMedia[i], false, false); if (!nextFile.isEmpty()) { this->loadMedia(i, folder, last); m_mae.playbackChanged(i, Status::PlayingFolder); } else { m_currentStatus[i] = Status::Stopped; m_lmsUi->m_aw->playbackChanged(i, Status::Stopped); m_lmsUi->m_showPlayer->cueTrackAtEnd(i); } } else if (m_currentStatus[i] == Status::PlayingFolderLoop) { uint last = m_played.last(); int folder = m_ola->getValue(i, DMX_FOLDER); last++; QString nextFile = getNextFile(m_currentMedia[i], true, false); if (!nextFile.isEmpty()) { this->loadMedia(i, folder, last); m_mae.playbackChanged(i, Status::PlayingFolder); } else { this->loadMedia(i, folder, 0); m_mae.playbackChanged(i, Status::PlayingFolderLoop); } } else if (m_currentStatus[i] == Status::PlayingFolderRandom) { int last = -1; int folder = m_ola->getValue(i, DMX_FOLDER); while (last == -1) { last = rand() % m_mediaLibrary->getMediaFolderCount(folder); if (m_played.contains(last)) last = -1; } this->loadMedia(i, folder, last); m_mae.playbackChanged(i, Status::PlayingFolderRandom); } } void libreMediaServerAudio::setUi(libreMediaServerAudioUi *lmsUi) { m_lmsUi = lmsUi; m_ui = true; connect(m_lmsUi->m_aw, SIGNAL(uiSliderChanged(int, Slider, int)), this, SLOT(uiSliderChanged(int, Slider, int))); connect(m_lmsUi->m_aw, SIGNAL(uiPlaybackChanged(int, Status)), this, SLOT(uiPlaybackChanged(int, Status))); connect(m_lmsUi->m_aw, SIGNAL(uiLoadMedia(int, QString)), this, SLOT(uiLoadMedia(int, QString))); connect(m_lmsUi->m_showPlayer, SIGNAL(uiSliderChanged(int, Slider, int)), this, SLOT(uiSliderChanged(int, Slider, int))); connect(m_lmsUi->m_showPlayer, SIGNAL(uiSliderChangedFaded(int, Slider, int, int, int)), this, SLOT(uiSliderChangedFaded(int, Slider, int, int, int))); connect(m_lmsUi->m_showPlayer, SIGNAL(uiPlaybackChanged(int, Status)), this, SLOT(uiPlaybackChanged(int, Status))); connect(m_lmsUi->m_showPlayer, SIGNAL(uiLoadMedia(int, QString)), this, SLOT(uiLoadMedia(int, QString))); if (m_settings->getDmxActive()) { connect(m_ola, SIGNAL(universeReceived(int)), m_lmsUi->m_dmxWidget, SLOT(updateWatchDMX(int))); m_ola->start(QThread::TimeCriticalPriority ); } else { m_lmsUi->m_dmxWidget->hide(); } for (uint i = 0; i < m_settings->getAudioDeviceQty(); i++) { char *name = m_mae.getDeviceName(i); m_lmsUi->m_aw->busNameChanged(i, name); } if (m_settings->getShowPlayerActive()) { m_lmsUi->m_showPlayer->loadCueTrackList("lastshow.xml"); m_lmsUi->m_showPlayer->show(); } m_refreshUi = new QTimer(this); connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi())); m_refreshUi->start(UI_REFRESH_TIME); }; // From Ui widgets and ShowPlayer void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value) { switch (s){ case Slider::Volume: m_mae.volChanged(layer, value); m_updateUi[layer][0] = value; break; case Slider::Pan: m_mae.panChanged(layer, value); m_updateUi[layer][1] = value; break; case Slider::Pitch: m_mae.pitchChanged(layer, value); m_updateUi[layer][2] = value; break; case Slider::Bypass: // ToDo: sigsev when no dmx, resolve this whitout dmxSettings, is it needed= m_mae.setBypass(m_dmxSettings.at(layer).audioDevice, layer, value); break; case Slider::Bus1: m_mae.filterParamChanged(layer, SEND1, value / 255.0f); m_lmsUi->m_aw->filterParamChanged(layer, SEND1, value / 255.0f); break; case Slider::Bus2: m_mae.filterParamChanged(layer, SEND2, value / 255.0f); m_lmsUi->m_aw->filterParamChanged(layer, SEND2, value / 255.0f); break; } } void libreMediaServerAudio::uiPlaybackChanged(int layer, Status s) { ma_result result; QString tmp; result = m_mae.playbackChanged(layer, s); if (result == MA_SUCCESS) { m_currentStatus[layer] = s; m_lmsUi->m_aw->playbackChanged(layer, s); } else { qWarning() << "ui playback change error " << result << " status " << statusToString(s) << "layer" << layer; } switch (s) { case Status::PlayingOnce: case Status::PlayingLoop: case Status::Iddle: case Status::Stopped: m_played.clear(); break; case Status::Paused: case Status::PlayingFolder: case Status::PlayingFolderLoop: break; case Status::PlayingFolderRandom: tmp = getNextFile(m_currentMedia[layer], false, true); uiLoadMedia(layer, tmp); break; } } void libreMediaServerAudio::uiLoadMedia(int layer, QString mediaFile) { ma_result result; if (mediaFile.isEmpty()) return ; if (mediaFile.compare(m_currentMedia[layer]) == 0) return; result = m_mae.loadMedia(layer, mediaFile.toLatin1().data()); if (result == MA_SUCCESS) { m_currentMedia[layer] = mediaFile; m_lmsUi->m_aw->mediaLoaded(layer, mediaFile, m_mae.getDuration(layer)); m_played.append(getFileIndexInFolder(mediaFile)); } else { qWarning() << "ui load media error" << result << "file" << mediaFile << "layer" << layer; } } void libreMediaServerAudio::uiSliderChangedFaded(int layer, Slider s, int value, int fadeIn, int fadeOut) { switch (s){ case Slider::Volume: m_mae.volChanged(layer, value, fadeIn, fadeOut); m_updateUi[layer][0] = value; break; } } #endif