diff options
author | Chris Xiong <chirs241097@gmail.com> | 2017-06-21 13:03:30 +0800 |
---|---|---|
committer | Chris Xiong <chirs241097@gmail.com> | 2017-06-21 13:03:30 +0800 |
commit | 0c3fe540e925829022d9d8aa567c2dc2bd3d33d5 (patch) | |
tree | ab9ecae4def5a329b5e796839ece97f4b9c0297f /core | |
parent | 64c91c7da66ba71e2bb32077680f234aba4ac65d (diff) | |
download | QMidiPlayer-0c3fe540e925829022d9d8aa567c2dc2bd3d33d5.tar.xz |
Complete rewrite of the MIDI mapper.
Enforces single fluidsynth instance.
Documentation update.
Minor changes to make lite version work.
Diffstat (limited to 'core')
-rw-r--r-- | core/qmpmidimapperrtmidi.cpp | 105 | ||||
-rw-r--r-- | core/qmpmidimappers.hpp | 25 | ||||
-rw-r--r-- | core/qmpmidioutfluid.cpp | 282 | ||||
-rw-r--r-- | core/qmpmidioutfluid.hpp | 80 | ||||
-rw-r--r-- | core/qmpmidioutrtmidi.cpp | 115 | ||||
-rw-r--r-- | core/qmpmidioutrtmidi.hpp | 36 | ||||
-rw-r--r-- | core/qmpmidiplay.cpp | 335 | ||||
-rw-r--r-- | core/qmpmidiplay.hpp | 54 |
8 files changed, 646 insertions, 386 deletions
diff --git a/core/qmpmidimapperrtmidi.cpp b/core/qmpmidimapperrtmidi.cpp deleted file mode 100644 index 263cada..0000000 --- a/core/qmpmidimapperrtmidi.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include <cstdio> -#include <cstring> -#include <vector> -#include RT_MIDI_H -#include "qmpmidimappers.hpp" -RtMidiOut* qmpMidiMapperRtMidi::dummy=NULL; -qmpMidiMapperRtMidi::qmpMidiMapperRtMidi() -{ - try{dummy=new RtMidiOut();} - catch(RtMidiError &e) - { - printf("Failed to initialize the dummy device: %s\n",e.what()); - dummy=NULL; - } - memset(ports,0,sizeof(ports)); -} -qmpMidiMapperRtMidi::~qmpMidiMapperRtMidi() -{ - delete dummy;dummy=NULL; - for(int i=0;i<16;++i)if(ports[i])delete ports[i]; -} -int qmpMidiMapperRtMidi::enumDevices() -{ - return dummy?dummy->getPortCount():0; -} -std::string qmpMidiMapperRtMidi::deviceName(int id) -{ - return dummy?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&0x7F); - message.push_back(val>>7);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); -} -void qmpMidiMapperRtMidi::panic(int iid,int ch) -{ - //maybe all notes off is more close to panic? - pitchBend(iid,ch,8192); - ctrlChange(iid,ch,120,0); - //ctrlChange(iid,ch,123,0); -} -void qmpMidiMapperRtMidi::reset(int iid,int ch) -{ - ctrlChange(iid,ch,120,0); - ctrlChange(iid,ch,121,0); -} diff --git a/core/qmpmidimappers.hpp b/core/qmpmidimappers.hpp deleted file mode 100644 index 7b9ff0e..0000000 --- a/core/qmpmidimappers.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef QMPMIDIMAPPERS_H -#define QMPMIDIMAPPERS_H -#include RT_MIDI_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); - void panic(int iid,int ch); - void reset(int iid,int ch); - int enumDevices(); - std::string deviceName(int id); -}; -#endif // QMPMIDIMAPPERS_H diff --git a/core/qmpmidioutfluid.cpp b/core/qmpmidioutfluid.cpp new file mode 100644 index 0000000..da3282f --- /dev/null +++ b/core/qmpmidioutfluid.cpp @@ -0,0 +1,282 @@ +#include <cstdio> +#include <cstring> +#include <map> +#include "qmpmidioutfluid.hpp" +qmpMidiOutFluid::qmpMidiOutFluid() +{ + settings=new_fluid_settings(); + synth=NULL;adriver=NULL; +} +qmpMidiOutFluid::~qmpMidiOutFluid() +{ + delete_fluid_settings(settings); + settings=NULL; +} +void qmpMidiOutFluid::deviceInit() +{ + synth=new_fluid_synth(settings); + if(!synth){fputs("Error creating fluidsynth instance!",stderr);return;} + fluid_set_log_function(FLUID_DBG,NULL,NULL); + fluid_set_log_function(FLUID_INFO,NULL,NULL); + fluid_set_log_function(FLUID_WARN,NULL,NULL); + fluid_set_log_function(FLUID_ERR,fluid_default_log_function,NULL); + fluid_set_log_function(FLUID_PANIC,fluid_default_log_function,NULL); + adriver=new_fluid_audio_driver(settings,synth); + if(!adriver) + { + fputs("Error creating fluidsynth audio driver!",stderr); + delete_fluid_synth(synth);synth=NULL; + return; + } + fluid_synth_set_chorus(synth,FLUID_CHORUS_DEFAULT_N,FLUID_CHORUS_DEFAULT_LEVEL, + FLUID_CHORUS_DEFAULT_SPEED,FLUID_CHORUS_DEFAULT_DEPTH, + FLUID_CHORUS_DEFAULT_TYPE); + /*if(midiFile->std==4) + fluid_synth_set_channel_type(synth,9,CHANNEL_TYPE_MELODIC); + else if(midiFile->std==1) + fluid_synth_set_channel_type(synth,9,CHANNEL_TYPE_DRUM); + else + { + fluid_synth_set_channel_type(synth,9,CHANNEL_TYPE_DRUM); + fluid_synth_bank_select(synth,9,128); + }*/ +} +void qmpMidiOutFluid::deviceDeinit(){deviceDeinit(false);} +void qmpMidiOutFluid::deviceDeinit(bool freshsettings) +{ + if(!synth||!adriver)return; + delete_fluid_audio_driver(adriver); + delete_fluid_synth(synth); + synth=NULL;adriver=NULL; + if(freshsettings) + { + delete_fluid_settings(settings); + settings=new_fluid_settings(); + } +} +void qmpMidiOutFluid::basicMessage(uint8_t type,uint8_t p1,uint8_t p2) +{ + uint8_t chan=type&0x0F; + switch(type&0xF0) + { + case 0x80: + fluid_synth_noteoff(synth,chan,p1); + break; + case 0x90: + if(p2)fluid_synth_noteon(synth,chan,p1,p2); + else fluid_synth_noteoff(synth,chan,p1); + break; + case 0xB0: + fluid_synth_cc(synth,chan,p1,p2); + break; + case 0xC0: + fluid_synth_program_change(synth,chan,p1); + break; + case 0xE0: + fluid_synth_pitch_bend(synth,chan,(p1|p2<<7)&0x3fff); + break; + } +} +void qmpMidiOutFluid::extendedMessage(uint8_t length,const char *data) +{ + int rlen=0; + fluid_synth_sysex(synth,data,length,NULL,&rlen,NULL,0); +} +void qmpMidiOutFluid::rpnMessage(uint8_t ch,uint16_t type,uint16_t val) +{ + if(type==0)fluid_synth_pitch_wheel_sens(synth,ch,val>>7); + else + { + fluid_synth_cc(synth,ch,0x64,type&0x7F); + fluid_synth_cc(synth,ch,0x65,type>>7); + fluid_synth_cc(synth,ch,0x06,val>>7); + fluid_synth_cc(synth,ch,0x26,val&0x7F); + } +} +void qmpMidiOutFluid::nrpnMessage(uint8_t ch,uint16_t type,uint16_t val) +{ + fluid_synth_cc(synth,ch,0x62,type&0x7F); + fluid_synth_cc(synth,ch,0x63,type>>7); + fluid_synth_cc(synth,ch,0x06,val>>7); + fluid_synth_cc(synth,ch,0x26,val&0x7F); +} +void qmpMidiOutFluid::panic(uint8_t ch) +{ + fluid_synth_cc(synth,ch,64,0); + fluid_synth_pitch_bend(synth,ch,8192); + fluid_synth_all_notes_off(synth,ch); +} +void qmpMidiOutFluid::reset(uint8_t ch) +{ + this->panic(ch); + fluid_synth_cc(synth,ch,0,0); + fluid_synth_cc(synth,ch,7,100); + fluid_synth_cc(synth,ch,10,64); + fluid_synth_cc(synth,ch,11,127); + fluid_synth_cc(synth,ch,32,0); + fluid_synth_pitch_wheel_sens(synth,ch,2); +} +void qmpMidiOutFluid::onMapped(uint8_t,int) +{ +} +void qmpMidiOutFluid::onUnmapped(uint8_t,int) +{ +} +void qmpMidiOutFluid::setOptStr(const char *opt,const char *val) +{ + fluid_settings_setstr(settings,opt,val); +} +void qmpMidiOutFluid::setOptInt(const char *opt,int val) +{ + fluid_settings_setint(settings,opt,val); +} +void qmpMidiOutFluid::setOptNum(const char *opt,double val) +{ + fluid_settings_setnum(settings,opt,val); +} +void qmpMidiOutFluid::loadSFont(const char *path) +{ + if(synth)fluid_synth_sfload(synth,path,1); +} +int qmpMidiOutFluid::getSFCount() +{ + return synth?fluid_synth_sfcount(synth):0; +} +std::vector<std::pair<std::pair<int,int>,std::string>> qmpMidiOutFluid::listPresets() +{ + std::vector<std::pair<std::pair<int,int>,std::string>> ret; + std::map<std::pair<int,int>,std::string> pmap; + for(int i=getSFCount()-1;i>=0;--i) + { + fluid_sfont_t* psf=fluid_synth_get_sfont(synth,i); + fluid_preset_t preset; + psf->iteration_start(psf); + while(psf->iteration_next(psf,&preset)) + pmap[std::make_pair( + preset.get_banknum(&preset), + preset.get_num(&preset) + )]=preset.get_name(&preset); + } + for(auto i=pmap.begin();i!=pmap.end();++i) + ret.push_back(std::make_pair(i->first,i->second)); + return ret; +} +int qmpMidiOutFluid::getPolyphone() +{ + return synth?fluid_synth_get_active_voice_count(synth):0; +} +int qmpMidiOutFluid::getMaxPolyphone() +{ + return synth?fluid_synth_get_polyphony(synth):0; +} +void qmpMidiOutFluid::setGain(double gain) +{ + if(settings)fluid_settings_setnum(settings,"synth.gain",gain); +} +void qmpMidiOutFluid::getChannelInfo(int ch,int *b, int *p, char *s) +{ + if(!synth)return; + fluid_synth_channel_info_t chinfo; + fluid_synth_get_channel_info(synth,ch,&chinfo); + *b=chinfo.bank;*p=chinfo.program; + strcpy(s,chinfo.name); +} +void qmpMidiOutFluid::getReverbPara(double *r,double *d,double *w,double *l) +{ + if(!synth)return; + *r=fluid_synth_get_reverb_roomsize(synth); + *d=fluid_synth_get_reverb_damp(synth); + *w=fluid_synth_get_reverb_width(synth); + *l=fluid_synth_get_reverb_level(synth); +} +void qmpMidiOutFluid::setReverbPara(int e,double r,double d,double w,double l) +{ + if(!synth)return; + fluid_synth_set_reverb_on(synth,e); + fluid_synth_set_reverb(synth,r,d,w,l); +} +void qmpMidiOutFluid::getChorusPara(int *fb,double *l,double *r,double *d,int *type) +{ + if(!synth)return; + *fb=fluid_synth_get_chorus_nr(synth); + *l=fluid_synth_get_chorus_level(synth); + *r=fluid_synth_get_chorus_speed_Hz(synth); + *d=fluid_synth_get_chorus_depth_ms(synth); + *type=fluid_synth_get_chorus_type(synth); +} +void qmpMidiOutFluid::setChorusPara(int e,int fb,double l,double r,double d,int type) +{ + if(!synth)return; + fluid_synth_set_chorus_on(synth,e); + fluid_synth_set_chorus(synth,fb,l,r,d,type); +} + +qmpFileRendererFluid::qmpFileRendererFluid(const char *_fn,const char *_ofn) +{ + settings=new_fluid_settings(); + fluid_settings_setstr(settings,"audio.file.name",_ofn); + fn=std::string(_fn); + finished=false; +} +qmpFileRendererFluid::~qmpFileRendererFluid() +{ + if(player||synth||settings)renderDeinit(); +} +void qmpFileRendererFluid::renderInit() +{ + synth=new_fluid_synth(settings); + player=new_fluid_player(synth); + fluid_player_add(player,fn.c_str()); +} +void qmpFileRendererFluid::renderDeinit() +{ + delete_fluid_player(player); + delete_fluid_synth(synth); + delete_fluid_settings(settings); + player=NULL;synth=NULL;settings=NULL; +} +void qmpFileRendererFluid::renderWorker() +{ + fluid_file_renderer_t* renderer=new_fluid_file_renderer(synth); + fluid_player_play(player); + while(fluid_player_get_status(player)==FLUID_PLAYER_PLAYING) + if(fluid_file_renderer_process_block(renderer)!=FLUID_OK)break; + delete_fluid_file_renderer(renderer); + finished=true; +} +void qmpFileRendererFluid::setOptStr(const char *opt,const char *val) +{ + fluid_settings_setstr(settings,opt,val); +} +void qmpFileRendererFluid::setOptInt(const char *opt,int val) +{ + fluid_settings_setint(settings,opt,val); +} +void qmpFileRendererFluid::setOptNum(const char *opt,double val) +{ + fluid_settings_setnum(settings,opt,val); +} +void qmpFileRendererFluid::loadSFont(const char *path) +{ + if(synth)fluid_synth_sfload(synth,path,1); +} +bool qmpFileRendererFluid::isFinished() +{ + return finished; +} +void qmpFileRendererFluid::setGain(double gain) +{ + if(settings)fluid_settings_setnum(settings,"synth.gain",gain); +} +void qmpFileRendererFluid::setReverbPara(int e,double r,double d,double w,double l) +{ + if(!synth)return; + fluid_synth_set_reverb_on(synth,e); + fluid_synth_set_reverb(synth,r,d,w,l); +} +void qmpFileRendererFluid::setChorusPara(int e,int fb,double l,double r,double d,int type) +{ + if(!synth)return; + fluid_synth_set_chorus_on(synth,e); + fluid_synth_set_chorus(synth,fb,l,r,d,type); +} diff --git a/core/qmpmidioutfluid.hpp b/core/qmpmidioutfluid.hpp new file mode 100644 index 0000000..963f9df --- /dev/null +++ b/core/qmpmidioutfluid.hpp @@ -0,0 +1,80 @@ +#ifndef QMPMIDIOUTFLUID_H +#define QMPMIDIOUTFLUID_H +#include <string> +#include <utility> +#include <vector> +#include "../include/qmpcorepublic.hpp" +#include <fluidsynth.h> +class IFluidSettings +{ + public: + virtual void setOptStr(const char* opt,const char* val)=0; + virtual void setOptInt(const char* opt,int val)=0; + virtual void setOptNum(const char* opt,double val)=0; + virtual void loadSFont(const char* path)=0; + virtual void setGain(double gain)=0; + virtual void setReverbPara(int e,double r,double d,double w,double l)=0; + virtual void setChorusPara(int e,int fb,double l,double r,double d,int type)=0; +}; +class qmpMidiOutFluid:public qmpMidiOutDevice,public IFluidSettings +{ + private: + fluid_settings_t* settings; + fluid_synth_t* synth; + fluid_audio_driver_t* adriver; + public: + qmpMidiOutFluid(); + ~qmpMidiOutFluid(); + void deviceInit(); + void deviceDeinit(); + void deviceDeinit(bool freshsettings); + void basicMessage(uint8_t type,uint8_t p1,uint8_t p2); + void extendedMessage(uint8_t length,const char *data); + void rpnMessage(uint8_t ch,uint16_t type,uint16_t val); + void nrpnMessage(uint8_t ch,uint16_t type,uint16_t val); + void panic(uint8_t ch); + void reset(uint8_t ch); + void onMapped(uint8_t ch,int refcnt); + void onUnmapped(uint8_t ch,int refcnt); + //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(); + void setGain(double gain); + void getChannelInfo(int ch,int *b,int *p,char *s); + void getReverbPara(double *r,double *d,double *w,double *l); + void setReverbPara(int e,double r,double d,double w,double l); + void getChorusPara(int *fb,double *l,double *r,double *d,int *type); + void setChorusPara(int e,int fb,double l,double r,double d,int type); +}; +class qmpFileRendererFluid:public IFluidSettings +{ + private: + fluid_settings_t* settings; + fluid_synth_t* synth; + fluid_player_t* player; + bool finished; + std::string fn; + public: + qmpFileRendererFluid(const char* _fn,const char* _ofn); + ~qmpFileRendererFluid(); + void renderInit(); + void renderDeinit(); + void renderWorker(); + 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); + bool isFinished(); + void setGain(double gain); + void setReverbPara(int e,double r,double d,double w,double l); + void setChorusPara(int e,int fb,double l,double r,double d,int type); + +}; +#endif // QMPMIDIOUTFLUID_H diff --git a/core/qmpmidioutrtmidi.cpp b/core/qmpmidioutrtmidi.cpp new file mode 100644 index 0000000..776eb6b --- /dev/null +++ b/core/qmpmidioutrtmidi.cpp @@ -0,0 +1,115 @@ +#include <cstdio> +#include <cstring> +#include <vector> +#include RT_MIDI_H +#include "qmpmidioutrtmidi.hpp" +qmpMidiOutRtMidi::qmpMidiOutRtMidi(unsigned _portid) +{ + portid=_portid; + outport=NULL; +} +qmpMidiOutRtMidi::~qmpMidiOutRtMidi() +{ + if(!outport)return; + if(outport->isPortOpen())outport->closePort(); + delete outport;outport=NULL; +} +void qmpMidiOutRtMidi::deviceInit() +{ + try + { + outport=new RtMidiOut(); + } + catch(RtMidiError &e) + { + printf("Cannot create RtMidi Output instance: %s\n",e.what()); + outport=NULL; + } +} +void qmpMidiOutRtMidi::deviceDeinit() +{ + if(!outport||!outport->isPortOpen())return; + outport->closePort(); +} +void qmpMidiOutRtMidi::basicMessage(uint8_t type,uint8_t p1,uint8_t p2) +{ + if(!outport||!outport->isPortOpen())return; + std::vector<unsigned char>msg; + msg.push_back(type); + msg.push_back(p1); + msg.push_back(p2); + outport->sendMessage(&msg); +} +void qmpMidiOutRtMidi::extendedMessage(uint8_t length,const char *data) +{ + if(!outport||!outport->isPortOpen())return; + std::vector<unsigned char>msg(data,data+length); + outport->sendMessage(&msg); +} +void qmpMidiOutRtMidi::rpnMessage(uint8_t ch,uint16_t type,uint16_t val) +{ + basicMessage(0xB0|ch,0x64,type&0x7F); + basicMessage(0xB0|ch,0x65,type>>7); + basicMessage(0xB0|ch,0x06,val>>7); + basicMessage(0xB0|ch,0x26,val&0x7F); +} +void qmpMidiOutRtMidi::nrpnMessage(uint8_t ch,uint16_t type,uint16_t val) +{ + basicMessage(0xB0|ch,0x62,type&0x7F); + basicMessage(0xB0|ch,0x63,type>>7); + basicMessage(0xB0|ch,0x06,val>>7); + basicMessage(0xB0|ch,0x26,val&0x7F); +} +void qmpMidiOutRtMidi::panic(uint8_t ch) +{ + //maybe all notes off is more close to panic? + basicMessage(0xE0|ch,0x0,0x40); + basicMessage(0xB0|ch,123,0); +} +void qmpMidiOutRtMidi::reset(uint8_t ch) +{ + basicMessage(0xB0|ch,120,0); + basicMessage(0xB0|ch,121,0); +} +void qmpMidiOutRtMidi::onMapped(uint8_t,int refcnt) +{ + if(!outport||outport->isPortOpen()||refcnt)return; + try + { + outport->openPort(portid); + } + catch(RtMidiError &e) + { + printf("Device initialization failure: %s\n",e.what()); + } + +} +void qmpMidiOutRtMidi::onUnmapped(uint8_t ch,int refcnt) +{ + panic(ch); + if(!refcnt)outport->closePort(); +} + +RtMidiOut* qmpRtMidiManager::dummy=NULL; +void qmpRtMidiManager::createDevices() +{ + try{dummy=new RtMidiOut();} + catch(RtMidiError &e) + { + printf("Failed to initialize the dummy device: %s\n",e.what()); + dummy=NULL; + } + for(unsigned i=0;i<dummy->getPortCount();++i) + devices.push_back(std::make_pair(new qmpMidiOutRtMidi(i),dummy->getPortName(i))); +} +void qmpRtMidiManager::deleteDevices() +{ + for(size_t i=0;i<devices.size();++i) + delete devices[i].first; + devices.clear(); + delete dummy; +} +std::vector<std::pair<qmpMidiOutRtMidi*,std::string>> qmpRtMidiManager::getDevices() +{ + return devices; +} diff --git a/core/qmpmidioutrtmidi.hpp b/core/qmpmidioutrtmidi.hpp new file mode 100644 index 0000000..48ee0cf --- /dev/null +++ b/core/qmpmidioutrtmidi.hpp @@ -0,0 +1,36 @@ +#ifndef QMPMIDIMAPPERS_H +#define QMPMIDIMAPPERS_H +#include <vector> +#define QMP_MAIN +#include "../include/qmpcorepublic.hpp" +#include RT_MIDI_H +class qmpMidiOutRtMidi:public qmpMidiOutDevice +{ +private: + unsigned portid; + RtMidiOut* outport; +public: + qmpMidiOutRtMidi(unsigned _portid); + ~qmpMidiOutRtMidi(); + void deviceInit(); + void deviceDeinit(); + void basicMessage(uint8_t type,uint8_t p1,uint8_t p2); + void extendedMessage(uint8_t length,const char *data); + void rpnMessage(uint8_t ch,uint16_t type,uint16_t val); + void nrpnMessage(uint8_t ch,uint16_t type,uint16_t val); + void panic(uint8_t ch); + void reset(uint8_t ch); + void onMapped(uint8_t ch,int refcnt); + void onUnmapped(uint8_t ch,int refcnt); +}; +class qmpRtMidiManager +{ + private: + static RtMidiOut* dummy; + std::vector<std::pair<qmpMidiOutRtMidi*,std::string>> devices; + public: + void createDevices(); + void deleteDevices(); + std::vector<std::pair<qmpMidiOutRtMidi*,std::string>> getDevices(); +}; +#endif // QMPMIDIMAPPERS_H diff --git a/core/qmpmidiplay.cpp b/core/qmpmidiplay.cpp index c8169ca..cca77d0 100644 --- a/core/qmpmidiplay.cpp +++ b/core/qmpmidiplay.cpp @@ -10,99 +10,42 @@ uint64_t pf; #endif CMidiPlayer* CMidiPlayer::ref=NULL; -void CMidiPlayer::fluidPreInitialize() -{ - settings=new_fluid_settings(); -} -void CMidiPlayer::fluidInitialize() -{ - synth=new_fluid_synth(settings); - fluid_set_log_function(FLUID_DBG,NULL,NULL); - fluid_set_log_function(FLUID_INFO,NULL,NULL); - fluid_set_log_function(FLUID_WARN,NULL,NULL); - fluid_set_log_function(FLUID_ERR,fluid_default_log_function,NULL); - fluid_set_log_function(FLUID_PANIC,fluid_default_log_function,NULL); - adriver=new_fluid_audio_driver(settings,synth); - fluid_synth_set_chorus(synth,FLUID_CHORUS_DEFAULT_N,FLUID_CHORUS_DEFAULT_LEVEL, - FLUID_CHORUS_DEFAULT_SPEED,FLUID_CHORUS_DEFAULT_DEPTH, - FLUID_CHORUS_DEFAULT_TYPE); -#ifndef _WIN32 - if(!singleInstance) - { - if(midiFile->std==4) - fluid_synth_set_channel_type(synth,9,CHANNEL_TYPE_MELODIC); - else if(midiFile->std==1) - fluid_synth_set_channel_type(synth,9,CHANNEL_TYPE_DRUM); - else - { - fluid_synth_set_channel_type(synth,9,CHANNEL_TYPE_DRUM); - fluid_synth_bank_select(synth,9,128); - } - } -#endif -} -void CMidiPlayer::fluidDeinitialize() -{ - if(!synth||!adriver||!settings)return; - delete_fluid_settings(settings); - delete_fluid_audio_driver(adriver); - delete_fluid_synth(synth); - settings=NULL;synth=NULL;adriver=NULL; -} -void CMidiPlayer::processEvent(const SEvent *e) +bool CMidiPlayer::processEvent(const SEvent *e) { SEventCallBackData cbd(e->type,e->p1,e->p2,tceptr); for(int i=0;i<16;++i)if(eventHandlerCB[i]) eventHandlerCB[i]->callBack(&cbd,eventHandlerCBuserdata[i]); + uint8_t ch=e->type&0x0F; switch(e->type&0xF0) { case 0x80://Note off - 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; + return true; case 0x90://Note on - if((mute>>(e->type&0x0F))&1)break;//muted - if(solo&&!((solo>>(e->type&0x0F))&1))break; - 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); - chstate[e->type&0x0F]=1; - break; + if((mute>>ch)&1&&e->p2)return false;//muted + if(solo&&!((solo>>ch)&1)&&e->p2)return false;//excluded by solo flags + if(e->p2)chstate[ch]=1; + return true; case 0xB0://CC - if(e->p1==100)rpnid[e->type&0x0F]=e->p2; - if(e->p1==6)rpnval[e->type&0x0F]=e->p2; - if(~rpnid[e->type&0x0F]&&~rpnval[e->type&0x0F]) + if(e->p1==100)rpnid[ch]=e->p2; + if(e->p1==6)rpnval[ch]=e->p2; + if(~rpnid[ch]&&~rpnval[ch]) { - if(rpnid[e->type&0x0F]==0) + if(rpnid[ch]==0) { - fluid_synth_pitch_wheel_sens(synth,e->type&0x0F,rpnval[e->type&0x0F]); - pbr[e->type&0x0F]=rpnval[e->type&0x0F]; + internalFluid->rpnMessage(ch,0,rpnval[ch]<<7); + mididev[mappedoutput[ch]].dev->rpnMessage(ch,0,rpnval[ch]<<7); + pbr[ch]=rpnval[ch]; } - rpnid[e->type&0x0F]=rpnval[e->type&0x0F]=-1; + rpnid[ch]=rpnval[ch]=-1; } - chstatus[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; + chstatus[ch][e->p1]=e->p2; + return true; case 0xC0://PC - chstatus[e->type&0x0F][128]=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; + chstatus[ch][128]=e->p1; + return true; case 0xE0://PW - pbv[e->type&0x0F]=(e->p1|(e->p2<<7))&0x3FFF;; - if(mappedoutput[e->type&0x0F]) - mapper->pitchBend(mappedoutput[e->type&0x0F]-1,e->type&0x0F,pbv[e->type&0x0F]); - else - fluid_synth_pitch_bend(synth,e->type&0x0F,pbv[e->type&0x0F]); - break; + pbv[ch]=(e->p1|(e->p2<<7))&0x3FFF; + return true; case 0xF0://Meta/SysEx if((e->type&0x0F)==0x0F) { @@ -127,15 +70,28 @@ void CMidiPlayer::processEvent(const SEvent *e) } if((e->type&0x0F)==0x00||(e->type&0x0F)==07) { - int io=0; if(sendSysEx) { - for(int i=0;i<16;++i)if(deviceusage[i])mapper->sysEx(i,e->p1,e->str.c_str()); - fluid_synth_sysex(synth,e->str.c_str(),e->p1,NULL,&io,NULL,0); + int l=e->p1;char *rmsg; + if(e->type&0x0F==0x00) + { + rmsg=(char*)malloc((++l)*sizeof(char)); + rmsg[0]=0xF0;rmsg[1]=0; + } + else + { + rmsg=(char*)malloc(l*sizeof(char)); + rmsg[0]=0; + } + strcat(rmsg,e->str.c_str()); + for(auto& i:mididev) + if(i.refcnt) + i.dev->extendedMessage(l,rmsg); } } - break; + return false; } + return false; } void CMidiPlayer::processEventStub(const SEvent *e) { @@ -203,8 +159,9 @@ SEvent* CMidiPlayer::getEvent(int id) void CMidiPlayer::prePlayInit() { playerPanic(true); - for(int i=0;i<16;++i)if(deviceusage[i]) - for(int j=0;j<16;++j)mapper->reset(i,j); + for(size_t i=0;i<mididev.size();++i) + if(mididev[i].refcnt) + for(int j=0;j<16;++j)mididev[i].dev->reset(j); } void CMidiPlayer::playEvents() { @@ -213,8 +170,12 @@ void CMidiPlayer::playEvents() while(tcpaused)std::this_thread::sleep_for(std::chrono::milliseconds(100)); using namespace std::chrono; high_resolution_clock::time_point b=high_resolution_clock::now(); - while(!tcstop&&midiReaders&&tceptr<ecnt&&ct==getEvent(tceptr)->time) - processEvent(getEvent(tceptr++)); + for(;!tcstop&&midiReaders&&tceptr<ecnt&&ct==getEvent(tceptr)->time;++tceptr) + if(processEvent(getEvent(tceptr))) + { + SEvent* e=getEvent(tceptr); + mididev[mappedoutput[e->type&0x0F]].dev->basicMessage(e->type,e->p1,e->p2); + } if(tcstop||!midiReaders||tceptr>=ecnt)break; high_resolution_clock::time_point a=high_resolution_clock::now(); auto sendtime=a-b; @@ -229,7 +190,7 @@ void CMidiPlayer::playEvents() if(tcstop||!midiReaders)break; ct=getEvent(tceptr)->time; } - while(!tcstop&&synth&&(waitvoice&&fluid_synth_get_active_voice_count(synth)>0))std::this_thread::sleep_for(std::chrono::milliseconds(2)); + while(!tcstop&&(waitvoice&&internalFluid->getPolyphone()>0))std::this_thread::sleep_for(std::chrono::milliseconds(2)); finished=1; } void CMidiPlayer::fileTimer1Pass() @@ -282,20 +243,20 @@ void CMidiPlayer::fileTimer2Pass() stamps[c++]=ecnt; } } -CMidiPlayer::CMidiPlayer(bool singleInst) + +CMidiPlayer::CMidiPlayer() { midiReaders=new CMidiFileReaderCollection(); - resumed=false;singleInstance=singleInst;midiFile=NULL; - settings=NULL;synth=NULL;adriver=NULL;waitvoice=true; + resumed=false;midiFile=NULL;internalFluid=new qmpMidiOutFluid(); + registerMidiOutDevice(internalFluid,"Internal FluidSynth"); + waitvoice=true; memset(eventHandlerCB,0,sizeof(eventHandlerCB)); memset(eventHandlerCBuserdata,0,sizeof(eventHandlerCBuserdata)); memset(eventReaderCB,0,sizeof(eventReaderCB)); memset(eventReaderCBuserdata,0,sizeof(eventReaderCBuserdata)); memset(fileReadFinishCB,0,sizeof(fileReadFinishCB)); memset(fileReadFinishCBuserdata,0,sizeof(fileReadFinishCBuserdata)); - memset(mappedoutput,0,sizeof(mappedoutput)); - memset(deviceusage,0,sizeof(deviceusage)); - mapper=new qmpMidiMapperRtMidi(); + memset(mappedoutput,0xFF,sizeof(mappedoutput)); memset(chstatus,0,sizeof(chstatus)); for(int i=0;i<16;++i) chstatus[i][7]=100,chstatus[i][11]=127, @@ -309,29 +270,21 @@ CMidiPlayer::CMidiPlayer(bool singleInst) } CMidiPlayer::~CMidiPlayer() { - if(singleInstance||settings||synth||adriver)fluidDeinitialize(); - if(midiFile)delete midiFile;delete midiReaders;delete mapper; + if(internalFluid) + { + internalFluid->deviceDeinit(); + delete internalFluid; + internalFluid=NULL; + } + if(midiFile)delete midiFile;delete midiReaders; } void CMidiPlayer::playerPanic(bool reset) { - for(int i=0;i<16;++i) + for(auto& i:mididev) + if(i.refcnt) { - if(synth){ - if(reset){ - fluid_synth_cc(synth,i,0,0); - fluid_synth_cc(synth,i,7,100); - fluid_synth_cc(synth,i,10,64); - fluid_synth_cc(synth,i,11,127); - fluid_synth_cc(synth,i,32,0); - fluid_synth_pitch_wheel_sens(synth,i,2); - } - fluid_synth_cc(synth,i,64,0); - fluid_synth_pitch_bend(synth,i,8192); - //all sounds off causes the minus polyphone bug... - fluid_synth_all_notes_off(synth,i); - } - if(deviceusage[i])for(int j=0;j<16;++j) - reset?mapper->reset(i,j):mapper->panic(i,j); + for(uint8_t j=0;j<16;++j) + reset?i.dev->reset(j):i.dev->panic(j); } } bool CMidiPlayer::playerLoadFile(const char* fn) @@ -372,13 +325,11 @@ void CMidiPlayer::playerInit() chstatus[i][10]=chstatus[i][71]=chstatus[i][72]= chstatus[i][73]=chstatus[i][74]=chstatus[i][75]= chstatus[i][76]=chstatus[i][77]=chstatus[i][78]=64; - if(!singleInstance)fluidPreInitialize(); } void CMidiPlayer::playerDeinit() { tceptr=0;tcstop=1;tcpaused=0; delete midiFile;midiFile=NULL; - if(!singleInstance)fluidDeinitialize(); } void CMidiPlayer::playerThread() { @@ -386,35 +337,6 @@ void CMidiPlayer::playerThread() playEvents(); } -void CMidiPlayer::rendererLoadFile(const char* ofn) -{ - settings=new_fluid_settings(); - fluid_settings_setstr(settings,"audio.file.name",ofn); -} -void CMidiPlayer::rendererInit(const char* fn) -{ - finished=0; - synth=new_fluid_synth(settings); - player=new_fluid_player(synth); - fluid_player_add(player,fn); -} -void CMidiPlayer::rendererThread() -{ - fluid_file_renderer_t* renderer=new_fluid_file_renderer(synth); - fluid_player_play(player); - while(fluid_player_get_status(player)==FLUID_PLAYER_PLAYING) - if(fluid_file_renderer_process_block(renderer)!=FLUID_OK)break; - delete_fluid_file_renderer(renderer); - finished=1; -} -void CMidiPlayer::rendererDeinit() -{ - delete_fluid_player(player); - delete_fluid_synth(synth); - delete_fluid_settings(settings); - player=NULL;synth=NULL;settings=NULL; -} - void CMidiPlayer::sendSysX(bool send){sendSysEx=send;} uint32_t CMidiPlayer::getStamp(int id){return stamps[id];} uint32_t CMidiPlayer::getTCeptr(){return tceptr;} @@ -424,10 +346,11 @@ void CMidiPlayer::setTCeptr(uint32_t ep,uint32_t st) if(ep==ecnt)tcstop=1;else tceptr=ep; for(int i=0;i<16;++i) { - for(int j=0;j<120;++j)fluid_synth_cc(synth,i,j,ccstamps[st][i][j]); - fluid_synth_program_change(synth,i,ccstamps[st][i][128]); + for(int j=0;j<120;++j) + internalFluid->basicMessage(0xB0|i,j,ccstamps[st][i][j]); + internalFluid->basicMessage(0xC0|i,ccstamps[st][i][128],0); //fluid_synth_pitch_bend(synth,i,ccstamps[st][i][130]); - fluid_synth_pitch_wheel_sens(synth,i,ccstamps[st][i][134]); + internalFluid->rpnMessage(i,0,ccstamps[st][i][134]<<7); pbr[i]=ccstamps[st][i][134]; dpt=ccstamps[st][0][131];ctempo=dpt*divs/1000; ctsn=ccstamps[st][0][132]>>24;ctsd=1<<((ccstamps[st][0][132]>>16)&0xFF); @@ -452,14 +375,9 @@ void CMidiPlayer::setTCpaused(uint32_t ps){tcpaused=ps;} uint32_t CMidiPlayer::isFinished(){return finished;} void CMidiPlayer::setResumed(){resumed=true;} void CMidiPlayer::setWaitVoice(bool wv){waitvoice=wv;} -void CMidiPlayer::setGain(double gain){if(settings)fluid_settings_setnum(settings,"synth.gain",gain);} -int CMidiPlayer::getPolyphone(){return synth?fluid_synth_get_active_voice_count(synth):0;} -int CMidiPlayer::getMaxPolyphone(){return synth?fluid_synth_get_polyphony(synth):0;} -void CMidiPlayer::setMaxPolyphone(int p){if(synth)fluid_synth_set_polyphony(synth,p);} void CMidiPlayer::getChannelPreset(int ch,int *b,int *p,char *name) { - if(!synth)return(void)(*b=0,*p=0,strcpy(name,"")); if(mappedoutput[ch]) { *b=((int)chstatus[ch][0]<<7)|chstatus[ch][32]; @@ -468,29 +386,27 @@ void CMidiPlayer::getChannelPreset(int ch,int *b,int *p,char *name) } else { - fluid_synth_channel_info_t info; - fluid_synth_get_channel_info(synth,ch,&info); - *b=info.bank;*p=info.program; - strcpy(name,info.name); + internalFluid->getChannelInfo(ch,b,p,name); } } void CMidiPlayer::setChannelPreset(int ch,int b,int p) { - if(!synth)return; chstatus[ch][128]=p; if(mappedoutput[ch]) { //external device mode? chstatus[ch][0]=b>>7;chstatus[ch][32]=b&0x7F; - mapper->ctrlChange(mappedoutput[ch]-1,ch,0,b>>7); - mapper->ctrlChange(mappedoutput[ch]-1,ch,32,b&0x7F); - mapper->progChange(mappedoutput[ch]-1,ch,p); + qmpMidiOutDevice* d=mididev[mappedoutput[ch]].dev; + d->basicMessage(0xB0|ch,0x00,b>>7); + d->basicMessage(0xB0|ch,0x20,b&0x7F); + d->basicMessage(0xC0|ch,p,0); } else { - chstatus[ch][0]=b;//!!FIXME: This is not correct... - fluid_synth_bank_select(synth,ch,b); - fluid_synth_program_change(synth,ch,p); + chstatus[ch][0]=b;//Assuming GS. !!FIXME: This is not correct... + qmpMidiOutDevice* d=mididev[mappedoutput[ch]].dev; + d->basicMessage(0xB0|ch,0x00,b); + d->basicMessage(0xC0|ch,p,0); } } void CMidiPlayer::dumpFile() @@ -516,85 +432,60 @@ bool CMidiPlayer::getChannelMask(int ch) {return((mute>>ch)&1)||(solo&&!((solo>>ch)&1));} int CMidiPlayer::getCC(int ch,int id) { - int ret=0; - if(mappedoutput[ch]) - ret=chstatus[ch][id]; - else - if(synth)fluid_synth_get_cc(synth,ch,id,&ret); - return ret; + return chstatus[ch][id]; } void CMidiPlayer::setCC(int ch,int id,int val) { - if(!synth)return; chstatus[ch][id]=val; - mappedoutput[ch]?mapper->ctrlChange(mappedoutput[ch]-1,ch,id,val): - (void)fluid_synth_cc(synth,ch,id,val); + mididev[mappedoutput[ch]].dev->basicMessage(0xB0|ch,id,val); } -void CMidiPlayer::getReverbPara(double *r,double *d,double *w,double *l) -{ - if(!synth)return; - *r=fluid_synth_get_reverb_roomsize(synth); - *d=fluid_synth_get_reverb_damp(synth); - *w=fluid_synth_get_reverb_width(synth); - *l=fluid_synth_get_reverb_level(synth); -} -void CMidiPlayer::setReverbPara(int e,double r,double d,double w,double l) + +qmpMidiOutFluid* CMidiPlayer::fluid(){return internalFluid;} + +void CMidiPlayer::registerMidiOutDevice(qmpMidiOutDevice* dev,std::string name) { - if(!synth)return; - fluid_synth_set_reverb_on(synth,e); - fluid_synth_set_reverb(synth,r,d,w,l); + SMidiDev d; + d.dev=dev;d.name=name; + d.refcnt=0; + mididev.push_back(d); } -void CMidiPlayer::getChorusPara(int *fb,double *l,double *r,double *d,int *type) +void CMidiPlayer::unregisterMidiOutDevice(std::string name) { - if(!synth)return; - *fb=fluid_synth_get_chorus_nr(synth); - *l=fluid_synth_get_chorus_level(synth); - *r=fluid_synth_get_chorus_speed_Hz(synth); - *d=fluid_synth_get_chorus_depth_ms(synth); - *type=fluid_synth_get_chorus_type(synth); + for(auto i=mididev.begin();i!=mididev.end();++i) + if(i->name==name) + { + i->dev->deviceDeinit(); + mididev.erase(i); + break; + } } -void CMidiPlayer::setChorusPara(int e,int fb,double l,double r,double d,int type) +std::vector<std::string> CMidiPlayer::getMidiOutDevices() { - if(!synth)return; - fluid_synth_set_chorus_on(synth,e); - fluid_synth_set_chorus(synth,fb,l,r,d,type); + std::vector<std::string> ret; + for(auto &i:mididev) + ret.push_back(i.name); + return ret; } -fluid_settings_t* CMidiPlayer::getFluidSettings(){return settings;} -void CMidiPlayer::pushSoundFont(const char *sf) -{fluid_synth_sfload(synth,sf,1);} -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;} int CMidiPlayer::getChannelOutput(int ch) { return mappedoutput[ch]; } -void CMidiPlayer::setChannelOutput(int ch,int devid) +void CMidiPlayer::setChannelOutput(int ch,int outid) { int origoutput=mappedoutput[ch]; - int newoutput=0; - if(devid>0) - { - if(!deviceusage[devid-1])deviceiid[devid]=newoutput=mapper->deviceInit(devid-1); - ++deviceusage[deviceiid[devid]];mapper->progChange(deviceiid[devid],ch,chstatus[ch][128]); - for(int i=0;i<128;++i)if(i!=100&&i!=101)mapper->ctrlChange(deviceiid[devid],ch,i,chstatus[ch][i]); - } - else + SMidiDev& dnew=mididev[outid]; + dnew.dev->onMapped(ch,++dnew.refcnt); + for(int i=0;i<128;++i) + if(i!=6&&i!=38&&i!=100&&i!=101)//avoid sending RPN/NRPN + dnew.dev->basicMessage(0xB0|ch,i,chstatus[ch][i]); + dnew.dev->basicMessage(0xC0|ch,chstatus[ch][128],0); + mappedoutput[ch]=outid; + if(~origoutput) { - fluid_synth_bank_select(synth,ch,chstatus[ch][0]); - fluid_synth_program_change(synth,ch,chstatus[ch][128]); - for(int i=0;i<128;++i)if(i!=100&&i!=101&&i!=0&&i!=32) - fluid_synth_cc(synth,ch,i,chstatus[ch][i]); + SMidiDev& dold=mididev[origoutput]; + dold.dev->onUnmapped(ch,--dold.refcnt); + } - mappedoutput[ch]=devid?deviceiid[devid]+1:0; - if(origoutput>0) - { - --deviceusage[origoutput-1];mapper->panic(origoutput-1,ch); - if(!deviceusage[origoutput-1])mapper->deviceDeinit(origoutput-1); - }else if(synth)fluid_synth_all_notes_off(synth,ch); } uint8_t* CMidiPlayer::getChstates(){return chstate;} int CMidiPlayer::setEventHandlerCB(IMidiCallBack *cb,void *userdata) diff --git a/core/qmpmidiplay.hpp b/core/qmpmidiplay.hpp index 8a146a7..c935084 100644 --- a/core/qmpmidiplay.hpp +++ b/core/qmpmidiplay.hpp @@ -5,10 +5,10 @@ #include <cstdlib> #include <utility> #include <vector> -#include <fluidsynth.h> #define QMP_MAIN #include "../include/qmpcorepublic.hpp" -#include "qmpmidimappers.hpp" +#include "qmpmidioutrtmidi.hpp" +#include "qmpmidioutfluid.hpp" class CMidiPlayer; class CSMFReader:public IMidiFileReader { @@ -60,20 +60,23 @@ class CMidiPlayer int32_t rpnid[16],rpnval[16]; uint16_t mute,solo; double ftime; - bool sendSysEx,singleInstance,waitvoice; - fluid_settings_t* settings; - fluid_synth_t* synth; - fluid_audio_driver_t* adriver; - fluid_player_t* player; + bool sendSysEx,waitvoice; + uint8_t chstate[16],chstatus[16][130];//0..127: cc 128: pc + qmpMidiOutFluid* internalFluid; uint32_t ctempo,ctsn,ctsd,dpt,divs,cks; //raw tempo, timesig num., timesig den., delay per tick, division, keysig //thread control uint32_t tceptr,tcpaused,tcstop,ct; uint32_t finished,resumed; uint32_t pbr[16],pbv[16]; - qmpMidiMapperRtMidi *mapper; - int mappedoutput[16],deviceusage[16],deviceiid[128]; - uint8_t chstate[16],chstatus[16][130];//0..127: cc 128: pc + struct SMidiDev + { + std::string name; + qmpMidiOutDevice* dev; + int refcnt; + }; + std::vector<SMidiDev> mididev; + int mappedoutput[16]; IMidiCallBack* eventHandlerCB[16]; IMidiCallBack* eventReaderCB[16]; IMidiCallBack* fileReadFinishCB[16]; @@ -85,29 +88,21 @@ class CMidiPlayer SEvent *getEvent(int id); void dumpFile(); void setBit(uint16_t &n,uint16_t bn,uint16_t b); - void processEvent(const SEvent *e); + bool processEvent(const SEvent *e); void processEventStub(const SEvent *e); void prePlayInit(); void playEvents(); void fileTimer1Pass(); void fileTimer2Pass(); public: - CMidiPlayer(bool singleInst=false); + CMidiPlayer(); ~CMidiPlayer(); bool playerLoadFile(const char* fn); void playerInit(); - void fluidPreInitialize(); - void fluidInitialize(); - void fluidDeinitialize(); void playerDeinit(); void playerThread(); void playerPanic(bool reset=false); - void rendererLoadFile(const char* ofn); - void rendererInit(const char *fn); - void rendererThread(); - void rendererDeinit(); - //playing control methods uint32_t getStamp(int id); uint32_t getTCeptr(); @@ -132,11 +127,7 @@ class CMidiPlayer const char* getTitle(); const char* getCopyright(); - void setGain(double gain); void sendSysX(bool send); - int getPolyphone(); - int getMaxPolyphone(); - void setMaxPolyphone(int p); void setChannelPreset(int ch,int b,int p); void getChannelPreset(int ch,int *b,int *p,char *name); @@ -145,19 +136,14 @@ class CMidiPlayer bool getChannelMask(int ch); int getCC(int ch,int id); void setCC(int ch,int id,int val); - void getReverbPara(double *r,double *d,double *w,double *l); - void setReverbPara(int e,double r,double d,double w,double l); - void getChorusPara(int *fb,double *l,double *r,double *d,int *type); - void setChorusPara(int e,int fb,double l,double r,double d,int type); - fluid_settings_t* getFluidSettings(); - void pushSoundFont(const char* sf); - int getSFCount(); - fluid_sfont_t* getSFPtr(int sfid); + qmpMidiOutFluid* fluid(); - qmpMidiMapperRtMidi* getMidiMapper(); + void registerMidiOutDevice(qmpMidiOutDevice* dev,std::string name); + void unregisterMidiOutDevice(std::string name); + std::vector<std::string> getMidiOutDevices(); int getChannelOutput(int ch); - void setChannelOutput(int ch,int devid); + void setChannelOutput(int ch,int outid); uint8_t* getChstates(); int setEventHandlerCB(IMidiCallBack *cb,void *userdata); void unsetEventHandlerCB(int id); |