#include #include #include #include #include "qmpmidiplay.hpp" #ifdef _WIN32 #include uint64_t pf; #endif void CMidiPlayer::fluidPreInitialize() { settings = new_fluid_settings(); } void CMidiPlayer::fluidInitialize() { synth = new_fluid_synth(settings); 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->getStandard() == 4) fluid_synth_set_channel_type(synth, 9, CHANNEL_TYPE_MELODIC); else if (midiFile->getStandard() == 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) { switch (e->type & 0xF0) { case 0x80://Note off 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); break; case 0xB0://CC if (e->p1 == 100)rpnid = e->p2; if (e->p1 == 6)rpnval = e->p2; if (~rpnid && ~rpnval) { 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); break; case 0xC0://PC fluid_synth_program_change(synth, e->type & 0x0F, e->p1); break; case 0xE0://PW fluid_synth_pitch_bend(synth, e->type & 0x0F, e->p1); break; case 0xF0://Meta/SysEx if ((e->type & 0x0F) == 0x0F) { switch (e->p1) { case 0x51: ctempo = e->p2; dpt = ctempo * 1000 / divs; break; case 0x58: ctsn = e->p2 >> 24; ctsd = 1 << ((e->p2 >> 16) & 0xFF); break; case 0x59: cks = e->p2; break; case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: if (e->str)puts(e->str); break; } } 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); } break; } } void CMidiPlayer::processEventStub(const SEvent *e) { switch (e->type & 0xF0) { case 0xB0://CC if (e->p1 == 100)rpnid = e->p2; if (e->p1 == 6)rpnval = e->p2; if (~rpnid && ~rpnval) { if (rpnid == 0)ccc[e->type & 0x0F][134] = rpnval; rpnid = rpnval = -1; } ccc[e->type & 0x0F][e->p1] = e->p2; break; case 0xC0://PC ccc[e->type & 0x0F][128] = e->p1; break; case 0xD0://CP ccc[e->type & 0x0F][129] = e->p1; break; case 0xE0://PW ccc[e->type & 0x0F][130] = e->p1; break; case 0xF0://Meta/SysEx if ((e->type & 0x0F) == 0x0F) { switch (e->p1) { case 0x51: ctempo = e->p2; dpt = ctempo * 1000 / divs; ccc[0][131] = dpt; break; case 0x58: ccc[0][132] = e->p2; break; case 0x59: ccc[0][133] = e->p2; break; } } break; } } #ifdef _WIN32 void w32usleep(uint64_t t) { uint64_t st = 0, ct = 0; QueryPerformanceCounter((LARGE_INTEGER *)&st); do { if (t > 10000 + (ct - st) * 1000000 / pf)Sleep((t - (ct - st) * 1000000 / pf) / 2000); else if (t > 5000 + (ct - st) * 1000000 / pf)Sleep(1); else std::this_thread::yield(); QueryPerformanceCounter((LARGE_INTEGER *)&ct); } while ((ct - st) * 1000000 < t * pf); } #endif void CMidiPlayer::playEvents() { for (uint32_t ct = midiFile->getEvent(0)->time; tceptr < midiFile->getEventCount();) { while (tcpaused)std::this_thread::sleep_for(std::chrono::milliseconds(100)); while (!tcstop && midiFile && tceptr < midiFile->getEventCount() && ct == midiFile->getEvent(tceptr)->time) processEvent(midiFile->getEvent(tceptr++)); if (tcstop || !midiFile || tceptr >= midiFile->getEventCount())break; if (resumed)resumed = false; else #ifdef _WIN32 w32usleep((midiFile->getEvent(tceptr)->time - ct) * (dpt / 1000)); #else std::this_thread::sleep_for(std::chrono::nanoseconds(midiFile->getEvent(tceptr)->time - ct)*dpt); #endif if (tcstop || !midiFile)break; ct = midiFile->getEvent(tceptr)->time; } while (!tcstop && synth && (waitvoice && fluid_synth_get_active_voice_count(synth) > 0))std::this_thread::sleep_for(std::chrono::milliseconds(2)); finished = 1; } void CMidiPlayer::fileTimer1Pass() { ftime = .0; ctempo = 0x7A120; dpt = ctempo * 1000 / divs; for (uint32_t eptr = 0, ct = midiFile->getEvent(0)->time; eptr < midiFile->getEventCount();) { while (eptr < midiFile->getEventCount() && ct == midiFile->getEvent(eptr)->time) processEventStub(midiFile->getEvent(eptr++)); if (eptr >= midiFile->getEventCount())break; ftime += (midiFile->getEvent(eptr)->time - ct) * dpt / 1e9; ct = midiFile->getEvent(eptr)->time; } } void CMidiPlayer::fileTimer2Pass() { double ctime = .0; uint32_t c = 1; ctempo = 0x7A120; dpt = ctempo * 1000 / divs; memset(stamps, 0, sizeof(stamps)); memset(ccstamps, 0, sizeof(ccstamps)); memset(ccc, 0, sizeof(ccc)); rpnid = rpnval = -1; for (int i = 0; i < 16; ++i) { ccc[i][7] = 100; ccc[i][10] = 64; ccc[i][11] = 127; 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; ccc[0][131] = dpt; ccc[0][132] = 0x04021808; ccc[0][133] = 0; ccc[0][134] = 2; } if (midiFile->getStandard() != 4)ccc[9][0] = 128; for (int i = 0; i < 16; ++i)for (int j = 0; j < 135; ++j) ccstamps[0][i][j] = ccc[i][j]; for (uint32_t eptr = 0, ct = midiFile->getEvent(0)->time; eptr < midiFile->getEventCount();) { while (eptr < midiFile->getEventCount() && ct == midiFile->getEvent(eptr)->time) processEventStub(midiFile->getEvent(eptr++)); if (eptr >= midiFile->getEventCount())break; ctime += (midiFile->getEvent(eptr)->time - ct) * dpt / 1e9; while (ctime > ftime * c / 100.) { for (int i = 0; i < 16; ++i)for (int j = 0; j < 135; ++j) ccstamps[c][i][j] = ccc[i][j]; stamps[c++] = eptr; if (c > 100)break; } ct = midiFile->getEvent(eptr)->time; } while (c < 101) { for (int i = 0; i < 16; ++i)for (int j = 0; j < 135; ++j) ccstamps[c][i][j] = ccc[i][j]; stamps[c++] = midiFile->getEventCount(); } } CMidiPlayer::CMidiPlayer(bool singleInst) { midiFile = NULL; resumed = false; singleInstance = singleInst; settings = NULL; synth = NULL; adriver = NULL; waitvoice = true; #ifdef _WIN32 QueryPerformanceFrequency((LARGE_INTEGER *)&pf); timeBeginPeriod(1); #endif } CMidiPlayer::~CMidiPlayer() { if (singleInstance)fluidDeinitialize(); #ifdef _WIN32 timeEndPeriod(1); #endif } void CMidiPlayer::playerPanic(bool reset) { if (reset)for (int i = 0; i < 16; ++i) { fluid_synth_pitch_bend(synth, i, 8192); fluid_synth_cc(synth, i, 7, 100); fluid_synth_cc(synth, i, 10, 64); fluid_synth_cc(synth, i, 11, 127); } for (int i = 0; i < 16; ++i)fluid_synth_all_notes_off(synth, i); } bool CMidiPlayer::playerLoadFile(const char *fn) { midiFile = new CMidiFile(fn); if (!midiFile->isValid())return false; divs = midiFile->getDivision(); fileTimer1Pass(); fileTimer2Pass(); return true; } void CMidiPlayer::playerInit() { ctempo = 0x7A120; ctsn = 4; ctsd = 4; cks = 0; dpt = ctempo * 1000 / divs; tceptr = 0; tcstop = 0; tcpaused = 0; finished = 0; mute = solo = 0; sendSysEx = true; rpnid = rpnval = -1; if (!singleInstance)fluidPreInitialize(); } void CMidiPlayer::playerDeinit() { tceptr = 0; tcstop = 1; tcpaused = 0; delete midiFile; midiFile = NULL; if (!singleInstance)fluidDeinitialize(); } 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; } void CMidiPlayer::setTCeptr(uint32_t ep, uint32_t st) { resumed = true; if (ep == midiFile->getEventCount())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]); //fluid_synth_pitch_bend(synth,i,ccstamps[st][i][130]); dpt = ccstamps[st][0][131]; ctempo = dpt * divs / 1000; ctsn = ccstamps[st][0][132] >> 24; ctsd = 1 << ((ccstamps[st][0][132] >> 16) & 0xFF); cks = ccstamps[st][0][133]; } } double CMidiPlayer::getFtime() { return ftime; } void CMidiPlayer::getCurrentTimeSignature(int *n, int *d) { *n = ctsn; *d = ctsd; } void CMidiPlayer::getCurrentKeySignature(int *ks) { *ks = cks; } uint32_t CMidiPlayer::getFileNoteCount() { return midiFile ? midiFile->getNoteCount() : 0; } uint32_t CMidiPlayer::getFileStandard() { return midiFile ? midiFile->getStandard() : 0; } const char *CMidiPlayer::getTitle() { return midiFile ? midiFile->getTitle() : ""; } const char *CMidiPlayer::getCopyright() { return midiFile ? midiFile->getCopyright() : ""; } double CMidiPlayer::getTempo() { return 60. / (ctempo / 1e6)/**ctsd/4.*/; } uint32_t CMidiPlayer::getTCpaused() { return tcpaused; } 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, "")); fluid_synth_channel_info_t info; fluid_synth_get_channel_info(synth, ch, &info); *b = info.bank; *p = info.program; strcpy(name, info.name); } void CMidiPlayer::setChannelPreset(int ch, int b, int p) { if (!synth)return; fluid_synth_bank_select(synth, ch, b); fluid_synth_program_change(synth, ch, p); } //16MSB..LSB1 void CMidiPlayer::setBit(uint16_t &n, uint16_t bn, uint16_t b) { n ^= (-b ^ n) & (1 << bn); } void CMidiPlayer::setMute(int ch, bool m) { setBit(mute, ch, m ? 1 : 0); } void CMidiPlayer::setSolo(int ch, bool s) { setBit(solo, ch, s ? 1 : 0); } int CMidiPlayer::getCC(int ch, int id) { int ret = 0; synth ? fluid_synth_get_cc(synth, ch, id, &ret) : 0; return ret; } void CMidiPlayer::setCC(int ch, int id, int val) { synth ? fluid_synth_cc(synth, ch, id, val) : 0; } 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) { if (!synth)return; fluid_synth_set_reverb_on(synth, e); fluid_synth_set_reverb(synth, r, d, w, l); } void CMidiPlayer::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 CMidiPlayer::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); } 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; }