diff options
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | common/qmpmidiplay.cpp (renamed from qmpmidiplay.cpp) | 0 | ||||
-rw-r--r-- | common/qmpmidiplay.hpp (renamed from qmpmidiplay.hpp) | 0 | ||||
-rw-r--r-- | common/qmpmidiread.cpp (renamed from qmpmidiread.cpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.pro | 74 | ||||
-rw-r--r-- | qmidiplayer.src.d/main.cpp (renamed from main.cpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qdialskulpturestyle.cpp (renamed from qdialskulpturestyle.cpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qdialskulpturestyle.hpp (renamed from qdialskulpturestyle.hpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpchanneleditor.cpp (renamed from qmpchanneleditor.cpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpchanneleditor.hpp (renamed from qmpchanneleditor.hpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpchanneleditor.ui (renamed from qmpchanneleditor.ui) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpchannelswindow.cpp (renamed from qmpchannelswindow.cpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpchannelswindow.hpp (renamed from qmpchannelswindow.hpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpchannelswindow.ui (renamed from qmpchannelswindow.ui) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpefxwindow.cpp (renamed from qmpefxwindow.cpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpefxwindow.hpp (renamed from qmpefxwindow.hpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpefxwindow.ui (renamed from qmpefxwindow.ui) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmphelpwindow.cpp (renamed from qmphelpwindow.cpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmphelpwindow.hpp (renamed from qmphelpwindow.hpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmphelpwindow.ui (renamed from qmphelpwindow.ui) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpimidimapper.hpp (renamed from qmpimidimapper.hpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpinfowindow.cpp (renamed from qmpinfowindow.cpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpinfowindow.hpp (renamed from qmpinfowindow.hpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpinfowindow.ui (renamed from qmpinfowindow.ui) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpmainwindow.cpp (renamed from qmpmainwindow.cpp) | 2 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpmainwindow.hpp (renamed from qmpmainwindow.hpp) | 2 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpmainwindow.ui (renamed from qmpmainwindow.ui) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpplistwindow.cpp (renamed from qmpplistwindow.cpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpplistwindow.hpp (renamed from qmpplistwindow.hpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpplistwindow.ui (renamed from qmpplistwindow.ui) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmppresetselect.cpp (renamed from qmppresetselect.cpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmppresetselect.hpp (renamed from qmppresetselect.hpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmppresetselect.ui (renamed from qmppresetselect.ui) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpsettingswindow.cpp (renamed from qmpsettingswindow.cpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpsettingswindow.hpp (renamed from qmpsettingswindow.hpp) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/qmpsettingswindow.ui (renamed from qmpsettingswindow.ui) | 0 | ||||
-rw-r--r-- | qmidiplayer.src.d/resources.qrc | 36 | ||||
-rw-r--r-- | qmidiplayerlite.pro | 24 | ||||
-rw-r--r-- | qmidiplayerlite.src.d/deployment.pri | 13 | ||||
-rw-r--r-- | qmidiplayerlite.src.d/main.cpp | 15 | ||||
-rw-r--r-- | qmidiplayerlite.src.d/main.qml | 144 | ||||
-rw-r--r-- | qmidiplayerlite.src.d/qml.qrc | 5 | ||||
-rw-r--r-- | qmidiplayerlite.src.d/qmpcorewrapper.hpp | 58 | ||||
-rw-r--r-- | qmidiplayerlite.src.d/qmpmidiplay.cpp | 406 | ||||
-rw-r--r-- | qmidiplayerlite.src.d/qmpmidiplay.hpp | 137 | ||||
-rw-r--r-- | qmidiplayerlite.src.d/qmpmidiread.cpp | 240 | ||||
-rw-r--r-- | resources.qrc | 36 |
47 files changed, 1120 insertions, 75 deletions
@@ -1,3 +1,6 @@ +2016-04-06 0.7.0 beta +Merge qmidiplayerlite. Hope this won't break the repo. + 2016-04-05 0.7.0 beta Raise player thread priority in Windows. I've been so tired with the timing bug... diff --git a/qmpmidiplay.cpp b/common/qmpmidiplay.cpp index 6f69e33..6f69e33 100644 --- a/qmpmidiplay.cpp +++ b/common/qmpmidiplay.cpp diff --git a/qmpmidiplay.hpp b/common/qmpmidiplay.hpp index fafd677..fafd677 100644 --- a/qmpmidiplay.hpp +++ b/common/qmpmidiplay.hpp diff --git a/qmpmidiread.cpp b/common/qmpmidiread.cpp index fd2e0d9..fd2e0d9 100644 --- a/qmpmidiread.cpp +++ b/common/qmpmidiread.cpp diff --git a/qmidiplayer.pro b/qmidiplayer.pro index da193e2..63e20b6 100644 --- a/qmidiplayer.pro +++ b/qmidiplayer.pro @@ -12,42 +12,42 @@ TARGET = qmidiplayer TEMPLATE = app -SOURCES += main.cpp\ - qmpmainwindow.cpp \ - qmpmidiplay.cpp \ - qmpmidiread.cpp \ - qmpplistwindow.cpp \ - qmpchannelswindow.cpp \ - qmppresetselect.cpp \ - qmpchanneleditor.cpp \ - qmpefxwindow.cpp \ - qmpinfowindow.cpp \ - qmpsettingswindow.cpp \ - qmphelpwindow.cpp \ - qdialskulpturestyle.cpp +SOURCES += ./qmidiplayer.src.d/main.cpp\ + ./qmidiplayer.src.d/qmpmainwindow.cpp \ + ./common/qmpmidiplay.cpp \ + ./common/qmpmidiread.cpp \ + ./qmidiplayer.src.d/qmpplistwindow.cpp \ + ./qmidiplayer.src.d/qmpchannelswindow.cpp \ + ./qmidiplayer.src.d/qmppresetselect.cpp \ + ./qmidiplayer.src.d/qmpchanneleditor.cpp \ + ./qmidiplayer.src.d/qmpefxwindow.cpp \ + ./qmidiplayer.src.d/qmpinfowindow.cpp \ + ./qmidiplayer.src.d/qmpsettingswindow.cpp \ + ./qmidiplayer.src.d/qmphelpwindow.cpp \ + ./qmidiplayer.src.d/qdialskulpturestyle.cpp -HEADERS += qmpmainwindow.hpp \ - qmpmidiplay.hpp \ - qmpplistwindow.hpp \ - qmpchannelswindow.hpp \ - qmppresetselect.hpp \ - qmpchanneleditor.hpp \ - qmpefxwindow.hpp \ - qmpinfowindow.hpp \ - qmpsettingswindow.hpp \ - qmphelpwindow.hpp \ - qdialskulpturestyle.hpp \ - qmpimidimapper.hpp +HEADERS += ./qmidiplayer.src.d/qmpmainwindow.hpp \ + ./common/qmpmidiplay.hpp \ + ./qmidiplayer.src.d/qmpplistwindow.hpp \ + ./qmidiplayer.src.d/qmpchannelswindow.hpp \ + ./qmidiplayer.src.d/qmppresetselect.hpp \ + ./qmidiplayer.src.d/qmpchanneleditor.hpp \ + ./qmidiplayer.src.d/qmpefxwindow.hpp \ + ./qmidiplayer.src.d/qmpinfowindow.hpp \ + ./qmidiplayer.src.d/qmpsettingswindow.hpp \ + ./qmidiplayer.src.d/qmphelpwindow.hpp \ + ./qmidiplayer.src.d/qdialskulpturestyle.hpp \ + ./qmidiplayer.src.d/qmpimidimapper.hpp -FORMS += qmpmainwindow.ui \ - qmpplistwindow.ui \ - qmpchannelswindow.ui \ - qmppresetselect.ui \ - qmpchanneleditor.ui \ - qmpefxwindow.ui \ - qmpinfowindow.ui \ - qmpsettingswindow.ui \ - qmphelpwindow.ui +FORMS += ./qmidiplayer.src.d/qmpmainwindow.ui \ + ./qmidiplayer.src.d/qmpplistwindow.ui \ + ./qmidiplayer.src.d/qmpchannelswindow.ui \ + ./qmidiplayer.src.d/qmppresetselect.ui \ + ./qmidiplayer.src.d/qmpchanneleditor.ui \ + ./qmidiplayer.src.d/qmpefxwindow.ui \ + ./qmidiplayer.src.d/qmpinfowindow.ui \ + ./qmidiplayer.src.d/qmpsettingswindow.ui \ + ./qmidiplayer.src.d/qmphelpwindow.ui unix{ isEmpty(PREFIX) { @@ -59,6 +59,6 @@ unix{ QMAKE_CXXFLAGS += -std=c++11 -Wall LIBS += -lfluidsynth } -win32:LIBS += e:/libs/fluidsynth/fluidsynth.lib #You have to change these -win32:INCLUDEPATH += e:/libs/fluidsynth/include #before building... -RESOURCES = resources.qrc +win32:LIBS += e:/libs/fluidsynth/fluidsynth.lib winmm.lib #You have to change these +win32:INCLUDEPATH += e:/libs/fluidsynth/include #before building... +RESOURCES = ./qmidiplayer.src.d/resources.qrc diff --git a/main.cpp b/qmidiplayer.src.d/main.cpp index c9f3b42..c9f3b42 100644 --- a/main.cpp +++ b/qmidiplayer.src.d/main.cpp diff --git a/qdialskulpturestyle.cpp b/qmidiplayer.src.d/qdialskulpturestyle.cpp index 7c181a0..7c181a0 100644 --- a/qdialskulpturestyle.cpp +++ b/qmidiplayer.src.d/qdialskulpturestyle.cpp diff --git a/qdialskulpturestyle.hpp b/qmidiplayer.src.d/qdialskulpturestyle.hpp index 2f3ba04..2f3ba04 100644 --- a/qdialskulpturestyle.hpp +++ b/qmidiplayer.src.d/qdialskulpturestyle.hpp diff --git a/qmpchanneleditor.cpp b/qmidiplayer.src.d/qmpchanneleditor.cpp index f1d4e5e..f1d4e5e 100644 --- a/qmpchanneleditor.cpp +++ b/qmidiplayer.src.d/qmpchanneleditor.cpp diff --git a/qmpchanneleditor.hpp b/qmidiplayer.src.d/qmpchanneleditor.hpp index 0653af5..0653af5 100644 --- a/qmpchanneleditor.hpp +++ b/qmidiplayer.src.d/qmpchanneleditor.hpp diff --git a/qmpchanneleditor.ui b/qmidiplayer.src.d/qmpchanneleditor.ui index 49e8c8e..49e8c8e 100644 --- a/qmpchanneleditor.ui +++ b/qmidiplayer.src.d/qmpchanneleditor.ui diff --git a/qmpchannelswindow.cpp b/qmidiplayer.src.d/qmpchannelswindow.cpp index a9cf60e..a9cf60e 100644 --- a/qmpchannelswindow.cpp +++ b/qmidiplayer.src.d/qmpchannelswindow.cpp diff --git a/qmpchannelswindow.hpp b/qmidiplayer.src.d/qmpchannelswindow.hpp index f0591b6..f0591b6 100644 --- a/qmpchannelswindow.hpp +++ b/qmidiplayer.src.d/qmpchannelswindow.hpp diff --git a/qmpchannelswindow.ui b/qmidiplayer.src.d/qmpchannelswindow.ui index a8b43cb..a8b43cb 100644 --- a/qmpchannelswindow.ui +++ b/qmidiplayer.src.d/qmpchannelswindow.ui diff --git a/qmpefxwindow.cpp b/qmidiplayer.src.d/qmpefxwindow.cpp index 7d9c08e..7d9c08e 100644 --- a/qmpefxwindow.cpp +++ b/qmidiplayer.src.d/qmpefxwindow.cpp diff --git a/qmpefxwindow.hpp b/qmidiplayer.src.d/qmpefxwindow.hpp index 2a080f0..2a080f0 100644 --- a/qmpefxwindow.hpp +++ b/qmidiplayer.src.d/qmpefxwindow.hpp diff --git a/qmpefxwindow.ui b/qmidiplayer.src.d/qmpefxwindow.ui index 4a1e0c6..4a1e0c6 100644 --- a/qmpefxwindow.ui +++ b/qmidiplayer.src.d/qmpefxwindow.ui diff --git a/qmphelpwindow.cpp b/qmidiplayer.src.d/qmphelpwindow.cpp index 10cf083..10cf083 100644 --- a/qmphelpwindow.cpp +++ b/qmidiplayer.src.d/qmphelpwindow.cpp diff --git a/qmphelpwindow.hpp b/qmidiplayer.src.d/qmphelpwindow.hpp index c2052b2..c2052b2 100644 --- a/qmphelpwindow.hpp +++ b/qmidiplayer.src.d/qmphelpwindow.hpp diff --git a/qmphelpwindow.ui b/qmidiplayer.src.d/qmphelpwindow.ui index fd21b5f..fd21b5f 100644 --- a/qmphelpwindow.ui +++ b/qmidiplayer.src.d/qmphelpwindow.ui diff --git a/qmpimidimapper.hpp b/qmidiplayer.src.d/qmpimidimapper.hpp index d35dbb9..d35dbb9 100644 --- a/qmpimidimapper.hpp +++ b/qmidiplayer.src.d/qmpimidimapper.hpp diff --git a/qmpinfowindow.cpp b/qmidiplayer.src.d/qmpinfowindow.cpp index 689a756..689a756 100644 --- a/qmpinfowindow.cpp +++ b/qmidiplayer.src.d/qmpinfowindow.cpp diff --git a/qmpinfowindow.hpp b/qmidiplayer.src.d/qmpinfowindow.hpp index 9a1e389..9a1e389 100644 --- a/qmpinfowindow.hpp +++ b/qmidiplayer.src.d/qmpinfowindow.hpp diff --git a/qmpinfowindow.ui b/qmidiplayer.src.d/qmpinfowindow.ui index 664531a..664531a 100644 --- a/qmpinfowindow.ui +++ b/qmidiplayer.src.d/qmpinfowindow.ui diff --git a/qmpmainwindow.cpp b/qmidiplayer.src.d/qmpmainwindow.cpp index aad0161..453bd01 100644 --- a/qmpmainwindow.cpp +++ b/qmidiplayer.src.d/qmpmainwindow.cpp @@ -5,7 +5,7 @@ #include <QDesktopWidget> #include "qmpmainwindow.hpp" #include "ui_qmpmainwindow.h" -#include "qmpmidiplay.hpp" +#include "../common/qmpmidiplay.hpp" #ifdef _WIN32 #include <Windows.h> #endif diff --git a/qmpmainwindow.hpp b/qmidiplayer.src.d/qmpmainwindow.hpp index 0b83c39..517f792 100644 --- a/qmpmainwindow.hpp +++ b/qmidiplayer.src.d/qmpmainwindow.hpp @@ -11,7 +11,7 @@ #include <QMenu> #include <thread> #include <chrono> -#include "qmpmidiplay.hpp" +#include "../common/qmpmidiplay.hpp" #include "qmpplistwindow.hpp" #include "qmpchannelswindow.hpp" #include "qmpefxwindow.hpp" diff --git a/qmpmainwindow.ui b/qmidiplayer.src.d/qmpmainwindow.ui index 0764e09..0764e09 100644 --- a/qmpmainwindow.ui +++ b/qmidiplayer.src.d/qmpmainwindow.ui diff --git a/qmpplistwindow.cpp b/qmidiplayer.src.d/qmpplistwindow.cpp index 8f04fc1..8f04fc1 100644 --- a/qmpplistwindow.cpp +++ b/qmidiplayer.src.d/qmpplistwindow.cpp diff --git a/qmpplistwindow.hpp b/qmidiplayer.src.d/qmpplistwindow.hpp index 6ceeb60..6ceeb60 100644 --- a/qmpplistwindow.hpp +++ b/qmidiplayer.src.d/qmpplistwindow.hpp diff --git a/qmpplistwindow.ui b/qmidiplayer.src.d/qmpplistwindow.ui index 99124df..99124df 100644 --- a/qmpplistwindow.ui +++ b/qmidiplayer.src.d/qmpplistwindow.ui diff --git a/qmppresetselect.cpp b/qmidiplayer.src.d/qmppresetselect.cpp index be589c5..be589c5 100644 --- a/qmppresetselect.cpp +++ b/qmidiplayer.src.d/qmppresetselect.cpp diff --git a/qmppresetselect.hpp b/qmidiplayer.src.d/qmppresetselect.hpp index 54f5764..54f5764 100644 --- a/qmppresetselect.hpp +++ b/qmidiplayer.src.d/qmppresetselect.hpp diff --git a/qmppresetselect.ui b/qmidiplayer.src.d/qmppresetselect.ui index f18600d..f18600d 100644 --- a/qmppresetselect.ui +++ b/qmidiplayer.src.d/qmppresetselect.ui diff --git a/qmpsettingswindow.cpp b/qmidiplayer.src.d/qmpsettingswindow.cpp index c2e31a2..c2e31a2 100644 --- a/qmpsettingswindow.cpp +++ b/qmidiplayer.src.d/qmpsettingswindow.cpp diff --git a/qmpsettingswindow.hpp b/qmidiplayer.src.d/qmpsettingswindow.hpp index c506de4..c506de4 100644 --- a/qmpsettingswindow.hpp +++ b/qmidiplayer.src.d/qmpsettingswindow.hpp diff --git a/qmpsettingswindow.ui b/qmidiplayer.src.d/qmpsettingswindow.ui index 330afa2..330afa2 100644 --- a/qmpsettingswindow.ui +++ b/qmidiplayer.src.d/qmpsettingswindow.ui diff --git a/qmidiplayer.src.d/resources.qrc b/qmidiplayer.src.d/resources.qrc new file mode 100644 index 0000000..351d2fa --- /dev/null +++ b/qmidiplayer.src.d/resources.qrc @@ -0,0 +1,36 @@ +<RCC> + <qresource prefix="/"> + <file>../img/add.png</file> + <file>../img/list.png</file> + <file>../img/addfolder.png</file> + <file>../img/channel.png</file> + <file>../img/prev.png</file> + <file>../img/qmidiplyr.png</file> + <file>../img/remove.png</file> + <file>../img/clear.png</file> + <file>../img/down.png</file> + <file>../img/effects.png</file> + <file>../img/repeat-all.png</file> + <file>../img/repeat-base.png</file> + <file>../img/repeat-non.png</file> + <file>../img/load.png</file> + <file>../img/next.png</file> + <file>../img/repeat-one.png</file> + <file>../img/save.png</file> + <file>../img/settings.png</file> + <file>../img/pause.png</file> + <file>../img/play.png</file> + <file>../img/shuffle-off.png</file> + <file>../img/shuffle.png</file> + <file>../img/stop.png</file> + <file>../img/up.png</file> + <file>../img/visualization.png</file> + <file>../img/mainw.png</file> + <file>../img/chanw.png</file> + <file>../doc/index.html</file> + <file>../doc/version.html</file> + <file>../doc/license.html</file> + <file>../doc/mainwindow.html</file> + <file>../doc/channeldialog.html</file> + </qresource> +</RCC> diff --git a/qmidiplayerlite.pro b/qmidiplayerlite.pro new file mode 100644 index 0000000..be7679d --- /dev/null +++ b/qmidiplayerlite.pro @@ -0,0 +1,24 @@ +TEMPLATE = app + +QT += qml quick +unix:QT += widgets +win32:QT += widgets +CONFIG += c++11 + +SOURCES += ./qmidiplayerlite.src.d/main.cpp \ + ./common/qmpmidiplay.cpp \ + ./common/qmpmidiread.cpp + +RESOURCES += ./qmidiplayerlite.src.d/qml.qrc + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = + +# Default rules for deployment. +include(./qmidiplayerlite.src.d/deployment.pri) + +HEADERS += \ + ./common/qmpmidiplay.hpp \ + ./qmidiplayerlite.src.d/qmpcorewrapper.hpp + +LIBS += -lfluidsynth diff --git a/qmidiplayerlite.src.d/deployment.pri b/qmidiplayerlite.src.d/deployment.pri new file mode 100644 index 0000000..265ce71 --- /dev/null +++ b/qmidiplayerlite.src.d/deployment.pri @@ -0,0 +1,13 @@ +unix:!android { + isEmpty(target.path) { + qnx { + target.path = /tmp/$${TARGET}/bin + } else { + target.path = /opt/$${TARGET}/bin + } + export(target.path) + } + INSTALLS += target +} + +export(INSTALLS) diff --git a/qmidiplayerlite.src.d/main.cpp b/qmidiplayerlite.src.d/main.cpp new file mode 100644 index 0000000..1a87b33 --- /dev/null +++ b/qmidiplayerlite.src.d/main.cpp @@ -0,0 +1,15 @@ +#include <QApplication> +#include <QtQml> +#include <QQmlApplicationEngine> +#include "qmpcorewrapper.hpp" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + qmlRegisterType<CQMPCoreWrapper>("org.chrisoft.qmpcore",1,0,"CQMPCoreWrapper"); + + QQmlApplicationEngine engine; + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + + return app.exec(); +} diff --git a/qmidiplayerlite.src.d/main.qml b/qmidiplayerlite.src.d/main.qml new file mode 100644 index 0000000..0ec0975 --- /dev/null +++ b/qmidiplayerlite.src.d/main.qml @@ -0,0 +1,144 @@ +import QtQuick 2.3 +import QtQuick.Window 2.2 +import QtQuick.Controls 1.0 +import QtQuick.Dialogs 1.0 +import org.chrisoft.qmpcore 1.0 + +Window { + id: window1 + width: 420 + height: 240 + title: "QMidiPlayer Lite" + visible: true + property bool playing + playing: false + + MouseArea { + id: mouseArea1 + anchors.rightMargin: 0 + anchors.bottomMargin: 0 + anchors.leftMargin: 0 + anchors.topMargin: 0 + anchors.fill: parent + onClicked: { + //Qt.quit(); + } + + Button { + id: button2 + x: 170 + text: qsTr("Play") + anchors.top: parent.top + anchors.topMargin: 172 + anchors.horizontalCenter: parent.horizontalCenter + onClicked: { + if(!playing) + { + qmpcore.loadFile(fileName.text); + qmpcore.initFluidSynth(); + qmpcore.playFile(); + playing=true; + uiTimer.start(); + text="Stop"; + } + else + { + qmpcore.stop(); + playing=false; + text="Play"; + hsTimer.value=0;uiTimer.stop(); + } + } + } + + Slider { + id: hsTimer + y: 210 + height: 22 + anchors.right: parent.right + anchors.rightMargin: 8 + anchors.left: parent.left + anchors.leftMargin: 8 + anchors.bottom: parent.bottom + anchors.bottomMargin: 8 + tickmarksEnabled: false + stepSize: 1 + maximumValue: 100 + property bool autovalchange: false + onValueChanged: { + if(autovalchange||pressed)return; + if(playing){qmpcore.setTCeptr(value);qmpcore.panic();} + } + onPressedChanged: { + if(!pressed) + { + /*if(playing) + { + if(ui->hsTimer->value()==100){on_pbNext_clicked();return;} + player->setTCeptr(player->getStamp(ui->hsTimer->value()),ui->hsTimer->value()); + player->playerPanic(); + offset=ui->hsTimer->value()/100.*player->getFtime(); + st=std::chrono::steady_clock::now(); + } + else + { + player->setTCeptr(player->getStamp(ui->hsTimer->value()),ui->hsTimer->value()); + offset=ui->hsTimer->value()/100.*player->getFtime(); + char ts[100]; + sprintf(ts,"%02d:%02d",(int)(offset)/60,(int)(offset)%60); + ui->lbCurTime->setText(ts); + }*/ + if(playing){qmpcore.setTCeptr(value);qmpcore.panic();} + } + } + } + } + + CQMPCoreWrapper { + id: qmpcore + } + Timer { + id: uiTimer + interval: 100 + running: false + repeat: true + onTriggered: { + if(!hsTimer.pressed) + { + hsTimer.autovalchange=true; + hsTimer.value=qmpcore.getProgress(); + hsTimer.autovalchange=false; + } + } + } + + Text { + id: fileName + text: qsTr("...") + anchors.centerIn: parent + } + + Button { + id: button1 + x: 170 + width: 80 + height: 27 + text: qsTr("Open") + anchors.top: parent.top + anchors.topMargin: 142 + anchors.horizontalCenter: parent.horizontalCenter + onClicked: { + fileDialog.open(); + } + } + + FileDialog { + id: fileDialog + title: qsTr("Select midi file") + nameFilters: ["MIDI Files (*.mid *.midi)"] + onAccepted: { + fileName.text=fileUrl; + } + } +} + diff --git a/qmidiplayerlite.src.d/qml.qrc b/qmidiplayerlite.src.d/qml.qrc new file mode 100644 index 0000000..5f6483a --- /dev/null +++ b/qmidiplayerlite.src.d/qml.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>main.qml</file> + </qresource> +</RCC> diff --git a/qmidiplayerlite.src.d/qmpcorewrapper.hpp b/qmidiplayerlite.src.d/qmpcorewrapper.hpp new file mode 100644 index 0000000..558ed74 --- /dev/null +++ b/qmidiplayerlite.src.d/qmpcorewrapper.hpp @@ -0,0 +1,58 @@ +#ifndef QMPCOREWRAPPER_H +#define QMPCOREWRAPPER_H +#include <QObject> +#include <QUrl> +#include <thread> +#include <fluidsynth.h> +#include "../common/qmpmidiplay.hpp" +class CQMPCoreWrapper:public QObject +{ + Q_OBJECT +private: + CMidiPlayer *mp; + std::thread *playerTh; + int curprog; +public: + explicit CQMPCoreWrapper(QObject* parent=0):QObject(parent) + { + mp=new CMidiPlayer(false); + } + ~CQMPCoreWrapper(){delete mp;} + Q_INVOKABLE void initFluidSynth() + { + fluid_settings_t *fsettings=mp->getFluidSettings(); + fluid_settings_setstr(fsettings,"audio.driver","pulseaudio"); + mp->fluidInitialize(); + mp->pushSoundFont("/media/Files/FluidR3_Ext.sf2"); + } + Q_INVOKABLE void deinitFluidSynth() + { + mp->fluidDeinitialize(); + } + Q_INVOKABLE void loadFile(QUrl file) + { + mp->playerLoadFile(file.toLocalFile().toStdString().c_str()); + mp->playerInit();curprog=0; + } + Q_INVOKABLE void playFile() + { + playerTh=new std::thread(&CMidiPlayer::playerThread,mp); + } + Q_INVOKABLE void stop() + { + mp->playerDeinit();playerTh->join();delete playerTh; + } + Q_INVOKABLE int getProgress() + { + while(!mp->isFinished()&&mp->getTCeptr()>mp->getStamp(curprog) + &&curprog<=100) + ++curprog; + return curprog; + } + Q_INVOKABLE void panic(){mp->playerPanic();} + Q_INVOKABLE void setTCeptr(int perct) + { + mp->setTCeptr(mp->getStamp(perct),perct);curprog=perct; + } +}; +#endif // QMPCOREWRAPPER_H diff --git a/qmidiplayerlite.src.d/qmpmidiplay.cpp b/qmidiplayerlite.src.d/qmpmidiplay.cpp new file mode 100644 index 0000000..baec9a2 --- /dev/null +++ b/qmidiplayerlite.src.d/qmpmidiplay.cpp @@ -0,0 +1,406 @@ +#include <cstdio> +#include <chrono> +#include <thread> +#include <fluidsynth.h> +#include "qmpmidiplay.hpp" +#ifdef _WIN32 +#include <windows.h> +uint64_t pf; +#endif +void CMidiPlayer::fluidPreInitialize() +{ + settings=new_fluid_settings(); +} +void CMidiPlayer::fluidInitialize() +{ + synth=new_fluid_synth(settings); + adriver=new_fluid_audio_driver(settings,synth); + fluid_synth_set_chorus(synth,FLUID_CHORUS_DEFAULT_N,FLUID_CHORUS_DEFAULT_LEVEL, + FLUID_CHORUS_DEFAULT_SPEED,FLUID_CHORUS_DEFAULT_DEPTH, + FLUID_CHORUS_DEFAULT_TYPE); +#ifndef _WIN32 + if(!singleInstance) + { + if(midiFile->getStandard()==4) + fluid_synth_set_channel_type(synth,9,CHANNEL_TYPE_MELODIC); + else if(midiFile->getStandard()==1) + fluid_synth_set_channel_type(synth,9,CHANNEL_TYPE_DRUM); + else + { + fluid_synth_set_channel_type(synth,9,CHANNEL_TYPE_DRUM); + fluid_synth_bank_select(synth,9,128); + } + } +#endif +} +void CMidiPlayer::fluidDeinitialize() +{ + if(!synth||!adriver||!settings)return; + delete_fluid_settings(settings); + delete_fluid_audio_driver(adriver); + delete_fluid_synth(synth); + settings=NULL;synth=NULL;adriver=NULL; +} +void CMidiPlayer::processEvent(const SEvent *e) +{ + switch(e->type&0xF0) + { + case 0x80://Note off + fluid_synth_noteoff(synth,e->type&0x0F,e->p1); + break; + case 0x90://Note on + if((mute>>(e->type&0x0F))&1)break;//muted + if(solo&&!((solo>>(e->type&0x0F))&1))break; + fluid_synth_noteon(synth,e->type&0x0F,e->p1,e->p2); + break; + case 0xB0://CC + if(e->p1==100)rpnid=e->p2; + if(e->p1==6)rpnval=e->p2; + if(~rpnid&&~rpnval) + { + if(rpnid==0)fluid_synth_pitch_wheel_sens(synth,e->type&0x0F,rpnval); + rpnid=rpnval=-1; + } + fluid_synth_cc(synth,e->type&0x0F,e->p1,e->p2); + break; + case 0xC0://PC + fluid_synth_program_change(synth,e->type&0x0F,e->p1); + break; + case 0xE0://PW + fluid_synth_pitch_bend(synth,e->type&0x0F,e->p1); + break; + case 0xF0://Meta/SysEx + if((e->type&0x0F)==0x0F) + { + switch(e->p1) + { + case 0x51: + ctempo=e->p2;dpt=ctempo*1000/divs; + break; + case 0x58: + ctsn=e->p2>>24; + ctsd=1<<((e->p2>>16)&0xFF); + break; + case 0x59: + cks=e->p2; + break; + case 0x01:case 0x02:case 0x03: + case 0x04:case 0x05:case 0x06: + case 0x07: + if(e->str)puts(e->str); + break; + } + } + if((e->type&0x0F)==0x00||(e->type&0x0F)==07) + { + int io=0; + if(sendSysEx)fluid_synth_sysex(synth,e->str,e->p1,NULL,&io,NULL,0); + } + break; + } +} +void CMidiPlayer::processEventStub(const SEvent *e) +{ + switch(e->type&0xF0) + { + case 0xB0://CC + if(e->p1==100)rpnid=e->p2; + if(e->p1==6)rpnval=e->p2; + if(~rpnid&&~rpnval) + { + if(rpnid==0)ccc[e->type&0x0F][134]=rpnval; + rpnid=rpnval=-1; + } + ccc[e->type&0x0F][e->p1]=e->p2; + break; + case 0xC0://PC + ccc[e->type&0x0F][128]=e->p1; + break; + case 0xD0://CP + ccc[e->type&0x0F][129]=e->p1; + break; + case 0xE0://PW + ccc[e->type&0x0F][130]=e->p1; + break; + case 0xF0://Meta/SysEx + if((e->type&0x0F)==0x0F) + { + switch(e->p1) + { + case 0x51: + ctempo=e->p2;dpt=ctempo*1000/divs; + ccc[0][131]=dpt; + break; + case 0x58: + ccc[0][132]=e->p2; + break; + case 0x59: + ccc[0][133]=e->p2; + break; + } + } + break; + } +} +#ifdef _WIN32 +void w32usleep(uint64_t t) +{ + uint64_t st=0,ct=0; + QueryPerformanceCounter((LARGE_INTEGER*)&st); + do{ + if(t>10000+(ct-st)*1000000/pf)Sleep((t-(ct-st)*1000000/pf)/2000); + else if(t>5000+(ct-st)*1000000/pf)Sleep(1); + else std::this_thread::yield(); + QueryPerformanceCounter((LARGE_INTEGER*)&ct); + }while((ct-st)*1000000<t*pf); +} +#endif +void CMidiPlayer::playEvents() +{ + for(uint32_t ct=midiFile->getEvent(0)->time;tceptr<midiFile->getEventCount();) + { + while(tcpaused)std::this_thread::sleep_for(std::chrono::milliseconds(100)); + while(!tcstop&&midiFile&&tceptr<midiFile->getEventCount()&&ct==midiFile->getEvent(tceptr)->time) + processEvent(midiFile->getEvent(tceptr++)); + if(tcstop||!midiFile||tceptr>=midiFile->getEventCount())break; + if(resumed)resumed=false; + else +#ifdef _WIN32 + w32usleep((midiFile->getEvent(tceptr)->time-ct)*(dpt/1000)); +#else + std::this_thread::sleep_for(std::chrono::nanoseconds(midiFile->getEvent(tceptr)->time-ct)*dpt); +#endif + if(tcstop||!midiFile)break; + ct=midiFile->getEvent(tceptr)->time; + } + while(!tcstop&&synth&&(waitvoice&&fluid_synth_get_active_voice_count(synth)>0))std::this_thread::sleep_for(std::chrono::milliseconds(2)); + finished=1; +} +void CMidiPlayer::fileTimer1Pass() +{ + ftime=.0;ctempo=0x7A120;dpt=ctempo*1000/divs; + for(uint32_t eptr=0,ct=midiFile->getEvent(0)->time;eptr<midiFile->getEventCount();) + { + while(eptr<midiFile->getEventCount()&&ct==midiFile->getEvent(eptr)->time) + processEventStub(midiFile->getEvent(eptr++)); + if(eptr>=midiFile->getEventCount())break; + ftime+=(midiFile->getEvent(eptr)->time-ct)*dpt/1e9; + ct=midiFile->getEvent(eptr)->time; + } +} +void CMidiPlayer::fileTimer2Pass() +{ + double ctime=.0;uint32_t c=1;ctempo=0x7A120;dpt=ctempo*1000/divs; + memset(stamps,0,sizeof(stamps));memset(ccstamps,0,sizeof(ccstamps)); + memset(ccc,0,sizeof(ccc));rpnid=rpnval=-1;for(int i=0;i<16;++i) + { + ccc[i][7]=100;ccc[i][10]=64;ccc[i][11]=127; + ccc[i][11]=127;ccc[i][71]=64;ccc[i][72]=64; + ccc[i][73]=64;ccc[i][74]=64;ccc[i][75]=64; + ccc[i][76]=64;ccc[i][77]=64;ccc[i][78]=64; + ccc[0][131]=dpt;ccc[0][132]=0x04021808; + ccc[0][133]=0;ccc[0][134]=2; + }if(midiFile->getStandard()!=4)ccc[9][0]=128; + for(int i=0;i<16;++i)for(int j=0;j<135;++j) + ccstamps[0][i][j]=ccc[i][j]; + for(uint32_t eptr=0,ct=midiFile->getEvent(0)->time;eptr<midiFile->getEventCount();) + { + while(eptr<midiFile->getEventCount()&&ct==midiFile->getEvent(eptr)->time) + processEventStub(midiFile->getEvent(eptr++)); + if(eptr>=midiFile->getEventCount())break; + ctime+=(midiFile->getEvent(eptr)->time-ct)*dpt/1e9; + while(ctime>ftime*c/100.) + { + for(int i=0;i<16;++i)for(int j=0;j<135;++j) + ccstamps[c][i][j]=ccc[i][j]; + stamps[c++]=eptr; + if(c>100)break; + } + ct=midiFile->getEvent(eptr)->time; + } + while(c<101) + { + for(int i=0;i<16;++i)for(int j=0;j<135;++j) + ccstamps[c][i][j]=ccc[i][j]; + stamps[c++]=midiFile->getEventCount(); + } +} +CMidiPlayer::CMidiPlayer(bool singleInst) +{ + midiFile=NULL;resumed=false;singleInstance=singleInst; + settings=NULL;synth=NULL;adriver=NULL;waitvoice=true; +#ifdef _WIN32 + QueryPerformanceFrequency((LARGE_INTEGER*)&pf); + timeBeginPeriod(1); +#endif +} +CMidiPlayer::~CMidiPlayer() +{ + if(singleInstance)fluidDeinitialize(); +#ifdef _WIN32 + timeEndPeriod(1); +#endif +} +void CMidiPlayer::playerPanic(bool reset) +{ + if(reset)for(int i=0;i<16;++i) + { + fluid_synth_pitch_bend(synth,i,8192); + fluid_synth_cc(synth,i,7,100); + fluid_synth_cc(synth,i,10,64); + fluid_synth_cc(synth,i,11,127); + } + for(int i=0;i<16;++i)fluid_synth_all_notes_off(synth,i); +} +bool CMidiPlayer::playerLoadFile(const char* fn) +{ + midiFile=new CMidiFile(fn); + if(!midiFile->isValid())return false; + divs=midiFile->getDivision(); + fileTimer1Pass(); + fileTimer2Pass(); + return true; +} +void CMidiPlayer::playerInit() +{ + ctempo=0x7A120;ctsn=4;ctsd=4;cks=0;dpt=ctempo*1000/divs; + tceptr=0;tcstop=0;tcpaused=0;finished=0;mute=solo=0; + sendSysEx=true;rpnid=rpnval=-1; + if(!singleInstance)fluidPreInitialize(); +} +void CMidiPlayer::playerDeinit() +{ + tceptr=0;tcstop=1;tcpaused=0; + delete midiFile;midiFile=NULL; + if(!singleInstance)fluidDeinitialize(); +} +void CMidiPlayer::playerThread() +{ + playEvents(); +} + +void CMidiPlayer::rendererLoadFile(const char* ofn) +{ + settings=new_fluid_settings(); + fluid_settings_setstr(settings,"audio.file.name",ofn); +} +void CMidiPlayer::rendererInit(const char* fn) +{ + finished=0; + synth=new_fluid_synth(settings); + player=new_fluid_player(synth); + fluid_player_add(player,fn); +} +void CMidiPlayer::rendererThread() +{ + fluid_file_renderer_t* renderer=new_fluid_file_renderer(synth); + fluid_player_play(player); + while(fluid_player_get_status(player)==FLUID_PLAYER_PLAYING) + if(fluid_file_renderer_process_block(renderer)!=FLUID_OK)break; + delete_fluid_file_renderer(renderer); + finished=1; +} +void CMidiPlayer::rendererDeinit() +{ + delete_fluid_player(player); + delete_fluid_synth(synth); + delete_fluid_settings(settings); + player=NULL;synth=NULL;settings=NULL; +} + +void CMidiPlayer::sendSysX(bool send){sendSysEx=send;} +uint32_t CMidiPlayer::getStamp(int id){return stamps[id];} +uint32_t CMidiPlayer::getTCeptr(){return tceptr;} +void CMidiPlayer::setTCeptr(uint32_t ep,uint32_t st) +{ + resumed=true; + if(ep==midiFile->getEventCount())tcstop=1;else tceptr=ep; + for(int i=0;i<16;++i) + { + for(int j=0;j<120;++j)fluid_synth_cc(synth,i,j,ccstamps[st][i][j]); + fluid_synth_program_change(synth,i,ccstamps[st][i][128]); + //fluid_synth_pitch_bend(synth,i,ccstamps[st][i][130]); + dpt=ccstamps[st][0][131];ctempo=dpt*divs/1000; + ctsn=ccstamps[st][0][132]>>24;ctsd=1<<((ccstamps[st][0][132]>>16)&0xFF); + cks=ccstamps[st][0][133]; + } +} +double CMidiPlayer::getFtime(){return ftime;} +void CMidiPlayer::getCurrentTimeSignature(int *n,int *d){*n=ctsn;*d=ctsd;} +void CMidiPlayer::getCurrentKeySignature(int *ks){*ks=cks;} +uint32_t CMidiPlayer::getFileNoteCount(){return midiFile?midiFile->getNoteCount():0;} +uint32_t CMidiPlayer::getFileStandard(){return midiFile?midiFile->getStandard():0;} +const char* CMidiPlayer::getTitle(){return midiFile?midiFile->getTitle():"";} +const char* CMidiPlayer::getCopyright(){return midiFile?midiFile->getCopyright():"";} +double CMidiPlayer::getTempo(){return 60./(ctempo/1e6)/**ctsd/4.*/;} +uint32_t CMidiPlayer::getTCpaused(){return tcpaused;} +void CMidiPlayer::setTCpaused(uint32_t ps){tcpaused=ps;} +uint32_t CMidiPlayer::isFinished(){return finished;} +void CMidiPlayer::setResumed(){resumed=true;} +void CMidiPlayer::setWaitVoice(bool wv){waitvoice=wv;} +void CMidiPlayer::setGain(double gain){if(settings)fluid_settings_setnum(settings,"synth.gain",gain);} +int CMidiPlayer::getPolyphone(){return synth?fluid_synth_get_active_voice_count(synth):0;} +int CMidiPlayer::getMaxPolyphone(){return synth?fluid_synth_get_polyphony(synth):0;} +void CMidiPlayer::setMaxPolyphone(int p){if(synth)fluid_synth_set_polyphony(synth,p);} + +void CMidiPlayer::getChannelPreset(int ch,int *b,int *p,char *name) +{ + if(!synth)return(void)(b=0,p=0,strcpy(name,"")); + fluid_synth_channel_info_t info; + fluid_synth_get_channel_info(synth,ch,&info); + *b=info.bank;*p=info.program; + strcpy(name,info.name); +} +void CMidiPlayer::setChannelPreset(int ch,int b,int p) +{ + if(!synth)return; + fluid_synth_bank_select(synth,ch,b); + fluid_synth_program_change(synth,ch,p); +} +//16MSB..LSB1 +void CMidiPlayer::setBit(uint16_t &n, uint16_t bn, uint16_t b) +{n^=(-b^n)&(1<<bn);} +void CMidiPlayer::setMute(int ch,bool m) +{setBit(mute,ch,m?1:0);} +void CMidiPlayer::setSolo(int ch,bool s) +{setBit(solo,ch,s?1:0);} +int CMidiPlayer::getCC(int ch, int id) +{int ret=0;synth?fluid_synth_get_cc(synth,ch,id,&ret):0;return ret;} +void CMidiPlayer::setCC(int ch, int id, int val) +{synth?fluid_synth_cc(synth,ch,id,val):0;} +void CMidiPlayer::getReverbPara(double *r,double *d,double *w,double *l) +{ + if(!synth)return; + *r=fluid_synth_get_reverb_roomsize(synth); + *d=fluid_synth_get_reverb_damp(synth); + *w=fluid_synth_get_reverb_width(synth); + *l=fluid_synth_get_reverb_level(synth); +} +void CMidiPlayer::setReverbPara(int e,double r,double d,double w,double l) +{ + if(!synth)return; + fluid_synth_set_reverb_on(synth,e); + fluid_synth_set_reverb(synth,r,d,w,l); +} +void CMidiPlayer::getChorusPara(int *fb,double *l,double *r,double *d,int *type) +{ + if(!synth)return; + *fb=fluid_synth_get_chorus_nr(synth); + *l=fluid_synth_get_chorus_level(synth); + *r=fluid_synth_get_chorus_speed_Hz(synth); + *d=fluid_synth_get_chorus_depth_ms(synth); + *type=fluid_synth_get_chorus_type(synth); +} +void CMidiPlayer::setChorusPara(int e,int fb,double l,double r,double d,int type) +{ + if(!synth)return; + fluid_synth_set_chorus_on(synth,e); + fluid_synth_set_chorus(synth,fb,l,r,d,type); +} +fluid_settings_t* CMidiPlayer::getFluidSettings(){return settings;} +void CMidiPlayer::pushSoundFont(const char *sf) +{fluid_synth_sfload(synth,sf,1);} +int CMidiPlayer::getSFCount() +{return synth?fluid_synth_sfcount(synth):0;} +fluid_sfont_t* CMidiPlayer::getSFPtr(int sfid) +{return synth&&sfid<getSFCount()?fluid_synth_get_sfont(synth,sfid):NULL;} diff --git a/qmidiplayerlite.src.d/qmpmidiplay.hpp b/qmidiplayerlite.src.d/qmpmidiplay.hpp new file mode 100644 index 0000000..fafd677 --- /dev/null +++ b/qmidiplayerlite.src.d/qmpmidiplay.hpp @@ -0,0 +1,137 @@ +//sorry for the stupid C-like code... +#ifndef QMPMIDIPLAY_H +#define QMPMIDIPLAY_H +#include <cstring> +#include <cstdint> +#include <cstdlib> +#include <fluidsynth.h> +struct SEvent +{ + uint32_t iid,time,p1,p2; + uint8_t type; + char *str; + SEvent(){time=p1=p2=0;type=0;str=NULL;} + SEvent(uint32_t _iid,uint32_t _t,char _tp,uint32_t _p1,uint32_t _p2,const char* s=NULL) + { + iid=_iid;time=_t;type=_tp; + p1=_p1;p2=_p2; + if(s){str=new char[strlen(s)+2];strcpy(str,s);}else str=NULL; + } +}; +class CMidiFile +{ + private: + SEvent *eventList[10000000]; + char *title,*copyright; + uint32_t eventc,std;//standard 0=? 1=GM 2=GM2 3=GS 4=XG + uint32_t fmt,trk,divs; + FILE *f; + int byteread,valid; + uint32_t notes,curt,curid; + + void error(int fatal,const char* format,...); + uint32_t readSW(); + uint32_t readDW(); + uint32_t readVL(); + int eventReader(); + void trackChunkReader(); + void headerChunkReader(); + int chunkReader(int hdrXp); + public: + CMidiFile(const char* fn); + ~CMidiFile(); + const SEvent* getEvent(uint32_t id); + uint32_t getEventCount(); + uint32_t getDivision(); + uint32_t getNoteCount(); + uint32_t getStandard(); + const char* getTitle(); + const char* getCopyright(); + bool isValid(); +}; +class CMidiPlayer +{ + private: + CMidiFile *midiFile; + uint32_t stamps[101]; + uint32_t ccstamps[101][16][135],ccc[16][135]; + //0..127:cc 128:pc 129:cp 130:pb 131:tempo 132:ts 133:ks 134:pbr + int32_t rpnid,rpnval; + uint16_t mute,solo; + double ftime; + bool sendSysEx,singleInstance,waitvoice; + fluid_settings_t* settings; + fluid_synth_t* synth; + fluid_audio_driver_t* adriver; + fluid_player_t* player; + uint32_t ctempo,ctsn,ctsd,dpt,divs,cks; + //raw tempo, timesig num., timesig den., delay per tick, division, keysig + //thread control + uint32_t tceptr,tcpaused,tcstop; + uint32_t finished,resumed; + + void setBit(uint16_t &n,uint16_t bn,uint16_t b); + void processEvent(const SEvent *e); + void processEventStub(const SEvent *e); + void playEvents(); + void fileTimer1Pass(); + void fileTimer2Pass(); + public: + CMidiPlayer(bool singleInst=false); + ~CMidiPlayer(); + bool playerLoadFile(const char* fn); + void playerInit(); + void fluidPreInitialize(); + void fluidInitialize(); + void fluidDeinitialize(); + void playerDeinit(); + void playerThread(); + void playerPanic(bool reset=false); + + void rendererLoadFile(const char* ofn); + void rendererInit(const char *fn); + void rendererThread(); + void rendererDeinit(); + + //playing control methods + uint32_t getStamp(int id); + uint32_t getTCeptr(); + void setTCeptr(uint32_t ep,uint32_t st); + uint32_t getTCpaused(); + void setTCpaused(uint32_t ps); + uint32_t isFinished(); + void setResumed(); + void setWaitVoice(bool wv); + + double getFtime(); + void getCurrentTimeSignature(int *n,int *d); + void getCurrentKeySignature(int *ks); + uint32_t getFileNoteCount(); + uint32_t getFileStandard(); + double getTempo(); + const char* getTitle(); + const char* getCopyright(); + + void setGain(double gain); + void sendSysX(bool send); + int getPolyphone(); + int getMaxPolyphone(); + void setMaxPolyphone(int p); + + void setChannelPreset(int ch,int b,int p); + void getChannelPreset(int ch,int *b,int *p,char *name); + void setMute(int ch,bool m); + void setSolo(int ch,bool s); + int getCC(int ch,int id); + void setCC(int ch,int id,int val); + void getReverbPara(double *r,double *d,double *w,double *l); + void setReverbPara(int e,double r,double d,double w,double l); + void getChorusPara(int *fb,double *l,double *r,double *d,int *type); + void setChorusPara(int e,int fb,double l,double r,double d,int type); + + fluid_settings_t* getFluidSettings(); + void pushSoundFont(const char* sf); + int getSFCount(); + fluid_sfont_t* getSFPtr(int sfid); +}; +#endif diff --git a/qmidiplayerlite.src.d/qmpmidiread.cpp b/qmidiplayerlite.src.d/qmpmidiread.cpp new file mode 100644 index 0000000..0bcf597 --- /dev/null +++ b/qmidiplayerlite.src.d/qmpmidiread.cpp @@ -0,0 +1,240 @@ +//CLI Midi file player based on libfluidsynth +//Midi file reading module +//Written by Chris Xiong, 2015 +#include <cstdio> +#include <cstring> +#include <cstdlib> +#include <cstdint> +#include <cstdarg> +#include <algorithm> +#include "qmpmidiplay.hpp" +const char* GM1SysX={"\xF0\x7E\x7F\x09\x01\xF7"}; +const char* GM2SysX={"\xF0\x7E\x7F\x09\x03\xF7"}; +const char* GSSysEx={"\xF0\x41\x10\x42\x12\x40\x00\x7F\x00\x41\xF7"}; +const char* XGSysEx={"\xF0\x43\x10\x4C\x00\x00\x7E\x00\xF7"}; +bool cmp(SEvent *a,SEvent *b){return a->time-b->time?a->time<b->time:a->iid<b->iid;} +void CMidiFile::error(int fatal,const char* format,...) +{ + va_list ap; + va_start(ap,format);vfprintf(stderr,format,ap);va_end(ap); + fprintf(stderr," at %#lx\n",ftell(f)); + if(fatal)throw 2; +} +uint32_t CMidiFile::readSW() +{ + byteread+=2; + uint32_t ret=0; + for(int i=0;i<2;++i){ret<<=8;ret|=((uint32_t)fgetc(f))&0xFF;} + return ret; +} +uint32_t CMidiFile::readDW() +{ + byteread+=4; + uint32_t ret=0; + for(int i=0;i<4;++i){ret<<=8;ret|=((uint32_t)fgetc(f))&0xFF;} + return ret; +} +uint32_t CMidiFile::readVL() +{ + uint32_t ret=0,t,c=0; + do + { + t=fgetc(f); + if(++c>4)error(1,"E: Variable length type overflow."); + ret<<=7;ret|=(t&0x7F); + }while(t&0x80); + byteread+=c; + return ret; +} +int CMidiFile::eventReader()//returns 0 if End of Track encountered +{ + uint32_t delta=readVL();curt+=delta; + char type=fgetc(f);++byteread;uint32_t p1,p2; + static char lasttype; +retry: + switch(type&0xF0) + { + case 0x80://Note Off + p1=fgetc(f);p2=fgetc(f);byteread+=2; + eventList[eventc++]=new SEvent(curid,curt,type,p1,p2); + break; + case 0x90://Note On + p1=fgetc(f);p2=fgetc(f);byteread+=2; + if(p2) + { + ++notes; + eventList[eventc++]=new SEvent(curid,curt,type,p1,p2); + } + else + eventList[eventc++]=new SEvent(curid,curt,(type&0x0F)|0x80,p1,p2); + break; + case 0xA0://Note Aftertouch + p1=fgetc(f);p2=fgetc(f);byteread+=2; + eventList[eventc++]=new SEvent(curid,curt,type,p1,p2); + break; + case 0xB0://Controller Change + p1=fgetc(f);p2=fgetc(f);byteread+=2; + eventList[eventc++]=new SEvent(curid,curt,type,p1,p2); + break; + case 0xC0://Patch Change + p1=fgetc(f);++byteread; + eventList[eventc++]=new SEvent(curid,curt,type,p1,0); + break; + case 0xD0://Channel Aftertouch + p1=fgetc(f);++byteread; + eventList[eventc++]=new SEvent(curid,curt,type,p1,0); + break; + case 0xE0://Pitch wheel + p1=fgetc(f);p2=fgetc(f);byteread+=2; + eventList[eventc++]=new SEvent(curid,curt,type,(p1|(p2<<7))&0x3FFF,0); + break; + case 0xF0: + if((type&0x0F)==0x0F)//Meta Event + { + char metatype=fgetc(f);++byteread; + switch(metatype) + { + case 0x00://Sequence Number + fgetc(f);fgetc(f);fgetc(f); + byteread+=3; + break; + case 0x20://Channel Prefix + fgetc(f);fgetc(f);byteread+=2; + break; + case 0x2F://End of Track + fgetc(f);++byteread; + return 0; + break; + case 0x51://Set Tempo + p1=readDW();p1&=0x00FFFFFF; + eventList[eventc++]=new SEvent(curid,curt,type,metatype,p1); + break; + case 0x54://SMTPE offset, not handled. + fgetc(f);fgetc(f);fgetc(f); + fgetc(f);fgetc(f);fgetc(f); + byteread+=6; + break; + case 0x58://Time signature + fgetc(f);++byteread; + p1=readDW(); + eventList[eventc++]=new SEvent(curid,curt,type,metatype,p1); + break; + case 0x59://Key signature + fgetc(f);++byteread; + p1=readSW(); + eventList[eventc++]=new SEvent(curid,curt,type,metatype,p1); + break; + case 0x01:case 0x02:case 0x03: + case 0x04:case 0x05:case 0x06: + case 0x07:case 0x7F:default://text-like meta + { + uint32_t len=readVL(),c;char* str=NULL; + if(len<=1024&&len>0)str=new char[len+8]; + for(c=0;c<len;++c) + { + ++byteread;if(str)str[c]=fgetc(f);else fgetc(f); + } + if(str)str[c]='\0';eventList[eventc++]=new SEvent(curid,curt,type,metatype,0,str); + if(str&&metatype==0x03&&!title) + { + title=new char[len+8]; + strcpy(title,str); + } + if(str&&metatype==0x02&&!copyright) + { + copyright=new char[len+8]; + strcpy(copyright,str); + } + if(len<=1024&&len>0)delete[] str; + } + } + } + else if((type&0x0F)==0x00||(type&0x0F)==0x07)//SysEx + { + uint32_t len=readVL(),c;char* str=NULL; + str=new char[len+8]; + if((type&0x0F)==0x00) + { + str[0]=0xF0;++len; + for(c=1;c<len;++c){++byteread;str[c]=fgetc(f);} + } + else for(c=0;c<len;++c){++byteread;str[c]=fgetc(f);} + eventList[eventc++]=new SEvent(curid,curt,type,len,0,str); + if(!strcmp(str,GM1SysX))std=1; + if(!strcmp(str,GM2SysX))std=2; + if(!strcmp(str,GSSysEx))std=3; + if(!strcmp(str,XGSysEx))std=4; + } + else error(0,"W: Unknown event type %#x",type); + break; + default: + fseek(f,-1,SEEK_CUR);--byteread;type=lasttype;goto retry; + } + lasttype=type;++curid; + return 1; +} +void CMidiFile::trackChunkReader() +{ + int chnklen=readDW();byteread=0;curt=0;curid=0; + while(/*byteread<chnklen&&*/eventReader()); + if(byteread<chnklen) + { + error(0,"W: Extra bytes after EOT event."); + while(byteread<chnklen){fgetc(f);++byteread;} + } + /*if(byteread>chnklen) + { + error(1,"E: Read past end of track."); + }*/ +} +void CMidiFile::headerChunkReader() +{ + int chnklen=readDW();byteread=0; + if(chnklen<6)error(1,"E: Header chunk too short."); + if(chnklen>6)error(0,"W: Header chunk length longer than expected. Ignoring extra bytes."); + fmt=readSW();trk=readSW();divs=readSW(); + if(divs&0x8000)error(1,"E: SMTPE format is not supported."); + for(;byteread<chnklen;++byteread){fgetc(f);} +} +int CMidiFile::chunkReader(int hdrXp) +{ + char hdr[6]; + if(!fgets(hdr,5,f))error(1,"E: Unexpected EOF."); + if(hdrXp) + if(strncmp(hdr,"MThd",4)){error(1,"E: Wrong MIDI header.");throw;} + else return headerChunkReader(),0; + else + if(strncmp(hdr,"MTrk",4)) + { + error(0,"W: Wrong track chunk header. Ignoring the whole chunk."); + for(int chnklen=readDW();chnklen>0;--chnklen)fgetc(f);return 0; + } + else return trackChunkReader(),1; +} +CMidiFile::CMidiFile(const char* fn) +{ + title=copyright=NULL;notes=eventc=0;std=0;valid=1; + try + { + if(!(f=fopen(fn,"rb")))throw (fprintf(stderr,"E: file %s doesn't exist!\n",fn),2); + chunkReader(1); + for(uint32_t i=0;i<trk;i+=chunkReader(0)); + printf("%d note(s)\n",notes); + fclose(f); + std::sort(eventList,eventList+eventc,cmp); + } + catch(int){fprintf(stderr,"E: %s is not a supported file.\n",fn);valid=0;} +} +CMidiFile::~CMidiFile() +{ + for(uint32_t i=0;i<eventc;++i)delete eventList[i]; + if(title)delete[] title;if(copyright)delete[] copyright; +} +const SEvent* CMidiFile::getEvent(uint32_t id){return id<eventc?eventList[id]:NULL;} +uint32_t CMidiFile::getEventCount(){return eventc;} +uint32_t CMidiFile::getDivision(){return divs;} +uint32_t CMidiFile::getNoteCount(){return notes;} +uint32_t CMidiFile::getStandard(){return std;} +bool CMidiFile::isValid(){return valid;} +const char* CMidiFile::getTitle(){return title;} +const char* CMidiFile::getCopyright(){return copyright;} diff --git a/resources.qrc b/resources.qrc deleted file mode 100644 index 2eb232c..0000000 --- a/resources.qrc +++ /dev/null @@ -1,36 +0,0 @@ -<RCC> - <qresource prefix="/"> - <file>img/add.png</file> - <file>img/list.png</file> - <file>img/addfolder.png</file> - <file>img/channel.png</file> - <file>img/prev.png</file> - <file>img/qmidiplyr.png</file> - <file>img/remove.png</file> - <file>img/clear.png</file> - <file>img/down.png</file> - <file>img/effects.png</file> - <file>img/repeat-all.png</file> - <file>img/repeat-base.png</file> - <file>img/repeat-non.png</file> - <file>img/load.png</file> - <file>img/next.png</file> - <file>img/repeat-one.png</file> - <file>img/save.png</file> - <file>img/settings.png</file> - <file>img/pause.png</file> - <file>img/play.png</file> - <file>img/shuffle-off.png</file> - <file>img/shuffle.png</file> - <file>img/stop.png</file> - <file>img/up.png</file> - <file>img/visualization.png</file> - <file>img/mainw.png</file> - <file>img/chanw.png</file> - <file>doc/index.html</file> - <file>doc/version.html</file> - <file>doc/license.html</file> - <file>doc/mainwindow.html</file> - <file>doc/channeldialog.html</file> - </qresource> -</RCC> |