1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
#include <cstring>
#include <algorithm>
#include <stdexcept>
#include "midifmtplugin.hpp"
qmpPluginAPI* qmpMidiFmtPlugin::api=nullptr;
uint32_t CMidiStreamReader::readDWLE()
{
uint32_t ret=0;
for(uint32_t i=0;i<4;++i)ret|=((uint32_t)fgetc(f))<<(i<<3);
return ret;
}
bool CMidiStreamReader::RIFFHeaderReader()
{
char hdr[9];
fread(hdr,1,4,f);
if(strncmp(hdr,"RIFF",4))return false;
fseek(f,4,SEEK_CUR);
fread(hdr,1,8,f);
if(strncmp(hdr,"MIDSfmt ",8))return false;
if(readDWLE()!=0x0C)return false;
ret->divs=readDWLE();
readDWLE();
fmt=readDWLE();
return true;
}
bool CMidiStreamReader::midsBodyReader()
{
char buf[9];
fread(buf,1,4,f);
if(strncmp(buf,"data",4))return false;
readDWLE();//size
uint32_t cblocks=readDWLE();
uint32_t curid=0,cts=0;
for(uint32_t i=0;i<cblocks;++i)
{
readDWLE();
uint32_t blocksz=readDWLE(),cpos=ftell(f);
while(ftell(f)-cpos<blocksz)
{
cts+=readDWLE();
if(!(fmt&1))readDWLE();
uint32_t e=readDWLE();
SEvent ev;
if(e>>24==1)//set tempo
{
char s[3]={'\0'};
for(int i=0;i<3;++i)
s[i]=(e>>(8*(2-i)))&0xff;
ev=SEvent(curid,cts,0xFF,0x51,0);
ev.str=std::string(s,3);
}
else if(e>>24==0)//midishortmsg
ev=SEvent(curid,cts,e&0xFF,(e>>8)&0xFF,(e>>16)&0xFF);
else return false;
ret->tracks.back().appendEvent(ev);eventdiscarded=0;
qmpMidiFmtPlugin::api->callEventReaderCB(ev);
if(eventdiscarded)ret->tracks.back().eventList.pop_back();
++curid;
}
}
return true;
}
CMidiFile* CMidiStreamReader::readFile(const char *fn)
{
ret=new CMidiFile;
ret->title=ret->copyright=nullptr;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");
}catch(std::runtime_error& e)
{
fprintf(stderr,"CMidiStreamReader E: %s is not a supported file. Cause: %s.\n",fn,e.what());
ret->valid=0;if(f)fclose(f);f=nullptr;
}
return ret;
}
void CMidiStreamReader::discardCurrentEvent()
{
eventdiscarded=1;
}
void CMidiStreamReader::commitEventChange(SEvent d)
{
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()
{
ret=nullptr;f=nullptr;
}
CMidiStreamReader::~CMidiStreamReader()
{
}
qmpMidiFmtPlugin::qmpMidiFmtPlugin(qmpPluginAPI *_api)
{api=_api;}
qmpMidiFmtPlugin::~qmpMidiFmtPlugin()
{api=nullptr;}
void qmpMidiFmtPlugin::init()
{
api->registerFileReader(mdsreader=new CMidiStreamReader,"MIDS reader");
}
void qmpMidiFmtPlugin::deinit()
{
api->unregisterFileReader("MIDS reader");
delete mdsreader;
}
const char* qmpMidiFmtPlugin::pluginGetName()
{return "QMidiPlayer extra midi formats plugin";}
const char* qmpMidiFmtPlugin::pluginGetVersion()
{return "0.8.7";}
|