aboutsummaryrefslogblamecommitdiff
path: root/core/qmpmidioutfluid.cpp
blob: da3282f2dc5aafaee13335656bab0a8b0f1a2c2e (plain) (tree)

























































































































































































































































































                                                                                                         
#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);
}