diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index fa68cd60..cc1428e1 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -491,6 +491,77 @@ void DivEngine::notifyWaveChange(int wave) { BUSY_END; } +int DivEngine::loadSampleRom(String path, ssize_t expectedSize, unsigned char*& ret) { + ret = NULL; + if (path.empty()) { + return 0; + } + logI("loading ROM %s...",path); + FILE* f=ps_fopen(path.c_str(),"rb"); + if (f==NULL) { + logE("error: %s",strerror(errno)); + lastError=strerror(errno); + return -1; + } + if (fseek(f,0,SEEK_END)<0) { + logE("size error: %s",strerror(errno)); + lastError=fmt::sprintf("on seek: %s",strerror(errno)); + fclose(f); + return -1; + } + ssize_t len=ftell(f); + if (len==(SIZE_MAX>>1)) { + logE("could not get file length: %s",strerror(errno)); + lastError=fmt::sprintf("on pre tell: %s",strerror(errno)); + fclose(f); + return -1; + } + if (len<1) { + if (len==0) { + logE("that file is empty!"); + lastError="file is empty"; + } else { + logE("tell error: %s",strerror(errno)); + lastError=fmt::sprintf("on tell: %s",strerror(errno)); + } + fclose(f); + return -1; + } + if (len!=expectedSize) { + logE("ROM size mismatch, expected: %d bytes, was: %d bytes", expectedSize, len); + lastError=fmt::sprintf("ROM size mismatch, expected: %d bytes, was: %d", expectedSize, len); + return -1; + } + if (fseek(f,0,SEEK_SET)<0) { + logE("size error: %s",strerror(errno)); + lastError=fmt::sprintf("on get size: %s",strerror(errno)); + fclose(f); + return -1; + } + unsigned char* file=new unsigned char[len]; + if (fread(file,1,(size_t)len,f)!=(size_t)len) { + logE("read error: %s",strerror(errno)); + lastError=fmt::sprintf("on read: %s",strerror(errno)); + fclose(f); + delete[] file; + return -1; + } + fclose(f); + ret = file; + return 0; +} + +int DivEngine::loadSampleRoms() { + delete[] yrw801Rom; + delete[] tg100Rom; + delete[] mu5Rom; + int error = 0; + error += loadSampleRom(getConfString("yrw801Path",""), 0x200000, yrw801Rom); + error += loadSampleRom(getConfString("tg100Path",""), 0x200000, tg100Rom); + error += loadSampleRom(getConfString("mu5Path",""), 0x200000, mu5Rom); + return error; +} + void DivEngine::renderSamplesP() { BUSY_BEGIN; renderSamples(); @@ -2708,6 +2779,8 @@ bool DivEngine::init() { loadConf(); + loadSampleRoms(); + // set default system preset if (!hasLoadedSomething) { logD("setting default preset"); @@ -2781,5 +2854,8 @@ bool DivEngine::quit() { active=false; delete[] oscBuf[0]; delete[] oscBuf[1]; + delete[] yrw801Rom; + delete[] tg100Rom; + delete[] mu5Rom; return true; } diff --git a/src/engine/engine.h b/src/engine/engine.h index b72832b3..3338b4a5 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -397,6 +397,8 @@ class DivEngine { void loadOPM(SafeReader& reader, std::vector& ret, String& stripPath); void loadFF(SafeReader& reader, std::vector& ret, String& stripPath); + int loadSampleRom(String path, ssize_t expectedSize, unsigned char*& ret); + bool initAudioBackend(); bool deinitAudioBackend(); @@ -783,6 +785,9 @@ class DivEngine { // get register cheatsheet const char** getRegisterSheet(int sys); + // load sample ROMs + int loadSampleRoms(); + // UNSAFE render samples - only execute when locked void renderSamples(); @@ -856,6 +861,10 @@ class DivEngine { // terminate the engine. bool quit(); + unsigned char* yrw801Rom; + unsigned char* tg100Rom; + unsigned char* mu5Rom; + DivEngine(): output(NULL), exportThread(NULL), @@ -930,7 +939,10 @@ class DivEngine { oscReadPos(0), oscWritePos(0), tickMult(1), - processTime(0) { + processTime(0), + yrw801Rom(NULL), + tg100Rom(NULL), + mu5Rom(NULL) { memset(isMuted,0,DIV_MAX_CHANS*sizeof(bool)); memset(keyHit,0,DIV_MAX_CHANS*sizeof(bool)); memset(dispatchChanOfChan,0,DIV_MAX_CHANS*sizeof(int)); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index c8e90237..4d237c1d 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1507,6 +1507,19 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { dpiScale ); break; + case GUI_FILE_YRW801_ROM_OPEN: + case GUI_FILE_TG100_ROM_OPEN: + case GUI_FILE_MU5_ROM_OPEN: + if (!dirExists(workingDirSample)) workingDirSample=getHomeDir(); + hasOpened=fileDialog->openLoad( + "Load ROM", + {"compatible files", "*.rom *.bin", + "all files", ".*"}, + "compatible files{.rom,.bin},.*", + workingDirRom, + dpiScale + ); + break; } if (hasOpened) curFileDialog=type; //ImGui::GetIO().ConfigFlags|=ImGuiConfigFlags_NavEnableKeyboard; @@ -3024,6 +3037,11 @@ bool FurnaceGUI::loop() { case GUI_FILE_EXPORT_LAYOUT: workingDirLayout=fileDialog->getPath()+DIR_SEPARATOR_STR; break; + case GUI_FILE_YRW801_ROM_OPEN: + case GUI_FILE_TG100_ROM_OPEN: + case GUI_FILE_MU5_ROM_OPEN: + workingDirRom=fileDialog->getPath()+DIR_SEPARATOR_STR; + break; } if (fileDialog->accepted()) { fileName=fileDialog->getFileName(); @@ -3237,6 +3255,15 @@ bool FurnaceGUI::loop() { case GUI_FILE_EXPORT_LAYOUT: exportLayout(copyOfName); break; + case GUI_FILE_YRW801_ROM_OPEN: + settings.yrw801Path=copyOfName; + break; + case GUI_FILE_TG100_ROM_OPEN: + settings.tg100Path=copyOfName; + break; + case GUI_FILE_MU5_ROM_OPEN: + settings.mu5Path=copyOfName; + break; } curFileDialog=GUI_FILE_OPEN; } diff --git a/src/gui/gui.h b/src/gui/gui.h index 0501e242..03a3d7e3 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -257,7 +257,10 @@ enum FurnaceGUIFileDialogs { GUI_FILE_IMPORT_LAYOUT, GUI_FILE_EXPORT_COLORS, GUI_FILE_EXPORT_KEYBINDS, - GUI_FILE_EXPORT_LAYOUT + GUI_FILE_EXPORT_LAYOUT, + GUI_FILE_YRW801_ROM_OPEN, + GUI_FILE_TG100_ROM_OPEN, + GUI_FILE_MU5_ROM_OPEN }; enum FurnaceGUIWarnings { @@ -765,7 +768,7 @@ class FurnaceGUI { bool updateSampleTex; String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile; - String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport, workingDirVGMExport, workingDirFont, workingDirColors, workingDirKeybinds, workingDirLayout; + String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport, workingDirVGMExport, workingDirFont, workingDirColors, workingDirKeybinds, workingDirLayout, workingDirRom; String mmlString[17]; String mmlStringW; @@ -823,6 +826,9 @@ class FurnaceGUI { int saaCore; int nesCore; int fdsCore; + String yrw801Path; + String tg100Path; + String mu5Path; int mainFont; int patFont; int audioRate; @@ -910,6 +916,9 @@ class FurnaceGUI { saaCore(1), nesCore(0), fdsCore(0), + yrw801Path(""), + tg100Path(""), + mu5Path(""), mainFont(0), patFont(0), audioRate(44100), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index e6ba74a2..c38e1dc8 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -883,6 +883,33 @@ void FurnaceGUI::drawSettings() { ImGui::Text("FDS core"); ImGui::SameLine(); ImGui::Combo("##FDSCore",&settings.fdsCore,nesCores,2); + + ImGui::Separator(); + ImGui::Text("Sample ROMs:"); + + ImGui::Text("OPL4 YRW801 path"); + ImGui::SameLine(); + ImGui::InputText("##YRW801Path",&settings.yrw801Path); + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_FOLDER "##YRW801Load")) { + openFileDialog(GUI_FILE_YRW801_ROM_OPEN); + } + + ImGui::Text("MultiPCM TG100 path"); + ImGui::SameLine(); + ImGui::InputText("##TG100Path",&settings.tg100Path); + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_FOLDER "##TG100Load")) { + openFileDialog(GUI_FILE_TG100_ROM_OPEN); + } + + ImGui::Text("MultiPCM MU5 path"); + ImGui::SameLine(); + ImGui::InputText("##MU5Path",&settings.mu5Path); + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_FOLDER "##MU5Load")) { + openFileDialog(GUI_FILE_MU5_ROM_OPEN); + } } ImGui::EndChild(); ImGui::EndTabItem(); @@ -1789,6 +1816,9 @@ void FurnaceGUI::syncSettings() { settings.saaCore=e->getConfInt("saaCore",1); settings.nesCore=e->getConfInt("nesCore",0); settings.fdsCore=e->getConfInt("fdsCore",0); + settings.yrw801Path=e->getConfString("yrw801Path",""); + settings.tg100Path=e->getConfString("tg100Path",""); + settings.mu5Path=e->getConfString("mu5Path",""); settings.mainFont=e->getConfInt("mainFont",0); settings.patFont=e->getConfInt("patFont",0); settings.mainFontPath=e->getConfString("mainFontPath",""); @@ -1960,6 +1990,10 @@ void FurnaceGUI::syncSettings() { } void FurnaceGUI::commitSettings() { + bool sampleRomsChanged = settings.yrw801Path!=e->getConfString("yrw801Path","") || + settings.tg100Path!=e->getConfString("tg100Path","") || + settings.mu5Path!=e->getConfString("mu5Path",""); + e->setConf("mainFontSize",settings.mainFontSize); e->setConf("patFontSize",settings.patFontSize); e->setConf("iconSize",settings.iconSize); @@ -1975,6 +2009,9 @@ void FurnaceGUI::commitSettings() { e->setConf("saaCore",settings.saaCore); e->setConf("nesCore",settings.nesCore); e->setConf("fdsCore",settings.fdsCore); + e->setConf("yrw801Path",settings.yrw801Path); + e->setConf("tg100Path",settings.tg100Path); + e->setConf("mu5Path",settings.mu5Path); e->setConf("mainFont",settings.mainFont); e->setConf("patFont",settings.patFont); e->setConf("mainFontPath",settings.mainFontPath); @@ -2063,6 +2100,12 @@ void FurnaceGUI::commitSettings() { e->saveConf(); + if (sampleRomsChanged) { + if (e->loadSampleRoms()) { + showError(e->getLastError()); + } + } + if (!e->switchMaster()) { showError("could not initialize audio!"); }