summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--README.md12
-rw-r--r--qmidiplayer.pro9
-rw-r--r--qmpchannelswindow.cpp88
-rw-r--r--qmpchannelswindow.hpp33
-rw-r--r--qmpchannelswindow.ui146
-rw-r--r--qmpmainwindow.cpp16
-rw-r--r--qmpmainwindow.hpp5
-rw-r--r--qmpmainwindow.ui3
-rw-r--r--qmpmidiplay.cpp94
-rw-r--r--qmpmidiplay.hpp9
-rw-r--r--qmpmidiread.cpp13
12 files changed, 395 insertions, 37 deletions
diff --git a/ChangeLog b/ChangeLog
index 3e6ead8..a4ea71e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2015-12-28 primitive version
+Partially implemented the channel window.
+Fixed a seeking bug.
+
2015-12-27 primitive version
Implemented the play list.
diff --git a/README.md b/README.md
index fa0c25a..50eb3cd 100644
--- a/README.md
+++ b/README.md
@@ -4,9 +4,9 @@ A cross-platform midi file player based on libfluidsynth and Qt.
Currently it's still very incomplete and not suitable for everyday use.
Planned features:
-> Channel mute/solo (not implemented)
-> Editing channel parameters on-the-fly (not implemented)
-> Playlists (partially implemented)
-> Editing synthesizer effects (not implemented)
-> Visualization (not implemented)
-> Rendering midi to wave file (not implemented)
+* Channel mute/solo (not implemented)
+* Editing channel parameters on-the-fly (not implemented)
+* Playlists (partially implemented)
+* Editing synthesizer effects (not implemented)
+* Visualization (not implemented)
+* Rendering midi to wave file (not implemented)
diff --git a/qmidiplayer.pro b/qmidiplayer.pro
index 386ea72..12745ee 100644
--- a/qmidiplayer.pro
+++ b/qmidiplayer.pro
@@ -16,14 +16,17 @@ SOURCES += main.cpp\
qmpmainwindow.cpp \
qmpmidiplay.cpp \
qmpmidiread.cpp \
- qmpplistwindow.cpp
+ qmpplistwindow.cpp \
+ qmpchannelswindow.cpp
HEADERS += qmpmainwindow.hpp \
qmpmidiplay.hpp \
- qmpplistwindow.hpp
+ qmpplistwindow.hpp \
+ qmpchannelswindow.hpp
FORMS += qmpmainwindow.ui \
- qmpplistwindow.ui
+ qmpplistwindow.ui \
+ qmpchannelswindow.ui
QMAKE_CXXFLAGS += -std=c++11 -Wall
LIBS += -lfluidsynth
diff --git a/qmpchannelswindow.cpp b/qmpchannelswindow.cpp
new file mode 100644
index 0000000..6aca878
--- /dev/null
+++ b/qmpchannelswindow.cpp
@@ -0,0 +1,88 @@
+#include <QCheckBox>
+#include <QPushButton>
+#include <QComboBox>
+#include <QLabel>
+#include "qmpchannelswindow.hpp"
+#include "ui_qmpchannelswindow.h"
+#include "qmpmainwindow.hpp"
+
+qmpchannelswindow::qmpchannelswindow(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::qmpchannelswindow)
+{
+ ui->setupUi(this);
+ connect(this,SIGNAL(dialogClosing()),parent,SLOT(dialogClosed()));
+ for(int i=0;i<16;++i)
+ {
+ ui->twChannels->setCellWidget(i,0,new QCheckBox(""));
+ connect(ui->twChannels->cellWidget(i,0),SIGNAL(stateChanged(int)),this,SLOT(channelMSChanged()));
+ ui->twChannels->setCellWidget(i,1,new QCheckBox(""));
+ connect(ui->twChannels->cellWidget(i,1),SIGNAL(stateChanged(int)),this,SLOT(channelMSChanged()));
+ ui->twChannels->setCellWidget(i,2,new QComboBox());
+ QComboBox *cb=(QComboBox*)ui->twChannels->cellWidget(i,2);
+ //stub
+ cb->addItem("Internal fluidsynth");
+ ui->twChannels->setCellWidget(i,3,new QLabel(""));
+ ui->twChannels->setCellWidget(i,4,new QPushButton("..."));
+ }
+ ui->twChannels->setColumnWidth(0,32);
+ ui->twChannels->setColumnWidth(1,32);
+ ui->twChannels->setColumnWidth(2,192);
+ ui->twChannels->setColumnWidth(3,192);
+ ui->twChannels->setColumnWidth(4,32);
+}
+
+void qmpchannelswindow::closeEvent(QCloseEvent *event)
+{
+ setVisible(false);
+ emit dialogClosing();
+ event->accept();
+}
+
+void qmpchannelswindow::channelWindowsUpdate()
+{
+ for(int i=0;i<16;++i)
+ {
+ char data[128],nm[24];
+ int b,p;
+ ((qmpMainWindow*)this->parent())->getPlayer()->getChannelPreset(i,&b,&p,nm);
+ sprintf(data,"%d:%d %s",b,p,nm);
+ ((QLabel*)ui->twChannels->cellWidget(i,3))->setText(data);
+ }
+}
+
+void qmpchannelswindow::channelMSChanged()
+{
+ for(int i=0;i<16;++i)
+ {
+ QCheckBox *m,*s;
+ m=(QCheckBox*)ui->twChannels->cellWidget(i,0);
+ s=(QCheckBox*)ui->twChannels->cellWidget(i,1);
+ if(m->isChecked()&&s->isChecked())s->setChecked(false);
+ ((qmpMainWindow*)this->parent())->getPlayer()->setMute(i,m->isChecked());
+ ((qmpMainWindow*)this->parent())->getPlayer()->setSolo(i,s->isChecked());
+ }
+}
+
+qmpchannelswindow::~qmpchannelswindow()
+{
+ delete ui;
+}
+
+void qmpchannelswindow::on_pbUnmute_clicked()
+{
+ for(int i=0;i<16;++i)
+ {
+ ((QCheckBox*)ui->twChannels->cellWidget(i,0))->setChecked(false);
+ ((qmpMainWindow*)this->parent())->getPlayer()->setMute(i,false);
+ }
+}
+
+void qmpchannelswindow::on_pbUnsolo_clicked()
+{
+ for(int i=0;i<16;++i)
+ {
+ ((QCheckBox*)ui->twChannels->cellWidget(i,1))->setChecked(false);
+ ((qmpMainWindow*)this->parent())->getPlayer()->setSolo(i,false);
+ }
+}
diff --git a/qmpchannelswindow.hpp b/qmpchannelswindow.hpp
new file mode 100644
index 0000000..4bf3ad2
--- /dev/null
+++ b/qmpchannelswindow.hpp
@@ -0,0 +1,33 @@
+#ifndef QMPCHANNELSWINDOW_H
+#define QMPCHANNELSWINDOW_H
+
+#include <QDialog>
+#include <QCloseEvent>
+
+namespace Ui {
+ class qmpchannelswindow;
+}
+
+class qmpchannelswindow : public QDialog
+{
+ Q_OBJECT
+
+ public:
+ explicit qmpchannelswindow(QWidget *parent = 0);
+ ~qmpchannelswindow();
+ void closeEvent(QCloseEvent *event);
+ signals:
+ void dialogClosing();
+ public slots:
+ void channelWindowsUpdate();
+ void channelMSChanged();
+ private slots:
+ void on_pbUnmute_clicked();
+
+ void on_pbUnsolo_clicked();
+
+ private:
+ Ui::qmpchannelswindow *ui;
+};
+
+#endif // QMPCHANNELSWINDOW_H
diff --git a/qmpchannelswindow.ui b/qmpchannelswindow.ui
new file mode 100644
index 0000000..dba6009
--- /dev/null
+++ b/qmpchannelswindow.ui
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>qmpchannelswindow</class>
+ <widget class="QDialog" name="qmpchannelswindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>580</width>
+ <height>410</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>580</width>
+ <height>410</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>580</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>Channels</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_1">
+ <item>
+ <widget class="QTableWidget" name="twChannels">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::NoSelection</enum>
+ </property>
+ <property name="cornerButtonEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="rowCount">
+ <number>16</number>
+ </property>
+ <property name="columnCount">
+ <number>5</number>
+ </property>
+ <row/>
+ <row/>
+ <row/>
+ <row/>
+ <row/>
+ <row/>
+ <row/>
+ <row/>
+ <row/>
+ <row/>
+ <row/>
+ <row/>
+ <row/>
+ <row/>
+ <row/>
+ <row/>
+ <column>
+ <property name="text">
+ <string>M</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>S</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Device</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Preset</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </column>
+ <item row="0" column="0">
+ <property name="text">
+ <string/>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="pbSave">
+ <property name="text">
+ <string>Save</string>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pbLoad">
+ <property name="text">
+ <string>Load</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pbUnmute">
+ <property name="text">
+ <string>Unmute All</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pbUnsolo">
+ <property name="text">
+ <string>Unsolo All</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/qmpmainwindow.cpp b/qmpmainwindow.cpp
index 7d2bf0c..69cf9df 100644
--- a/qmpmainwindow.cpp
+++ b/qmpmainwindow.cpp
@@ -11,9 +11,11 @@ qmpMainWindow::qmpMainWindow(QWidget *parent) :
ui->setupUi(this);player=new CMidiPlayer();
playing=false;stopped=true;dragging=false;
plistw=new qmpplistwindow(this);
+ chnlw=new qmpchannelswindow(this);
ui->lbFileName->setText("");
timer=new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(updateWidgets()));
+ connect(timer,SIGNAL(timeout()),chnlw,SLOT(channelWindowsUpdate()));
}
qmpMainWindow::~qmpMainWindow()
@@ -120,14 +122,14 @@ void qmpMainWindow::on_hsTimer_sliderReleased()
if(playing)
{
if(ui->hsTimer->value()==100){on_pbNext_clicked();return;}
- player->setTCeptr(player->getStamp(ui->hsTimer->value()));
+ 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()));
+ 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);
@@ -157,6 +159,7 @@ void qmpMainWindow::on_pbStop_clicked()
void qmpMainWindow::dialogClosed()
{
if(!plistw->isVisible())ui->pbPList->setChecked(false);
+ if(!chnlw->isVisible())ui->pbChannels->setChecked(false);
}
void qmpMainWindow::on_pbPList_clicked()
@@ -164,12 +167,17 @@ void qmpMainWindow::on_pbPList_clicked()
if(ui->pbPList->isChecked())plistw->show();else plistw->close();
}
+void qmpMainWindow::on_pbChannels_clicked()
+{
+ if(ui->pbChannels->isChecked())chnlw->show();else chnlw->close();
+}
+
void qmpMainWindow::on_pbPrev_clicked()
{
timer->stop();player->playerDeinit();
if(playerTh){playerTh->join();delete playerTh;playerTh=NULL;}
ui->hsTimer->setValue(0);
- QString fns=plistw->getPrevItem();
+ QString fns=plistw->getPrevItem();if(fns.length()==0)return on_pbStop_clicked();
ui->lbFileName->setText(QUrl(fns).fileName());
player->playerLoadFile(fns.toStdString().c_str());
char ts[100];
@@ -186,7 +194,7 @@ void qmpMainWindow::on_pbNext_clicked()
timer->stop();player->playerDeinit();
if(playerTh){playerTh->join();delete playerTh;playerTh=NULL;}
ui->hsTimer->setValue(0);
- QString fns=plistw->getNextItem();
+ QString fns=plistw->getNextItem();if(fns.length()==0)return on_pbStop_clicked();
ui->lbFileName->setText(QUrl(fns).fileName());
player->playerLoadFile(fns.toStdString().c_str());
char ts[100];
diff --git a/qmpmainwindow.hpp b/qmpmainwindow.hpp
index cfb740d..8d64f37 100644
--- a/qmpmainwindow.hpp
+++ b/qmpmainwindow.hpp
@@ -8,6 +8,7 @@
#include <chrono>
#include "qmpmidiplay.hpp"
#include "qmpplistwindow.hpp"
+#include "qmpchannelswindow.hpp"
namespace Ui {
class qmpMainWindow;
@@ -21,6 +22,7 @@ class qmpMainWindow : public QMainWindow
explicit qmpMainWindow(QWidget *parent = 0);
void closeEvent(QCloseEvent *event);
~qmpMainWindow();
+ CMidiPlayer* getPlayer(){return player;}
private slots:
void on_pbPlayPause_clicked();
@@ -39,6 +41,8 @@ class qmpMainWindow : public QMainWindow
void on_pbNext_clicked();
+ void on_pbChannels_clicked();
+
public slots:
void dialogClosed();
void selectionChanged();
@@ -52,6 +56,7 @@ class qmpMainWindow : public QMainWindow
double offset;
CMidiPlayer *player;
qmpplistwindow *plistw;
+ qmpchannelswindow *chnlw;
};
diff --git a/qmpmainwindow.ui b/qmpmainwindow.ui
index e1bbd29..1cce37d 100644
--- a/qmpmainwindow.ui
+++ b/qmpmainwindow.ui
@@ -210,6 +210,9 @@
<height>32</height>
</size>
</property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
</widget>
<widget class="QPushButton" name="pbPList">
<property name="geometry">
diff --git a/qmpmidiplay.cpp b/qmpmidiplay.cpp
index 9760f81..b676c99 100644
--- a/qmpmidiplay.cpp
+++ b/qmpmidiplay.cpp
@@ -7,7 +7,7 @@ void CMidiPlayer::fluidInitialize(const char* sf)
{
settings=new_fluid_settings();
fluid_settings_setstr(settings,"audio.driver","pulseaudio");
- fluid_settings_setint(settings,"synth.cpu-cores",1);
+ fluid_settings_setint(settings,"synth.cpu-cores",4);
fluid_settings_setint(settings,"synth.min-note-length",0);
fluid_settings_setint(settings,"synth.polyphony",256);
synth=new_fluid_synth(settings);
@@ -30,6 +30,8 @@ void CMidiPlayer::processEvent(const SEvent *e)
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
@@ -65,8 +67,33 @@ void CMidiPlayer::processEvent(const SEvent *e)
}
void CMidiPlayer::processEventStub(const SEvent *e)
{
- if(e->type==0xFF&&e->p1==0x51)
- {ctempo=e->p2;dpt=ctempo*1000/divs;}
+ switch(e->type&0xF0)
+ {
+ case 0xB0://CC
+ 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;
+ }
+ }
+ break;
+ }
}
void CMidiPlayer::playEvents()
{
@@ -98,18 +125,37 @@ void CMidiPlayer::fileTimer1Pass()
}
void CMidiPlayer::fileTimer2Pass()
{
- memset(stamps,0,sizeof(stamps));
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));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;
+ }
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.){stamps[c++]=eptr;if(c>100)throw;}
+ while(ctime>ftime*c/100.)
+ {
+ for(int i=0;i<16;++i)for(int j=0;j<132;++j)
+ ccstamps[c][i][j]=ccc[i][j];
+ stamps[c++]=eptr;
+ if(c>100)throw;
+ }
ct=midiFile->getEvent(eptr)->time;
}
- while(c<101)stamps[c++]=midiFile->getEventCount();
+ while(c<101)
+ {
+ for(int i=0;i<16;++i)for(int j=0;j<132;++j)
+ ccstamps[c][i][j]=ccc[i][j];
+ stamps[c++]=midiFile->getEventCount();
+ }
}
CMidiPlayer::CMidiPlayer()
{
@@ -118,8 +164,6 @@ CMidiPlayer::CMidiPlayer()
}
void CMidiPlayer::playerPanic()
{
- //for(int i=0;i<16;++i)fluid_synth_cc(synth,i,123,0);//not supported?
- //fluid_synth_system_reset(synth);//reverts to default presets...
for(int i=0;i<16;++i)fluid_synth_all_notes_off(synth,i);
//for(int i=0;i<16;++i)for(int j=0;j<128;++j)fluid_synth_noteoff(synth,i,j);
}
@@ -133,7 +177,7 @@ void CMidiPlayer::playerLoadFile(const char* fn)
void CMidiPlayer::playerInit()
{
ctempo=0x7A120;ctsn=4;ctsd=2;dpt=ctempo*1000/divs;
- tceptr=0;tcstop=0;tcpaused=0;finished=0;
+ tceptr=0;tcstop=0;tcpaused=0;finished=0;mute=solo=0;
fluidInitialize("/media/Files/FluidR3_Ext.sf2");
}
void CMidiPlayer::playerDeinit()
@@ -147,7 +191,17 @@ void CMidiPlayer::playerThread()
}
uint32_t CMidiPlayer::getStamp(int id){return stamps[id];}
uint32_t CMidiPlayer::getTCeptr(){return tceptr;}
-void CMidiPlayer::setTCeptr(uint32_t ep){tceptr=ep;}
+void CMidiPlayer::setTCeptr(uint32_t ep,uint32_t st)
+{
+ 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];
+ }
+}
double CMidiPlayer::getFtime(){return ftime;}
uint32_t CMidiPlayer::getTCpaused(){return tcpaused;}
void CMidiPlayer::setTCpaused(uint32_t ps){tcpaused=ps;}
@@ -157,3 +211,23 @@ void CMidiPlayer::setGain(double gain){if(settings)fluid_settings_setnum(setting
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;
+ fluid_synth_channel_info_t info;
+ fluid_synth_get_channel_info(synth,ch,&info);
+ *b=info.bank;*p=info.program;
+ strcpy(name,info.name);
+}
+//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);
+}
diff --git a/qmpmidiplay.hpp b/qmpmidiplay.hpp
index f32e215..d5f0c54 100644
--- a/qmpmidiplay.hpp
+++ b/qmpmidiplay.hpp
@@ -48,6 +48,8 @@ class CMidiPlayer
private:
CMidiFile *midiFile;
uint32_t stamps[101];
+ uint32_t ccstamps[101][16][132],ccc[16][132];//0..127:cc 128:pc 129:cp 130:pb 131:tempo
+ uint16_t mute,solo;
double ftime;
fluid_settings_t* settings;
fluid_synth_t* synth;
@@ -57,6 +59,7 @@ class CMidiPlayer
uint32_t tceptr,tcpaused,tcstop;
uint32_t finished,resumed;
+ void setBit(uint16_t &n,uint16_t bn,uint16_t b);
void fluidInitialize(const char* sf);
void fluidDeinitialize();
void processEvent(const SEvent *e);
@@ -74,7 +77,7 @@ class CMidiPlayer
uint32_t getStamp(int id);
uint32_t getTCeptr();
- void setTCeptr(uint32_t ep);
+ void setTCeptr(uint32_t ep,uint32_t st);
uint32_t getTCpaused();
void setTCpaused(uint32_t ps);
double getFtime();
@@ -85,5 +88,9 @@ class CMidiPlayer
int getPolyphone();
int getMaxPolyphone();
void setMaxPolyphone(int p);
+
+ void getChannelPreset(int ch,int *b,int *p,char *name);
+ void setMute(int ch,bool m);
+ void setSolo(int ch,bool s);
};
#endif
diff --git a/qmpmidiread.cpp b/qmpmidiread.cpp
index dff91a1..b960369 100644
--- a/qmpmidiread.cpp
+++ b/qmpmidiread.cpp
@@ -45,7 +45,6 @@ uint32_t CMidiFile::readVL()
int CMidiFile::eventReader()//returns 0 if End of Track encountered
{
uint32_t delta=readVL();curt+=delta;
- //printf("event@%#lx, delta %u: ",ftell(f),delta);
char type=fgetc(f);++byteread;uint32_t p1,p2;
static char lasttype;
retry:
@@ -54,7 +53,6 @@ retry:
case 0x80://Note Off
p1=fgetc(f);p2=fgetc(f);byteread+=2;
eventList[eventc++]=new SEvent(curid,curt,type,p1,p2);
- //printf("Note off at ch#%d, note #%d, vel %d.\n",ch,p1,p2);
break;
case 0x90://Note On
p1=fgetc(f);p2=fgetc(f);byteread+=2;
@@ -65,32 +63,26 @@ retry:
}
else
eventList[eventc++]=new SEvent(curid,curt,(type&0x0F)|0x80,p1,p2);
- //printf("Note on at ch#%d, note #%d, vel %d.\n",ch,p1,p2);
break;
case 0xA0://Note Aftertouch
p1=fgetc(f);p2=fgetc(f);byteread+=2;
eventList[eventc++]=new SEvent(curid,curt,type,p1,p2);
- //printf("Note aftertouch at ch#%d, note #%d, vel %d.\n",ch,p1,p2);
break;
case 0xB0://Controller Change
p1=fgetc(f);p2=fgetc(f);byteread+=2;
eventList[eventc++]=new SEvent(curid,curt,type,p1,p2);
- //printf("Controller change at ch#%d, cc #%d, val %d.\n",ch,p1,p2);
break;
case 0xC0://Patch Change
p1=fgetc(f);++byteread;
eventList[eventc++]=new SEvent(curid,curt,type,p1,0);
- //printf("Patch change at ch#%d, pc #%d.\n",ch,p1);
break;
case 0xD0://Channel Aftertouch
p1=fgetc(f);++byteread;
eventList[eventc++]=new SEvent(curid,curt,type,p1,0);
- //printf("Channel aftertouch at ch#%d, vel #%d.\n",ch,p1);
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);
- //printf("Pitch wheel at ch#%d, val %u.\n",type&0x0F,(p1|(p2<<7))&0x3FFF);
break;
case 0xF0:
if((type&0x0F)==0x0F)//Meta Event
@@ -101,22 +93,17 @@ retry:
case 0x00://Sequence Number
fgetc(f);fgetc(f);fgetc(f);
byteread+=3;
- //printf("seqence number.\n");
break;
case 0x20://Channel Prefix
fgetc(f);fgetc(f);byteread+=2;
- //printf("channel prefix.\n");
break;
case 0x2F://End of Track
fgetc(f);++byteread;
- //printf("end of track.\n");
return 0;
break;
case 0x51://Set Tempo
- //fgetc(f);fgetc(f);fgetc(f);fgetc(f);
p1=readDW();p1&=0x00FFFFFF;
eventList[eventc++]=new SEvent(curid,curt,type,metatype,p1);
- //byteread+=4;
break;
case 0x54://SMTPE offset, not handled.
fgetc(f);fgetc(f);fgetc(f);