aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2017-06-16 23:51:26 +0800
committerGravatar Chris Xiong <chirs241097@gmail.com> 2017-06-16 23:51:26 +0800
commit64c91c7da66ba71e2bb32077680f234aba4ac65d (patch)
treedc44e44c4f2b1530952f57538d7164f712b61b02
parent37ba9dd1ce449bc2c2f422dd04225bc68bd89c59 (diff)
downloadQMidiPlayer-64c91c7da66ba71e2bb32077680f234aba4ac65d.tar.xz
Code refactoring and fix to memory leaks.
-rw-r--r--ChangeLog10
-rw-r--r--core/qmpmidiplay.cpp104
-rw-r--r--core/qmpmidiplay.hpp39
-rw-r--r--core/qmpmidiread.cpp110
-rw-r--r--include/qmpcorepublic.hpp16
-rw-r--r--midifmt-plugin/midifmtplugin.cpp20
-rw-r--r--qmidiplayer-desktop/qmphelpwindow.hpp2
-rw-r--r--qmidiplayer-desktop/qmpmainwindow.cpp9
-rw-r--r--visualization/qmpvisualization.cpp4
-rw-r--r--visualization/qmpvisualization.hpp2
10 files changed, 162 insertions, 154 deletions
diff --git a/ChangeLog b/ChangeLog
index f7626be..ab665b6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2017-06-16 0.8.6 indev
+Code refactoring:
+ Tracks information are now preserved.
+ CMidiReaderCollection no longer handles file info
+ operations.
+ Note on with zero velocity are no longer treated
+ separately.
+Small fixes to several memory leaks.
+More code refactoring is going on.
+
2017-06-02 0.8.5 indev
Accumulative changes from 2017-03:
Don't crash if RtMidi initialization failed.
diff --git a/core/qmpmidiplay.cpp b/core/qmpmidiplay.cpp
index b72ebe8..c8169ca 100644
--- a/core/qmpmidiplay.cpp
+++ b/core/qmpmidiplay.cpp
@@ -1,5 +1,6 @@
#include <cstdio>
#include <cstring>
+#include <algorithm>
#include <chrono>
#include <thread>
#include <fluidsynth.h>
@@ -28,9 +29,9 @@ void CMidiPlayer::fluidInitialize()
#ifndef _WIN32
if(!singleInstance)
{
- if(midiReaders->getStandard()==4)
+ if(midiFile->std==4)
fluid_synth_set_channel_type(synth,9,CHANNEL_TYPE_MELODIC);
- else if(midiReaders->getStandard()==1)
+ else if(midiFile->std==1)
fluid_synth_set_channel_type(synth,9,CHANNEL_TYPE_DRUM);
else
{
@@ -194,6 +195,11 @@ void w32usleep(uint64_t t)
timeEndPeriod(1);
}
#endif
+SEvent* CMidiPlayer::getEvent(int id)
+{
+ size_t t=eorder[id].first,e=eorder[id].second;
+ return &midiFile->tracks[t].eventList[e];
+}
void CMidiPlayer::prePlayInit()
{
playerPanic(true);
@@ -202,26 +208,26 @@ void CMidiPlayer::prePlayInit()
}
void CMidiPlayer::playEvents()
{
- for(ct=midiReaders->getEvent(0)->time;tceptr<midiReaders->getEventCount();)
+ for(ct=getEvent(0)->time;tceptr<ecnt;)
{
while(tcpaused)std::this_thread::sleep_for(std::chrono::milliseconds(100));
using namespace std::chrono;
high_resolution_clock::time_point b=high_resolution_clock::now();
- while(!tcstop&&midiReaders&&tceptr<midiReaders->getEventCount()&&ct==midiReaders->getEvent(tceptr)->time)
- processEvent(midiReaders->getEvent(tceptr++));
- if(tcstop||!midiReaders||tceptr>=midiReaders->getEventCount())break;
+ while(!tcstop&&midiReaders&&tceptr<ecnt&&ct==getEvent(tceptr)->time)
+ processEvent(getEvent(tceptr++));
+ if(tcstop||!midiReaders||tceptr>=ecnt)break;
high_resolution_clock::time_point a=high_resolution_clock::now();
auto sendtime=a-b;
if(resumed)resumed=false;
else
- if(sendtime.count()<(midiReaders->getEvent(tceptr)->time-ct)*dpt)
+ if(sendtime.count()<(getEvent(tceptr)->time-ct)*dpt)
#ifdef _WIN32
- w32usleep(((midiReaders->getEvent(tceptr)->time-ct)*dpt-sendtime.count())/1000);
+ w32usleep(((getEvent(tceptr)->time-ct)*dpt-sendtime.count())/1000);
#else
- std::this_thread::sleep_for(std::chrono::nanoseconds((midiReaders->getEvent(tceptr)->time-ct)*dpt-sendtime.count()));
+ std::this_thread::sleep_for(std::chrono::nanoseconds((getEvent(tceptr)->time-ct)*dpt-sendtime.count()));
#endif
if(tcstop||!midiReaders)break;
- ct=midiReaders->getEvent(tceptr)->time;
+ ct=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;
@@ -229,13 +235,13 @@ void CMidiPlayer::playEvents()
void CMidiPlayer::fileTimer1Pass()
{
ftime=.0;ctempo=0x7A120;dpt=ctempo*1000/divs;
- for(uint32_t eptr=0,ct=midiReaders->getEvent(0)->time;eptr<midiReaders->getEventCount();)
+ for(uint32_t eptr=0,ct=getEvent(0)->time;eptr<ecnt;)
{
- while(eptr<midiReaders->getEventCount()&&ct==midiReaders->getEvent(eptr)->time)
- processEventStub(midiReaders->getEvent(eptr++));
- if(eptr>=midiReaders->getEventCount())break;
- ftime+=(midiReaders->getEvent(eptr)->time-ct)*dpt/1e9;
- ct=midiReaders->getEvent(eptr)->time;
+ while(eptr<ecnt&&ct==getEvent(eptr)->time)
+ processEventStub(getEvent(eptr++));
+ if(eptr>=ecnt)break;
+ ftime+=(getEvent(eptr)->time-ct)*dpt/1e9;
+ ct=getEvent(eptr)->time;
}
}
void CMidiPlayer::fileTimer2Pass()
@@ -251,15 +257,15 @@ void CMidiPlayer::fileTimer2Pass()
ccc[i][76]=64;ccc[i][77]=64;ccc[i][78]=64;
ccc[i][131]=dpt;ccc[i][132]=0x04021808;
ccc[i][133]=0;ccc[i][134]=2;
- }if(midiReaders->getStandard()!=4)ccc[9][0]=128;
+ }if(midiFile->std!=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=midiReaders->getEvent(0)->time;eptr<midiReaders->getEventCount();)
+ for(uint32_t eptr=0,ct=getEvent(0)->time;eptr<ecnt;)
{
- while(eptr<midiReaders->getEventCount()&&ct==midiReaders->getEvent(eptr)->time)
- processEventStub(midiReaders->getEvent(eptr++));
- if(eptr>=midiReaders->getEventCount())break;
- ctime+=(midiReaders->getEvent(eptr)->time-ct)*dpt/1e9;
+ while(eptr<ecnt&&ct==getEvent(eptr)->time)
+ processEventStub(getEvent(eptr++));
+ if(eptr>=ecnt)break;
+ ctime+=(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)
@@ -267,19 +273,19 @@ void CMidiPlayer::fileTimer2Pass()
stamps[c++]=eptr;
if(c>100)break;
}
- ct=midiReaders->getEvent(eptr)->time;
+ ct=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++]=midiReaders->getEventCount();
+ stamps[c++]=ecnt;
}
}
CMidiPlayer::CMidiPlayer(bool singleInst)
{
midiReaders=new CMidiFileReaderCollection();
- resumed=false;singleInstance=singleInst;
+ resumed=false;singleInstance=singleInst;midiFile=NULL;
settings=NULL;synth=NULL;adriver=NULL;waitvoice=true;
memset(eventHandlerCB,0,sizeof(eventHandlerCB));
memset(eventHandlerCBuserdata,0,sizeof(eventHandlerCBuserdata));
@@ -304,7 +310,7 @@ CMidiPlayer::CMidiPlayer(bool singleInst)
CMidiPlayer::~CMidiPlayer()
{
if(singleInstance||settings||synth||adriver)fluidDeinitialize();
- delete midiReaders;delete mapper;
+ if(midiFile)delete midiFile;delete midiReaders;delete mapper;
}
void CMidiPlayer::playerPanic(bool reset)
{
@@ -330,11 +336,27 @@ void CMidiPlayer::playerPanic(bool reset)
}
bool CMidiPlayer::playerLoadFile(const char* fn)
{
- notes=0;midiReaders->readFile(fn);
- if(!midiReaders->isValid())return false;
- divs=midiReaders->getDivision();
+ notes=0;if(midiFile)delete midiFile;
+ midiFile=midiReaders->readFile(fn);
+ if(!midiFile->valid)return false;
+ divs=midiFile->divs;maxtk=ecnt=0;
+ for(CMidiTrack& i:midiFile->tracks)
+ {
+ ecnt+=i.eventList.size();
+ maxtk=std::max(maxtk,i.eventList.back().time);
+ }
for(int i=0;i<16;++i)if(fileReadFinishCB[i])
fileReadFinishCB[i]->callBack(NULL,fileReadFinishCBuserdata[i]);
+ eorder.clear();
+ for(size_t i=0;i<midiFile->tracks.size();++i)
+ for(size_t j=0;j<midiFile->tracks[i].eventList.size();++j)
+ eorder.push_back(std::make_pair(i,j));
+ std::sort(eorder.begin(),eorder.end(),
+ [this](std::pair<size_t,size_t> &a,std::pair<size_t,size_t> &b)->bool{
+ return midiFile->tracks[a.first].eventList[a.second]<
+ midiFile->tracks[b.first].eventList[b.second];
+ }
+ );
fileTimer1Pass();
fileTimer2Pass();
return true;
@@ -355,7 +377,7 @@ void CMidiPlayer::playerInit()
void CMidiPlayer::playerDeinit()
{
tceptr=0;tcstop=1;tcpaused=0;
- midiReaders->destructFile();
+ delete midiFile;midiFile=NULL;
if(!singleInstance)fluidDeinitialize();
}
void CMidiPlayer::playerThread()
@@ -399,7 +421,7 @@ uint32_t CMidiPlayer::getTCeptr(){return tceptr;}
void CMidiPlayer::setTCeptr(uint32_t ep,uint32_t st)
{
resumed=true;
- if(ep==midiReaders->getEventCount())tcstop=1;else tceptr=ep;
+ if(ep==ecnt)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]);
@@ -416,14 +438,14 @@ double CMidiPlayer::getFtime(){return ftime;}
void CMidiPlayer::getCurrentTimeSignature(int *n,int *d){*n=ctsn;*d=ctsd;}
int CMidiPlayer::getCurrentKeySignature(){return cks;}
uint32_t CMidiPlayer::getFileNoteCount(){return notes;}
-uint32_t CMidiPlayer::getFileStandard(){return midiReaders?midiReaders->getStandard():0;}
-const char* CMidiPlayer::getTitle(){return midiReaders?midiReaders->getTitle():"";}
-const char* CMidiPlayer::getCopyright(){return midiReaders?midiReaders->getCopyright():"";}
+uint32_t CMidiPlayer::getFileStandard(){return midiFile?midiFile->std:0;}
+const char* CMidiPlayer::getTitle(){return midiFile?midiFile->title:"";}
+const char* CMidiPlayer::getCopyright(){return midiFile?midiFile->copyright:"";}
double CMidiPlayer::getTempo(){return 60./(ctempo/1e6);}
uint32_t CMidiPlayer::getTick(){return ct;}
uint32_t CMidiPlayer::getRawTempo(){return ctempo;}
uint32_t CMidiPlayer::getDivision(){return divs;}
-uint32_t CMidiPlayer::getMaxTick(){return midiReaders->getMaxTick();}
+uint32_t CMidiPlayer::getMaxTick(){return maxtk;}
double CMidiPlayer::getPitchBend(int ch){return((int)pbv[ch]-8192)/8192.*pbr[ch];}
uint32_t CMidiPlayer::getTCpaused(){return tcpaused;}
void CMidiPlayer::setTCpaused(uint32_t ps){tcpaused=ps;}
@@ -471,6 +493,18 @@ void CMidiPlayer::setChannelPreset(int ch,int b,int p)
fluid_synth_program_change(synth,ch,p);
}
}
+void CMidiPlayer::dumpFile()
+{
+ if(!midiFile)return;
+ for(CMidiTrack &i:midiFile->tracks)
+ for(SEvent &j:i.eventList)
+ if(j.str.length())
+ printf("type %x #%d @%d p1 %d p2 %d str %s\n",j.type,
+ j.iid,j.time,j.p1,j.p2,j.str.c_str());
+ else
+ printf("type %x #%d @%d p1 %d p2 %d\n",j.type,j.iid,
+ j.time,j.p1,j.p2);
+}
//16MSB..LSB1
void CMidiPlayer::setBit(uint16_t &n, uint16_t bn, uint16_t b)
{n^=(((~b)+1)^n)&(1<<bn);}
diff --git a/core/qmpmidiplay.hpp b/core/qmpmidiplay.hpp
index ebc62d6..8a146a7 100644
--- a/core/qmpmidiplay.hpp
+++ b/core/qmpmidiplay.hpp
@@ -14,6 +14,7 @@ class CSMFReader:public IMidiFileReader
{
private:
CMidiFile* ret;
+ CMidiTrack* curTrack;
uint32_t fmt,trk;
FILE *f;
int byteread,valid,eventdiscarded;
@@ -35,35 +36,25 @@ class CSMFReader:public IMidiFileReader
void commitEventChange(SEventCallBackData d);
};
class CMidiFileReaderCollection{
- std::vector<std::pair<IMidiFileReader*,std::string>> readers;
- CMidiFile* file;
- uint32_t maxtk;
- IMidiFileReader* currentReader;
- void destructFile(CMidiFile*& f);
- void dumpFile();
-public:
- CMidiFileReaderCollection();
- ~CMidiFileReaderCollection();
- void registerReader(IMidiFileReader* reader,std::string name);
- void unregisterReader(std::string name);
- void readFile(const char* fn);
- void destructFile();
- IMidiFileReader* getCurrentReader();
- bool isValid();
- const char* getTitle();
- const char* getCopyright();
- const SEvent* getEvent(uint32_t id);
- uint32_t getEventCount();
- uint32_t getDivision();
- uint32_t getMaxTick();
- uint32_t getStandard();
+ private:
+ std::vector<std::pair<IMidiFileReader*,std::string>> readers;
+ IMidiFileReader* currentReader;
+ public:
+ CMidiFileReaderCollection();
+ ~CMidiFileReaderCollection();
+ void registerReader(IMidiFileReader* reader,std::string name);
+ void unregisterReader(std::string name);
+ CMidiFile* readFile(const char* fn);
+ IMidiFileReader* getCurrentReader();
};
class CMidiPlayer
{
friend class CMidiFileReaderCollection;
private:
CMidiFileReaderCollection *midiReaders;
- uint32_t stamps[101],notes;
+ CMidiFile* midiFile;
+ std::vector<std::pair<size_t,size_t>> eorder;
+ uint32_t stamps[101],notes,ecnt,maxtk;
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[16],rpnval[16];
@@ -91,6 +82,8 @@ class CMidiPlayer
void* fileReadFinishCBuserdata[16];
static CMidiPlayer* ref;
+ SEvent *getEvent(int id);
+ void dumpFile();
void setBit(uint16_t &n,uint16_t bn,uint16_t b);
void processEvent(const SEvent *e);
void processEventStub(const SEvent *e);
diff --git a/core/qmpmidiread.cpp b/core/qmpmidiread.cpp
index 5add648..cd3ffa3 100644
--- a/core/qmpmidiread.cpp
+++ b/core/qmpmidiread.cpp
@@ -8,10 +8,10 @@
#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"};
+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";
void CSMFReader::error(int fatal,const char* format,...)
{
va_list ap;
@@ -54,35 +54,17 @@ int CSMFReader::eventReader()//returns 0 if End of Track encountered
switch(type&0xF0)
{
case 0x80://Note Off
- p1=fgetc(f);p2=fgetc(f);byteread+=2;
- ret->eventList.push_back(SEvent(curid,curt,type,p1,p2));
- break;
case 0x90://Note On
- p1=fgetc(f);p2=fgetc(f);byteread+=2;
- if(p2)
- ret->eventList.push_back(SEvent(curid,curt,type,p1,p2));
- else
- ret->eventList.push_back(SEvent(curid,curt,(type&0x0F)|0x80,p1,p2));
- break;
case 0xA0://Note Aftertouch
- p1=fgetc(f);p2=fgetc(f);byteread+=2;
- ret->eventList.push_back(SEvent(curid,curt,type,p1,p2));
- break;
case 0xB0://Controller Change
+ case 0xE0://Pitch wheel
p1=fgetc(f);p2=fgetc(f);byteread+=2;
- ret->eventList.push_back(SEvent(curid,curt,type,p1,p2));
+ curTrack->appendEvent(SEvent(curid,curt,type,p1,p2));
break;
case 0xC0://Patch Change
- p1=fgetc(f);++byteread;
- ret->eventList.push_back(SEvent(curid,curt,type,p1,0));
- break;
case 0xD0://Channel Aftertouch
p1=fgetc(f);++byteread;
- ret->eventList.push_back(SEvent(curid,curt,type,p1,0));
- break;
- case 0xE0://Pitch wheel
- p1=fgetc(f);p2=fgetc(f);byteread+=2;
- ret->eventList.push_back(SEvent(curid,curt,type,p1,p2));
+ curTrack->appendEvent(SEvent(curid,curt,type,p1,0));
break;
case 0xF0:
if((type&0x0F)==0x0F)//Meta Event
@@ -103,7 +85,7 @@ int CSMFReader::eventReader()//returns 0 if End of Track encountered
break;
case 0x51://Set Tempo
p1=readDW();p1&=0x00FFFFFF;
- ret->eventList.push_back(SEvent(curid,curt,type,metatype,p1));
+ curTrack->appendEvent(SEvent(curid,curt,type,metatype,p1));
break;
case 0x54://SMTPE offset, not handled.
fgetc(f);fgetc(f);fgetc(f);
@@ -113,12 +95,12 @@ int CSMFReader::eventReader()//returns 0 if End of Track encountered
case 0x58://Time signature
fgetc(f);++byteread;
p1=readDW();
- ret->eventList.push_back(SEvent(curid,curt,type,metatype,p1));
+ curTrack->appendEvent(SEvent(curid,curt,type,metatype,p1));
break;
case 0x59://Key signature
fgetc(f);++byteread;
p1=readSW();
- ret->eventList.push_back(SEvent(curid,curt,type,metatype,p1));
+ curTrack->appendEvent(SEvent(curid,curt,type,metatype,p1));
break;
case 0x01:case 0x02:case 0x03:
case 0x04:case 0x05:case 0x06:
@@ -130,7 +112,8 @@ int CSMFReader::eventReader()//returns 0 if End of Track encountered
{
++byteread;if(str)str[c]=fgetc(f);else fgetc(f);
}
- if(str)str[c]='\0';ret->eventList.push_back(SEvent(curid,curt,type,metatype,0,str));
+ if(str)str[c]='\0';
+ curTrack->appendEvent(SEvent(curid,curt,type,metatype,0,str));
if(str&&metatype==0x03&&!ret->title)
{
ret->title=new char[len+8];
@@ -155,7 +138,7 @@ int CSMFReader::eventReader()//returns 0 if End of Track encountered
for(c=1;c<len;++c){++byteread;str[c]=fgetc(f);}
}
else for(c=0;c<len;++c){++byteread;str[c]=fgetc(f);}
- ret->eventList.push_back(SEvent(curid,curt,type,len,0,str));
+ curTrack->appendEvent(SEvent(curid,curt,type,len,0,str));
if(!strcmp(str,GM1SysX))ret->std=1;
if(!strcmp(str,GM2SysX))ret->std=2;
if(!strcmp(str,GSSysEx))ret->std=3;
@@ -168,9 +151,9 @@ int CSMFReader::eventReader()//returns 0 if End of Track encountered
error(0,"W: Unknown event type %#x",type);
}
lasttype=type;++curid;
- if(ret->eventList.size())
+ if(curTrack->eventList.size())
{
- SEvent& le=ret->eventList[ret->eventList.size()-1];
+ SEvent& le=curTrack->eventList.back();
SEventCallBackData cbd(le.type,le.p1,le.p2,le.time);
CMidiPlayer::getInstance()->callEventReaderCB(cbd);
}
@@ -178,6 +161,8 @@ int CSMFReader::eventReader()//returns 0 if End of Track encountered
}
void CSMFReader::trackChunkReader()
{
+ ret->tracks.push_back(CMidiTrack());
+ curTrack=&ret->tracks.back();
int chnklen=readDW();byteread=0;curt=0;curid=0;
while(/*byteread<chnklen&&*/eventReader());
if(byteread<chnklen)
@@ -239,7 +224,6 @@ CMidiFile* CSMFReader::readFile(const char* fn)
chunkReader(1);
for(uint32_t i=0;i<trk;i+=chunkReader(0));
fclose(f);f=NULL;
- std::sort(ret->eventList.begin(),ret->eventList.end());
}
catch(std::runtime_error&){fprintf(stderr,"E: %s is not a supported file.\n",fn);ret->valid=0;if(f)fclose(f);f=NULL;}
return ret;
@@ -251,44 +235,23 @@ CSMFReader::~CSMFReader()
void CSMFReader::discardCurrentEvent()
{
if(eventdiscarded)return;eventdiscarded=1;
- ret->eventList.pop_back();
+ curTrack->eventList.pop_back();
}
void CSMFReader::commitEventChange(SEventCallBackData d)
{
- ret->eventList[ret->eventList.size()-1].time=d.time;
- ret->eventList[ret->eventList.size()-1].type=d.type;
- ret->eventList[ret->eventList.size()-1].p1=d.p1;
- ret->eventList[ret->eventList.size()-1].p2=d.p2;
+ curTrack->eventList.back().time=d.time;
+ curTrack->eventList.back().type=d.type;
+ curTrack->eventList.back().p1=d.p1;
+ curTrack->eventList.back().p2=d.p2;
}
-void CMidiFileReaderCollection::destructFile(CMidiFile*& f)
-{
- if(!f)return;
- if(f->copyright)delete[] f->copyright;
- if(f->title)delete[] f->title;
- delete f;
- f=NULL;
-}
-void CMidiFileReaderCollection::dumpFile()
-{
- if(!file)return;
- std::vector<SEvent> &eventList=file->eventList;
- for(uint32_t i=0;i<eventList.size();++i)
- if(eventList[i].str.length())
- printf("type %x #%d @%d p1 %d p2 %d str %s\n",eventList[i].type,
- eventList[i].iid,eventList[i].time,eventList[i].p1,eventList[i].p2,eventList[i].str.c_str());
- else
- printf("type %x #%d @%d p1 %d p2 %d\n",eventList[i].type,
- eventList[i].iid,eventList[i].time,eventList[i].p1,eventList[i].p2);
-}
CMidiFileReaderCollection::CMidiFileReaderCollection()
{
- file=NULL;readers.clear();currentReader=NULL;
+ readers.clear();currentReader=NULL;
registerReader(new CSMFReader(),"Default SMF Reader");
}
CMidiFileReaderCollection::~CMidiFileReaderCollection()
{
- if(file)destructFile(file);
delete readers[0].first;
}
void CMidiFileReaderCollection::registerReader(IMidiFileReader* reader,std::string name)
@@ -306,38 +269,19 @@ void CMidiFileReaderCollection::unregisterReader(std::string name)
return;
}
}
-void CMidiFileReaderCollection::readFile(const char* fn)
+CMidiFile* CMidiFileReaderCollection::readFile(const char* fn)
{
- if(file)destructFile(file);
+ CMidiFile *file=NULL;
for(unsigned i=0;i<readers.size();++i)
{
currentReader=readers[i].first;
CMidiPlayer::getInstance()->notes=0;
CMidiFile* t=readers[i].first->readFile(fn);
if(t->valid){file=t;break;}
- else destructFile(t);
+ else delete t;
}
currentReader=NULL;
- if(file)
- maxtk=file->eventList[file->eventList.size()-1].time;
+ return file;
}
-void CMidiFileReaderCollection::destructFile()
-{destructFile(file);}
IMidiFileReader* CMidiFileReaderCollection::getCurrentReader()
{return currentReader;}
-bool CMidiFileReaderCollection::isValid()
-{return file&&file->valid;}
-const char* CMidiFileReaderCollection::getTitle()
-{return file?file->title:NULL;}
-const char* CMidiFileReaderCollection::getCopyright()
-{return file?file->copyright:NULL;}
-const SEvent* CMidiFileReaderCollection::getEvent(uint32_t id)
-{return file?&(file->eventList[id]):NULL;}
-uint32_t CMidiFileReaderCollection::getEventCount()
-{return file?file->eventList.size():0;}
-uint32_t CMidiFileReaderCollection::getDivision()
-{return file?file->divs:0;}
-uint32_t CMidiFileReaderCollection::getMaxTick()
-{return maxtk;}
-uint32_t CMidiFileReaderCollection::getStandard()
-{return file?file->std:0;}
diff --git a/include/qmpcorepublic.hpp b/include/qmpcorepublic.hpp
index 4adb83a..ba38f4e 100644
--- a/include/qmpcorepublic.hpp
+++ b/include/qmpcorepublic.hpp
@@ -8,7 +8,7 @@
#else
#define EXPORTSYM __attribute__ ((visibility ("default")))
#endif
-#define QMP_PLUGIN_API_REV "1+indev3"
+#define QMP_PLUGIN_API_REV "1+indev4"
//MIDI Event structure
struct SEvent
{
@@ -32,13 +32,25 @@ public:
uint32_t time,type,p1,p2;
SEventCallBackData(uint32_t _t,uint32_t _p1,uint32_t _p2,uint32_t _tm){type=_t;p1=_p1;p2=_p2;time=_tm;}
};
+//MIDI Track class
+class CMidiTrack{
+ public:
+ std::vector<SEvent> eventList;
+ void appendEvent(SEvent e){eventList.push_back(e);}
+ SEvent& operator[](size_t sub){return eventList[sub];}
+};
//MIDI File class
class CMidiFile{
public:
bool valid;
char *title,*copyright;
- std::vector<SEvent> eventList;
+ std::vector<CMidiTrack> tracks;
uint32_t std,divs;
+ ~CMidiFile()
+ {
+ if(title)delete[] title;
+ if(copyright)delete[] copyright;
+ }
};
//Generic callback function that can be used for hooking the core.
//"userdata" is set when you register the callback function.
diff --git a/midifmt-plugin/midifmtplugin.cpp b/midifmt-plugin/midifmtplugin.cpp
index bd87d98..05b5b87 100644
--- a/midifmt-plugin/midifmtplugin.cpp
+++ b/midifmt-plugin/midifmtplugin.cpp
@@ -50,9 +50,9 @@ bool CMidiStreamReader::midsBodyReader()
//fprintf(stderr,"ev: @ %x t %x p1 %x p2 %x\n",ev.time,ev.type,ev.p1,ev.p2);
if((ev.type&0xF0)==0x90&&ev.p2==0)//Note on with zero velo
ev.type=(ev.type&0x0F)|0x80;
- ret->eventList.push_back(ev);eventdiscarded=0;
+ ret->tracks.back().appendEvent(ev);eventdiscarded=0;
qmpMidiFmtPlugin::api->callEventReaderCB(SEventCallBackData(ev.type,ev.p1,ev.p2,ev.time));
- if(eventdiscarded)ret->eventList.pop_back();
+ if(eventdiscarded)ret->tracks.back().eventList.pop_back();
++curid;
}
}
@@ -62,13 +62,17 @@ CMidiFile* CMidiStreamReader::readFile(const char *fn)
{
ret=new CMidiFile;
ret->title=ret->copyright=NULL;ret->std=0;ret->valid=1;
+ ret->tracks.push_back(CMidiTrack());
try
{
if(!(f=fopen(fn,"rb")))throw std::runtime_error("File doesn't exist");
if(!RIFFHeaderReader())throw std::runtime_error("Wrong RIFF header");
if(!midsBodyReader())throw std::runtime_error("MIDS data error");
- std::sort(ret->eventList.begin(),ret->eventList.end());
- }catch(std::runtime_error& e){fprintf(stderr,"MIDI Format plugin: E: %s is not a supported file. Cause: %s.\n",fn,e.what());ret->valid=0;if(f)fclose(f);f=NULL;}
+ }catch(std::runtime_error& e)
+ {
+ fprintf(stderr,"MIDI Format plugin: E: %s is not a supported file. Cause: %s.\n",fn,e.what());
+ ret->valid=0;if(f)fclose(f);f=NULL;
+ }
return ret;
}
void CMidiStreamReader::discardCurrentEvent()
@@ -77,10 +81,10 @@ void CMidiStreamReader::discardCurrentEvent()
}
void CMidiStreamReader::commitEventChange(SEventCallBackData d)
{
- ret->eventList[ret->eventList.size()-1].time=d.time;
- ret->eventList[ret->eventList.size()-1].type=d.type;
- ret->eventList[ret->eventList.size()-1].p1=d.p1;
- ret->eventList[ret->eventList.size()-1].p2=d.p2;
+ ret->tracks.back().eventList.back().time=d.time;
+ ret->tracks.back().eventList.back().type=d.type;
+ ret->tracks.back().eventList.back().p1=d.p1;
+ ret->tracks.back().eventList.back().p2=d.p2;
}
CMidiStreamReader::CMidiStreamReader()
{
diff --git a/qmidiplayer-desktop/qmphelpwindow.hpp b/qmidiplayer-desktop/qmphelpwindow.hpp
index 75f8679..f68e38e 100644
--- a/qmidiplayer-desktop/qmphelpwindow.hpp
+++ b/qmidiplayer-desktop/qmphelpwindow.hpp
@@ -2,7 +2,7 @@
#define QMPHELPWINDOW_H
#include <QDialog>
-#define APP_VERSION "0.8.5"
+#define APP_VERSION "0.8.6"
#ifndef BUILD_MACHINE
#define BUILD_MACHINE UNKNOWN
#endif
diff --git a/qmidiplayer-desktop/qmpmainwindow.cpp b/qmidiplayer-desktop/qmpmainwindow.cpp
index d65d873..d2c2d0d 100644
--- a/qmidiplayer-desktop/qmpmainwindow.cpp
+++ b/qmidiplayer-desktop/qmpmainwindow.cpp
@@ -70,6 +70,12 @@ qmpMainWindow::qmpMainWindow(QWidget *parent) :
qmpMainWindow::~qmpMainWindow()
{
+ QList<QAction*>a=ui->lbFileName->actions();
+ for(unsigned i=0;i<a.size();++i)
+ {
+ ui->lbFileName->removeAction(a[i]);
+ delete a[i];
+ }
pmgr->deinitPlugins();
delete pmgr;if(player)delete player;
if(timer)delete timer;
@@ -79,6 +85,9 @@ qmpMainWindow::~qmpMainWindow()
delete plistw;plistw=NULL;
delete infow;infow=NULL;
delete settingsw;settingsw=NULL;
+ delete panicf;panicf=NULL;
+ delete renderf;renderf=NULL;
+ delete reloadsynf;reloadsynf=NULL;
delete ui;
}
diff --git a/visualization/qmpvisualization.cpp b/visualization/qmpvisualization.cpp
index ffc01ad..43414b6 100644
--- a/visualization/qmpvisualization.cpp
+++ b/visualization/qmpvisualization.cpp
@@ -50,7 +50,10 @@ void CReaderCallBack::callBack(void *callerdata,void *)
par->pushNoteOff(cbd->time,cbd->type&0x0F,cbd->p1);
break;
case 0x90:
+ if(cbd->p2)
par->pushNoteOn(cbd->time,cbd->type&0x0F,cbd->p1,cbd->p2);
+ else
+ par->pushNoteOff(cbd->time,cbd->type&0x0F,cbd->p1);
break;
case 0xF0:
if(cbd->type==0xFF&&cbd->p1==0x58)
@@ -854,5 +857,4 @@ void qmpVisualization::pushNoteOff(uint32_t tc,uint32_t ch,uint32_t key)
ne->tce=tc;ne->ch=ch;ne->key=key;
ne->vel=pendingv[ch][key].top();pendingv[ch][key].pop();
pool.push_back(ne);
- if(tc>fintk)fintk=tc;
}
diff --git a/visualization/qmpvisualization.hpp b/visualization/qmpvisualization.hpp
index 6518376..b52fa3d 100644
--- a/visualization/qmpvisualization.hpp
+++ b/visualization/qmpvisualization.hpp
@@ -67,7 +67,7 @@ class qmpVisualization:public qmpPluginIntf
smParticleSystem* pss[16][128];
smPSEmissionPositionGenerator* psepg;
float pos[3],rot[3],lastx,lasty;
- uint32_t ctc,ctk,fintk,elb;
+ uint32_t ctc,ctk,elb;
double etps;
bool shouldclose,playing;
int herif,hehif,hfrf;