diff options
author | Chris Xiong <chirs241097@gmail.com> | 2017-06-22 11:26:48 +0800 |
---|---|---|
committer | Chris Xiong <chirs241097@gmail.com> | 2017-06-22 11:26:48 +0800 |
commit | b03133b80b268c74d1dd5c92e2af6907b51c91b2 (patch) | |
tree | 2700bf29cecd5ae89fd7d99e3d6acb88ebb44e61 /core/qmpmidiread.cpp | |
parent | a97307ba6e625468a1d8ad1049e6d9db0ad42d4d (diff) | |
download | QMidiPlayer-b03133b80b268c74d1dd5c92e2af6907b51c91b2.tar.xz |
Minor bug fixes.
SMF reader finally takes chunk length into account.
Do not prepend sysex header to F0h sysex. Let the
readers do it.
File readers code cleanups and refined error messages.
Diffstat (limited to 'core/qmpmidiread.cpp')
-rw-r--r-- | core/qmpmidiread.cpp | 92 |
1 files changed, 44 insertions, 48 deletions
diff --git a/core/qmpmidiread.cpp b/core/qmpmidiread.cpp index cd3ffa3..6089ac5 100644 --- a/core/qmpmidiread.cpp +++ b/core/qmpmidiread.cpp @@ -14,21 +14,20 @@ 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; - va_start(ap,format);vfprintf(stderr,format,ap);va_end(ap); - fprintf(stderr," at %#lx\n",ftell(f)); - if(fatal)throw std::runtime_error("fatal error"); + va_list ap;char buf[1024],bufr[1024]; + va_start(ap,format);vsnprintf(buf,1024,format,ap);va_end(ap); + snprintf(bufr,1024,"%s at %#lx",buf,ftell(f)); + if(fatal)throw std::runtime_error(bufr); + else fprintf(stderr,"CSMFReader W: %s.\n",bufr); } uint32_t CSMFReader::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 CSMFReader::readDW() { - byteread+=4; uint32_t ret=0; for(int i=0;i<4;++i){ret<<=8;ret|=((uint32_t)fgetc(f))&0xFF;} return ret; @@ -39,18 +38,17 @@ uint32_t CSMFReader::readVL() do { t=fgetc(f); - if(++c>4)error(1,"E: Variable length type overflow."); + if(++c>4)error(1,"Variable length type overflow"); ret<<=7;ret|=(t&0x7F); }while(t&0x80); - byteread+=c; return ret; } int CSMFReader::eventReader()//returns 0 if End of Track encountered { uint32_t delta=readVL();curt+=delta; - char type=fgetc(f);++byteread;uint32_t p1,p2; + char type=fgetc(f);uint32_t p1,p2; static char lasttype;eventdiscarded=0; - if(!(type&0x80)){fseek(f,-1,SEEK_CUR);--byteread;type=lasttype;} + if(!(type&0x80)){fseek(f,-1,SEEK_CUR);type=lasttype;} switch(type&0xF0) { case 0x80://Note Off @@ -58,29 +56,28 @@ int CSMFReader::eventReader()//returns 0 if End of Track encountered case 0xA0://Note Aftertouch case 0xB0://Controller Change case 0xE0://Pitch wheel - p1=fgetc(f);p2=fgetc(f);byteread+=2; + p1=fgetc(f);p2=fgetc(f); curTrack->appendEvent(SEvent(curid,curt,type,p1,p2)); break; case 0xC0://Patch Change case 0xD0://Channel Aftertouch - p1=fgetc(f);++byteread; + p1=fgetc(f); curTrack->appendEvent(SEvent(curid,curt,type,p1,0)); break; case 0xF0: if((type&0x0F)==0x0F)//Meta Event { - char metatype=fgetc(f);++byteread; + char metatype=fgetc(f); 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; + fgetc(f);fgetc(f); break; case 0x2F://End of Track - fgetc(f);++byteread; + fgetc(f); return 0; break; case 0x51://Set Tempo @@ -90,16 +87,13 @@ int CSMFReader::eventReader()//returns 0 if End of Track encountered 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(); + fgetc(f);p1=readDW(); curTrack->appendEvent(SEvent(curid,curt,type,metatype,p1)); break; case 0x59://Key signature - fgetc(f);++byteread; - p1=readSW(); + fgetc(f);p1=readSW(); curTrack->appendEvent(SEvent(curid,curt,type,metatype,p1)); break; case 0x01:case 0x02:case 0x03: @@ -109,9 +103,7 @@ int CSMFReader::eventReader()//returns 0 if End of Track encountered 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]=fgetc(f);else fgetc(f); if(str)str[c]='\0'; curTrack->appendEvent(SEvent(curid,curt,type,metatype,0,str)); if(str&&metatype==0x03&&!ret->title) @@ -135,9 +127,9 @@ int CSMFReader::eventReader()//returns 0 if End of Track encountered if((type&0x0F)==0x00) { str[0]=0xF0;++len; - for(c=1;c<len;++c){++byteread;str[c]=fgetc(f);} + for(c=1;c<len;++c){str[c]=fgetc(f);} } - else for(c=0;c<len;++c){++byteread;str[c]=fgetc(f);} + else for(c=0;c<len;++c){str[c]=fgetc(f);} curTrack->appendEvent(SEvent(curid,curt,type,len,0,str)); if(!strcmp(str,GM1SysX))ret->std=1; if(!strcmp(str,GM2SysX))ret->std=2; @@ -145,10 +137,10 @@ int CSMFReader::eventReader()//returns 0 if End of Track encountered if(!strcmp(str,XGSysEx))ret->std=4; delete[] str; } - else error(0,"W: Unknown event type %#x",type); + else error(0,"Unknown event type %#x",type); break; default: - error(0,"W: Unknown event type %#x",type); + error(0,"Unknown event type %#x",type); } lasttype=type;++curid; if(curTrack->eventList.size()) @@ -163,50 +155,49 @@ 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()); + int chnklen=readDW();byteread=ftell(f);curt=0;curid=0; + while(eventReader()); + byteread=ftell(f)-byteread; if(byteread<chnklen) { - error(0,"W: Extra bytes after EOT event."); - while(byteread<chnklen){fgetc(f);++byteread;} + error(0,"Extra bytes after EOT event"); + for(;byteread<chnklen;++byteread)fgetc(f); } - /*if(byteread>chnklen) - { - error(1,"E: Read past end of track."); - }*/ + if(byteread>chnklen) + error(1,"Read past end of track"); } void CSMFReader::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."); + int chnklen=readDW();byteread=ftell(f); + if(chnklen<6)error(1,"Header chunk too short"); + if(chnklen>6)error(0,"Header chunk length longer than expected. Ignoring extra bytes"); fmt=readSW();trk=readSW();ret->divs=readSW(); - if(ret->divs&0x8000)error(1,"E: SMTPE format is not supported."); - for(;byteread<chnklen;++byteread){fgetc(f);} + if(ret->divs&0x8000)error(1,"SMTPE format is not supported"); + for(byteread=ftell(f)-byteread;byteread<chnklen;++byteread){fgetc(f);} } int CSMFReader::chunkReader(int hdrXp) { char hdr[6]; fread(hdr,1,4,f); - if(feof(f))error(1,"E: Unexpected EOF."); + if(feof(f))error(1,"Unexpected EOF"); if(hdrXp) { if(!strncmp(hdr,"RIFF",4)) { fseek(f,4,SEEK_CUR); fread(hdr,1,4,f); - if(strncmp(hdr,"RMID",4)){error(1,"E: Wrong file type in RIFF container.");throw std::runtime_error("Wrong file type in RIFF container");} + if(strncmp(hdr,"RMID",4)){error(1,"Wrong file type in RIFF container");} fseek(f,8,SEEK_CUR); fread(hdr,1,4,f); } - if(strncmp(hdr,"MThd",4)){error(1,"E: Wrong MIDI header.");throw std::runtime_error("Wrong MIDI header");} + if(strncmp(hdr,"MThd",4)){error(1,"Wrong MIDI header.");} 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; + error(0,"Wrong track chunk header. Ignoring the whole chunk"); + uint32_t chnklen=readDW();fseek(f,chnklen,SEEK_CUR);return 0; } else return trackChunkReader(),1; } @@ -220,12 +211,17 @@ CMidiFile* CSMFReader::readFile(const char* fn) ret->title=ret->copyright=NULL;ret->std=0;ret->valid=1; try { - if(!(f=fopen(fn,"rb")))throw (fprintf(stderr,"E: file %s doesn't exist!\n",fn),std::runtime_error("File doesn't exist")); + if(!(f=fopen(fn,"rb"))) + throw std::runtime_error("File doesn't exist"); chunkReader(1); for(uint32_t i=0;i<trk;i+=chunkReader(0)); fclose(f);f=NULL; } - catch(std::runtime_error&){fprintf(stderr,"E: %s is not a supported file.\n",fn);ret->valid=0;if(f)fclose(f);f=NULL;} + catch(std::runtime_error& e) + { + fprintf(stderr,"CSMFReader E: %s is not a supported file. Cause: %s.\n",fn,e.what()); + ret->valid=0;if(f)fclose(f);f=NULL; + } return ret; } CSMFReader::~CSMFReader() |