diff --git a/extern/ESFMu/README.md b/extern/ESFMu/README.md index 5e04ef6fb..723f17967 100644 --- a/extern/ESFMu/README.md +++ b/extern/ESFMu/README.md @@ -1,3 +1,7 @@ +# MODIFIED + +this is a modified version of ESFMu which adds a "fast" mode that uses OPL3 feedback calculation rather than patent workaround calculation (which is slow but accurate). + # ESFMu An emulator for the ESS "ESFM" enhanced OPL3 clone, based on Nuke.YKT's **Nuked OPL3** and reverse-engineering efforts from the community. diff --git a/extern/ESFMu/esfm.c b/extern/ESFMu/esfm.c index b7373d58a..dc8cccfc4 100644 --- a/extern/ESFMu/esfm.c +++ b/extern/ESFMu/esfm.c @@ -1776,6 +1776,14 @@ ESFM_process_feedback(esfm_chip *chip) phase_acc = (uint32_t)(slot->in.phase_acc - phase_offset * 28); eg_output = slot->in.eg_output; + if (chip->fast_mode) { + phase_feedback = (slot->in.fb_out0 + slot->in.fb_out1) >> 2; + slot->in.fb_out1 = slot->in.fb_out0; + phase = phase_feedback >> mod_in_shift; + phase += phase_acc >> 9; + wave_out = slot->in.fb_out0 = ESFM_envelope_wavegen(waveform, phase, eg_output); + phase_acc += phase_offset; + } else { // ASM optimizaions! #if defined(__GNUC__) && defined(__x86_64__) asm ( @@ -1974,6 +1982,7 @@ ESFM_process_feedback(esfm_chip *chip) phase_acc += phase_offset; } #endif + } // TODO: Figure out - is this how the ESFM chip does it, like the // patent literally says? (it's really hacky...) diff --git a/extern/ESFMu/esfm.h b/extern/ESFMu/esfm.h index f33567aeb..73100ce57 100644 --- a/extern/ESFMu/esfm.h +++ b/extern/ESFMu/esfm.h @@ -58,7 +58,7 @@ typedef struct _esfm_channel esfm_channel; typedef struct _esfm_chip esfm_chip; -void ESFM_init (esfm_chip *chip); +void ESFM_init (esfm_chip *chip, uint8_t fast); void ESFM_write_reg (esfm_chip *chip, uint16_t address, uint8_t data); void ESFM_write_reg_buffered (esfm_chip *chip, uint16_t address, uint8_t data); void ESFM_write_reg_buffered_fast (esfm_chip *chip, uint16_t address, uint8_t data); @@ -148,6 +148,8 @@ typedef struct _esfm_slot_internal uint16 eg_delay_counter; uint16 eg_delay_counter_compare; + uint16 fb_out0; + uint16 fb_out1; } esfm_slot_internal; struct _esfm_slot @@ -270,6 +272,8 @@ struct _esfm_chip size_t write_buf_start; size_t write_buf_end; uint64_t write_buf_timestamp; + + flag fast_mode; }; #ifdef __cplusplus diff --git a/extern/ESFMu/esfm_registers.c b/extern/ESFMu/esfm_registers.c index d87a5944f..3c944e86d 100644 --- a/extern/ESFMu/esfm_registers.c +++ b/extern/ESFMu/esfm_registers.c @@ -948,7 +948,7 @@ ESFM_set_mode (esfm_chip *chip, bool native_mode) /* ------------------------------------------------------------------------- */ void -ESFM_init (esfm_chip *chip) +ESFM_init (esfm_chip *chip, uint8_t fast) { esfm_slot *slot; esfm_channel *channel; @@ -999,5 +999,6 @@ ESFM_init (esfm_chip *chip) } chip->lfsr = 1; + chip->fast_mode = fast; } diff --git a/src/engine/dispatchContainer.cpp b/src/engine/dispatchContainer.cpp index 8118c4a54..7146e90c6 100644 --- a/src/engine/dispatchContainer.cpp +++ b/src/engine/dispatchContainer.cpp @@ -649,6 +649,11 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do break; case DIV_SYSTEM_ESFM: dispatch=new DivPlatformESFM; + if (isRender) { + ((DivPlatformESFM*)dispatch)->setFast(eng->getConfInt("esfmCoreRender",0)); + } else { + ((DivPlatformESFM*)dispatch)->setFast(eng->getConfInt("esfmCore",0)); + } break; case DIV_SYSTEM_POWERNOISE: dispatch=new DivPlatformPowerNoise; diff --git a/src/engine/platform/esfm.cpp b/src/engine/platform/esfm.cpp index 090254a00..3adab20f5 100644 --- a/src/engine/platform/esfm.cpp +++ b/src/engine/platform/esfm.cpp @@ -983,7 +983,7 @@ int DivPlatformESFM::getRegisterPoolSize() { void DivPlatformESFM::reset() { while (!writes.empty()) writes.pop(); - ESFM_init(&chip); + ESFM_init(&chip,isFast?1:0); // set chip to native mode ESFM_write_reg(&chip, 0x105, 0x80); // ensure NTS bit in register 0x408 is reset, for smooth envelope rate scaling @@ -1053,6 +1053,10 @@ void DivPlatformESFM::setFlags(const DivConfig& flags) { rate=chipClock/288.0; } +void DivPlatformESFM::setFast(bool fast) { + isFast=fast; +} + int DivPlatformESFM::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) { parent=p; dumpWrites=false; diff --git a/src/engine/platform/esfm.h b/src/engine/platform/esfm.h index 58fafbfab..8321369bf 100644 --- a/src/engine/platform/esfm.h +++ b/src/engine/platform/esfm.h @@ -120,6 +120,7 @@ class DivPlatformESFM: public DivDispatch { }; FixedQueue writes; esfm_chip chip; + bool isFast; unsigned char regPool[ESFM_REG_POOL_SIZE]; short oldWrites[ESFM_REG_POOL_SIZE]; @@ -201,6 +202,7 @@ class DivPlatformESFM: public DivDispatch { void poke(unsigned int addr, unsigned short val); void poke(std::vector& wlist); void setFlags(const DivConfig& flags); + void setFast(bool fast); int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags); void quit(); ~DivPlatformESFM(); diff --git a/src/gui/about.cpp b/src/gui/about.cpp index a20be2cc7..56da97c73 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -216,7 +216,7 @@ const char* aboutLine[]={ "adpcm by superctr", "Nuked-OPL3/OPLL/OPM/OPN2/PSG by nukeykt", "YM3812-LLE, YMF262-LLE and YMF276-LLE by nukeykt", - "ESFMu by Kagamiin~", + "ESFMu (modified version) by Kagamiin~", "ymfm by Aaron Giles", "MAME SN76496 by Nicola Salmoria", "MAME AY-3-8910 by Couriersud", diff --git a/src/gui/fmPreview.cpp b/src/gui/fmPreview.cpp index 525d30339..7c034e3d9 100644 --- a/src/gui/fmPreview.cpp +++ b/src/gui/fmPreview.cpp @@ -350,7 +350,7 @@ void FurnaceGUI::renderFMPreviewESFM(const DivInstrumentFM& params, const DivIns bool mult0=false; if (pos==0) { - ESFM_init((esfm_chip*)fmPreviewESFM); + ESFM_init((esfm_chip*)fmPreviewESFM,0); // set native mode ESFM_WRITE(0x105, 0x80); diff --git a/src/gui/gui.h b/src/gui/gui.h index 3bda6b320..1188d78d1 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1638,6 +1638,7 @@ class FurnaceGUI { int opnCore; int opl2Core; int opl3Core; + int esfmCore; int arcadeCoreRender; int ym2612CoreRender; int snCoreRender; @@ -1648,6 +1649,7 @@ class FurnaceGUI { int opnCoreRender; int opl2CoreRender; int opl3CoreRender; + int esfmCoreRender; int pcSpeakerOutMethod; String yrw801Path; String tg100Path; @@ -1843,6 +1845,7 @@ class FurnaceGUI { opnCore(1), opl2Core(0), opl3Core(0), + esfmCore(0), arcadeCoreRender(1), ym2612CoreRender(0), snCoreRender(0), @@ -1853,6 +1856,7 @@ class FurnaceGUI { opnCoreRender(1), opl2CoreRender(0), opl3CoreRender(0), + esfmCoreRender(0), pcSpeakerOutMethod(0), yrw801Path(""), tg100Path(""), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index f19dc9d04..68e30445d 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -169,6 +169,11 @@ const char* opl3Cores[]={ "YMF262-LLE" }; +const char* esfmCores[]={ + "ESFMu", + "ESFMu (fast)" +}; + const char* pcspkrOutMethods[]={ "evdev SND_TONE", "KIOCSOUND on /dev/tty1", @@ -1629,6 +1634,17 @@ void FurnaceGUI::drawSettings() { ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); if (ImGui::Combo("##OPL3CoreRender",&settings.opl3CoreRender,opl3Cores,3)) settingsChanged=true; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::AlignTextToFramePadding(); + ImGui::Text("ESFM"); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::Combo("##ESFMCore",&settings.esfmCore,esfmCores,2)) settingsChanged=true; + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::Combo("##ESFMCoreRender",&settings.esfmCoreRender,esfmCores,2)) settingsChanged=true; + ImGui::EndTable(); } ImGui::Separator(); @@ -4108,6 +4124,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { settings.opnCore=conf.getInt("opnCore",1); settings.opl2Core=conf.getInt("opl2Core",0); settings.opl3Core=conf.getInt("opl3Core",0); + settings.esfmCore=conf.getInt("esfmCore",0); settings.arcadeCoreRender=conf.getInt("arcadeCoreRender",1); settings.ym2612CoreRender=conf.getInt("ym2612CoreRender",0); settings.snCoreRender=conf.getInt("snCoreRender",0); @@ -4118,6 +4135,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { settings.opnCoreRender=conf.getInt("opnCoreRender",1); settings.opl2CoreRender=conf.getInt("opl2CoreRender",0); settings.opl3CoreRender=conf.getInt("opl3CoreRender",0); + settings.esfmCoreRender=conf.getInt("esfmCoreRender",0); settings.pcSpeakerOutMethod=conf.getInt("pcSpeakerOutMethod",0); @@ -4146,6 +4164,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { clampSetting(settings.opnCore,0,1); clampSetting(settings.opl2Core,0,2); clampSetting(settings.opl3Core,0,2); + clampSetting(settings.esfmCore,0,1); clampSetting(settings.arcadeCoreRender,0,1); clampSetting(settings.ym2612CoreRender,0,2); clampSetting(settings.snCoreRender,0,1); @@ -4156,6 +4175,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { clampSetting(settings.opnCoreRender,0,1); clampSetting(settings.opl2CoreRender,0,2); clampSetting(settings.opl3CoreRender,0,2); + clampSetting(settings.esfmCoreRender,0,1); clampSetting(settings.pcSpeakerOutMethod,0,4); clampSetting(settings.mainFont,0,6); clampSetting(settings.patFont,0,6); @@ -4579,6 +4599,7 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { conf.set("opnCore",settings.opnCore); conf.set("opl2Core",settings.opl2Core); conf.set("opl3Core",settings.opl3Core); + conf.set("esfmCore",settings.esfmCore); conf.set("arcadeCoreRender",settings.arcadeCoreRender); conf.set("ym2612CoreRender",settings.ym2612CoreRender); conf.set("snCoreRender",settings.snCoreRender); @@ -4589,6 +4610,7 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) { conf.set("opnCoreRender",settings.opnCoreRender); conf.set("opl2CoreRender",settings.opl2CoreRender); conf.set("opl3CoreRender",settings.opl3CoreRender); + conf.set("esfmCoreRender",settings.esfmCoreRender); conf.set("pcSpeakerOutMethod",settings.pcSpeakerOutMethod); @@ -4629,6 +4651,7 @@ void FurnaceGUI::commitSettings() { settings.opnCore!=e->getConfInt("opnCore",1) || settings.opl2Core!=e->getConfInt("opl2Core",0) || settings.opl3Core!=e->getConfInt("opl3Core",0) || + settings.esfmCore!=e->getConfInt("esfmCore",0) || settings.arcadeCoreRender!=e->getConfInt("arcadeCoreRender",0) || settings.ym2612CoreRender!=e->getConfInt("ym2612CoreRender",0) || settings.snCoreRender!=e->getConfInt("snCoreRender",0) || @@ -4639,6 +4662,7 @@ void FurnaceGUI::commitSettings() { settings.opnCoreRender!=e->getConfInt("opnCoreRender",1) || settings.opl2CoreRender!=e->getConfInt("opl2CoreRender",0) || settings.opl3CoreRender!=e->getConfInt("opl3CoreRender",0) || + settings.esfmCoreRender!=e->getConfInt("esfmCoreRender",0) || settings.audioQuality!=e->getConfInt("audioQuality",0) || settings.audioHiPass!=e->getConfInt("audioHiPass",1) ); diff --git a/src/main.cpp b/src/main.cpp index 0dcbcfa5a..8601b48c4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -212,7 +212,7 @@ TAParamResult pVersion(String) { printf("- YM3812-LLE by nukeykt (GPLv2)\n"); printf("- YMF262-LLE by nukeykt (GPLv2)\n"); printf("- YMF276-LLE by nukeykt (GPLv2)\n"); - printf("- ESFMu by Kagamiin~ (LGPLv2.1)\n"); + printf("- ESFMu (modified version) by Kagamiin~ (LGPLv2.1)\n"); printf("- ymfm by Aaron Giles (BSD 3-clause)\n"); printf("- adpcm by superctr (public domain)\n"); printf("- MAME SN76496 emulation core by Nicola Salmoria (BSD 3-clause)\n");