diff --git a/src/engine/engine.h b/src/engine/engine.h index fc063a2b1..3ec530f87 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -287,6 +287,7 @@ class DivEngine { void loadVGI(SafeReader& reader, std::vector& ret, String& stripPath); void loadS3I(SafeReader& reader, std::vector& ret, String& stripPath); void loadSBI(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); diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index af0c06d83..f9eaab38b 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -30,10 +30,66 @@ enum DivInsFormats { DIV_INSFORMAT_BTI, DIV_INSFORMAT_S3I, DIV_INSFORMAT_SBI, + DIV_INSFORMAT_BNK, DIV_INSFORMAT_OPM, DIV_INSFORMAT_FF, }; +// Patch data structures + +// SBI and some other OPL containers +struct sbi_t { + uint8_t Mcharacteristics, + Ccharacteristics, + Mscaling_output, + Cscaling_output, + Meg_AD, + Ceg_AD, + Meg_SR, + Ceg_SR, + Mwave, + Cwave, + FeedConnect; +}; + +// Adlib Visual Composer BNK +struct bnkop_t { + uint8_t ksl, + multiple, + feedback, // op1 only + attack, + sustain, + eg, + decay, + releaseRate, + totalLevel, + am, + vib, + ksr, + con; // op1 only +}; +struct bnktimbre_t { + uint8_t mode, + percVoice; + bnkop_t op[2]; + uint8_t wave0, + wave1; +}; + +auto readSbiOpData = [](sbi_t& sbi, SafeReader& reader) { + sbi.Mcharacteristics = reader.readC(); + sbi.Ccharacteristics = reader.readC(); + sbi.Mscaling_output = reader.readC(); + sbi.Cscaling_output = reader.readC(); + sbi.Meg_AD = reader.readC(); + sbi.Ceg_AD = reader.readC(); + sbi.Meg_SR = reader.readC(); + sbi.Ceg_SR = reader.readC(); + sbi.Mwave = reader.readC(); + sbi.Cwave = reader.readC(); + sbi.FeedConnect = reader.readC(); +}; + void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, String& stripPath) { DivInstrument* ins=new DivInstrument; // this is a ridiculous mess @@ -45,7 +101,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St logD(".dmp version %d",version); } catch (EndOfFileException& e) { lastError="premature end of file"; - logE("premature end of file!"); + logE("premature end of file"); delete ins; return; } @@ -104,7 +160,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE("premature end of file!"); + logE("premature end of file"); delete ins; return; } @@ -296,7 +352,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE("premature end of file!"); + logE("premature end of file"); delete ins; return; } @@ -331,7 +387,7 @@ void DivEngine::loadTFI(SafeReader& reader, std::vector& ret, St } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE("premature end of file!"); + logE("premature end of file"); delete ins; return; } @@ -373,7 +429,7 @@ void DivEngine::loadVGI(SafeReader& reader, std::vector& ret, St } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE("premature end of file!"); + logE("premature end of file"); delete ins; return; } @@ -390,71 +446,70 @@ void DivEngine::loadS3I(SafeReader& reader, std::vector& ret, St if (s3i_type >= 2) { ins->type = DIV_INS_OPL; + if (s3i_type > 2 && s3i_type <= 7) { + ins->fm.opllPreset = (uint8_t)(1<<4); // Flag as Drum preset. + } // skip internal filename - we'll use the long name description reader.seek(12, SEEK_CUR); // skip reserved bytes reader.seek(3, SEEK_CUR); - // 12-byte opl value - uint8_t s3i_Mcharacteristics = reader.readC(); - uint8_t s3i_Ccharacteristics = reader.readC(); - uint8_t s3i_Mscaling_output = reader.readC(); - uint8_t s3i_Cscaling_output = reader.readC(); - uint8_t s3i_Meg_AD = reader.readC(); - uint8_t s3i_Ceg_AD = reader.readC(); - uint8_t s3i_Meg_SR = reader.readC(); - uint8_t s3i_Ceg_SR = reader.readC(); - uint8_t s3i_Mwave = reader.readC(); - uint8_t s3i_Cwave = reader.readC(); - uint8_t s3i_FeedConnect = reader.readC(); + // 12-byte opl value - identical to SBI format + sbi_t s3i; + + readSbiOpData(s3i, reader); DivInstrumentFM::Operator& opM = ins->fm.op[0]; DivInstrumentFM::Operator& opC = ins->fm.op[1]; ins->fm.ops = 2; - opM.mult = s3i_Mcharacteristics & 0xF; - opM.ksr = ((s3i_Mcharacteristics >> 4) & 0x1); - opM.sus = ((s3i_Mcharacteristics >> 5) & 0x1); - opM.vib = ((s3i_Mcharacteristics >> 6) & 0x1); - opM.am = ((s3i_Mcharacteristics >> 7) & 0x1); - opM.tl = s3i_Mscaling_output & 0x3F; - opM.ksl = ((s3i_Mscaling_output >> 6) & 0x3); - opM.ar = ((s3i_Meg_AD >> 4) & 0xF); - opM.dr = (s3i_Meg_AD & 0xF); - opM.rr = (s3i_Meg_SR & 0xF); - opM.sl = ((s3i_Meg_SR >> 4) & 0xF); - opM.ws = s3i_Mwave; + opM.mult = s3i.Mcharacteristics & 0xF; + opM.ksr = ((s3i.Mcharacteristics >> 4) & 0x1); + opM.sus = ((s3i.Mcharacteristics >> 5) & 0x1); + opM.vib = ((s3i.Mcharacteristics >> 6) & 0x1); + opM.am = ((s3i.Mcharacteristics >> 7) & 0x1); + opM.tl = s3i.Mscaling_output & 0x3F; + opM.ksl = ((s3i.Mscaling_output >> 6) & 0x3); + opM.ar = ((s3i.Meg_AD >> 4) & 0xF); + opM.dr = (s3i.Meg_AD & 0xF); + opM.rr = (s3i.Meg_SR & 0xF); + opM.sl = ((s3i.Meg_SR >> 4) & 0xF); + opM.ws = s3i.Mwave; - ins->fm.alg = (s3i_FeedConnect & 0x1); - ins->fm.fb = ((s3i_FeedConnect >> 1) & 0x7); + ins->fm.alg = (s3i.FeedConnect & 0x1); + ins->fm.fb = ((s3i.FeedConnect >> 1) & 0x7); - opC.mult = s3i_Ccharacteristics & 0xF; - opC.ksr = ((s3i_Ccharacteristics >> 4) & 0x1); - opC.sus = ((s3i_Ccharacteristics >> 5) & 0x1); - opC.vib = ((s3i_Ccharacteristics >> 6) & 0x1); - opC.am = ((s3i_Ccharacteristics >> 7) & 0x1); - opC.tl = s3i_Cscaling_output & 0x3F; - opC.ksl = ((s3i_Cscaling_output >> 6) & 0x3); - opC.ar = ((s3i_Ceg_AD >> 4) & 0xF); - opC.dr = (s3i_Ceg_AD & 0xF); - opC.rr = (s3i_Ceg_SR & 0xF); - opC.sl = ((s3i_Ceg_SR >> 4) & 0xF); - opC.ws = s3i_Cwave; + opC.mult = s3i.Ccharacteristics & 0xF; + opC.ksr = ((s3i.Ccharacteristics >> 4) & 0x1); + opC.sus = ((s3i.Ccharacteristics >> 5) & 0x1); + opC.vib = ((s3i.Ccharacteristics >> 6) & 0x1); + opC.am = ((s3i.Ccharacteristics >> 7) & 0x1); + opC.tl = s3i.Cscaling_output & 0x3F; + opC.ksl = ((s3i.Cscaling_output >> 6) & 0x3); + opC.ar = ((s3i.Ceg_AD >> 4) & 0xF); + opC.dr = (s3i.Ceg_AD & 0xF); + opC.rr = (s3i.Ceg_SR & 0xF); + opC.sl = ((s3i.Ceg_SR >> 4) & 0xF); + opC.ws = s3i.Cwave; // Skip more stuff we don't need reader.seek(21, SEEK_CUR); } else { + lastError = "S3I PCM samples currently not supported."; logE("S3I PCM samples currently not supported."); } ins->name = reader.readString(28); + ins->name = (ins->name.length() == 0) ? stripPath : ins->name; + int s3i_signature = reader.readI(); if (s3i_signature != 0x49524353) { + addWarning("S3I signature invalid."); logW("S3I signature invalid."); }; } catch (EndOfFileException& e) { lastError = "premature end of file"; - logE("premature end of file!"); + logE("premature end of file"); delete ins; return; } @@ -470,77 +525,69 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St int sbi_header = reader.readI(); // SBI header determines format - bool is_2op = (sbi_header == 0x1A494253); // SBI\x1A + bool is_2op = (sbi_header == 0x1A494253 || sbi_header == 0x1A504F32); // SBI\x1A or 2OP\x1A bool is_4op = (sbi_header == 0x1A504F34); // 4OP\x1A bool is_6op = (sbi_header == 0x1A504F36); // 6OP\x1A - Freq Monster 801-specific // 32-byte null terminated instrument name - ins->name = reader.readString(32); + String patchName = reader.readString(32); + patchName = (patchName.length() == 0) ? stripPath : patchName; - // 2op SBI - uint8_t sbi_Mcharacteristics = reader.readC(); - uint8_t sbi_Ccharacteristics = reader.readC(); - uint8_t sbi_Mscaling_output = reader.readC(); - uint8_t sbi_Cscaling_output = reader.readC(); - uint8_t sbi_Meg_AD = reader.readC(); - uint8_t sbi_Ceg_AD = reader.readC(); - uint8_t sbi_Meg_SR = reader.readC(); - uint8_t sbi_Ceg_SR = reader.readC(); - uint8_t sbi_Mwave = reader.readC(); - uint8_t sbi_Cwave = reader.readC(); - uint8_t sbi_FeedConnect = reader.readC(); + auto writeOp = [](sbi_t& sbi, DivInstrumentFM::Operator& opM, DivInstrumentFM::Operator& opC) { + opM.mult = sbi.Mcharacteristics & 0xF; + opM.ksr = ((sbi.Mcharacteristics >> 4) & 0x1); + opM.sus = ((sbi.Mcharacteristics >> 5) & 0x1); + opM.vib = ((sbi.Mcharacteristics >> 6) & 0x1); + opM.am = ((sbi.Mcharacteristics >> 7) & 0x1); + opM.tl = sbi.Mscaling_output & 0x3F; + opM.ksl = ((sbi.Mscaling_output >> 6) & 0x3); + opM.ar = ((sbi.Meg_AD >> 4) & 0xF); + opM.dr = (sbi.Meg_AD & 0xF); + opM.rr = (sbi.Meg_SR & 0xF); + opM.sl = ((sbi.Meg_SR >> 4) & 0xF); + opM.ws = sbi.Mwave; - // 4op SBI - uint8_t sbi_M4characteristics; - uint8_t sbi_C4characteristics; - uint8_t sbi_M4scaling_output; - uint8_t sbi_C4scaling_output; - uint8_t sbi_M4eg_AD; - uint8_t sbi_C4eg_AD; - uint8_t sbi_M4eg_SR; - uint8_t sbi_C4eg_SR; - uint8_t sbi_M4wave; - uint8_t sbi_C4wave; - uint8_t sbi_4opConnect; + opC.mult = sbi.Ccharacteristics & 0xF; + opC.ksr = ((sbi.Ccharacteristics >> 4) & 0x1); + opC.sus = ((sbi.Ccharacteristics >> 5) & 0x1); + opC.vib = ((sbi.Ccharacteristics >> 6) & 0x1); + opC.am = ((sbi.Ccharacteristics >> 7) & 0x1); + opC.tl = sbi.Cscaling_output & 0x3F; + opC.ksl = ((sbi.Cscaling_output >> 6) & 0x3); + opC.ar = ((sbi.Ceg_AD >> 4) & 0xF); + opC.dr = (sbi.Ceg_AD & 0xF); + opC.rr = (sbi.Ceg_SR & 0xF); + opC.sl = ((sbi.Ceg_SR >> 4) & 0xF); + opC.ws = sbi.Cwave; + }; + + sbi_t sbi_op12; // 2op (+6op portion) + sbi_t sbi_op34; // 4op + readSbiOpData(sbi_op12, reader); + if (is_2op) { DivInstrumentFM::Operator& opM = ins->fm.op[0]; DivInstrumentFM::Operator& opC = ins->fm.op[1]; ins->fm.ops = 2; - opM.mult = sbi_Mcharacteristics & 0xF; - opM.ksr = ((sbi_Mcharacteristics >> 4) & 0x1); - opM.sus = ((sbi_Mcharacteristics >> 5) & 0x1); - opM.vib = ((sbi_Mcharacteristics >> 6) & 0x1); - opM.am = ((sbi_Mcharacteristics >> 7) & 0x1); - opM.tl = sbi_Mscaling_output & 0x3F; - opM.ksl = ((sbi_Mscaling_output >> 6) & 0x3); - opM.ar = ((sbi_Meg_AD >> 4) & 0xF); - opM.dr = (sbi_Meg_AD & 0xF); - opM.rr = (sbi_Meg_SR & 0xF); - opM.sl = ((sbi_Meg_SR >> 4) & 0xF); - opM.ws = sbi_Mwave; + ins->name = patchName; + writeOp(sbi_op12, opM, opC); + ins->fm.alg = (sbi_op12.FeedConnect & 0x1); + ins->fm.fb = ((sbi_op12.FeedConnect >> 1) & 0x7); - ins->fm.alg = (sbi_FeedConnect & 0x1); - ins->fm.fb = ((sbi_FeedConnect >> 1) & 0x7); - - opC.mult = sbi_Ccharacteristics & 0xF; - opC.ksr = ((sbi_Ccharacteristics >> 4) & 0x1); - opC.sus = ((sbi_Ccharacteristics >> 5) & 0x1); - opC.vib = ((sbi_Ccharacteristics >> 6) & 0x1); - opC.am = ((sbi_Ccharacteristics >> 7) & 0x1); - opC.tl = sbi_Cscaling_output & 0x3F; - opC.ksl = ((sbi_Cscaling_output >> 6) & 0x3); - opC.ar = ((sbi_Ceg_AD >> 4) & 0xF); - opC.dr = (sbi_Ceg_AD & 0xF); - opC.rr = (sbi_Ceg_SR & 0xF); - opC.sl = ((sbi_Ceg_SR >> 4) & 0xF); - opC.ws = sbi_Cwave; + // SBTimbre extensions + uint8_t perc_voc = reader.readC(); + if (perc_voc >= 6) { + ins->fm.opllPreset = (uint8_t)(1 << 4); + } // Ignore rest of file - rest is 'reserved padding'. - reader.seek(0, SEEK_END); - } + reader.seek(4, SEEK_CUR); + ret.push_back(ins); - if (is_4op || is_6op) { + } else if (is_4op || is_6op) { + readSbiOpData(sbi_op34, reader); + // Operator placement is different so need to place in correct registers. // Note: 6op is an unofficial extension of 4op SBIs by Darron Broad (Freq Monster 801). // We'll only use the 4op portion here for pure OPL3. @@ -549,87 +596,144 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St DivInstrumentFM::Operator& opM4 = ins->fm.op[1]; DivInstrumentFM::Operator& opC4 = ins->fm.op[3]; ins->fm.ops = 4; + ins->name = patchName; + ins->fm.alg = (sbi_op12.FeedConnect & 0x1) | ((sbi_op34.FeedConnect & 0x1) << 1); + ins->fm.fb = ((sbi_op34.FeedConnect >> 1) & 0x7); + writeOp(sbi_op12, opM, opC); + writeOp(sbi_op34, opM4, opC4); - sbi_M4characteristics = reader.readC(); - sbi_C4characteristics = reader.readC(); - sbi_M4scaling_output = reader.readC(); - sbi_C4scaling_output = reader.readC(); - sbi_M4eg_AD = reader.readC(); - sbi_C4eg_AD = reader.readC(); - sbi_M4eg_SR = reader.readC(); - sbi_C4eg_SR = reader.readC(); - sbi_M4wave = reader.readC(); - sbi_C4wave = reader.readC(); - sbi_4opConnect = reader.readC(); - - ins->fm.alg = (sbi_FeedConnect & 0x1) | ((sbi_4opConnect & 0x1) << 1); - ins->fm.fb = ((sbi_FeedConnect >> 1) & 0x7); + if (is_6op) { + // Freq Monster 801 6op SBIs use a 4+2op layout + // Save the 4op portion before reading the 2op part + ins->name = fmt::format("{0} (4op)", ins->name); + ret.push_back(ins); - opM.mult = sbi_Mcharacteristics & 0xF; - opM.ksr = ((sbi_Mcharacteristics >> 4) & 0x1); - opM.sus = ((sbi_Mcharacteristics >> 5) & 0x1); - opM.vib = ((sbi_Mcharacteristics >> 6) & 0x1); - opM.am = ((sbi_Mcharacteristics >> 7) & 0x1); - opM.tl = sbi_Mscaling_output & 0x3F; - opM.ksl = ((sbi_Mscaling_output >> 6) & 0x3); - opM.ar = ((sbi_Meg_AD >> 4) & 0xF); - opM.dr = (sbi_Meg_AD & 0xF); - opM.rr = (sbi_Meg_SR & 0xF); - opM.sl = ((sbi_Meg_SR >> 4) & 0xF); - opM.ws = sbi_Mwave; + readSbiOpData(sbi_op12, reader); - opC.mult = sbi_Ccharacteristics & 0xF; - opC.ksr = ((sbi_Ccharacteristics >> 4) & 0x1); - opC.sus = ((sbi_Ccharacteristics >> 5) & 0x1); - opC.vib = ((sbi_Ccharacteristics >> 6) & 0x1); - opC.am = ((sbi_Ccharacteristics >> 7) & 0x1); - opC.tl = sbi_Cscaling_output & 0x3F; - opC.ksl = ((sbi_Cscaling_output >> 6) & 0x3); - opC.ar = ((sbi_Ceg_AD >> 4) & 0xF); - opC.dr = (sbi_Ceg_AD & 0xF); - opC.rr = (sbi_Ceg_SR & 0xF); - opC.sl = ((sbi_Ceg_SR >> 4) & 0xF); - opC.ws = sbi_Cwave; - - opM4.mult = sbi_M4characteristics & 0xF; - opM4.ksr = ((sbi_M4characteristics >> 4) & 0x1); - opM4.sus = ((sbi_M4characteristics >> 5) & 0x1); - opM4.vib = ((sbi_M4characteristics >> 6) & 0x1); - opM4.am = ((sbi_M4characteristics >> 7) & 0x1); - opM4.tl = sbi_M4scaling_output & 0x3F; - opM4.ksl = ((sbi_M4scaling_output >> 6) & 0x3); - opM4.ar = ((sbi_M4eg_AD >> 4) & 0xF); - opM4.dr = (sbi_M4eg_AD & 0xF); - opM4.rr = (sbi_M4eg_SR & 0xF); - opM4.sl = ((sbi_M4eg_SR >> 4) & 0xF); - opM4.ws = sbi_M4wave; - - opC4.mult = sbi_C4characteristics & 0xF; - opC4.ksr = ((sbi_C4characteristics >> 4) & 0x1); - opC4.sus = ((sbi_C4characteristics >> 5) & 0x1); - opC4.vib = ((sbi_C4characteristics >> 6) & 0x1); - opC4.am = ((sbi_C4characteristics >> 7) & 0x1); - opC4.tl = sbi_C4scaling_output & 0x3F; - opC4.ksl = ((sbi_C4scaling_output >> 6) & 0x3); - opC4.ar = ((sbi_C4eg_AD >> 4) & 0xF); - opC4.dr = (sbi_C4eg_AD & 0xF); - opC4.rr = (sbi_C4eg_SR & 0xF); - opC4.sl = ((sbi_C4eg_SR >> 4) & 0xF); - opC4.ws = sbi_C4wave; + ins = new DivInstrument; + DivInstrumentFM::Operator& opM6 = ins->fm.op[0]; + DivInstrumentFM::Operator& opC6 = ins->fm.op[1]; + ins->type = DIV_INS_OPL; + ins->fm.ops = 2; + ins->name = fmt::format("{0} (2op)", patchName); + writeOp(sbi_op12, opM6, opC6); + ins->fm.alg = (sbi_op12.FeedConnect & 0x1); + ins->fm.fb = ((sbi_op12.FeedConnect >> 1) & 0x7); + } // Ignore rest of file once we've read in all we need. // Note: Freq Monster 801 adds a ton of other additional fields irrelevant to chip registers. + // If instrument transpose is ever supported, we can read it in maybe? reader.seek(0, SEEK_END); + ret.push_back(ins); } } catch (EndOfFileException& e) { lastError = "premature end of file"; - logE("premature end of file!"); + logE("premature end of file"); delete ins; - return; + } +} +void DivEngine::loadBNK(SafeReader& reader, std::vector& ret, String& stripPath) { + std::vector insList; + std::vector instNames; + reader.seek(0, SEEK_SET); + + // First distinguish between GEMS BNK and Adlib BNK + uint64_t header = reader.readL(); + bool is_adlib = ((header>>8) == 0x2d42494c444100L); + bool is_failed = false; + int readCount = 0; + + if (is_adlib) { + try { + reader.seek(0x0c, SEEK_SET); + uint32_t name_offset = reader.readI(); + reader.seek(0x10, SEEK_SET); + uint32_t data_offset = reader.readI(); + + // Seek to BNK patch names + reader.seek(name_offset, SEEK_SET); + while (reader.tell() < data_offset) { + reader.seek(3, SEEK_CUR); + instNames.push_back(new String(reader.readString(9))); + ++readCount; + } + + // Seek to BNK data + reader.seek(data_offset, SEEK_SET); + + // Read until EOF + for (int i = 0; i < readCount; ++i) { + bnktimbre_t timbre; + insList.push_back(new DivInstrument); + auto& ins = insList[i]; + + ins->type = DIV_INS_OPL; + + timbre.mode = reader.readC(); + timbre.percVoice = reader.readC(); + if (timbre.mode == 1) { + ins->fm.opllPreset = (uint8_t)(1<<4); + } + ins->fm.op[0].ksl = reader.readC(); + ins->fm.op[0].mult = reader.readC(); + ins->fm.fb = reader.readC(); + ins->fm.op[0].ar = reader.readC(); + ins->fm.op[0].sl = reader.readC(); + ins->fm.op[0].sus = (reader.readC() != 0) ? 1 : 0; + ins->fm.op[0].dr = reader.readC(); + ins->fm.op[0].rr = reader.readC(); + ins->fm.op[0].tl = reader.readC(); + ins->fm.op[0].am = reader.readC(); + ins->fm.op[0].vib = reader.readC(); + ins->fm.op[0].ksr = reader.readC(); + ins->fm.alg = (reader.readC() == 0) ? 1 : 0; + + ins->fm.op[1].ksl = reader.readC(); + ins->fm.op[1].mult = reader.readC(); + reader.readC(); // skip + ins->fm.op[1].ar = reader.readC(); + ins->fm.op[1].sl = reader.readC(); + ins->fm.op[1].sus = (reader.readC() != 0) ? 1 : 0; + ins->fm.op[1].dr = reader.readC(); + ins->fm.op[1].rr = reader.readC(); + ins->fm.op[1].tl = reader.readC(); + ins->fm.op[1].am = reader.readC(); + ins->fm.op[1].vib = reader.readC(); + ins->fm.op[1].ksr = reader.readC(); + reader.readC(); // skip + + ins->fm.op[0].ws = reader.readC(); + ins->fm.op[1].ws = reader.readC(); + ins->name = instNames[i]->length() > 0 ? (*instNames[i]) : fmt::format("{0}[{1}]", stripPath, i); + } + reader.seek(0, SEEK_END); + + } catch (EndOfFileException& e) { + lastError = "premature end of file"; + logE("premature end of file"); + for (int i = readCount; i >= 0; --i) { + delete insList[i]; + } + is_failed = true; + } + + } else { + // assume GEMS BNK for now. + lastError = "GEMS BNK currently not supported."; + logE("GEMS BNK currently not supported."); } - ret.push_back(ins); + if (!is_failed) { + for (int i = 0; i < readCount; ++i) { + ret.push_back(insList[i]); + } + } + + for (auto& name : instNames) { + delete name; + } } void DivEngine::loadFF(SafeReader& reader, std::vector& ret, String& stripPath) { @@ -693,7 +797,7 @@ void DivEngine::loadFF(SafeReader& reader, std::vector& ret, Str } } catch (EndOfFileException& e) { lastError = "premature end of file"; - logE("premature end of file!\n"); + logE("premature end of file"); for (int i = readCount; i >= 0; --i) { delete insList[i]; } @@ -714,7 +818,7 @@ void DivEngine::loadOPM(SafeReader& reader, std::vector& ret, St } catch (EndOfFileException& e) { lastError="premature end of file"; - logE("premature end of file!"); + logE("premature end of file"); return; } } @@ -812,7 +916,7 @@ std::vector DivEngine::instrumentFromFile(const char* path) { } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE("premature end of file!"); + logE("premature end of file"); delete ins; delete[] buf; return ret; @@ -843,6 +947,8 @@ std::vector DivEngine::instrumentFromFile(const char* path) { format=DIV_INSFORMAT_S3I; } else if (extS==String(".sbi")) { format=DIV_INSFORMAT_SBI; + } else if (extS==String(".bnk")) { + format=DIV_INSFORMAT_BNK; } else if (extS==String(".opm")) { format=DIV_INSFORMAT_OPM; } else if (extS==String(".ff")) { @@ -873,6 +979,9 @@ std::vector DivEngine::instrumentFromFile(const char* path) { case DIV_INSFORMAT_SBI: loadSBI(reader,ret,stripPath); break; + case DIV_INSFORMAT_BNK: + loadBNK(reader, ret, stripPath); + break; case DIV_INSFORMAT_FF: loadFF(reader,ret,stripPath); break; diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index efac0e482..7817c060e 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -713,10 +713,10 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { bool writeDACSamples=false; bool writeNESSamples=false; bool writePCESamples=false; - bool writeADPCM=false; - bool writeSegaPCM=false; - bool writeX1010=false; - bool writeQSound=false; + int writeADPCM=0; + int writeSegaPCM=0; + int writeX1010=0; + int writeQSound=0; for (int i=0; ichipClock; willExport[i]=true; - writeX1010=true; + writeX1010=1; } else if (!(hasX1&0x40000000)) { isSecond[i]=true; willExport[i]=true; + writeX1010=2; hasX1|=0x40000000; howManyChips++; } @@ -821,10 +823,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { if (!hasOPNB) { hasOPNB=disCont[i].dispatch->chipClock; willExport[i]=true; - writeADPCM=true; + writeADPCM=1; } else if (!(hasOPNB&0x40000000)) { isSecond[i]=true; willExport[i]=true; + writeADPCM=2; hasOPNB|=0x40000000; howManyChips++; } @@ -926,10 +929,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { // not be able to handle the 64kb sample bank trick hasQSound=disCont[i].dispatch->chipClock; willExport[i]=true; - writeQSound=true; + writeQSound=1; } else if (!(hasQSound&0x40000000)) { isSecond[i]=true; willExport[i]=false; + writeQSound=2; addWarning("dual QSound is not supported by the VGM format"); } break; @@ -1200,7 +1204,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { } } - if (writeSegaPCM) { + if (writeSegaPCM>0) { unsigned char* pcmMem=new unsigned char[16777216]; size_t memPos=0; @@ -1232,60 +1236,70 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { if (memPos>=16777216) break; } - w->writeC(0x67); - w->writeC(0x66); - w->writeC(0x80); - w->writeI(memPos+8); - w->writeI(memPos); - w->writeI(0); - w->write(pcmMem,memPos); + for (int i=0; iwriteC(0x67); + w->writeC(0x66); + w->writeC(0x80); + w->writeI((memPos+8)|(i*0x80000000)); + w->writeI(memPos); + w->writeI(0); + w->write(pcmMem,memPos); + } delete[] pcmMem; } - if (writeADPCM && adpcmAMemLen>0) { - w->writeC(0x67); - w->writeC(0x66); - w->writeC(0x82); - w->writeI(adpcmAMemLen+8); - w->writeI(adpcmAMemLen); - w->writeI(0); - w->write(adpcmAMem,adpcmAMemLen); + if (adpcmAMemLen>0) { + for (int i=0; iwriteC(0x67); + w->writeC(0x66); + w->writeC(0x82); + w->writeI((adpcmAMemLen+8)|(i*0x80000000)); + w->writeI(adpcmAMemLen); + w->writeI(0); + w->write(adpcmAMem,adpcmAMemLen); + } } - if (writeADPCM && adpcmBMemLen>0) { - w->writeC(0x67); - w->writeC(0x66); - w->writeC(0x83); - w->writeI(adpcmBMemLen+8); - w->writeI(adpcmBMemLen); - w->writeI(0); - w->write(adpcmBMem,adpcmBMemLen); + if (adpcmBMemLen>0) { + for (int i=0; iwriteC(0x67); + w->writeC(0x66); + w->writeC(0x83); + w->writeI((adpcmBMemLen+8)|(i*0x80000000)); + w->writeI(adpcmBMemLen); + w->writeI(0); + w->write(adpcmBMem,adpcmBMemLen); + } } - if (writeQSound && qsoundMemLen>0) { + if (qsoundMemLen>0) { // always write a whole bank unsigned int blockSize=(qsoundMemLen+0xffff)&(~0xffff); if (blockSize > 0x1000000) { blockSize = 0x1000000; } - w->writeC(0x67); - w->writeC(0x66); - w->writeC(0x8F); - w->writeI(blockSize+8); - w->writeI(0x1000000); - w->writeI(0); - w->write(qsoundMem,blockSize); + for (int i=0; iwriteC(0x67); + w->writeC(0x66); + w->writeC(0x8F); + w->writeI((blockSize+8)|(i*0x80000000)); + w->writeI(0x1000000); + w->writeI(0); + w->write(qsoundMem,blockSize); + } } - if (writeX1010 && x1_010MemLen>0) { - w->writeC(0x67); - w->writeC(0x66); - w->writeC(0x91); - w->writeI(x1_010MemLen+8); - w->writeI(x1_010MemLen); - w->writeI(0); - w->write(x1_010Mem,x1_010MemLen); + if (x1_010MemLen>0) { + for (int i=0; iwriteC(0x67); + w->writeC(0x66); + w->writeC(0x91); + w->writeI((x1_010MemLen+8)|(i*0x80000000)); + w->writeI(x1_010MemLen); + w->writeI(0); + w->write(x1_010Mem,x1_010MemLen); + } } // initialize streams diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index b2d1e5c94..7f8f0d729 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1235,9 +1235,9 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) { if (!dirExists(workingDirIns)) workingDirIns=getHomeDir(); hasOpened=fileDialog->openLoad( "Load Instrument", - {"compatible files", "*.fui *.dmp *.tfi *.vgi *.s3i *.sbi *.ff", + {"compatible files", "*.fui *.dmp *.tfi *.vgi *.s3i *.sbi *.bnk *.ff", "all files", ".*"}, - "compatible files{.fui,.dmp,.tfi,.vgi,.s3i,.sbi,.ff},.*", + "compatible files{.fui,.dmp,.tfi,.vgi,.s3i,.sbi,.bnk,.ff},.*", workingDirIns, dpiScale ); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 5e0bdbad6..be0805f3a 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -2476,6 +2476,7 @@ 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,".bnk",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);