fix playing folder modes in ui. read/write settings and cue list at

start/exit.shortcuts.
This commit is contained in:
snt 2024-07-08 20:23:25 +02:00
parent b4988a1307
commit 46b7624fb5
10 changed files with 252 additions and 90 deletions

View file

@ -12,6 +12,7 @@
#include <QTableWidgetItem>
#include <QFile>
#include <QXmlStreamReader>
#include <QMessageBox>
#include "cuetracklistwidget.h"
CueTrackListWidget::CueTrackListWidget(QWidget *parent)
@ -25,6 +26,19 @@ CueTrackListWidget::CueTrackListWidget(QWidget *parent)
QObject::connect(shortcut_up, SIGNAL(activated()), this, SLOT(key_up()));
QShortcut *shortcut_down = new QShortcut(QKeySequence("Down"), parent);
QObject::connect(shortcut_down, SIGNAL(activated()), this, SLOT(key_down()));
QShortcut *shortcut_copy = new QShortcut(QKeySequence("Ctrl+C"), parent);
QObject::connect(shortcut_copy, SIGNAL(activated()), this, SLOT(copyCueTrack()));
QShortcut *shortcut_cut = new QShortcut(QKeySequence("Ctrl+X"), parent);
QObject::connect(shortcut_cut, SIGNAL(activated()), this, SLOT(cutCueTrack()));
QShortcut *shortcut_paste = new QShortcut(QKeySequence("Ctrl+V"), parent);
QObject::connect(shortcut_paste, SIGNAL(activated()), this, SLOT(pasteCueTrack()));
tableWidget->installEventFilter(this);
QShortcut *shortcut_delete = new QShortcut(QKeySequence("Delete"), parent);
QObject::connect(shortcut_delete, SIGNAL(activated()), this, SLOT(deleteCueTrack()));
QShortcut *shortcut_insert = new QShortcut(QKeySequence("Insert"), parent);
QObject::connect(shortcut_insert, SIGNAL(activated()), this, SLOT(createNewCueTrack()));
QShortcut *shortcut_edit = new QShortcut(QKeySequence("e"), parent);
QObject::connect(shortcut_edit, SIGNAL(activated()), this, SLOT(editCueTrack()));
}
void CueTrackListWidget::addCueTrack(CueTrack* cue) {
@ -95,18 +109,6 @@ void CueTrackListWidget::displayCueTrackInTable(CueTrack *cueTrack, int index) {
tableWidget->setItem(index, 5, new QTableWidgetItem(statusStr));
tableWidget->setItem(index, 6, new QTableWidgetItem(*getFileName(cueTrack->filePath)));
}
//ToDo: make shortcuts in showplayer instead
void CueTrackListWidget::keyPressEvent(QKeyEvent* event) {
if (event->key() == Qt::Key_Delete) {
deleteCueTrack();
}
if (event->key() == Qt::Key_Insert) {
createNewCueTrack();
}
if (event->key() == Qt::Key_Return) {
editCueTrack();
}
}
void CueTrackListWidget::updateSelectedCueTrack(bool highlightRow) {
if (selectedIndex >= 0 && selectedIndex < tableWidget->rowCount()) {
@ -183,13 +185,18 @@ void CueTrackListWidget::editCueTrack()
void CueTrackListWidget::deleteCueTrack()
{
removeCueTrack(selectedIndex);
if (selectedIndex >= m_size)
{
selectedIndex = m_size - 1;
emit changeSelectedIndex(selectedIndex);
}
redrawCueTrackList();
QMessageBox::StandardButton reply;
reply = QMessageBox::question(this, "Delete Cue Track", "Are you sure you want to delete this cue track?",
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
removeCueTrack(selectedIndex);
if (selectedIndex >= m_size)
{
selectedIndex = m_size - 1;
emit changeSelectedIndex(selectedIndex);
}
redrawCueTrackList();
}
}
void CueTrackListWidget::copyCueTrack(CueTrack *src, CueTrack *dst)

View file

@ -50,7 +50,6 @@ private slots:
void key_up();
void key_down();
void displayCueTrackInTable(CueTrack *cueTrack, int index);
void keyPressEvent(QKeyEvent* event);
void updateSelectedCueTrack(bool highlightRow);
void cueTrackLoadDefaults(CueTrack * t);
void copyCueTrack(CueTrack *src, CueTrack *dst);

View file

@ -65,9 +65,13 @@ void CueTrackWidget::go()
void CueTrackWidget::waitInSlot()
{
emit goAction(ui->audioLayer->intValue());
tlFade.setDuration(ui->fade->value() * 1000);
tlFade.start();
ui->cueProgressBar->setStyleSheet("QProgressBar::chunk { background-color: #00FF00; }");
if (ui->fade->value() > 0) {
tlFade.setDuration(ui->fade->value() * 1000);
tlFade.start();
ui->cueProgressBar->setStyleSheet("QProgressBar::chunk { background-color: #00FF00; }");
} else {
fadeSlot();
}
}
void CueTrackWidget::fadeSlot()

View file

@ -27,9 +27,6 @@ libreMediaServerAudio::libreMediaServerAudio()
m_settings->readFile();
m_ui = m_settings->getShowUi();
m_layersQty = m_settings->getLayersNumber();
m_dmxSettings = m_settings->getDmxSettings();
m_mediaLibrary = new MediaLibrary;
m_mediaLibrary->initMediaLibrary();
for (uint i = 0; i < m_layersQty; i++) {
m_currentMedia[i] = "";
m_currentStatus[i] = Status::Iddle;
@ -44,21 +41,44 @@ libreMediaServerAudio::libreMediaServerAudio()
cout << "Can not start Audio Engine!" << endl;
exit(-1);
}
m_ola = new olaThread(this, m_layersQty);
Q_CHECK_PTR(m_ola);
m_ola->blockSignals(true);
m_ola->registerUniverse();
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 );
m_ola->start(QThread::TimeCriticalPriority );
#endif
m_ola->blockSignals(false);
m_ola->blockSignals(false);
} else {
qDebug() << "DMX inactive";
}
if (!m_settings->getShowPlayerActive())
qDebug() << "ShowPlayer inactive";
cout << "Core init Complete." << endl;
}
libreMediaServerAudio::~libreMediaServerAudio()
{
m_ola->stop();
if (m_settings->getDmxActive())
m_ola->stop();
m_mae.stopEngine();
Settings::getInstance()->beginGroup("mainwindow");
Settings::getInstance()->setValue("size", m_lmsUi->size());
Settings::getInstance()->setValue("fullScreen", m_lmsUi->isFullScreen());
Settings::getInstance()->setValue("geometry", m_lmsUi->saveGeometry());
Settings::getInstance()->setValue("showPlayer", m_lmsUi->m_showPlayer->isVisible());
Settings::getInstance()->setValue("showPlayerSize", m_lmsUi->m_showPlayer->size());
Settings::getInstance()->setValue("showPlayerGeometry", m_lmsUi->m_showPlayer->saveGeometry());
Settings::getInstance()->endGroup();
m_settings->settingsSaver();
if (m_settings->getShowPlayerActive())
m_lmsUi->m_showPlayer->saveCueTrackList("lastshow.xml");
delete m_lmsUi;
delete m_settings;
sleep(1);
cout << "bye!" << endl;
exit(0);
@ -170,52 +190,113 @@ void libreMediaServerAudio::refreshUi() {
}
m_lmsUi->m_aw->levelChanged(i, m_mae.getLevel(i));
if (m_mae.getAtEnd(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);
}
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);
if (last < m_mediaLibrary->getMediaFolderCount(folder)) {
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++;
if (last >= m_mediaLibrary->getMediaFolderCount(folder)) {
this->loadMedia(i, folder, 0);
m_mae.playbackChanged(i, Status::PlayingFolderLoop);
} else {
this->loadMedia(i, folder, last);
m_mae.playbackChanged(i, Status::PlayingFolder);
}
}
else if (m_currentStatus[i] == Status::PlayingFolderRandom) {
int last = -1;
int folder = m_ola->getValue(i, DMX_FOLDER);
if (uint(abs(m_played.size())) >= m_mediaLibrary->getMediaFolderCount(folder))
m_played.clear();
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);
}
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);
}
}
@ -223,7 +304,6 @@ void libreMediaServerAudio::setUi(libreMediaServerAudioUi *lmsUi)
{
m_lmsUi = lmsUi;
m_ui = true;
connect(m_ola, SIGNAL(universeReceived(int)), m_lmsUi->m_dmxWidget, SLOT(updateWatchDMX(int)));
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)));
@ -231,14 +311,32 @@ void libreMediaServerAudio::setUi(libreMediaServerAudioUi *lmsUi)
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)));
m_refreshUi = new QTimer(this);
connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi()));
m_refreshUi->start(UI_REFRESH_TIME);
m_ola->start(QThread::TimeCriticalPriority );
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();
//m_lmsUi->topWidget->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_settings->beginGroup("mainwindow");
auto geometry = m_settings->value("geometry", QByteArray()).toByteArray();
if (!geometry.isEmpty())
lmsUi->restoreGeometry(geometry);
geometry = m_settings->value("showPlayerGeometry", QByteArray()).toByteArray();
if (!geometry.isEmpty())
lmsUi->m_showPlayer->restoreGeometry(geometry);
m_settings->endGroup();
m_refreshUi = new QTimer(this);
connect(m_refreshUi, SIGNAL(timeout()), this, SLOT(refreshUi()));
m_refreshUi->start(UI_REFRESH_TIME);
};
// From Ui widgets and ShowPlayer
@ -274,6 +372,7 @@ void libreMediaServerAudio::uiSliderChanged(int layer, Slider s, int value)
void libreMediaServerAudio::uiPlaybackChanged(int layer, Status s)
{
ma_result result;
QString tmp;
result = m_mae.playbackChanged(layer, s);
if (result == MA_SUCCESS) {
@ -282,6 +381,22 @@ void libreMediaServerAudio::uiPlaybackChanged(int layer, Status 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)
@ -296,6 +411,7 @@ void libreMediaServerAudio::uiLoadMedia(int layer, QString mediaFile)
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;
}
@ -310,4 +426,5 @@ void libreMediaServerAudio::uiSliderChangedFaded(int layer, Slider s, int value,
break;
}
}
#endif

View file

@ -62,13 +62,18 @@ private:
QTimer *m_refreshUi;
libreMediaServerAudioUi *m_lmsUi;
float m_updateUi[MAX_LAYERS][4];
int m_folderSize;
private slots:
void refreshUi();
void uiSliderChanged(int layer, Slider s, int value);
void uiSliderChangedFaded(int layer, Slider s, int value, int fadeIn, int fadeOut);
void uiPlaybackChanged(int layer, Status s);
void uiLoadMedia(int layer, QString s);
void endMediaDMX(int layer);
void endMediaUi(int layer);
QString getNextFile(const QString& currentFilePath, bool loop, bool random);
int getFileIndexInFolder(const QString& currentFilePath);
#endif
};

View file

@ -35,7 +35,10 @@ int main(int argc, char *argv[])
libreMediaServerAudio lms;
app.setApplicationName("LibreMediaServerAudio");
app.setOrganizationName("Criptomart");
app.setOrganizationDomain("Criptomart.net");
app.setOrganizationDomain("criptomart.net");
QCoreApplication::setOrganizationName("Criptomart");
QCoreApplication::setOrganizationDomain("criptomart.net");
QCoreApplication::setApplicationName("LibreMediaServerAudio");
app.setApplicationVersion(VERSION);
#ifndef NOGUI
if (hasUi(argc, argv) || lms.getShowUi())

View file

@ -12,7 +12,7 @@ Settings *Settings::getInstance(QObject *parent) {
}
Settings::Settings(QObject *parent) :
QSettings{parent}
QSettings("Criptomart", "LibreMediaServer", parent)
{
m_layersNumber = 0;
m_ui = false;
@ -30,6 +30,8 @@ void Settings::settingsLoader()
{
beginGroup("lmsAudio");
m_ui = value("ui", 0).toBool();
m_dmxActive = value("dmxActive", 0).toBool();
m_showPlayerActive = value("showPlayerActive", 0).toBool();
m_layersNumber = value("layersNumber", 0).toInt();
m_pathmedia = value("path", "").toString();
endGroup();
@ -60,6 +62,8 @@ void Settings::settingsSaver()
{
beginGroup("lmsAudio");
setValue("ui", m_ui);
setValue("dmxActive", m_dmxActive);
setValue("showPlayerActive", m_showPlayerActive);
setValue("layersNumber", m_layersNumber);
setValue("path", m_pathmedia);
endGroup();
@ -78,15 +82,17 @@ void Settings::settingsSaver()
endGroup();
}
endGroup();
sync();
qDebug() << "writed settings to " << fileName();
}
// Read the dmx settings for dmx.xml At the moment we need:
// Read the dmx settings. At the moment we need:
// - The path to the medias folder tree
// - The number of sources/layers controlled by DMX
// - The first DMX channel of each source/layer
// - The universe to bind in OLA
// - dmxActive and The universe to bind in OLA
// - Audio device id
// - Show the Ui or not
// - Show Ui, showPlayer
void Settings::readFromFile(QString file) {
QFile* xmlFile = new QFile(file);
if (!xmlFile->open(QIODevice::ReadOnly | QIODevice::Text)) {
@ -106,6 +112,8 @@ void Settings::readFromFile(QString file) {
if(token == QXmlStreamReader::StartElement) {
if(xmlReader->name() == "lmsAudio") {
m_ui = xmlReader->attributes().value("ui").toLocal8Bit().toInt();
m_dmxActive = xmlReader->attributes().value("dmxActive").toInt();
m_showPlayerActive = xmlReader->attributes().value("showPlayerActive").toInt();
m_layersNumber = xmlReader->attributes().value("layersNumber").toLocal8Bit().toInt();
m_pathmedia = xmlReader->attributes().value("path").toLocal8Bit();
continue;
@ -142,6 +150,7 @@ void Settings::readFromFile(QString file) {
void Settings::printSettings() {
qInfo() << "Settings readed:\nShow Ui:" << m_ui << "Layers:" << m_layersNumber << "Path:" << m_pathmedia <<"Audio Device qty:" << m_audioDeviceQty;
qInfo() << "dmx: " << m_dmxActive << " showPlayer: " << m_showPlayerActive;
for (uint i = 0; i < m_audioDeviceQty; i++)
qInfo() << "Audio device internal id:" << i << "system id:" << m_audioDeviceId[i];
for (int i = 0; i < m_layersNumber; i++)

View file

@ -28,6 +28,8 @@ public:
inline uint *getAudioDeviceId() { return m_audioDeviceId; }
inline uint getAudioDeviceQty() { return m_audioDeviceQty; }
inline bool getShowUi() { return m_ui; }
inline bool getDmxActive() { return m_dmxActive; }
inline bool getShowPlayerActive() { return m_showPlayerActive; }
void readFile();
void readFromFile(QString file);
void printSettings();
@ -43,6 +45,8 @@ private:
QSet<int> m_universe;
int m_layersNumber;
bool m_ui;
bool m_dmxActive;
bool m_showPlayerActive;
};
#endif // SETTINGS_H

View file

@ -23,7 +23,11 @@ ShowPlayer::ShowPlayer(QWidget *parent) :
ui->nextCue->setNextCue();
}
ShowPlayer::~ShowPlayer() {}
ShowPlayer::~ShowPlayer()
{
saveCueTrackList("lastshow.xml");
delete ui;
}
void ShowPlayer::onAddTrack() {
ui->cueListWidget->createNewCueTrack();
@ -167,3 +171,11 @@ void ShowPlayer::updateIndex(int index) {
ui->nextCue->loadCueTrack(track);
}
}
void ShowPlayer::loadCueTrackList(QString path) {
ui->cueListWidget->loadCueTrackList(path.toStdString());
}
void ShowPlayer::saveCueTrackList(QString path) {
ui->cueListWidget->saveCueTrackList(path.toStdString());
}

View file

@ -29,6 +29,8 @@ public:
public slots:
void cueTrackAtEnd(int layer);
void loadCueTrackList(QString path);
void saveCueTrackList(QString path);
private:
Ui::ShowPlayer *ui;