diff --git a/src/engine/engine.h b/src/engine/engine.h index c8afb86a9..5e840362e 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -291,13 +291,10 @@ class DivEngine { void loadSBI(SafeReader& reader, std::vector& ret, String& stripPath); void loadOPLI(SafeReader& reader, std::vector& ret, String& stripPath); void loadOPNI(SafeReader& reader, std::vector& ret, String& stripPath); - void loadPAT(SafeReader& reader, std::vector& ret, String& stripPath); void loadY12(SafeReader& reader, std::vector& ret, String& stripPath); void loadBNK(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); - void loadWOPL(SafeReader& reader, std::vector& ret, String& stripPath); - void loadWOPN(SafeReader& reader, std::vector& ret, String& stripPath); bool initAudioBackend(); bool deinitAudioBackend(); diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index 602fbba55..87233ef63 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -30,15 +30,12 @@ enum DivInsFormats { DIV_INSFORMAT_BTI, DIV_INSFORMAT_S3I, DIV_INSFORMAT_SBI, - DIV_INSFORMAT_PAT, DIV_INSFORMAT_Y12, DIV_INSFORMAT_OPLI, DIV_INSFORMAT_OPNI, DIV_INSFORMAT_BNK, DIV_INSFORMAT_OPM, DIV_INSFORMAT_FF, - DIV_INSFORMAT_WOPL, - DIV_INSFORMAT_WOPN, }; // Patch data structures @@ -641,6 +638,105 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St } } +void DivEngine::loadOPLI(SafeReader& reader, std::vector& ret, String& stripPath) { + DivInstrument* ins = new DivInstrument; + + try { + reader.seek(0, SEEK_SET); + String header = reader.readString(11); + if (header.compare("WOPL3-INST") == 0) { + uint16_t version = reader.readS(); + bool isPerc = (reader.readC() == 1); + + ins->type = DIV_INS_OPL; + String insName = reader.readString(32); + insName = (insName.length() > 0) ? insName : stripPath; + ins->name = insName; + reader.seek(7, SEEK_CUR); // skip MIDI params + uint8_t instTypeFlags = reader.readC(); // [0EEEDCBA] - see WOPL/OPLI spec + + bool is_2op = ((instTypeFlags & 0x1) > 0); + bool is_4op = (((instTypeFlags>>1) & 0x1) > 0); + bool is_2x2op = (((instTypeFlags>>2) & 0x1) > 0); + bool is_rhythm = (((instTypeFlags>>4) & 0x7) > 0); + + auto readOpliOp = [](SafeReader& reader, DivInstrumentFM::Operator op) { + uint8_t characteristics = reader.readC(); + uint8_t keyScaleLevel = reader.readC(); + uint8_t attackDecay = reader.readC(); + uint8_t sustainRelease = reader.readC(); + uint8_t waveSelect = reader.readC(); + + op.mult = characteristics & 0xF; + op.ksr = ((characteristics >> 4) & 0x1); + op.sus = ((characteristics >> 5) & 0x1); + op.vib = ((characteristics >> 6) & 0x1); + op.am = ((characteristics >> 7) & 0x1); + op.tl = keyScaleLevel & 0x3F; + op.ksl = ((keyScaleLevel >> 6) & 0x3); + op.ar = ((attackDecay >> 4) & 0xF); + op.dr = attackDecay & 0xF; + op.rr = sustainRelease & 0xF; + op.sl = ((sustainRelease >> 4) & 0xF); + op.ws = waveSelect; + }; + + uint8_t feedConnect = reader.readC(); + uint8_t feedConnect2nd = reader.readC(); + + ins->fm.alg = (feedConnect & 0x1); + ins->fm.fb = ((feedConnect >> 1) & 0xF); + + if (is_4op) { + ins->fm.ops = 4; + ins->fm.alg = (feedConnect & 0x1) | ((feedConnect2nd & 0x1) << 1); + for (int i : {0,2,1,3}) { + readOpliOp(reader, ins->fm.op[i]); + } + } else { + ins->fm.ops = 2; + for (int i = 0; i < 2; ++i) { + readOpliOp(reader, ins->fm.op[i]); + } + if (is_rhythm) { + ins->fm.opllPreset = (uint8_t)(1<<4); + + } else if (is_2x2op) { + ins->name = fmt::format("{0} (1)", insName); + ret.push_back(ins); + + ins = new DivInstrument; + ins->type = DIV_INS_OPL; + ins->name = fmt::format("{0} (2)", insName); + for (int i = 0; i < 2; ++i) { + readOpliOp(reader, ins->fm.op[i]); + } + } + } + + // Skip rest of file + reader.seek(0, SEEK_END); + ret.push_back(ins); + } + } catch (EndOfFileException& e) { + lastError = "premature end of file"; + logE("premature end of file"); + delete ins; + } +} + +void DivEngine::loadOPNI(SafeReader& reader, std::vector& ret, String& stripPath) { + DivInstrument* ins = new DivInstrument; + + try { + reader.seek(0, SEEK_SET); + } catch (EndOfFileException& e) { + lastError = "premature end of file"; + logE("premature end of file"); + delete ins; + } +} + void DivEngine::loadY12(SafeReader& reader, std::vector& ret, String& stripPath) { DivInstrument *ins = new DivInstrument; @@ -653,18 +749,18 @@ void DivEngine::loadY12(SafeReader& reader, std::vector& ret, St for (int i : {0,1,2,3}) { DivInstrumentFM::Operator& insOp = ins->fm.op[i]; uint8_t tmp = reader.readC(); - insOp.mult = (tmp & 0xF); + insOp.mult = tmp & 0xF; insOp.dt = ((tmp >> 4) & 0x7); insOp.tl = (reader.readC() & 0x3F); tmp = reader.readC(); insOp.rs = ((tmp >> 6) & 0x3); - insOp.ar = (tmp & 0x1F); + insOp.ar = tmp & 0x1F; tmp = reader.readC(); - insOp.dr = (tmp & 0x1F); + insOp.dr = tmp & 0x1F; insOp.am = ((tmp >> 7) & 0x1); insOp.d2r = (reader.readC() & 0x1F); tmp = reader.readC(); - insOp.rr = (tmp & 0xF); + insOp.rr = tmp & 0xF; insOp.sl = ((tmp >> 4) & 0xF); insOp.ssgEnv = reader.readC(); reader.seek(9, SEEK_CUR); @@ -884,7 +980,7 @@ void DivEngine::loadOPM(SafeReader& reader, std::vector& ret, St return (x>limitHigh) ? limitHigh : (x DivEngine::instrumentFromFile(const char* path) { } else if (extS==String(".opli")) { format=DIV_INSFORMAT_OPLI; } else if (extS==String(".opni")) { - format=DIV_INSFORMAT_OPNI; - } else if (extS==String(".pat")) { - format=DIV_INSFORMAT_PAT; + format=DIV_INSFORMAT_OPNI;; } else if (extS==String(".y12")) { format=DIV_INSFORMAT_Y12; } else if (extS==String(".bnk")) { @@ -1141,10 +1235,6 @@ std::vector DivEngine::instrumentFromFile(const char* path) { format=DIV_INSFORMAT_OPM; } else if (extS==String(".ff")) { format=DIV_INSFORMAT_FF; - } else if (extS==String(".wopl")) { - format=DIV_INSFORMAT_WOPL; - } else if (extS==String(".wopn")) { - format=DIV_INSFORMAT_WOPN; } } @@ -1169,6 +1259,12 @@ std::vector DivEngine::instrumentFromFile(const char* path) { case DIV_INSFORMAT_SBI: loadSBI(reader,ret,stripPath); break; + case DIV_INSFORMAT_OPLI: + loadOPLI(reader,ret,stripPath); + break; + case DIV_INSFORMAT_OPNI: + loadOPNI(reader, ret, stripPath); + break; case DIV_INSFORMAT_Y12: loadY12(reader,ret,stripPath); break; diff --git a/src/engine/safeReader.cpp b/src/engine/safeReader.cpp index e46827c68..97031b2be 100644 --- a/src/engine/safeReader.cpp +++ b/src/engine/safeReader.cpp @@ -139,7 +139,7 @@ double SafeReader::readD() { } String SafeReader::readString(size_t stlen) { - String ret(stlen, ' '); + String ret; #ifdef READ_DEBUG logD("SR: reading string len %d at %x",stlen,curSeek); #endif diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 5ed9cf0ad..c7a235113 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -2485,6 +2485,8 @@ void FurnaceGUI::applyUISettings(bool updateFonts) { ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".vgi",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".s3i",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".sbi",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE); + ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".opli",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE); + ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".opni",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".y12",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".bnk",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE); ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fti",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);