#include #include #include #include "qmpmidioutfluid.hpp" qmpMidiOutFluid::qmpMidiOutFluid() { settings=new_fluid_settings(); synth=nullptr;adriver=nullptr; } qmpMidiOutFluid::~qmpMidiOutFluid() { delete_fluid_settings(settings); settings=nullptr; } void qmpMidiOutFluid::deviceInit() { synth=new_fluid_synth(settings); if(!synth){fputs("Error creating fluidsynth instance!",stderr);return;} fluid_set_log_function(FLUID_DBG,nullptr,nullptr); fluid_set_log_function(FLUID_INFO,nullptr,nullptr); fluid_set_log_function(FLUID_WARN,nullptr,nullptr); fluid_set_log_function(FLUID_ERR,fluid_default_log_function,nullptr); fluid_set_log_function(FLUID_PANIC,fluid_default_log_function,nullptr); adriver=new_fluid_audio_driver(settings,synth); if(!adriver) { fputs("Error creating fluidsynth audio driver!",stderr); delete_fluid_synth(synth);synth=nullptr; return; } 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) { if(!synth||!adriver)return; delete_fluid_audio_driver(adriver); delete_fluid_synth(synth); synth=nullptr;adriver=nullptr; bnk.clear();pst.clear(); 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,nullptr,&rlen,nullptr,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); for(int i=0;i<128;++i) fluid_synth_cc(synth,ch,i,0); if(ch==9) fluid_synth_cc(synth,ch,0,127); else fluid_synth_cc(synth,ch,0,0); fluid_synth_cc(synth,ch,7,100); fluid_synth_cc(synth,ch,8,64); fluid_synth_cc(synth,ch,10,64); fluid_synth_cc(synth,ch,11,127); fluid_synth_pitch_wheel_sens(synth,ch,2); } void qmpMidiOutFluid::onMapped(uint8_t,int) { } void qmpMidiOutFluid::onUnmapped(uint8_t,int) { } std::vector> qmpMidiOutFluid::getBankList() { return bnk; } std::vector> qmpMidiOutFluid::getPresets(uint16_t bank) { std::vector> 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 ""; //should consult fluidsynth instead? (4 bank mapping methods) 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); } 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); update_preset_list(); } int qmpMidiOutFluid::getSFCount() { return synth?fluid_synth_sfcount(synth):0; } void qmpMidiOutFluid::update_preset_list() { 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)) { 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]=" "; } } std::sort(bnk.begin(),bnk.end()); bnk.erase(std::unique(bnk.begin(),bnk.end()),bnk.end()); } 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_preset_t* chpreset=fluid_synth_get_channel_preset(synth,ch); if(!chpreset) { *b=*p=-1; strcpy(s,"---"); return; } *b=fluid_preset_get_banknum(chpreset); *p=fluid_preset_get_num(chpreset); strncpy(s,fluid_preset_get_name(chpreset),256); } 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(synth); *d=fluid_synth_get_chorus_depth(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=nullptr;synth=nullptr;settings=nullptr; } 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); }