aboutsummaryrefslogblamecommitdiff
path: root/midifmt-plugin/midifmtplugin.cpp
blob: 39d6d4f93e320b29cad251e316b0e76124542de4 (plain) (tree)
1
2
3
4
5
6
7
8



                            
                                              


                                      



                                                


                                          













                                    


                                        




































                                                                                     
 
                                                      
 






















                                                                                                       


                                             
                       
 
                                                   
 



                                                      


                                      

                  





                                                      


               
                                     


                  

                             
                                                                              


                               









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