aboutsummaryrefslogtreecommitdiff
path: root/core/qmpmidiread.cpp
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2017-06-22 11:26:48 +0800
committerGravatar Chris Xiong <chirs241097@gmail.com> 2017-06-22 11:26:48 +0800
commitb03133b80b268c74d1dd5c92e2af6907b51c91b2 (patch)
tree2700bf29cecd5ae89fd7d99e3d6acb88ebb44e61 /core/qmpmidiread.cpp
parenta97307ba6e625468a1d8ad1049e6d9db0ad42d4d (diff)
downloadQMidiPlayer-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.cpp92
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()