diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/qmpmidimapperrtmidi.cpp | 88 | ||||
-rw-r--r-- | core/qmpmidimappers.hpp | 23 | ||||
-rw-r--r-- | core/qmpmidiplay.cpp | 54 | ||||
-rw-r--r-- | core/qmpmidiplay.hpp | 6 |
4 files changed, 165 insertions, 6 deletions
diff --git a/core/qmpmidimapperrtmidi.cpp b/core/qmpmidimapperrtmidi.cpp new file mode 100644 index 0000000..adba267 --- /dev/null +++ b/core/qmpmidimapperrtmidi.cpp @@ -0,0 +1,88 @@ +#include <cstdio> +#include <cstring> +#include <vector> +#include "RtMidi.h" +#include "qmpmidimappers.hpp" +RtMidiOut* qmpMidiMapperRtMidi::dummy=NULL; +qmpMidiMapperRtMidi::qmpMidiMapperRtMidi() +{ + dummy=new RtMidiOut(); + memset(ports,0,sizeof(ports)); +} +qmpMidiMapperRtMidi::~qmpMidiMapperRtMidi() +{ + delete dummy;for(int i=0;i<16;++i)if(ports[i])delete ports[i]; +} +int qmpMidiMapperRtMidi::enumDevices() +{ + return dummy->getPortCount(); +} +std::string qmpMidiMapperRtMidi::deviceName(int id) +{ + fprintf(stderr,"port #%d: %s\n",id,dummy->getPortName(id).c_str()); + return dummy->getPortName(id); +} +int qmpMidiMapperRtMidi::deviceInit(int id) +{ + int i=0;for(;ports[i]&&i<16;++i); + if(i==16)return -1; + try + { + ports[i]=new RtMidiOut(); + ports[i]->openPort(id); + } + catch(RtMidiError e) + { + printf("Device initialization failure: %s\n",e.what()); + ports[i]=NULL; + return -1; + } + return i; +} +void qmpMidiMapperRtMidi::deviceDeinit(int iid) +{ + if(ports[iid]){ports[iid]->closePort();delete ports[iid];ports[iid]=NULL;} +} +void qmpMidiMapperRtMidi::noteOn(int iid,int ch,int key,int vel) +{ + if(!ports[iid])return;ch&=0x0F; + std::vector<unsigned char>message; + message.push_back(0x90|ch); + message.push_back(key); + message.push_back(vel); + ports[iid]->sendMessage(&message); +} +void qmpMidiMapperRtMidi::noteOff(int iid,int ch,int key) +{ + if(!ports[iid])return;ch&=0x0F; + std::vector<unsigned char>message; + message.push_back(0x80|ch);message.push_back(key);message.push_back(0); + ports[iid]->sendMessage(&message); +} +void qmpMidiMapperRtMidi::ctrlChange(int iid,int ch,int cc,int val) +{ + if(!ports[iid])return;ch&=0x0F; + std::vector<unsigned char>message; + message.push_back(0xB0|ch);message.push_back(cc);message.push_back(val); + ports[iid]->sendMessage(&message); +} +void qmpMidiMapperRtMidi::progChange(int iid,int ch,int val) +{ + if(!ports[iid])return;ch&=0x0F; + std::vector<unsigned char>message; + message.push_back(0xC0|ch);message.push_back(val); + ports[iid]->sendMessage(&message); +} +void qmpMidiMapperRtMidi::pitchBend(int iid,int ch,int val) +{ + if(!ports[iid])return;ch&=0x0F; + std::vector<unsigned char>message; + message.push_back(0xE0|ch);message.push_back(val&0xFF); + message.push_back(val>>8);ports[iid]->sendMessage(&message); +} +void qmpMidiMapperRtMidi::sysEx(int iid,int length,const char *data) +{ + if(!ports[iid])return; + std::vector<unsigned char>message(data,data+length); + ports[iid]->sendMessage(&message); +} diff --git a/core/qmpmidimappers.hpp b/core/qmpmidimappers.hpp new file mode 100644 index 0000000..156caaa --- /dev/null +++ b/core/qmpmidimappers.hpp @@ -0,0 +1,23 @@ +#ifndef QMPMIDIMAPPERS_H +#define QMPMIDIMAPPERS_H +#include "RtMidi.h" +class qmpMidiMapperRtMidi +{ +private: + RtMidiOut *ports[16]; + static RtMidiOut *dummy; +public: + qmpMidiMapperRtMidi(); + ~qmpMidiMapperRtMidi(); + int deviceInit(int id); + void deviceDeinit(int iid); + void noteOn(int iid,int ch,int key,int vel); + void noteOff(int iid,int ch,int key); + void ctrlChange(int iid,int ch,int cc,int val); + void progChange(int iid,int ch,int val); + void pitchBend(int iid,int ch,int val); + void sysEx(int iid,int length,const char* data); + int enumDevices(); + std::string deviceName(int id); +}; +#endif // QMPMIDIMAPPERS_H diff --git a/core/qmpmidiplay.cpp b/core/qmpmidiplay.cpp index 6f69e33..e65a2a1 100644 --- a/core/qmpmidiplay.cpp +++ b/core/qmpmidiplay.cpp @@ -1,4 +1,5 @@ #include <cstdio> +#include <cstring> #include <chrono> #include <thread> #include <fluidsynth.h> @@ -46,12 +47,18 @@ void CMidiPlayer::processEvent(const SEvent *e) switch(e->type&0xF0) { case 0x80://Note off - fluid_synth_noteoff(synth,e->type&0x0F,e->p1); + if(mappedoutput[e->type&0x0F]) + mapper->noteOff(mappedoutput[e->type&0x0F]-1,e->type*0x0F,e->p1); + else + fluid_synth_noteoff(synth,e->type&0x0F,e->p1); break; case 0x90://Note on if((mute>>(e->type&0x0F))&1)break;//muted if(solo&&!((solo>>(e->type&0x0F))&1))break; - fluid_synth_noteon(synth,e->type&0x0F,e->p1,e->p2); + if(mappedoutput[e->type&0x0F]) + mapper->noteOn(mappedoutput[e->type&0x0F]-1,e->type*0x0F,e->p1,e->p2); + else + fluid_synth_noteon(synth,e->type&0x0F,e->p1,e->p2); break; case 0xB0://CC if(e->p1==100)rpnid=e->p2; @@ -61,13 +68,22 @@ void CMidiPlayer::processEvent(const SEvent *e) if(rpnid==0)fluid_synth_pitch_wheel_sens(synth,e->type&0x0F,rpnval); rpnid=rpnval=-1; } - fluid_synth_cc(synth,e->type&0x0F,e->p1,e->p2); + if(mappedoutput[e->type&0x0F]) + mapper->ctrlChange(mappedoutput[e->type&0x0F]-1,e->type*0x0F,e->p1,e->p2); + else + fluid_synth_cc(synth,e->type&0x0F,e->p1,e->p2); break; case 0xC0://PC - fluid_synth_program_change(synth,e->type&0x0F,e->p1); + if(mappedoutput[e->type&0x0F]) + mapper->progChange(mappedoutput[e->type&0x0F]-1,e->type*0x0F,e->p1); + else + fluid_synth_program_change(synth,e->type&0x0F,e->p1); break; case 0xE0://PW - fluid_synth_pitch_bend(synth,e->type&0x0F,e->p1); + if(mappedoutput[e->type&0x0F]) + mapper->pitchBend(mappedoutput[e->type&0x0F]-1,e->type*0x0F,e->p1); + else + fluid_synth_pitch_bend(synth,e->type&0x0F,e->p1); break; case 0xF0://Meta/SysEx if((e->type&0x0F)==0x0F) @@ -94,7 +110,11 @@ void CMidiPlayer::processEvent(const SEvent *e) if((e->type&0x0F)==0x00||(e->type&0x0F)==07) { int io=0; - if(sendSysEx)fluid_synth_sysex(synth,e->str,e->p1,NULL,&io,NULL,0); + if(sendSysEx) + { + for(int i=0;i<16;++i)if(deviceusage[i])mapper->sysEx(i,e->p1,e->str); + fluid_synth_sysex(synth,e->str,e->p1,NULL,&io,NULL,0); + } } break; } @@ -231,6 +251,9 @@ CMidiPlayer::CMidiPlayer(bool singleInst) { midiFile=NULL;resumed=false;singleInstance=singleInst; settings=NULL;synth=NULL;adriver=NULL;waitvoice=true; + memset(mappedoutput,0,sizeof(mappedoutput)); + memset(deviceusage,0,sizeof(deviceusage)); + mapper=new qmpMidiMapperRtMidi(); #ifdef _WIN32 QueryPerformanceFrequency((LARGE_INTEGER*)&pf); #endif @@ -238,6 +261,7 @@ CMidiPlayer::CMidiPlayer(bool singleInst) CMidiPlayer::~CMidiPlayer() { if(singleInstance)fluidDeinitialize(); + delete mapper; } void CMidiPlayer::playerPanic(bool reset) { @@ -402,3 +426,21 @@ int CMidiPlayer::getSFCount() {return synth?fluid_synth_sfcount(synth):0;} fluid_sfont_t* CMidiPlayer::getSFPtr(int sfid) {return synth&&sfid<getSFCount()?fluid_synth_get_sfont(synth,sfid):NULL;} + +qmpMidiMapperRtMidi* CMidiPlayer::getMidiMapper(){return mapper;} +void CMidiPlayer::setChannelOutput(int ch,int devid) +{ + int origoutput=mappedoutput[ch]; + int newoutput=0; + if(devid>0) + { + if(!deviceusage[devid-1])deviceiid[devid]=newoutput=mapper->deviceInit(devid-1); + ++deviceusage[deviceiid[devid]]; + } + mappedoutput[ch]=devid?deviceiid[devid]+1:0; + if(origoutput>0) + { + --deviceusage[origoutput-1]; + if(!deviceusage[origoutput-1])mapper->deviceDeinit(origoutput-1); + } +} diff --git a/core/qmpmidiplay.hpp b/core/qmpmidiplay.hpp index fafd677..a7e7f88 100644 --- a/core/qmpmidiplay.hpp +++ b/core/qmpmidiplay.hpp @@ -5,6 +5,7 @@ #include <cstdint> #include <cstdlib> #include <fluidsynth.h> +#include "qmpmidimappers.hpp" struct SEvent { uint32_t iid,time,p1,p2; @@ -69,6 +70,8 @@ class CMidiPlayer //thread control uint32_t tceptr,tcpaused,tcstop; uint32_t finished,resumed; + qmpMidiMapperRtMidi *mapper; + int mappedoutput[16],deviceusage[16],deviceiid[128]; void setBit(uint16_t &n,uint16_t bn,uint16_t b); void processEvent(const SEvent *e); @@ -133,5 +136,8 @@ class CMidiPlayer void pushSoundFont(const char* sf); int getSFCount(); fluid_sfont_t* getSFPtr(int sfid); + + qmpMidiMapperRtMidi* getMidiMapper(); + void setChannelOutput(int ch,int devid); }; #endif |