diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/qmpmidioutfluid.cpp | 76 | ||||
-rw-r--r-- | core/qmpmidioutfluid.hpp | 10 | ||||
-rw-r--r-- | core/qmpmidioutrtmidi.cpp | 151 | ||||
-rw-r--r-- | core/qmpmidioutrtmidi.hpp | 19 | ||||
-rw-r--r-- | core/qmpmidiplay.cpp | 19 | ||||
-rw-r--r-- | core/qmpmidiplay.hpp | 2 | ||||
-rw-r--r-- | core/qmpmidiread.cpp | 11 |
7 files changed, 256 insertions, 32 deletions
diff --git a/core/qmpmidioutfluid.cpp b/core/qmpmidioutfluid.cpp index bb8f290..414cb3a 100644 --- a/core/qmpmidioutfluid.cpp +++ b/core/qmpmidioutfluid.cpp @@ -1,6 +1,6 @@ #include <cstdio> #include <cstring> -#include <map> +#include <algorithm> #include "qmpmidioutfluid.hpp" qmpMidiOutFluid::qmpMidiOutFluid() { @@ -30,6 +30,7 @@ void qmpMidiOutFluid::deviceInit() } fluid_synth_set_chorus(synth,3,2.0,0.3,8.0, FLUID_CHORUS_MOD_SINE); + bnk.clear();pst.clear(); } void qmpMidiOutFluid::deviceDeinit(){deviceDeinit(false);} void qmpMidiOutFluid::deviceDeinit(bool freshsettings) @@ -38,6 +39,7 @@ void qmpMidiOutFluid::deviceDeinit(bool freshsettings) delete_fluid_audio_driver(adriver); delete_fluid_synth(synth); synth=nullptr;adriver=nullptr; + bnk.clear();pst.clear(); if(freshsettings) { delete_fluid_settings(settings); @@ -117,6 +119,54 @@ void qmpMidiOutFluid::onMapped(uint8_t,int) void qmpMidiOutFluid::onUnmapped(uint8_t,int) { } +std::vector<std::pair<uint16_t,std::string>> qmpMidiOutFluid::getBankList() +{ + return bnk; +} +std::vector<std::pair<uint8_t,std::string>> qmpMidiOutFluid::getPresets(int bank) +{ + std::vector<std::pair<uint8_t,std::string>> ret; + if(pst.find(bank)==pst.end())return ret; + for(uint8_t i=0;i<128;++i) + { + if(pst[bank][i].length()) + ret.emplace_back(i,pst[bank][i]); + } + return ret; +} +std::string qmpMidiOutFluid::getPresetName(uint16_t bank,uint8_t preset) +{ + if(pst.find(bank)==pst.end())return ""; + return pst[bank][preset]; +} +bool qmpMidiOutFluid::getChannelPreset(int ch,uint16_t *bank,uint8_t *preset,std::string &presetname) +{ + if(!synth)return false; + fluid_preset_t* chpreset=fluid_synth_get_channel_preset(synth,ch); + if(!chpreset) + { + *bank=*preset=-1; + presetname="---"; + return true; + } + *bank=fluid_preset_get_banknum(chpreset); + *preset=fluid_preset_get_num(chpreset); + presetname=fluid_preset_get_name(chpreset); + return true; +} +uint8_t qmpMidiOutFluid::getInitialCCValue(uint8_t cc) +{ + switch(cc) + { + case 11:return 127; + case 7:return 100; + case 8:case 10:case 71:case 72: + case 73:case 74:case 75:case 76: + case 77:case 78:return 64; + case 129:return 2; + default:return 0; + } +} void qmpMidiOutFluid::setOptStr(const char *opt,const char *val) { fluid_settings_setstr(settings,opt,val); @@ -132,29 +182,33 @@ void qmpMidiOutFluid::setOptNum(const char *opt,double val) void qmpMidiOutFluid::loadSFont(const char *path) { if(synth)fluid_synth_sfload(synth,path,1); + update_preset_list(); } int qmpMidiOutFluid::getSFCount() { return synth?fluid_synth_sfcount(synth):0; } -std::vector<std::pair<std::pair<int,int>,std::string>> qmpMidiOutFluid::listPresets() +void qmpMidiOutFluid::update_preset_list() { - std::vector<std::pair<std::pair<int,int>,std::string>> ret; - std::map<std::pair<int,int>,std::string> pmap; + bnk.clear();pst.clear(); for(int i=getSFCount()-1;i>=0;--i) { fluid_sfont_t* psf=fluid_synth_get_sfont(synth,i); fluid_preset_t* preset; fluid_sfont_iteration_start(psf); while(preset=fluid_sfont_iteration_next(psf)) - pmap[std::make_pair( - fluid_preset_get_banknum(preset), - fluid_preset_get_num(preset) - )]=fluid_preset_get_name(preset); + { + uint16_t b=fluid_preset_get_banknum(preset); + uint8_t p=fluid_preset_get_num(preset); + if(bnk.empty()||bnk.back().first!=b) + bnk.emplace_back(b,""); + if(pst[b].empty())pst[b].resize(128); + pst[b][p]=std::string(fluid_preset_get_name(preset)); + if(!pst[b][p].length())pst[b][p]=" "; + } } - for(auto i=pmap.begin();i!=pmap.end();++i) - ret.push_back(std::make_pair(i->first,i->second)); - return ret; + std::sort(bnk.begin(),bnk.end()); + bnk.erase(std::unique(bnk.begin(),bnk.end()),bnk.end()); } int qmpMidiOutFluid::getPolyphone() { diff --git a/core/qmpmidioutfluid.hpp b/core/qmpmidioutfluid.hpp index 963f9df..72197e7 100644 --- a/core/qmpmidioutfluid.hpp +++ b/core/qmpmidioutfluid.hpp @@ -3,6 +3,7 @@ #include <string> #include <utility> #include <vector> +#include <unordered_map> #include "../include/qmpcorepublic.hpp" #include <fluidsynth.h> class IFluidSettings @@ -22,6 +23,9 @@ class qmpMidiOutFluid:public qmpMidiOutDevice,public IFluidSettings fluid_settings_t* settings; fluid_synth_t* synth; fluid_audio_driver_t* adriver; + std::vector<std::pair<uint16_t,std::string>> bnk; + std::unordered_map<uint16_t,std::vector<std::string>> pst; + void update_preset_list(); public: qmpMidiOutFluid(); ~qmpMidiOutFluid(); @@ -36,13 +40,17 @@ class qmpMidiOutFluid:public qmpMidiOutDevice,public IFluidSettings void reset(uint8_t ch); void onMapped(uint8_t ch,int refcnt); void onUnmapped(uint8_t ch,int refcnt); + std::vector<std::pair<uint16_t,std::string>> getBankList(); + std::vector<std::pair<uint8_t,std::string>> getPresets(int bank); + std::string getPresetName(uint16_t bank,uint8_t preset); + bool getChannelPreset(int ch,uint16_t *bank,uint8_t *preset,std::string &presetname); + uint8_t getInitialCCValue(uint8_t cc); //FluidSynth specific stuff void setOptStr(const char* opt,const char* val); void setOptInt(const char* opt,int val); void setOptNum(const char* opt,double val); void loadSFont(const char* path); int getSFCount(); - std::vector<std::pair<std::pair<int,int>,std::string>> listPresets(); int getPolyphone(); int getMaxPolyphone(); 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() diff --git a/core/qmpmidioutrtmidi.hpp b/core/qmpmidioutrtmidi.hpp index 48ee0cf..23adec6 100644 --- a/core/qmpmidioutrtmidi.hpp +++ b/core/qmpmidioutrtmidi.hpp @@ -1,9 +1,23 @@ #ifndef QMPMIDIMAPPERS_H #define QMPMIDIMAPPERS_H +#include <unordered_map> #include <vector> #define QMP_MAIN #include "../include/qmpcorepublic.hpp" #include RT_MIDI_H +struct qmpDeviceInitializer +{ + CMidiTrack initseq; + struct BankStore + { + std::unordered_map<uint8_t,std::string> presets; + std::string bankname; + }; + std::unordered_map<uint16_t,BankStore> banks; + uint8_t initv[130]; + + static qmpDeviceInitializer* parse(const char* path); +}; class qmpMidiOutRtMidi:public qmpMidiOutDevice { private: @@ -22,6 +36,11 @@ public: void reset(uint8_t ch); void onMapped(uint8_t ch,int refcnt); void onUnmapped(uint8_t ch,int refcnt); + std::vector<std::pair<uint16_t,std::string>> getBankList(); + std::vector<std::pair<uint8_t,std::string>> getPresets(int bank); + std::string getPresetName(uint16_t bank,uint8_t preset); + bool getChannelPreset(int ch,uint16_t *bank,uint8_t *preset,std::string &presetname); + uint8_t getInitialCCValue(uint8_t cc); }; class qmpRtMidiManager { diff --git a/core/qmpmidiplay.cpp b/core/qmpmidiplay.cpp index 28ca9e7..bbf1c3a 100644 --- a/core/qmpmidiplay.cpp +++ b/core/qmpmidiplay.cpp @@ -241,7 +241,7 @@ void CMidiPlayer::fileTimer2Pass() memset(ccc,0,sizeof(ccc));memset(rpnid,0xFF,sizeof(rpnid));memset(rpnval,0xFF,sizeof(rpnval)); for(int i=0;i<16;++i) { - ccc[i][7]=100;ccc[i][8]=64;ccc[i][10]=64;ccc[i][11]=127; + ccc[i][7]=100;ccc[i][8]=64;ccc[i][10]=64; ccc[i][11]=127;ccc[i][71]=64;ccc[i][72]=64; ccc[i][73]=64;ccc[i][74]=64;ccc[i][75]=64; ccc[i][76]=64;ccc[i][77]=64;ccc[i][78]=64; @@ -427,19 +427,6 @@ uint32_t CMidiPlayer::isFinished(){return finished;} void CMidiPlayer::setResumed(){resumed=true;} void CMidiPlayer::setWaitVoice(bool wv){waitvoice=wv;} -void CMidiPlayer::getChannelPreset(int ch,int *b,int *p,char *name) -{ - if(mappedoutput[ch]) - { - *b=((int)chstatus[ch][0]<<7)|chstatus[ch][32]; - *p=chstatus[ch][128]; - strcpy(name,""); - } - else - { - internalFluid->getChannelInfo(ch,b,p,name); - } -} void CMidiPlayer::setChannelPreset(int ch,int b,int p) { chstatus[ch][128]=p; @@ -510,6 +497,10 @@ int CMidiPlayer::getChannelOutput(int ch) { return mappedoutput[ch]; } +qmpMidiOutDevice* CMidiPlayer::getChannelOutputDevice(int ch) +{ + return mididev[mappedoutput[ch]].dev; +} void CMidiPlayer::setChannelOutput(int ch,int outid) { int origoutput=mappedoutput[ch]; diff --git a/core/qmpmidiplay.hpp b/core/qmpmidiplay.hpp index f42c98b..da9e9ef 100644 --- a/core/qmpmidiplay.hpp +++ b/core/qmpmidiplay.hpp @@ -141,7 +141,6 @@ class CMidiPlayer void sendSysX(bool send); void setChannelPreset(int ch,int b,int p); - void getChannelPreset(int ch,int *b,int *p,char *name); void setMute(int ch,bool m); void setSolo(int ch,bool s); bool getChannelMask(int ch); @@ -154,6 +153,7 @@ class CMidiPlayer void unregisterMidiOutDevice(std::string name); std::vector<std::string> getMidiOutDevices(); int getChannelOutput(int ch); + qmpMidiOutDevice* getChannelOutputDevice(int ch); void setChannelOutput(int ch,int outid); uint8_t* getChstates(); int setEventHandlerCB(ICallBack *cb,void *userdata); diff --git a/core/qmpmidiread.cpp b/core/qmpmidiread.cpp index 7f5bdfc..48a149d 100644 --- a/core/qmpmidiread.cpp +++ b/core/qmpmidiread.cpp @@ -94,7 +94,8 @@ int CSMFReader::read_event()//returns 0 if End of Track encountered uint32_t len=read_varlen();char* str=nullptr; if(len<=1024&&len>0)str=new char[len+8]; if(str)fread(str,1,len,f);else fseek(f,len,SEEK_CUR); - if(str)str[len]='\0'; + std::string sstr; + if(str){str[len]='\0';sstr=std::string(str,len);} switch(metatype) { case 0x00://Sequence Number @@ -108,24 +109,24 @@ int CSMFReader::read_event()//returns 0 if End of Track encountered return 0; case 0x51://Set Tempo assert(len==3); - curTrack->appendEvent(SEvent(curid,curt,type,metatype,0,str)); + curTrack->appendEvent(SEvent(curid,curt,type,metatype,0,sstr)); break; case 0x54://SMTPE offset, not handled. assert(len==5); break; case 0x58://Time signature assert(len==4); - curTrack->appendEvent(SEvent(curid,curt,type,metatype,0,str)); + curTrack->appendEvent(SEvent(curid,curt,type,metatype,0,sstr)); break; case 0x59://Key signature assert(len==2); - curTrack->appendEvent(SEvent(curid,curt,type,metatype,0,str)); + curTrack->appendEvent(SEvent(curid,curt,type,metatype,0,sstr)); break; case 0x01:case 0x02:case 0x03: case 0x04:case 0x05:case 0x06: case 0x07:case 0x7F:default://text-like meta { - curTrack->appendEvent(SEvent(curid,curt,type,metatype,0,str)); + curTrack->appendEvent(SEvent(curid,curt,type,metatype,0,sstr)); if(str&&metatype==0x03&&!ret->title) { ret->title=new char[len+8]; |