From 64c91c7da66ba71e2bb32077680f234aba4ac65d Mon Sep 17 00:00:00 2001 From: Chris Xiong Date: Fri, 16 Jun 2017 23:51:26 +0800 Subject: Code refactoring and fix to memory leaks. --- core/qmpmidiplay.cpp | 104 ++++++++++++++++++++++++++++++++---------------- core/qmpmidiplay.hpp | 39 ++++++++---------- core/qmpmidiread.cpp | 110 +++++++++++++-------------------------------------- 3 files changed, 112 insertions(+), 141 deletions(-) (limited to 'core') 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 #include +#include #include #include #include @@ -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;tceptrgetEventCount();) + for(ct=getEvent(0)->time;tceptrgetEventCount()&&ct==midiReaders->getEvent(tceptr)->time) - processEvent(midiReaders->getEvent(tceptr++)); - if(tcstop||!midiReaders||tceptr>=midiReaders->getEventCount())break; + while(!tcstop&&midiReaders&&tceptrtime) + 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;eptrgetEventCount();) + for(uint32_t eptr=0,ct=getEvent(0)->time;eptrgetEventCount()&&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(eptrtime) + 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;eptrgetEventCount();) + for(uint32_t eptr=0,ct=getEvent(0)->time;eptrgetEventCount()&&ct==midiReaders->getEvent(eptr)->time) - processEventStub(midiReaders->getEvent(eptr++)); - if(eptr>=midiReaders->getEventCount())break; - ctime+=(midiReaders->getEvent(eptr)->time-ct)*dpt/1e9; + while(eptrtime) + 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;itracks.size();++i) + for(size_t j=0;jtracks[i].eventList.size();++j) + eorder.push_back(std::make_pair(i,j)); + std::sort(eorder.begin(),eorder.end(), + [this](std::pair &a,std::pair &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<> 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> 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> 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 #include #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;ceventList.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(/*bytereadeventList.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 &eventList=file->eventList; - for(uint32_t i=0;inotes=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;} -- cgit v1.2.3