aboutsummaryrefslogblamecommitdiff
path: root/midifmt-plugin/midifmtplugin.cpp
blob: 62a9af17d0089429c25e9ff565f9c331d903f314 (plain) (tree)
1
2
3
4
5



                            
                                            




























                                                                   
                                       









                                                          






                                                                 


                                                                             
                                                                            
                                                                     
                                                                                  







                                                      
                                                                  
                                            




                                                                                      

                                     
                                                                                                            
                                                      
         





                                             
                                                   
 



                                                        


                                      
                              







                                                      
              











                                                                               
                        
#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 PLUGIN_VERSION;}