aboutsummaryrefslogtreecommitdiff
path: root/core/qmpmidioutrtmidi.cpp
diff options
context:
space:
mode:
authorGravatar Chris Xiong <chirs241097@gmail.com> 2019-06-16 20:12:14 +0800
committerGravatar Chris Xiong <chirs241097@gmail.com> 2019-06-16 20:12:14 +0800
commit795043d6851a355d70aa2341e2edfd526c24d041 (patch)
tree203991e9a062934254bc9c6ca2053bdf4c096773 /core/qmpmidioutrtmidi.cpp
parent7b03fd544837fbe0bc5a5373b60dfd5de50892e1 (diff)
downloadQMidiPlayer-795043d6851a355d70aa2341e2edfd526c24d041.tar.xz
Inital implementation of the device properties API.
Added new interfaces to qmpMidiOutDevice. Implemented the new interfaces for qmpMidiOutFluid. Initial infra for device initialization file parsing. Move to the new interfaces for getting list of presets. Use DevIL instead of CxImage. External output devices are broken now but that is for another commit.
Diffstat (limited to 'core/qmpmidioutrtmidi.cpp')
-rw-r--r--core/qmpmidioutrtmidi.cpp151
1 files changed, 151 insertions, 0 deletions
diff --git a/core/qmpmidioutrtmidi.cpp b/core/qmpmidioutrtmidi.cpp
index 2d6d41f..0ff2c86 100644
--- a/core/qmpmidioutrtmidi.cpp
+++ b/core/qmpmidioutrtmidi.cpp
@@ -1,8 +1,144 @@
+#include <cctype>
#include <cstdio>
#include <cstring>
+#include <deque>
#include <vector>
#include RT_MIDI_H
#include "qmpmidioutrtmidi.hpp"
+
+void split(std::string s,char c,std::deque<std::string>& v)
+{
+ v.clear();
+ for(size_t anch=0;;)
+ {
+ std::string sec;
+ if(s.find(c,anch)==std::string::npos)
+ sec=s.substr(anch);
+ else sec=s.substr(anch,s.find(c,anch)-anch);
+ if(!sec.empty())v.push_back(sec);
+ if(s.find(c,anch)==std::string::npos)break;
+ anch=s.find(c,anch)+1;
+ }
+}
+
+qmpDeviceInitializer* qmpDeviceInitializer::parse(const char* path)
+{
+ qmpDeviceInitializer *ret=new qmpDeviceInitializer();
+ ret->initseq.eventList.clear();
+ FILE* f=fopen(path, "r");
+ if(!f)return nullptr;
+
+ bool st_inmapping=false;
+ char buf[1024];
+ int ln=0;
+ int cmsb=-1,clsb=-1;
+
+ //writing such a bad parser makes me want my money for
+ //the credits from "compiler principles" back...
+ auto h2d=[](char c)->char{return 'F'>=c&&c>='A'?c-'A'+10:'9'>=c&&c>='0'?c-'0':-1;};
+ auto hh2d=[](const char *c)->int
+ {
+ if(!c||!*c||strlen(c)>2)return -1;
+ int x=-1,r;
+ r=sscanf(c,"%x",&x);
+ (x<0||x>0xff)&&(x=-1);
+ return r==1?x:-1;
+ };
+#define err(e) {delete ret;return fprintf(stderr,"line %d: %s",ln,e),nullptr;}
+ while(fgets(buf,1024,f))
+ {
+ ++ln;
+ if(buf[0]=='#')continue;
+ std::string b(buf);
+ while(b.length()&&b.back()=='\n')b.pop_back();
+ std::deque<std::string> tok;
+ split(b,' ',tok);
+ if(!tok.size())continue;
+ if(tok.front()=="MAP")
+ {
+ if(st_inmapping)
+ err("invalid command")
+ st_inmapping=true;
+ }
+ else if(tok.front()=="ENDMAP")
+ {
+ if(!st_inmapping)
+ err("invalid command")
+ st_inmapping=false;
+ }
+ else if(tok.front()=="X")
+ {
+ if(st_inmapping)
+ err("invalid command")
+ tok.pop_front();
+ std::string sysx;
+ for(auto&i:tok)sysx+=i;
+ SEvent ev;
+ ev.type=0xF0;
+ ev.str="";
+ for(auto i=sysx.begin();i!=sysx.end();++i)
+ {
+ char hn=h2d((char)toupper(*i));
+ if(hn<0)err("invalid sysex")
+ if(++i==sysx.end())err("invalid sysex")
+ char ln=h2d((char)toupper(*i));
+ ev.str.push_back((char)(hn<<4|ln));
+ }
+ ret->initseq.appendEvent(ev);
+ }
+ else if(tok.front()=="C")
+ {
+ if(tok.size()!=4)err("invalid control")
+ int ch=hh2d(tok[1].c_str());
+ int cc=hh2d(tok[2].c_str());
+ int cv=hh2d(tok[3].c_str());
+ if(!~cc||!~cv)err("invalid control parameters")
+ if(ch==0xff)
+ {
+ for(int i=0;i<16;++i)
+ {
+ SEvent e;
+ e.type=(uint8_t)(0xB0|i);
+ e.p1=(uint8_t)cc;
+ e.p2=(uint8_t)cv;
+ ret->initseq.appendEvent(e);
+ }
+ }
+ else if(ch>=0&&ch<0x10)
+ {
+ SEvent e;
+ e.type=(uint8_t)(0xB0|ch);
+ e.p1=(uint8_t)cc;
+ e.p2=(uint8_t)cv;
+ ret->initseq.appendEvent(e);
+ }
+ else err("invalid channel")
+ }
+ else if(tok.front()=="IV")
+ {
+ int ci=0;
+ tok.pop_front();
+ for(auto&tk:tok)
+ {
+ int v=0,rep=1;
+ if(tk.find(',')!=std::string::npos)
+ sscanf(tk.c_str(),"%x,%d",&v,&rep);
+ else sscanf(tk.c_str(),"%x",&v);
+ if(v>0xff||v<0)err("invalid init vector value")
+ for(int i=0;i<rep;++i)
+ {
+ if(ci>=130)err("invalid init vector")
+ ret->initv[ci++]=(uint8_t)v;
+ }
+ }
+ }
+ }
+#undef err
+
+ fclose(f);
+ return ret;
+}
+
qmpMidiOutRtMidi::qmpMidiOutRtMidi(unsigned _portid)
{
portid=_portid;
@@ -91,6 +227,21 @@ void qmpMidiOutRtMidi::onUnmapped(uint8_t ch,int refcnt)
panic(ch);
if(!refcnt&&outport)outport->closePort();
}
+std::vector<std::pair<uint16_t,std::string>> qmpMidiOutRtMidi::getBankList()
+{
+}
+std::vector<std::pair<uint8_t,std::string>> qmpMidiOutRtMidi::getPresets(int bank)
+{
+}
+std::string qmpMidiOutRtMidi::getPresetName(uint16_t bank,uint8_t preset)
+{
+}
+bool qmpMidiOutRtMidi::getChannelPreset(int ch,uint16_t *bank,uint8_t *preset,std::string &presetname)
+{
+}
+uint8_t qmpMidiOutRtMidi::getInitialCCValue(uint8_t cc)
+{
+}
RtMidiOut* qmpRtMidiManager::dummy=nullptr;
void qmpRtMidiManager::createDevices()