diff --git a/src/engine/engine.h b/src/engine/engine.h index 32e89fd4..d11c5470 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -285,6 +285,7 @@ class DivEngine { void loadS3I(SafeReader& reader, std::vector& ret, String& stripPath); void loadSBI(SafeReader& reader, std::vector& ret, String& stripPath); void loadOPM(SafeReader& reader, std::vector& ret, String& stripPath); + void loadFF(SafeReader& reader, std::vector& ret, String& stripPath); bool initAudioBackend(); bool deinitAudioBackend(); diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index b88da310..af0c06d8 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -30,7 +30,8 @@ enum DivInsFormats { DIV_INSFORMAT_BTI, DIV_INSFORMAT_S3I, DIV_INSFORMAT_SBI, - DIV_INSFORMAT_OPM + DIV_INSFORMAT_OPM, + DIV_INSFORMAT_FF, }; void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, String& stripPath) { @@ -631,6 +632,79 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St ret.push_back(ins); } +void DivEngine::loadFF(SafeReader& reader, std::vector& ret, String& stripPath) { + DivInstrument* insList[256]; + memset(insList,0,256*sizeof(void*)); + int readCount = 0; + size_t insCount = reader.size(); + insCount = (insCount >> 5) + (((insCount % 0x20) > 0) ? 1 : 0); + if (insCount > 256) insCount = 256; + uint8_t buf; + try { + reader.seek(0, SEEK_SET); + for (unsigned int i = 0; i < insCount; ++i) { + insList[i] = new DivInstrument; + DivInstrument* ins = insList[i]; + + ins->type = DIV_INS_FM; + DivInstrumentFM::Operator op; + + for (unsigned int j = 0; j < 4; j++) { + buf = reader.readC(); + ins->fm.op[j].mult = buf & 0xf; + // detune needs extra translation from register to furnace format + const int dtNative = (buf >> 4) & 0x7; + ins->fm.op[j].dt = (dtNative >= 4) ? (7 - dtNative) : (dtNative + 3); + ins->fm.op[j].ssgEnv = (buf >> 4) & 0x8; + } + for (unsigned int j = 0; j < 4; j++) { + buf = reader.readC(); + ins->fm.op[j].tl = buf & 0x7f; + ins->fm.op[j].ssgEnv |= (buf >> 5) & 0x4; + } + for (unsigned int j = 0; j < 4; j++) { + buf = reader.readC(); + ins->fm.op[j].ar = buf & 0x1f; + ins->fm.op[j].rs = buf >> 6; + } + for (unsigned int j = 0; j < 4; j++) { + buf = reader.readC(); + ins->fm.op[j].dr = buf & 0x1f; + ins->fm.op[j].ssgEnv |= (buf >> 5) & 0x3; + ins->fm.op[j].am = buf >> 7; + } + for (unsigned int j = 0; j < 4; j++) { + buf = reader.readC(); + ins->fm.op[j].d2r = buf & 0x1f; + } + for (unsigned int j = 0; j < 4; j++) { + buf = reader.readC(); + ins->fm.op[j].rr = buf & 0xf; + ins->fm.op[j].sl = buf >> 4; + } + + buf = reader.readC(); + ins->fm.alg = buf & 0x7; + ins->fm.fb = (buf >> 3) & 0x7; + + // FIXME This is encoded in Shift-JIS + ins->name = reader.readString(7); + ++readCount; + } + } catch (EndOfFileException& e) { + lastError = "premature end of file"; + logE("premature end of file!\n"); + for (int i = readCount; i >= 0; --i) { + delete insList[i]; + } + return; + } + + for (unsigned int i = 0; i < insCount; ++i) { + ret.push_back(insList[i]); + } +} + void DivEngine::loadOPM(SafeReader& reader, std::vector& ret, String& stripPath) { DivInstrument* ins[128]; memset(ins,0,128*sizeof(void*)); @@ -771,6 +845,8 @@ std::vector DivEngine::instrumentFromFile(const char* path) { format=DIV_INSFORMAT_SBI; } else if (extS==String(".opm")) { format=DIV_INSFORMAT_OPM; + } else if (extS==String(".ff")) { + format=DIV_INSFORMAT_FF; } } @@ -797,6 +873,9 @@ std::vector DivEngine::instrumentFromFile(const char* path) { case DIV_INSFORMAT_SBI: loadSBI(reader,ret,stripPath); break; + case DIV_INSFORMAT_FF: + loadFF(reader,ret,stripPath); + break; } if (reader.tell()openLoad( "Load Instrument", - {"compatible files", "*.fui *.dmp *.tfi *.vgi *.s3i *.sbi", + {"compatible files", "*.fui *.dmp *.tfi *.vgi *.s3i *.sbi *.ff", "all files", ".*"}, - "compatible files{.fui,.dmp,.tfi,.vgi,.s3i,.sbi},.*", + "compatible files{.fui,.dmp,.tfi,.vgi,.s3i,.sbi,.ff},.*", workingDirIns, dpiScale ); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 64900282..ad122058 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -2269,6 +2269,7 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".sbi",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fti",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".bti",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE); + ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".ff",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE); if (updateFonts) { if (fileDialog!=NULL) delete fileDialog;