From ee14f0fa8c27e531631e817668a31be48f4de688 Mon Sep 17 00:00:00 2001 From: James Alan Nguyen Date: Tue, 12 Apr 2022 21:07:21 +1000 Subject: [PATCH 01/77] SBI fixes: - Support 2OP\x1A header (used in some third party implementations) - Include 2op pair for Freq Monster 801 6op (4+2op) patches. - Fall back to filename if no internal patch name found. --- src/engine/fileOpsIns.cpp | 71 +++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index af0c06d83..b8978f2a6 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -447,6 +447,8 @@ void DivEngine::loadS3I(SafeReader& reader, std::vector& ret, St logE("S3I PCM samples currently not supported."); } ins->name = reader.readString(28); + ins->name = (ins->name[0] == '\0') ? stripPath : ins->name; + int s3i_signature = reader.readI(); if (s3i_signature != 0x49524353) { @@ -470,12 +472,13 @@ 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(); @@ -502,11 +505,13 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St uint8_t sbi_M4wave; uint8_t sbi_C4wave; uint8_t sbi_4opConnect; - + if (is_2op) { DivInstrumentFM::Operator& opM = ins->fm.op[0]; DivInstrumentFM::Operator& opC = ins->fm.op[1]; ins->fm.ops = 2; + ins->name = patchName; + opM.mult = sbi_Mcharacteristics & 0xF; opM.ksr = ((sbi_Mcharacteristics >> 4) & 0x1); opM.sus = ((sbi_Mcharacteristics >> 5) & 0x1); @@ -538,6 +543,7 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St // Ignore rest of file - rest is 'reserved padding'. reader.seek(0, SEEK_END); + ret.push_back(ins); } if (is_4op || is_6op) { @@ -549,6 +555,7 @@ 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; sbi_M4characteristics = reader.readC(); sbi_C4characteristics = reader.readC(); @@ -617,19 +624,71 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St opC4.sl = ((sbi_C4eg_SR >> 4) & 0xF); opC4.ws = sbi_C4wave; + // Freq Monster 801 SBIs use a 4op+2op layout + if (is_6op) { + ins->name = ins->name + " (4op)"; + ret.push_back(ins); + + 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 = patchName + " (2op)"; + + 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(); + + opM6.mult = sbi_Mcharacteristics & 0xF; + opM6.ksr = ((sbi_Mcharacteristics >> 4) & 0x1); + opM6.sus = ((sbi_Mcharacteristics >> 5) & 0x1); + opM6.vib = ((sbi_Mcharacteristics >> 6) & 0x1); + opM6.am = ((sbi_Mcharacteristics >> 7) & 0x1); + opM6.tl = sbi_Mscaling_output & 0x3F; + opM6.ksl = ((sbi_Mscaling_output >> 6) & 0x3); + opM6.ar = ((sbi_Meg_AD >> 4) & 0xF); + opM6.dr = (sbi_Meg_AD & 0xF); + opM6.rr = (sbi_Meg_SR & 0xF); + opM6.sl = ((sbi_Meg_SR >> 4) & 0xF); + opM6.ws = sbi_Mwave; + + ins->fm.alg = (sbi_FeedConnect & 0x1); + ins->fm.fb = ((sbi_FeedConnect >> 1) & 0x7); + + opC6.mult = sbi_Ccharacteristics & 0xF; + opC6.ksr = ((sbi_Ccharacteristics >> 4) & 0x1); + opC6.sus = ((sbi_Ccharacteristics >> 5) & 0x1); + opC6.vib = ((sbi_Ccharacteristics >> 6) & 0x1); + opC6.am = ((sbi_Ccharacteristics >> 7) & 0x1); + opC6.tl = sbi_Cscaling_output & 0x3F; + opC6.ksl = ((sbi_Cscaling_output >> 6) & 0x3); + opC6.ar = ((sbi_Ceg_AD >> 4) & 0xF); + opC6.dr = (sbi_Ceg_AD & 0xF); + opC6.rr = (sbi_Ceg_SR & 0xF); + opC6.sl = ((sbi_Ceg_SR >> 4) & 0xF); + opC6.ws = sbi_Cwave; + } + // 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. reader.seek(0, SEEK_END); + ret.push_back(ins); } } catch (EndOfFileException& e) { lastError = "premature end of file"; logE("premature end of file!"); delete ins; - return; } - - ret.push_back(ins); } void DivEngine::loadFF(SafeReader& reader, std::vector& ret, String& stripPath) { From 29ed73a1577de8f136623e07f206519935216840 Mon Sep 17 00:00:00 2001 From: James Alan Nguyen Date: Thu, 14 Apr 2022 21:33:20 +1000 Subject: [PATCH 02/77] Start BNK --- src/engine/engine.h | 1 + src/engine/fileOpsIns.cpp | 30 ++++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 6bcaa38c9..d7860f37f 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 b8978f2a6..9be3f02cf 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -30,6 +30,7 @@ enum DivInsFormats { DIV_INSFORMAT_BTI, DIV_INSFORMAT_S3I, DIV_INSFORMAT_SBI, + DIV_INSFORMAT_BNK, DIV_INSFORMAT_OPM, DIV_INSFORMAT_FF, }; @@ -447,7 +448,7 @@ void DivEngine::loadS3I(SafeReader& reader, std::vector& ret, St logE("S3I PCM samples currently not supported."); } ins->name = reader.readString(28); - ins->name = (ins->name[0] == '\0') ? stripPath : ins->name; + ins->name = (ins->name.length() == 0) ? stripPath : ins->name; int s3i_signature = reader.readI(); @@ -544,9 +545,8 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St // Ignore rest of file - rest is 'reserved padding'. reader.seek(0, SEEK_END); ret.push_back(ins); - } - if (is_4op || is_6op) { + } else if (is_4op || is_6op) { // 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. @@ -624,8 +624,9 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St opC4.sl = ((sbi_C4eg_SR >> 4) & 0xF); opC4.ws = sbi_C4wave; - // Freq Monster 801 SBIs use a 4op+2op layout if (is_6op) { + // Freq Monster 801 6op SBIs use a 4+2op layout + // Save the 4op portion before reading the 2op part ins->name = ins->name + " (4op)"; ret.push_back(ins); @@ -680,6 +681,7 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St // 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); } @@ -690,6 +692,22 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St delete ins; } } +void DivEngine::loadBNK(SafeReader& reader, std::vector& ret, String& stripPath) { + DivInstrument* insList[256]; + memset(insList, 0, 256 * sizeof(void*)); + + // First distinguish between GEMS BNK and Adlib BNK + bool is_gems = false; // TODO + bool is_adlib = true; // TODO + + if (is_gems) { + logE("GEMS BNK currently not supported."); + + } else if (is_adlib) { + // TODO + } +} + void DivEngine::loadFF(SafeReader& reader, std::vector& ret, String& stripPath) { DivInstrument* insList[256]; @@ -902,6 +920,8 @@ std::vector DivEngine::instrumentFromFile(const char* path) { format=DIV_INSFORMAT_S3I; } else if (extS==String(".sbi")) { format=DIV_INSFORMAT_SBI; + } else if (ext5==String(".bnk")) { + format=DIV_INSFORMAT_BNK; } else if (extS==String(".opm")) { format=DIV_INSFORMAT_OPM; } else if (extS==String(".ff")) { @@ -932,6 +952,8 @@ std::vector DivEngine::instrumentFromFile(const char* path) { case DIV_INSFORMAT_SBI: loadSBI(reader,ret,stripPath); break; + case DIV_INSFORMAT_BNK: + loadBNK(reader, ret, stripPath); case DIV_INSFORMAT_FF: loadFF(reader,ret,stripPath); break; From 7e692eb0735d13072ff83c3d76e9a6504903972c Mon Sep 17 00:00:00 2001 From: James Alan Nguyen Date: Fri, 15 Apr 2022 00:32:55 +1000 Subject: [PATCH 03/77] Checkpoint: BNK presets now loading and also refactoring duplicated operations. --- src/engine/fileOpsIns.cpp | 378 +++++++++++++++++++++----------------- 1 file changed, 207 insertions(+), 171 deletions(-) diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index 9be3f02cf..7d2dda373 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -391,6 +391,9 @@ 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); @@ -481,72 +484,89 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St 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(); + typedef struct { + uint8_t Mcharacteristics, + Ccharacteristics, + Mscaling_output, + Cscaling_output, + Meg_AD, + Ceg_AD, + Meg_SR, + Ceg_SR, + Mwave, + Cwave, + FeedConnect; + } sbi_t; - // 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; + 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(); + }; + + 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; + + 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; ins->name = patchName; + writeOp(sbi_op12, opM, opC); + ins->fm.alg = (sbi_op12.FeedConnect & 0x1); + ins->fm.fb = ((sbi_op12.FeedConnect >> 1) & 0x7); - 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->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); } 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. @@ -556,127 +576,28 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St DivInstrumentFM::Operator& opC4 = ins->fm.op[3]; ins->fm.ops = 4; ins->name = patchName; - - 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); - - 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; - - 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->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); if (is_6op) { // Freq Monster 801 6op SBIs use a 4+2op layout // Save the 4op portion before reading the 2op part - ins->name = ins->name + " (4op)"; + ins->name = fmt::format("{0} (4op)", ins->name); ret.push_back(ins); + readSbiOpData(sbi_op12, reader); + 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 = patchName + " (2op)"; - - 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(); - - opM6.mult = sbi_Mcharacteristics & 0xF; - opM6.ksr = ((sbi_Mcharacteristics >> 4) & 0x1); - opM6.sus = ((sbi_Mcharacteristics >> 5) & 0x1); - opM6.vib = ((sbi_Mcharacteristics >> 6) & 0x1); - opM6.am = ((sbi_Mcharacteristics >> 7) & 0x1); - opM6.tl = sbi_Mscaling_output & 0x3F; - opM6.ksl = ((sbi_Mscaling_output >> 6) & 0x3); - opM6.ar = ((sbi_Meg_AD >> 4) & 0xF); - opM6.dr = (sbi_Meg_AD & 0xF); - opM6.rr = (sbi_Meg_SR & 0xF); - opM6.sl = ((sbi_Meg_SR >> 4) & 0xF); - opM6.ws = sbi_Mwave; - - ins->fm.alg = (sbi_FeedConnect & 0x1); - ins->fm.fb = ((sbi_FeedConnect >> 1) & 0x7); - - opC6.mult = sbi_Ccharacteristics & 0xF; - opC6.ksr = ((sbi_Ccharacteristics >> 4) & 0x1); - opC6.sus = ((sbi_Ccharacteristics >> 5) & 0x1); - opC6.vib = ((sbi_Ccharacteristics >> 6) & 0x1); - opC6.am = ((sbi_Ccharacteristics >> 7) & 0x1); - opC6.tl = sbi_Cscaling_output & 0x3F; - opC6.ksl = ((sbi_Cscaling_output >> 6) & 0x3); - opC6.ar = ((sbi_Ceg_AD >> 4) & 0xF); - opC6.dr = (sbi_Ceg_AD & 0xF); - opC6.rr = (sbi_Ceg_SR & 0xF); - opC6.sl = ((sbi_Ceg_SR >> 4) & 0xF); - opC6.ws = sbi_Cwave; + 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. @@ -694,18 +615,133 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St } void DivEngine::loadBNK(SafeReader& reader, std::vector& ret, String& stripPath) { DivInstrument* insList[256]; + String instNames[256]; memset(insList, 0, 256 * sizeof(void*)); + reader.seek(0, SEEK_SET); // First distinguish between GEMS BNK and Adlib BNK - bool is_gems = false; // TODO - bool is_adlib = true; // TODO + uint64_t header = reader.readL(); + bool is_adlib = ((header>>8) == 0x2d42494c444100L); + + if (is_adlib) { + // Caveat: Technically Adlib BNK can hold up to 0xFFFF instruments, + // but Furnace only can handle up to 0xFF. + + typedef struct { + uint8_t ksl, + multiple, + feedback, // op1 only + attack, + sustain, + eg, + decay, + releaseRate, + totalLevel, + am, + vib, + ksr, + con; // op1 only + } bnkop_t; - if (is_gems) { - logE("GEMS BNK currently not supported."); + typedef struct { + uint8_t mode, // version + percVoice; // perc + bnkop_t op[2]; + uint8_t wave0, // wave op1 + wave1; // wave op2 + } bnktimbre_t; - } else if (is_adlib) { - // TODO - } + int readCount = 0; + + try { + // Seek to BNK patch names + reader.seek(0x0c, SEEK_SET); + int name_offset = reader.readI(); + reader.seek(0x10, SEEK_SET); + int data_offset = reader.readI(); + + reader.seek(name_offset, SEEK_SET); + + while (readCount < 256 && reader.tell() < data_offset) { + reader.seek(3, SEEK_CUR); + instNames[readCount] = reader.readString(9); + ++readCount; + } + + if (readCount >= 256) { + logW("BNK exceeds 256 presets. Only first 256 will be imported.\n"); + } + + // Seek to BNK data + reader.seek(data_offset, SEEK_SET); + + // Read until EOF + for (int i = 0; i < readCount && i < 256; ++i) { + try { + bnktimbre_t timbre; + insList[i] = 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].ksr = reader.readC(); + 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].ksr = reader.readC(); + 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); + + ret.push_back(insList[i]); + } catch (EndOfFileException& e) { + // Reached end of BNK data + delete insList[i]; + break; + } + } + } 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; + } + + } else { + // assume GEMS BNK for now. + lastError = "GEMS BNK currently not supported.\n"; + logE("GEMS BNK currently not supported.\n"); + } } @@ -920,7 +956,7 @@ std::vector DivEngine::instrumentFromFile(const char* path) { format=DIV_INSFORMAT_S3I; } else if (extS==String(".sbi")) { format=DIV_INSFORMAT_SBI; - } else if (ext5==String(".bnk")) { + } else if (extS==String(".bnk")) { format=DIV_INSFORMAT_BNK; } else if (extS==String(".opm")) { format=DIV_INSFORMAT_OPM; From c431add35b4b42a4b14fc2e999b8178c973397ff Mon Sep 17 00:00:00 2001 From: James Alan Nguyen Date: Fri, 15 Apr 2022 00:42:05 +1000 Subject: [PATCH 04/77] BNK - Fix sustain flag --- src/engine/fileOpsIns.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index 7d2dda373..1338b7965 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -694,7 +694,7 @@ void DivEngine::loadBNK(SafeReader& reader, std::vector& ret, St ins->fm.fb = reader.readC(); ins->fm.op[0].ar = reader.readC(); ins->fm.op[0].sl = reader.readC(); - ins->fm.op[0].ksr = 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(); @@ -708,7 +708,7 @@ void DivEngine::loadBNK(SafeReader& reader, std::vector& ret, St reader.readC(); // skip ins->fm.op[1].ar = reader.readC(); ins->fm.op[1].sl = reader.readC(); - ins->fm.op[1].ksr = 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(); From 1985546d0b23059aaca88b5e3018c1d98e033c9b Mon Sep 17 00:00:00 2001 From: James Alan Nguyen Date: Fri, 15 Apr 2022 00:46:26 +1000 Subject: [PATCH 05/77] Add file extension to picker --- src/gui/gui.cpp | 4 ++-- src/gui/settings.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index ba83b8654..bdee56563 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1303,9 +1303,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 f4d62a81d..d9495f976 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -2437,6 +2437,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); From c3b393004d4915187b23cd87e258bc7bd80db05a Mon Sep 17 00:00:00 2001 From: James Alan Nguyen Date: Fri, 15 Apr 2022 00:57:24 +1000 Subject: [PATCH 06/77] Fix for -Werror o/ o/ o/ --- buildme.bat | 6 ++++++ src/engine/fileOpsIns.cpp | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 buildme.bat diff --git a/buildme.bat b/buildme.bat new file mode 100644 index 000000000..239d4fe06 --- /dev/null +++ b/buildme.bat @@ -0,0 +1,6 @@ +@echo off +git pull +git submodule update --init --recursive +cmake -Bbuild +cmake --build build --target ALL_BUILD --config Release --parallel 12 +copy build\Release\furnace.exe \Apps\Audio\Furnace\ diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index 1338b7965..4556e5a8b 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -656,9 +656,9 @@ void DivEngine::loadBNK(SafeReader& reader, std::vector& ret, St try { // Seek to BNK patch names reader.seek(0x0c, SEEK_SET); - int name_offset = reader.readI(); + uint32_t name_offset = reader.readI(); reader.seek(0x10, SEEK_SET); - int data_offset = reader.readI(); + uint32_t data_offset = reader.readI(); reader.seek(name_offset, SEEK_SET); @@ -990,6 +990,7 @@ std::vector DivEngine::instrumentFromFile(const char* path) { break; case DIV_INSFORMAT_BNK: loadBNK(reader, ret, stripPath); + break; case DIV_INSFORMAT_FF: loadFF(reader,ret,stripPath); break; From 2dc80e8d8ed859f1fa046b21b1faf498eed3940a Mon Sep 17 00:00:00 2001 From: James Alan Nguyen Date: Fri, 15 Apr 2022 01:07:11 +1000 Subject: [PATCH 07/77] Batch file wasn't supposed to be there --- buildme.bat | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 buildme.bat diff --git a/buildme.bat b/buildme.bat deleted file mode 100644 index 239d4fe06..000000000 --- a/buildme.bat +++ /dev/null @@ -1,6 +0,0 @@ -@echo off -git pull -git submodule update --init --recursive -cmake -Bbuild -cmake --build build --target ALL_BUILD --config Release --parallel 12 -copy build\Release\furnace.exe \Apps\Audio\Furnace\ From c3ca175e4635b683975416746fa6e06e6af044f9 Mon Sep 17 00:00:00 2001 From: James Alan Nguyen Date: Fri, 15 Apr 2022 11:57:57 +1000 Subject: [PATCH 08/77] Nitpicky cruft cleanup. --- src/engine/fileOpsIns.cpp | 125 +++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 63 deletions(-) diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index 4556e5a8b..2391f2a1a 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -448,7 +448,8 @@ void DivEngine::loadS3I(SafeReader& reader, std::vector& ret, St // Skip more stuff we don't need reader.seek(21, SEEK_CUR); } else { - logE("S3I PCM samples currently not supported."); + lastError = "S3I PCM samples currently not supported."; + logE("S3I PCM samples currently not supported.\n"); } ins->name = reader.readString(28); ins->name = (ins->name.length() == 0) ? stripPath : ins->name; @@ -456,7 +457,8 @@ void DivEngine::loadS3I(SafeReader& reader, std::vector& ret, St int s3i_signature = reader.readI(); if (s3i_signature != 0x49524353) { - logW("S3I signature invalid."); + lastError = "S3I signature invalid."; + logW("S3I signature invalid.\n"); }; } catch (EndOfFileException& e) { lastError = "premature end of file"; @@ -622,7 +624,8 @@ void DivEngine::loadBNK(SafeReader& reader, std::vector& ret, St // First distinguish between GEMS BNK and Adlib BNK uint64_t header = reader.readL(); bool is_adlib = ((header>>8) == 0x2d42494c444100L); - + int readCount = 0; + if (is_adlib) { // Caveat: Technically Adlib BNK can hold up to 0xFFFF instruments, // but Furnace only can handle up to 0xFF. @@ -644,90 +647,82 @@ void DivEngine::loadBNK(SafeReader& reader, std::vector& ret, St } bnkop_t; typedef struct { - uint8_t mode, // version - percVoice; // perc + uint8_t mode, + percVoice; bnkop_t op[2]; - uint8_t wave0, // wave op1 - wave1; // wave op2 + uint8_t wave0, + wave1; } bnktimbre_t; - int readCount = 0; - try { - // Seek to BNK patch names 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 (readCount < 256 && reader.tell() < data_offset) { + while (reader.tell() < data_offset) { + if (readCount >= 256) { + lastError = "BNK exceeds 256 presets. Only first 256 will be imported."; + logW("BNK exceeds 256 presets. Only first 256 will be imported.\n"); + break; + } reader.seek(3, SEEK_CUR); instNames[readCount] = reader.readString(9); ++readCount; } - if (readCount >= 256) { - logW("BNK exceeds 256 presets. Only first 256 will be imported.\n"); - } - // Seek to BNK data reader.seek(data_offset, SEEK_SET); // Read until EOF for (int i = 0; i < readCount && i < 256; ++i) { - try { - bnktimbre_t timbre; - insList[i] = new DivInstrument; - auto& ins = insList[i]; + bnktimbre_t timbre; + insList[i] = new DivInstrument; + auto& ins = insList[i]; - ins->type = DIV_INS_OPL; + 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); - - ret.push_back(insList[i]); - } catch (EndOfFileException& e) { - // Reached end of BNK data - delete insList[i]; - break; + 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!\n"); @@ -742,6 +737,10 @@ void DivEngine::loadBNK(SafeReader& reader, std::vector& ret, St lastError = "GEMS BNK currently not supported.\n"; logE("GEMS BNK currently not supported.\n"); } + + for (int i = 0; i < readCount; ++i) { + ret.push_back(insList[i]); + } } From eb70086234de1949c43c90efeeaa4216584099b5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 15 Apr 2022 14:38:13 -0500 Subject: [PATCH 09/77] sample 8-bit blep resample fix --- src/engine/sample.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/sample.cpp b/src/engine/sample.cpp index bd34daa5b..3aec450b0 100644 --- a/src/engine/sample.cpp +++ b/src/engine/sample.cpp @@ -587,8 +587,8 @@ bool DivSample::resampleSinc(double r) { result+=s[j]*t2[7-j]; result+=s[8+j]*t1[j]; } - if (result<-32768) result=-32768; - if (result>32767) result=32767; + if (result<-128) result=-128; + if (result>127) result=127; if (i>=8) { data8[i-8]=result; } From 45460df96d24c87fea90e58fe3d48a235c23e9f1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 15 Apr 2022 14:38:25 -0500 Subject: [PATCH 10/77] improve low-latency mode strategy --- src/engine/engine.cpp | 2 ++ src/engine/macroInt.cpp | 25 ++++++++++++++++--------- src/engine/macroInt.h | 11 ++++++----- src/engine/playback.cpp | 2 +- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 81d7947a7..6257ff537 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2237,6 +2237,8 @@ bool DivEngine::initAudioBackend() { if (metroVol<0.0f) metroVol=0.0f; if (metroVol>2.0f) metroVol=2.0f; + if (lowLatency) logI("using low latency mode."); + switch (audioEngine) { case DIV_AUDIO_JACK: #ifndef HAVE_JACK diff --git a/src/engine/macroInt.cpp b/src/engine/macroInt.cpp index ae6caf5df..00fee080e 100644 --- a/src/engine/macroInt.cpp +++ b/src/engine/macroInt.cpp @@ -21,14 +21,19 @@ #include "instrument.h" #include "engine.h" -void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released) { +void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tick) { + if (!tick) { + had=false; + return; + } if (finished) { finished=false; } - if (had!=has) { + if (actualHad!=has) { finished=true; } - had=has; + actualHad=has; + had=actualHad; if (has) { val=source.val[pos++]; if (source.rel>=0 && pos>source.rel && !released) { @@ -52,17 +57,18 @@ void DivMacroInt::next() { if (ins==NULL) return; // run macros // TODO: potentially get rid of list to avoid allocations - if (--subTick<=0) { + subTick--; + for (size_t i=0; idoMacro(*macroSource[i],released,subTick==0); + } + } + if (subTick<=0) { if (e==NULL) { subTick=1; } else { subTick=e->tickMult; } - for (size_t i=0; idoMacro(*macroSource[i],released); - } - } } } @@ -85,6 +91,7 @@ void DivMacroInt::init(DivInstrument* which) { if (macroList[i]!=NULL) macroList[i]->init(); } macroListLen=0; + subTick=1; released=false; diff --git a/src/engine/macroInt.h b/src/engine/macroInt.h index 886ecbe23..f1cd29a7e 100644 --- a/src/engine/macroInt.h +++ b/src/engine/macroInt.h @@ -27,17 +27,17 @@ class DivEngine; struct DivMacroStruct { int pos; int val; - bool has, had, finished, will; + bool has, had, actualHad, finished, will; unsigned int mode; - void doMacro(DivInstrumentMacro& source, bool released); + void doMacro(DivInstrumentMacro& source, bool released, bool tick); void init() { pos=mode=0; - has=had=will=false; + has=had=actualHad=will=false; // TODO: test whether this breaks anything? val=0; } void prepare(DivInstrumentMacro& source) { - has=had=will=true; + has=had=actualHad=will=true; mode=source.mode; } DivMacroStruct(): @@ -45,6 +45,7 @@ struct DivMacroStruct { val(0), has(false), had(false), + actualHad(false), finished(false), will(false), mode(0) {} @@ -128,7 +129,7 @@ class DivMacroInt { e(NULL), ins(NULL), macroListLen(0), - subTick(0), + subTick(1), released(false), vol(), arp(), diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index ea2213305..fe42c73af 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1654,7 +1654,7 @@ bool DivEngine::nextTick(bool noAccum) { } } - if (consoleMode) fprintf(stderr,"\x1b[2K> %d:%.2d:%.2d.%.2d %.2x/%.2x:%.3d/%.3d %4dcmd/s\x1b[G",totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000,curOrder,song.ordersLen,curRow,song.patLen,cmdsPerSecond); + if (consoleMode && subticks<=1) fprintf(stderr,"\x1b[2K> %d:%.2d:%.2d.%.2d %.2x/%.2x:%.3d/%.3d %4dcmd/s\x1b[G",totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000,curOrder,song.ordersLen,curRow,song.patLen,cmdsPerSecond); } if (haltOn==DIV_HALT_TICK) halted=true; From fd3d57b1cba942ded63d532c5db4f0ca3d378ace Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 15 Apr 2022 15:01:11 -0500 Subject: [PATCH 11/77] even more improvements to low-latency mode --- src/engine/dispatch.h | 3 ++- src/engine/platform/abstract.cpp | 2 +- src/engine/platform/amiga.cpp | 2 +- src/engine/platform/amiga.h | 2 +- src/engine/platform/arcade.cpp | 2 +- src/engine/platform/arcade.h | 2 +- src/engine/platform/ay.cpp | 2 +- src/engine/platform/ay.h | 2 +- src/engine/platform/ay8930.cpp | 2 +- src/engine/platform/ay8930.h | 2 +- src/engine/platform/bubsyswsg.cpp | 2 +- src/engine/platform/bubsyswsg.h | 2 +- src/engine/platform/c64.cpp | 16 +++++++++------- src/engine/platform/c64.h | 2 +- src/engine/platform/dummy.cpp | 10 ++++++---- src/engine/platform/dummy.h | 2 +- src/engine/platform/fds.cpp | 2 +- src/engine/platform/fds.h | 2 +- src/engine/platform/gb.cpp | 2 +- src/engine/platform/gb.h | 2 +- src/engine/platform/genesis.cpp | 2 +- src/engine/platform/genesis.h | 2 +- src/engine/platform/genesisext.cpp | 4 ++-- src/engine/platform/genesisext.h | 2 +- src/engine/platform/lynx.cpp | 2 +- src/engine/platform/lynx.h | 2 +- src/engine/platform/mmc5.cpp | 2 +- src/engine/platform/mmc5.h | 2 +- src/engine/platform/n163.cpp | 2 +- src/engine/platform/n163.h | 2 +- src/engine/platform/nes.cpp | 2 +- src/engine/platform/nes.h | 2 +- src/engine/platform/opl.cpp | 2 +- src/engine/platform/opl.h | 2 +- src/engine/platform/opll.cpp | 2 +- src/engine/platform/opll.h | 2 +- src/engine/platform/pce.cpp | 2 +- src/engine/platform/pce.h | 2 +- src/engine/platform/pcspkr.cpp | 2 +- src/engine/platform/pcspkr.h | 2 +- src/engine/platform/pet.cpp | 2 +- src/engine/platform/pet.h | 2 +- src/engine/platform/qsound.cpp | 2 +- src/engine/platform/qsound.h | 2 +- src/engine/platform/saa.cpp | 2 +- src/engine/platform/saa.h | 2 +- src/engine/platform/segapcm.cpp | 2 +- src/engine/platform/segapcm.h | 2 +- src/engine/platform/sms.cpp | 2 +- src/engine/platform/sms.h | 2 +- src/engine/platform/swan.cpp | 2 +- src/engine/platform/swan.h | 2 +- src/engine/platform/tia.cpp | 2 +- src/engine/platform/tia.h | 2 +- src/engine/platform/tx81z.cpp | 2 +- src/engine/platform/tx81z.h | 2 +- src/engine/platform/vera.cpp | 2 +- src/engine/platform/vera.h | 2 +- src/engine/platform/vic20.cpp | 2 +- src/engine/platform/vic20.h | 2 +- src/engine/platform/vrc6.cpp | 2 +- src/engine/platform/vrc6.h | 2 +- src/engine/platform/x1_010.cpp | 2 +- src/engine/platform/x1_010.h | 2 +- src/engine/platform/ym2610.cpp | 4 ++-- src/engine/platform/ym2610.h | 2 +- src/engine/platform/ym2610b.cpp | 4 ++-- src/engine/platform/ym2610b.h | 2 +- src/engine/platform/ym2610bext.cpp | 4 ++-- src/engine/platform/ym2610bext.h | 2 +- src/engine/platform/ym2610ext.cpp | 4 ++-- src/engine/platform/ym2610ext.h | 2 +- src/engine/playback.cpp | 2 +- src/engine/waveSynth.cpp | 4 ++++ src/engine/waveSynth.h | 3 ++- 75 files changed, 98 insertions(+), 88 deletions(-) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 37e36a2bf..c35ff919c 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -245,8 +245,9 @@ class DivDispatch { /** * ticks this dispatch. + * @param sysTick whether the engine has ticked (if not then this may be a sub-tick used in low-latency mode). */ - virtual void tick(); + virtual void tick(bool sysTick=true); /** * get the state of a channel. diff --git a/src/engine/platform/abstract.cpp b/src/engine/platform/abstract.cpp index b860f6808..343838e73 100644 --- a/src/engine/platform/abstract.cpp +++ b/src/engine/platform/abstract.cpp @@ -22,7 +22,7 @@ void DivDispatch::acquire(short* bufL, short* bufR, size_t start, size_t len) { } -void DivDispatch::tick() { +void DivDispatch::tick(bool sysTick) { } void* DivDispatch::getChanState(int chan) { diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index b8419d197..104e66d45 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -155,7 +155,7 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le } } -void DivPlatformAmiga::tick() { +void DivPlatformAmiga::tick(bool sysTick) { for (int i=0; i<4; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { diff --git a/src/engine/platform/amiga.h b/src/engine/platform/amiga.h index 8fbe8fec8..07c44ee7c 100644 --- a/src/engine/platform/amiga.h +++ b/src/engine/platform/amiga.h @@ -88,7 +88,7 @@ class DivPlatformAmiga: public DivDispatch { void* getChanState(int chan); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); bool isStereo(); bool keyOffAffectsArp(int ch); diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index a7ab53ec0..0bcb3b990 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -219,7 +219,7 @@ inline int hScale(int note) { return ((note/12)<<4)+(noteMap[note%12]); } -void DivPlatformArcade::tick() { +void DivPlatformArcade::tick(bool sysTick) { for (int i=0; i<8; i++) { chan[i].std.next(); diff --git a/src/engine/platform/arcade.h b/src/engine/platform/arcade.h index a6ec82c94..41af49e33 100644 --- a/src/engine/platform/arcade.h +++ b/src/engine/platform/arcade.h @@ -107,7 +107,7 @@ class DivPlatformArcade: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); void notifyInsChange(int ins); void setFlags(unsigned int flags); diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index e8a61b9ae..d3db4ba8b 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -172,7 +172,7 @@ void DivPlatformAY8910::updateOutSel(bool immediate) { } } -void DivPlatformAY8910::tick() { +void DivPlatformAY8910::tick(bool sysTick) { // PSG for (int i=0; i<3; i++) { chan[i].std.next(); diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index b1a3ea127..a78f21bc8 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -90,7 +90,7 @@ class DivPlatformAY8910: public DivDispatch { void flushWrites(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); void setFlags(unsigned int flags); bool isStereo(); diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 9f684a048..9fa39131c 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -187,7 +187,7 @@ const unsigned char regMode[3]={ 0x0d, 0x14, 0x15 }; -void DivPlatformAY8930::tick() { +void DivPlatformAY8930::tick(bool sysTick) { // PSG for (int i=0; i<3; i++) { chan[i].std.next(); diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index 6bd51bdcd..adbe0be87 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -78,7 +78,7 @@ class DivPlatformAY8930: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); void setFlags(unsigned int flags); bool isStereo(); diff --git a/src/engine/platform/bubsyswsg.cpp b/src/engine/platform/bubsyswsg.cpp index 4a80bf414..91f50d461 100644 --- a/src/engine/platform/bubsyswsg.cpp +++ b/src/engine/platform/bubsyswsg.cpp @@ -81,7 +81,7 @@ void DivPlatformBubSysWSG::updateWave(int ch) { } } -void DivPlatformBubSysWSG::tick() { +void DivPlatformBubSysWSG::tick(bool sysTick) { for (int i=0; i<2; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { diff --git a/src/engine/platform/bubsyswsg.h b/src/engine/platform/bubsyswsg.h index 6c0e2261e..2efcc4d98 100644 --- a/src/engine/platform/bubsyswsg.h +++ b/src/engine/platform/bubsyswsg.h @@ -67,7 +67,7 @@ class DivPlatformBubSysWSG: public DivDispatch { int getRegisterPoolDepth(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); bool isStereo(); bool keyOffAffectsArp(int ch); diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index db5ab46a6..4c3cc32e4 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -122,7 +122,7 @@ void DivPlatformC64::updateFilter() { rWrite(0x18,(filtControl<<4)|vol); } -void DivPlatformC64::tick() { +void DivPlatformC64::tick(bool sysTick) { for (int i=0; i<3; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { @@ -166,12 +166,14 @@ void DivPlatformC64::tick() { rWrite(i*7+2,chan[i].duty&0xff); rWrite(i*7+3,chan[i].duty>>8); } - if (chan[i].testWhen>0) { - if (--chan[i].testWhen<1) { - if (!chan[i].resetMask) { - rWrite(i*7+5,0); - rWrite(i*7+6,0); - rWrite(i*7+4,(chan[i].wave<<4)|8|(chan[i].ring<<2)|(chan[i].sync<<1)); + if (sysTick) { + if (chan[i].testWhen>0) { + if (--chan[i].testWhen<1) { + if (!chan[i].resetMask) { + rWrite(i*7+5,0); + rWrite(i*7+6,0); + rWrite(i*7+4,(chan[i].wave<<4)|8|(chan[i].ring<<2)|(chan[i].sync<<1)); + } } } } diff --git a/src/engine/platform/c64.h b/src/engine/platform/c64.h index e288940e5..f77e24b97 100644 --- a/src/engine/platform/c64.h +++ b/src/engine/platform/c64.h @@ -83,7 +83,7 @@ class DivPlatformC64: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); void setFlags(unsigned int flags); void notifyInsChange(int ins); diff --git a/src/engine/platform/dummy.cpp b/src/engine/platform/dummy.cpp index 308b83722..e751e3b6f 100644 --- a/src/engine/platform/dummy.cpp +++ b/src/engine/platform/dummy.cpp @@ -38,10 +38,12 @@ void DivPlatformDummy::muteChannel(int ch, bool mute) { isMuted[ch]=mute; } -void DivPlatformDummy::tick() { +void DivPlatformDummy::tick(bool sysTick) { for (unsigned char i=0; isampleAudio( bufL + start, bufR + start, len ); } -void DivPlatformLynx::tick() { +void DivPlatformLynx::tick(bool sysTick) { for (int i=0; i<4; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { diff --git a/src/engine/platform/lynx.h b/src/engine/platform/lynx.h index 536a874a8..61f6e67df 100644 --- a/src/engine/platform/lynx.h +++ b/src/engine/platform/lynx.h @@ -80,7 +80,7 @@ class DivPlatformLynx: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); bool isStereo(); bool keyOffAffectsArp(int ch); diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index a9f9bb796..3c7f3dcab 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -95,7 +95,7 @@ void DivPlatformMMC5::acquire(short* bufL, short* bufR, size_t start, size_t len } } -void DivPlatformMMC5::tick() { +void DivPlatformMMC5::tick(bool sysTick) { for (int i=0; i<2; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { diff --git a/src/engine/platform/mmc5.h b/src/engine/platform/mmc5.h index 6b364d5ad..02ca06e84 100644 --- a/src/engine/platform/mmc5.h +++ b/src/engine/platform/mmc5.h @@ -71,7 +71,7 @@ class DivPlatformMMC5: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); bool keyOffAffectsArp(int ch); float getPostAmp(); diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index a66157d9e..6a1eb60e0 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -214,7 +214,7 @@ void DivPlatformN163::updateWaveCh(int ch) { } } -void DivPlatformN163::tick() { +void DivPlatformN163::tick(bool sysTick) { for (int i=0; i<=chanMax; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { diff --git a/src/engine/platform/n163.h b/src/engine/platform/n163.h index 2f68d6c9d..38ebeace3 100644 --- a/src/engine/platform/n163.h +++ b/src/engine/platform/n163.h @@ -93,7 +93,7 @@ class DivPlatformN163: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); void setFlags(unsigned int flags); void notifyWaveChange(int wave); diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 4c65ce4f2..7e291446f 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -140,7 +140,7 @@ static unsigned char noiseTable[253]={ 15 }; -void DivPlatformNES::tick() { +void DivPlatformNES::tick(bool sysTick) { for (int i=0; i<4; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index 1dbb4411b..2cf2a8a15 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -72,7 +72,7 @@ class DivPlatformNES: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); bool keyOffAffectsArp(int ch); float getPostAmp(); diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index add3815c5..e73ca41e4 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -228,7 +228,7 @@ void DivPlatformOPL::acquire(short* bufL, short* bufR, size_t start, size_t len) //} } -void DivPlatformOPL::tick() { +void DivPlatformOPL::tick(bool sysTick) { for (int i=0; i>4))/15)|(((vol*(pan&15))/15)<<4); } -void DivPlatformSAA1099::tick() { +void DivPlatformSAA1099::tick(bool sysTick) { for (int i=0; i<6; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { diff --git a/src/engine/platform/saa.h b/src/engine/platform/saa.h index 8df44f616..0542ff513 100644 --- a/src/engine/platform/saa.h +++ b/src/engine/platform/saa.h @@ -90,7 +90,7 @@ class DivPlatformSAA1099: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); void setCore(DivSAACores core); void setFlags(unsigned int flags); diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index b2a8b3db8..97ff900ae 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -76,7 +76,7 @@ void DivPlatformSegaPCM::acquire(short* bufL, short* bufR, size_t start, size_t } } -void DivPlatformSegaPCM::tick() { +void DivPlatformSegaPCM::tick(bool sysTick) { for (int i=0; i<16; i++) { chan[i].std.next(); diff --git a/src/engine/platform/segapcm.h b/src/engine/platform/segapcm.h index b3c84cd3b..4b05c160c 100644 --- a/src/engine/platform/segapcm.h +++ b/src/engine/platform/segapcm.h @@ -78,7 +78,7 @@ class DivPlatformSegaPCM: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); void notifyInsChange(int ins); void setFlags(unsigned int flags); diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index a0f8abdda..acd2c0726 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -53,7 +53,7 @@ int DivPlatformSMS::acquireOne() { return v; } -void DivPlatformSMS::tick() { +void DivPlatformSMS::tick(bool sysTick) { for (int i=0; i<4; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { diff --git a/src/engine/platform/sms.h b/src/engine/platform/sms.h index b49a5e276..0aeb9e81a 100644 --- a/src/engine/platform/sms.h +++ b/src/engine/platform/sms.h @@ -63,7 +63,7 @@ class DivPlatformSMS: public DivDispatch { void* getChanState(int chan); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); bool keyOffAffectsArp(int ch); bool keyOffAffectsPorta(int ch); diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 30be897be..99d819b1f 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -141,7 +141,7 @@ void DivPlatformSwan::writeOutVol(int ch) { } } -void DivPlatformSwan::tick() { +void DivPlatformSwan::tick(bool sysTick) { unsigned char sndCtrl=(pcm?0x20:0)|(sweep?0x40:0)|((noise>0)?0x80:0); for (int i=0; i<4; i++) { chan[i].std.next(); diff --git a/src/engine/platform/swan.h b/src/engine/platform/swan.h index 610884b00..0f1643c53 100644 --- a/src/engine/platform/swan.h +++ b/src/engine/platform/swan.h @@ -77,7 +77,7 @@ class DivPlatformSwan: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); void notifyWaveChange(int wave); void notifyInsDeletion(void* ins); diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index 474cd00e3..dc6c607fe 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -84,7 +84,7 @@ unsigned char DivPlatformTIA::dealWithFreq(unsigned char shape, int base, int pi return 0; } -void DivPlatformTIA::tick() { +void DivPlatformTIA::tick(bool sysTick) { for (int i=0; i<2; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { diff --git a/src/engine/platform/tia.h b/src/engine/platform/tia.h index ea149ec34..3ec3c7f34 100644 --- a/src/engine/platform/tia.h +++ b/src/engine/platform/tia.h @@ -51,7 +51,7 @@ class DivPlatformTIA: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); void setFlags(unsigned int flags); bool isStereo(); diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 34b975dd0..6f71be755 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -183,7 +183,7 @@ inline int hScale(int note) { return ((note/12)<<4)+(noteMap[note%12]); } -void DivPlatformTX81Z::tick() { +void DivPlatformTX81Z::tick(bool sysTick) { for (int i=0; i<8; i++) { chan[i].std.next(); diff --git a/src/engine/platform/tx81z.h b/src/engine/platform/tx81z.h index 363d5c234..c61b4bfe7 100644 --- a/src/engine/platform/tx81z.h +++ b/src/engine/platform/tx81z.h @@ -102,7 +102,7 @@ class DivPlatformTX81Z: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); void notifyInsChange(int ins); void setFlags(unsigned int flags); diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 7e887be80..31d52569a 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -156,7 +156,7 @@ int DivPlatformVERA::calcNoteFreq(int ch, int note) { } } -void DivPlatformVERA::tick() { +void DivPlatformVERA::tick(bool sysTick) { for (int i=0; i<16; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { diff --git a/src/engine/platform/vera.h b/src/engine/platform/vera.h index 2b47f99a7..ec6dcde11 100644 --- a/src/engine/platform/vera.h +++ b/src/engine/platform/vera.h @@ -63,7 +63,7 @@ class DivPlatformVERA: public DivDispatch { unsigned char* getRegisterPool(); int getRegisterPoolSize(); void reset(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); void notifyInsDeletion(void* ins); float getPostAmp(); diff --git a/src/engine/platform/vic20.cpp b/src/engine/platform/vic20.cpp index b3062a630..7817cd839 100644 --- a/src/engine/platform/vic20.cpp +++ b/src/engine/platform/vic20.cpp @@ -91,7 +91,7 @@ void DivPlatformVIC20::writeOutVol(int ch) { } } -void DivPlatformVIC20::tick() { +void DivPlatformVIC20::tick(bool sysTick) { for (int i=0; i<4; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { diff --git a/src/engine/platform/vic20.h b/src/engine/platform/vic20.h index 1c4d384b7..7948c5ef2 100644 --- a/src/engine/platform/vic20.h +++ b/src/engine/platform/vic20.h @@ -66,7 +66,7 @@ class DivPlatformVIC20: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); void setFlags(unsigned int flags); void notifyInsDeletion(void* ins); diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index b126deb6e..048b42cdb 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -135,7 +135,7 @@ void DivPlatformVRC6::acquire(short* bufL, short* bufR, size_t start, size_t len } } -void DivPlatformVRC6::tick() { +void DivPlatformVRC6::tick(bool sysTick) { for (int i=0; i<3; i++) { // 16 for pulse; 14 for saw int CHIP_DIVIDER=(i==2)?14:16; diff --git a/src/engine/platform/vrc6.h b/src/engine/platform/vrc6.h index 05cd89415..d28265a47 100644 --- a/src/engine/platform/vrc6.h +++ b/src/engine/platform/vrc6.h @@ -82,7 +82,7 @@ class DivPlatformVRC6: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); bool keyOffAffectsArp(int ch); void setFlags(unsigned int flags); diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index 1bbd2a809..df6682adb 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -336,7 +336,7 @@ void DivPlatformX1_010::updateEnvelope(int ch) { } } -void DivPlatformX1_010::tick() { +void DivPlatformX1_010::tick(bool sysTick) { for (int i=0; i<16; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { diff --git a/src/engine/platform/x1_010.h b/src/engine/platform/x1_010.h index 2bfb78cc9..bee546473 100644 --- a/src/engine/platform/x1_010.h +++ b/src/engine/platform/x1_010.h @@ -126,7 +126,7 @@ class DivPlatformX1_010: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); bool isStereo(); bool keyOffAffectsArp(int ch); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index a1f5ea658..3d6c8ed29 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -365,9 +365,9 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l } } -void DivPlatformYM2610::tick() { +void DivPlatformYM2610::tick(bool sysTick) { // PSG - ay->tick(); + ay->tick(sysTick); ay->flushWrites(); for (DivRegWrite& i: ay->getRegisterWrites()) { immWrite(i.addr&15,i.val); diff --git a/src/engine/platform/ym2610.h b/src/engine/platform/ym2610.h index 2fd525b08..e75e24d79 100644 --- a/src/engine/platform/ym2610.h +++ b/src/engine/platform/ym2610.h @@ -116,7 +116,7 @@ class DivPlatformYM2610: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); bool isStereo(); bool keyOffAffectsArp(int ch); diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 130eb29a2..aeadeae47 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -429,9 +429,9 @@ void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t } } -void DivPlatformYM2610B::tick() { +void DivPlatformYM2610B::tick(bool sysTick) { // PSG - ay->tick(); + ay->tick(sysTick); ay->flushWrites(); for (DivRegWrite& i: ay->getRegisterWrites()) { immWrite(i.addr&15,i.val); diff --git a/src/engine/platform/ym2610b.h b/src/engine/platform/ym2610b.h index d6b616c50..6d46ecb26 100644 --- a/src/engine/platform/ym2610b.h +++ b/src/engine/platform/ym2610b.h @@ -107,7 +107,7 @@ class DivPlatformYM2610B: public DivDispatch { int getRegisterPoolSize(); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); bool isStereo(); bool keyOffAffectsArp(int ch); diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index 03e9f8699..496a308e0 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -212,7 +212,7 @@ static int opChanOffsH[4]={ 0xad, 0xae, 0xac, 0xa6 }; -void DivPlatformYM2610BExt::tick() { +void DivPlatformYM2610BExt::tick(bool sysTick) { if (extMode) { bool writeSomething=false; unsigned char writeMask=2; @@ -229,7 +229,7 @@ void DivPlatformYM2610BExt::tick() { } } - DivPlatformYM2610B::tick(); + DivPlatformYM2610B::tick(sysTick); bool writeNoteOn=false; unsigned char writeMask=2; diff --git a/src/engine/platform/ym2610bext.h b/src/engine/platform/ym2610bext.h index 25ca59196..e908916e3 100644 --- a/src/engine/platform/ym2610bext.h +++ b/src/engine/platform/ym2610bext.h @@ -41,7 +41,7 @@ class DivPlatformYM2610BExt: public DivPlatformYM2610B { void* getChanState(int chan); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); bool keyOffAffectsArp(int ch); void notifyInsChange(int ins); diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index 40294733d..dc4625080 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -212,7 +212,7 @@ static int opChanOffsH[4]={ 0xad, 0xae, 0xac, 0xa6 }; -void DivPlatformYM2610Ext::tick() { +void DivPlatformYM2610Ext::tick(bool sysTick) { if (extMode) { bool writeSomething=false; unsigned char writeMask=2; @@ -229,7 +229,7 @@ void DivPlatformYM2610Ext::tick() { } } - DivPlatformYM2610::tick(); + DivPlatformYM2610::tick(sysTick); bool writeNoteOn=false; unsigned char writeMask=2; diff --git a/src/engine/platform/ym2610ext.h b/src/engine/platform/ym2610ext.h index 37c9e328d..9fa44d0b1 100644 --- a/src/engine/platform/ym2610ext.h +++ b/src/engine/platform/ym2610ext.h @@ -41,7 +41,7 @@ class DivPlatformYM2610Ext: public DivPlatformYM2610 { void* getChanState(int chan); void reset(); void forceIns(); - void tick(); + void tick(bool sysTick=true); void muteChannel(int ch, bool mute); bool keyOffAffectsArp(int ch); void notifyInsChange(int ins); diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index fe42c73af..0f3789635 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1638,7 +1638,7 @@ bool DivEngine::nextTick(bool noAccum) { firstTick=false; // system tick - for (int i=0; itick(); + for (int i=0; itick(subticks==tickMult); if (!freelance) { if (stepPlay!=1) { diff --git a/src/engine/waveSynth.cpp b/src/engine/waveSynth.cpp index 2b9946ee2..7bae30d9a 100644 --- a/src/engine/waveSynth.cpp +++ b/src/engine/waveSynth.cpp @@ -30,8 +30,11 @@ bool DivWaveSynth::activeChanged() { } bool DivWaveSynth::tick() { + if (--subDivCounter>0) return false; + bool updated=first; first=false; + subDivCounter=e->tickMult; if (!state.enabled) return updated; if (width<1) return false; @@ -167,6 +170,7 @@ void DivWaveSynth::init(DivInstrument* which, int w, int h, bool insChanged) { pos=0; stage=0; divCounter=1+state.rateDivider; + subDivCounter=0; first=true; changeWave1(state.wave1); diff --git a/src/engine/waveSynth.h b/src/engine/waveSynth.h index ecd6f8a86..f5c89e3ac 100644 --- a/src/engine/waveSynth.h +++ b/src/engine/waveSynth.h @@ -28,7 +28,7 @@ class DivEngine; class DivWaveSynth { DivEngine* e; DivInstrumentWaveSynth state; - int pos, stage, divCounter, width, height; + int pos, stage, divCounter, width, height, subDivCounter; bool first, activeChangedB; unsigned char wave1[256]; unsigned char wave2[256]; @@ -78,6 +78,7 @@ class DivWaveSynth { divCounter(0), width(32), height(31), + subDivCounter(0), first(false), activeChangedB(false) { memset(wave1,0,256); From 55d821de6e99eb574cfcdf96fa917b871cc2d0e2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 15 Apr 2022 16:00:21 -0500 Subject: [PATCH 12/77] potential to-do for Windows --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.cpp b/src/main.cpp index f8c749f7a..8f41b10cb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -239,6 +239,7 @@ void initParams() { params.push_back(TAParam("W","warranty",false,pWarranty,"","view warranty disclaimer.")); } +// TODO: CoInitializeEx on Windows? int main(int argc, char** argv) { initLog(); #if !(defined(__APPLE__) || defined(_WIN32)) From 98b9bd32b94b350b1fbca1bc558ddafb2b604f5b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 15 Apr 2022 16:10:57 -0500 Subject: [PATCH 13/77] static_assert() on cmdName --- src/engine/playback.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 0f3789635..2b22abd24 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -40,7 +40,7 @@ const char* notes[12]={ }; // update this when adding new commands. -const char* cmdName[DIV_CMD_MAX]={ +const char* cmdName[]={ "NOTE_ON", "NOTE_OFF", "NOTE_OFF_ENV", @@ -144,6 +144,7 @@ const char* cmdName[DIV_CMD_MAX]={ "N163_WAVE_LOAD", "N163_WAVE_LOADPOS", "N163_WAVE_LOADLEN", + "N163_WAVE_LOADMODE", "N163_CHANNEL_LIMIT", "N163_GLOBAL_WAVE_LOAD", "N163_GLOBAL_WAVE_LOADPOS", @@ -153,6 +154,8 @@ const char* cmdName[DIV_CMD_MAX]={ "ALWAYS_SET_VOLUME" }; +static_assert((sizeof(cmdName)/sizeof(void*))==DIV_CMD_MAX,"update cmdName!"); + const char* formatNote(unsigned char note, unsigned char octave) { static char ret[4]; if (note==100) { From a8201fa535174df56e80d805101fc715e349ef1d Mon Sep 17 00:00:00 2001 From: James Alan Nguyen Date: Sat, 16 Apr 2022 09:34:12 +1000 Subject: [PATCH 14/77] Address review comments --- src/engine/fileOpsIns.cpp | 242 ++++++++++++++++++-------------------- 1 file changed, 117 insertions(+), 125 deletions(-) diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index 2391f2a1a..b1e5b3974 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -35,6 +35,61 @@ enum DivInsFormats { 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 @@ -46,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(lastError.c_str()); delete ins; return; } @@ -105,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(lastError.c_str()); delete ins; return; } @@ -297,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(lastError.c_str()); delete ins; return; } @@ -332,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(lastError.c_str()); delete ins; return; } @@ -374,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(lastError.c_str()); delete ins; return; } @@ -400,56 +455,48 @@ void DivEngine::loadS3I(SafeReader& reader, std::vector& ret, St // 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.\n"); + logE(lastError.c_str()); } ins->name = reader.readString(28); ins->name = (ins->name.length() == 0) ? stripPath : ins->name; @@ -457,12 +504,12 @@ void DivEngine::loadS3I(SafeReader& reader, std::vector& ret, St int s3i_signature = reader.readI(); if (s3i_signature != 0x49524353) { - lastError = "S3I signature invalid."; - logW("S3I signature invalid.\n"); + warnings = "S3I signature invalid."; + logW(lastError.c_str()); }; } catch (EndOfFileException& e) { lastError = "premature end of file"; - logE("premature end of file!"); + logE(lastError.c_str()); delete ins; return; } @@ -486,34 +533,6 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St String patchName = reader.readString(32); patchName = (patchName.length() == 0) ? stripPath : patchName; - typedef struct { - uint8_t Mcharacteristics, - Ccharacteristics, - Mscaling_output, - Cscaling_output, - Meg_AD, - Ceg_AD, - Meg_SR, - Ceg_SR, - Mwave, - Cwave, - FeedConnect; - } sbi_t; - - 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(); - }; - auto writeOp = [](sbi_t& sbi, DivInstrumentFM::Operator& opM, DivInstrumentFM::Operator& opC) { opM.mult = sbi.Mcharacteristics & 0xF; opM.ksr = ((sbi.Mcharacteristics >> 4) & 0x1); @@ -611,49 +630,22 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St } catch (EndOfFileException& e) { lastError = "premature end of file"; - logE("premature end of file!"); + logE(lastError.c_str()); delete ins; } } void DivEngine::loadBNK(SafeReader& reader, std::vector& ret, String& stripPath) { - DivInstrument* insList[256]; - String instNames[256]; - memset(insList, 0, 256 * sizeof(void*)); + 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) { - // Caveat: Technically Adlib BNK can hold up to 0xFFFF instruments, - // but Furnace only can handle up to 0xFF. - - typedef struct { - uint8_t ksl, - multiple, - feedback, // op1 only - attack, - sustain, - eg, - decay, - releaseRate, - totalLevel, - am, - vib, - ksr, - con; // op1 only - } bnkop_t; - - typedef struct { - uint8_t mode, - percVoice; - bnkop_t op[2]; - uint8_t wave0, - wave1; - } bnktimbre_t; - try { reader.seek(0x0c, SEEK_SET); uint32_t name_offset = reader.readI(); @@ -663,13 +655,8 @@ void DivEngine::loadBNK(SafeReader& reader, std::vector& ret, St // Seek to BNK patch names reader.seek(name_offset, SEEK_SET); while (reader.tell() < data_offset) { - if (readCount >= 256) { - lastError = "BNK exceeds 256 presets. Only first 256 will be imported."; - logW("BNK exceeds 256 presets. Only first 256 will be imported.\n"); - break; - } reader.seek(3, SEEK_CUR); - instNames[readCount] = reader.readString(9); + instNames.push_back(new String(reader.readString(9))); ++readCount; } @@ -677,9 +664,9 @@ void DivEngine::loadBNK(SafeReader& reader, std::vector& ret, St reader.seek(data_offset, SEEK_SET); // Read until EOF - for (int i = 0; i < readCount && i < 256; ++i) { + for (int i = 0; i < readCount; ++i) { bnktimbre_t timbre; - insList[i] = new DivInstrument; + insList.push_back(new DivInstrument); auto& ins = insList[i]; ins->type = DIV_INS_OPL; @@ -719,31 +706,36 @@ void DivEngine::loadBNK(SafeReader& reader, std::vector& ret, St 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); + 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!\n"); + logE(lastError.c_str()); for (int i = readCount; i >= 0; --i) { delete insList[i]; } - return; + is_failed = true; } } else { // assume GEMS BNK for now. - lastError = "GEMS BNK currently not supported.\n"; - logE("GEMS BNK currently not supported.\n"); + lastError = "GEMS BNK currently not supported."; + logE(lastError.c_str()); } - for (int i = 0; i < readCount; ++i) { - ret.push_back(insList[i]); + 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) { DivInstrument* insList[256]; memset(insList,0,256*sizeof(void*)); @@ -805,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(lastError.c_str()); for (int i = readCount; i >= 0; --i) { delete insList[i]; } @@ -826,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(lastError.c_str()); return; } } @@ -924,7 +916,7 @@ std::vector DivEngine::instrumentFromFile(const char* path) { } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE("premature end of file!"); + logE(lastError.c_str()); delete ins; delete[] buf; return ret; From b48a2368bed445e11da1265600bf17f71a8456d2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 15 Apr 2022 22:22:47 -0500 Subject: [PATCH 15/77] more low-latency mode work playSub() runs at normal tick rate --- src/engine/engine.cpp | 1 + src/engine/playback.cpp | 10 +++-- src/gui/gui.cpp | 91 +++++++++++++++++++---------------------- src/gui/gui.h | 1 + 4 files changed, 51 insertions(+), 52 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 6257ff537..bb53fd2a3 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -853,6 +853,7 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) { } if (!preserveDrift) { ticks=1; + subticks=1; } skipping=false; cmdStream.clear(); diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 2b22abd24..bd8b2b8af 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1476,15 +1476,17 @@ bool DivEngine::nextTick(bool noAccum) { bool ret=false; if (divider<10) divider=10; - if (lowLatency) { + if (lowLatency && !skipping) { tickMult=1000/divider; if (tickMult<1) tickMult=1; + } else { + tickMult=1; } cycles=got.rate*pow(2,MASTER_CLOCK_PREC)/(divider*tickMult); - clockDrift+=fmod(got.rate*pow(2,MASTER_CLOCK_PREC),(double)divider); - if (clockDrift>=divider) { - clockDrift-=divider; + clockDrift+=fmod(got.rate*pow(2,MASTER_CLOCK_PREC),(double)(divider*tickMult)); + if (clockDrift>=(divider*tickMult)) { + clockDrift-=(divider*tickMult); cycles++; } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index ba83b8654..4fcd60ddd 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1078,9 +1078,6 @@ void FurnaceGUI::keyDown(SDL_Event& ev) { if (edit) { noteInput(num,key); } - if (key!=100 && key!=101 && key!=102) { - previewNote(cursor.xCoarse,num); - } } catch (std::out_of_range& e) { } } else if (edit) { // value @@ -1184,22 +1181,8 @@ void FurnaceGUI::keyDown(SDL_Event& ev) { } // PER-WINDOW PREVIEW KEYS + // TODO: move this to new event handler switch (curWindow) { - case GUI_WINDOW_INS_EDIT: - case GUI_WINDOW_INS_LIST: - case GUI_WINDOW_EDIT_CONTROLS: - case GUI_WINDOW_SONG_INFO: - if (!ev.key.repeat) { - try { - int key=noteKeys.at(ev.key.keysym.scancode); - int num=12*curOctave+key; - if (key!=100 && key!=101 && key!=102) { - previewNote(cursor.xCoarse,num); - } - } catch (std::out_of_range& e) { - } - } - break; case GUI_WINDOW_SAMPLE_EDIT: case GUI_WINDOW_SAMPLE_LIST: if (!ev.key.repeat) { @@ -1238,19 +1221,7 @@ void FurnaceGUI::keyDown(SDL_Event& ev) { } void FurnaceGUI::keyUp(SDL_Event& ev) { - stopPreviewNote(ev.key.keysym.scancode,true); - if (wavePreviewOn) { - if (ev.key.keysym.scancode==wavePreviewKey) { - wavePreviewOn=false; - e->stopWavePreview(); - } - } - if (samplePreviewOn) { - if (ev.key.keysym.scancode==samplePreviewKey) { - samplePreviewOn=false; - e->stopSamplePreview(); - } - } + // nothing for now } bool dirExists(String what) { @@ -2021,7 +1992,47 @@ void FurnaceGUI::editOptions(bool topMenu) { } } +int _processEvent(void* instance, SDL_Event* event) { + return ((FurnaceGUI*)instance)->processEvent(event); +} + +int FurnaceGUI::processEvent(SDL_Event* ev) { + if (ev->type==SDL_KEYDOWN) { + if (!ev->key.repeat) { + try { + int key=noteKeys.at(ev->key.keysym.scancode); + int num=12*curOctave+key; + + if (num<-60) num=-60; // C-(-5) + if (num>119) num=119; // B-9 + + if (key!=100 && key!=101 && key!=102) { + previewNote(cursor.xCoarse,num); + } + } catch (std::out_of_range& e) { + } + } + } else if (ev->type==SDL_KEYUP) { + stopPreviewNote(ev->key.keysym.scancode,true); + if (wavePreviewOn) { + if (ev->key.keysym.scancode==wavePreviewKey) { + wavePreviewOn=false; + e->stopWavePreview(); + } + } + if (samplePreviewOn) { + if (ev->key.keysym.scancode==samplePreviewKey) { + samplePreviewOn=false; + e->stopSamplePreview(); + } + } + } + return 1; +} + bool FurnaceGUI::loop() { + SDL_SetEventFilter(_processEvent,this); + while (!quit) { SDL_Event ev; while (SDL_PollEvent(&ev)) { @@ -2131,23 +2142,7 @@ bool FurnaceGUI::loop() { } break; case SDL_KEYUP: - if (!ImGui::GetIO().WantCaptureKeyboard) { - keyUp(ev); - } else { - stopPreviewNote(ev.key.keysym.scancode,true); - if (wavePreviewOn) { - if (ev.key.keysym.scancode==wavePreviewKey) { - wavePreviewOn=false; - e->stopWavePreview(); - } - } - if (samplePreviewOn) { - if (ev.key.keysym.scancode==samplePreviewKey) { - samplePreviewOn=false; - e->stopSamplePreview(); - } - } - } + // for now break; case SDL_DROPFILE: if (ev.drop.file!=NULL) { diff --git a/src/gui/gui.h b/src/gui/gui.h index 67d084a47..5983057b5 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1215,6 +1215,7 @@ class FurnaceGUI { void addScroll(int amount); void setFileName(String name); void runBackupThread(); + int processEvent(SDL_Event* ev); bool loop(); bool finish(); bool init(); From 6b294933bca61f11b955ab47a402fa1d946b6732 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 15 Apr 2022 22:27:44 -0500 Subject: [PATCH 16/77] VGM export: fix it under low-latency mode --- src/engine/engine.h | 2 +- src/engine/playback.cpp | 4 ++-- src/engine/vgmOps.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index 6bcaa38c9..6c1129e9d 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -271,7 +271,7 @@ class DivEngine { void nextRow(); void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool isSecond); // returns true if end of song. - bool nextTick(bool noAccum=false); + bool nextTick(bool noAccum=false, bool inhibitLowLat=false); bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal); bool perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal); void recalcChans(); diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index bd8b2b8af..38c7309d7 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1472,11 +1472,11 @@ void DivEngine::nextRow() { firstTick=true; } -bool DivEngine::nextTick(bool noAccum) { +bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { bool ret=false; if (divider<10) divider=10; - if (lowLatency && !skipping) { + if (lowLatency && !skipping && !inhibitLowLat) { tickMult=1000/divider; if (tickMult<1) tickMult=1; } else { diff --git a/src/engine/vgmOps.cpp b/src/engine/vgmOps.cpp index b20813489..efac0e482 100644 --- a/src/engine/vgmOps.cpp +++ b/src/engine/vgmOps.cpp @@ -1384,7 +1384,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) { writeLoop=true; } } - if (nextTick() || !playing) { + if (nextTick(false,true) || !playing) { done=true; if (!loop) { for (int i=0; i Date: Fri, 15 Apr 2022 23:47:39 -0500 Subject: [PATCH 17/77] GUI: move all preview actions to callback --- src/gui/gui.cpp | 96 ++++++++++++++++++++++++------------------------- src/gui/gui.h | 2 +- 2 files changed, 48 insertions(+), 50 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 4fcd60ddd..0488fd539 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1179,45 +1179,6 @@ void FurnaceGUI::keyDown(SDL_Event& ev) { } } catch (std::out_of_range& e) { } - - // PER-WINDOW PREVIEW KEYS - // TODO: move this to new event handler - switch (curWindow) { - case GUI_WINDOW_SAMPLE_EDIT: - case GUI_WINDOW_SAMPLE_LIST: - if (!ev.key.repeat) { - try { - int key=noteKeys.at(ev.key.keysym.scancode); - int num=12*curOctave+key; - if (key!=100 && key!=101 && key!=102) { - e->previewSample(curSample,num); - samplePreviewOn=true; - samplePreviewKey=ev.key.keysym.scancode; - samplePreviewNote=num; - } - } catch (std::out_of_range& e) { - } - } - break; - case GUI_WINDOW_WAVE_LIST: - case GUI_WINDOW_WAVE_EDIT: - if (!ev.key.repeat) { - try { - int key=noteKeys.at(ev.key.keysym.scancode); - int num=12*curOctave+key; - if (key!=100 && key!=101 && key!=102) { - e->previewWave(curWave,num); - wavePreviewOn=true; - wavePreviewKey=ev.key.keysym.scancode; - wavePreviewNote=num; - } - } catch (std::out_of_range& e) { - } - } - break; - default: - break; - } } void FurnaceGUI::keyUp(SDL_Event& ev) { @@ -1998,18 +1959,52 @@ int _processEvent(void* instance, SDL_Event* event) { int FurnaceGUI::processEvent(SDL_Event* ev) { if (ev->type==SDL_KEYDOWN) { - if (!ev->key.repeat) { - try { - int key=noteKeys.at(ev->key.keysym.scancode); - int num=12*curOctave+key; + if (!ev->key.repeat && !wantCaptureKeyboard) { + switch (curWindow) { + case GUI_WINDOW_SAMPLE_EDIT: + case GUI_WINDOW_SAMPLE_LIST: + try { + int key=noteKeys.at(ev->key.keysym.scancode); + int num=12*curOctave+key; + if (key!=100 && key!=101 && key!=102) { + e->previewSample(curSample,num); + samplePreviewOn=true; + samplePreviewKey=ev->key.keysym.scancode; + samplePreviewNote=num; + } + } catch (std::out_of_range& e) { + } + break; + case GUI_WINDOW_WAVE_LIST: + case GUI_WINDOW_WAVE_EDIT: + try { + int key=noteKeys.at(ev->key.keysym.scancode); + int num=12*curOctave+key; + if (key!=100 && key!=101 && key!=102) { + e->previewWave(curWave,num); + wavePreviewOn=true; + wavePreviewKey=ev->key.keysym.scancode; + wavePreviewNote=num; + } + } catch (std::out_of_range& e) { + } + break; + case GUI_WINDOW_ORDERS: // ignore here + break; + default: + try { + int key=noteKeys.at(ev->key.keysym.scancode); + int num=12*curOctave+key; - if (num<-60) num=-60; // C-(-5) - if (num>119) num=119; // B-9 + if (num<-60) num=-60; // C-(-5) + if (num>119) num=119; // B-9 - if (key!=100 && key!=101 && key!=102) { - previewNote(cursor.xCoarse,num); - } - } catch (std::out_of_range& e) { + if (key!=100 && key!=101 && key!=102) { + previewNote(cursor.xCoarse,num); + } + } catch (std::out_of_range& e) { + } + break; } } } else if (ev->type==SDL_KEYUP) { @@ -2167,6 +2162,8 @@ bool FurnaceGUI::loop() { break; } } + + wantCaptureKeyboard=ImGui::GetIO().WantCaptureKeyboard; while (true) { midiLock.lock(); @@ -3417,6 +3414,7 @@ FurnaceGUI::FurnaceGUI(): displayError(false), displayExporting(false), vgmExportLoop(true), + wantCaptureKeyboard(false), displayNew(false), vgmExportVersion(0x171), curFileDialog(GUI_FILE_OPEN), diff --git a/src/gui/gui.h b/src/gui/gui.h index 5983057b5..eaab6df43 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -711,7 +711,7 @@ class FurnaceGUI { String mmlString[17]; String mmlStringW; - bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop; + bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, wantCaptureKeyboard; bool displayNew; bool willExport[32]; int vgmExportVersion; From d0c76e020cef2d05011a7fb24176f014ece475fa Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 16 Apr 2022 00:10:52 -0500 Subject: [PATCH 18/77] GUI: more note preview fixes --- src/engine/engine.cpp | 14 ++++++++++++++ src/engine/engine.h | 1 + src/gui/doAction.cpp | 10 ++-------- src/gui/editControls.cpp | 20 ++++---------------- src/gui/gui.cpp | 2 +- 5 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index bb53fd2a3..04029c46b 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1997,6 +1997,20 @@ void DivEngine::autoNoteOff(int ch, int note, int vol) { } } +void DivEngine::autoNoteOffAll() { + if (!playing) { + reset(); + freelance=true; + playing=true; + } + for (int i=0; i7) { curOctave=7; } else { - for (size_t i=0; inoteOff(activeNotes[i].chan); - } - activeNotes.clear(); + e->autoNoteOffAll(); } break; case GUI_ACTION_OCTAVE_DOWN: if (--curOctave<-5) { curOctave=-5; } else { - for (size_t i=0; inoteOff(activeNotes[i].chan); - } - activeNotes.clear(); + e->autoNoteOffAll(); } break; case GUI_ACTION_INS_UP: diff --git a/src/gui/editControls.cpp b/src/gui/editControls.cpp index 5098a73de..722c38f2a 100644 --- a/src/gui/editControls.cpp +++ b/src/gui/editControls.cpp @@ -35,10 +35,7 @@ void FurnaceGUI::drawEditControls() { if (ImGui::InputInt("##Octave",&curOctave,1,1)) { if (curOctave>7) curOctave=7; if (curOctave<-5) curOctave=-5; - for (size_t i=0; inoteOff(activeNotes[i].chan); - } - activeNotes.clear(); + e->autoNoteOffAll(); if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) { nextWindow=GUI_WINDOW_PATTERN; @@ -139,10 +136,7 @@ void FurnaceGUI::drawEditControls() { if (ImGui::InputInt("##Octave",&curOctave,1,1)) { if (curOctave>7) curOctave=7; if (curOctave<-5) curOctave=-5; - for (size_t i=0; inoteOff(activeNotes[i].chan); - } - activeNotes.clear(); + e->autoNoteOffAll(); if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) { nextWindow=GUI_WINDOW_PATTERN; @@ -213,10 +207,7 @@ void FurnaceGUI::drawEditControls() { if (ImGui::InputInt("##Octave",&curOctave,0,0)) { if (curOctave>7) curOctave=7; if (curOctave<-5) curOctave=-5; - for (size_t i=0; inoteOff(activeNotes[i].chan); - } - activeNotes.clear(); + e->autoNoteOffAll(); if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) { nextWindow=GUI_WINDOW_PATTERN; @@ -314,10 +305,7 @@ void FurnaceGUI::drawEditControls() { if (ImGui::InputInt("##Octave",&curOctave,1,1)) { if (curOctave>7) curOctave=7; if (curOctave<-5) curOctave=-5; - for (size_t i=0; inoteOff(activeNotes[i].chan); - } - activeNotes.clear(); + e->autoNoteOffAll(); if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) { nextWindow=GUI_WINDOW_PATTERN; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 0488fd539..b37726059 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1959,7 +1959,7 @@ int _processEvent(void* instance, SDL_Event* event) { int FurnaceGUI::processEvent(SDL_Event* ev) { if (ev->type==SDL_KEYDOWN) { - if (!ev->key.repeat && !wantCaptureKeyboard) { + if (!ev->key.repeat && !wantCaptureKeyboard && (ev->key.keysym.mod&(~(KMOD_NUM|KMOD_CAPS|KMOD_SCROLL)))==0) { switch (curWindow) { case GUI_WINDOW_SAMPLE_EDIT: case GUI_WINDOW_SAMPLE_LIST: From af41e56acced0ae6a68d94aa5074fda7bd9849a8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 16 Apr 2022 00:39:03 -0500 Subject: [PATCH 19/77] Lynx: set freqChanged to false! --- src/engine/platform/lynx.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index 307d2059a..a62f0d458 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -184,8 +184,8 @@ void DivPlatformLynx::tick(bool sysTick) { } WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7)); WRITE_BACKUP( i, chan[i].fd.backup ); - } - else if (chan[i].std.duty.had) { + chan[i].freqChanged=false; + } else if (chan[i].std.duty.had) { chan[i].duty = chan[i].std.duty.val; WRITE_FEEDBACK(i, chan[i].duty.feedback); WRITE_CONTROL(i, (chan[i].fd.clockDivider|0x18|chan[i].duty.int_feedback7)); From b4ac5c7e6a28169c1c2d30dda242ac28becf0e3d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 16 Apr 2022 01:39:40 -0500 Subject: [PATCH 20/77] implement pitch macro --- src/engine/platform/arcade.cpp | 4 ++++ src/engine/platform/ay.cpp | 3 +++ src/engine/platform/ay8930.cpp | 3 +++ src/engine/platform/bubsyswsg.cpp | 3 +++ src/engine/platform/c64.cpp | 3 +++ src/engine/platform/fds.cpp | 19 ++++++------------- src/engine/platform/gb.cpp | 3 +++ src/engine/platform/genesis.cpp | 4 ++++ src/engine/platform/lynx.cpp | 4 ++++ src/engine/platform/mmc5.cpp | 3 +++ src/engine/platform/n163.cpp | 3 +++ src/engine/platform/nes.cpp | 3 +++ src/engine/platform/opl.cpp | 4 ++++ src/engine/platform/opll.cpp | 4 ++++ src/engine/platform/pce.cpp | 3 +++ src/engine/platform/pcspkr.cpp | 3 +++ src/engine/platform/pet.cpp | 3 +++ src/engine/platform/qsound.cpp | 3 +++ src/engine/platform/saa.cpp | 3 +++ src/engine/platform/segapcm.cpp | 4 ++++ src/engine/platform/sms.cpp | 3 +++ src/engine/platform/swan.cpp | 3 +++ src/engine/platform/tia.cpp | 3 +++ src/engine/platform/tx81z.cpp | 4 ++++ src/engine/platform/vera.cpp | 3 +++ src/engine/platform/vic20.cpp | 3 +++ src/engine/platform/vrc6.cpp | 3 +++ src/engine/platform/x1_010.cpp | 3 +++ src/engine/platform/ym2610.cpp | 4 ++++ src/engine/platform/ym2610b.cpp | 4 ++++ 30 files changed, 102 insertions(+), 13 deletions(-) diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 0bcb3b990..2935bad06 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -264,6 +264,10 @@ void DivPlatformArcade::tick(bool sysTick) { rWrite(0x1b,chan[i].std.wave.val&3); } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } + if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { chan[i].keyOn=true; diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index d3db4ba8b..25f49e950 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -215,6 +215,9 @@ void DivPlatformAY8910::tick(bool sysTick) { rWrite(0x08+i,(chan[i].outVol&15)|((chan[i].psgMode&4)<<2)); } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { oldWrites[0x08+i]=-1; diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 9fa39131c..e4fa30dc4 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -226,6 +226,9 @@ void DivPlatformAY8930::tick(bool sysTick) { rWrite(0x08+i,(chan[i].outVol&31)|((chan[i].psgMode&4)<<3)); } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { oldWrites[0x08+i]=-1; diff --git a/src/engine/platform/bubsyswsg.cpp b/src/engine/platform/bubsyswsg.cpp index 91f50d461..569e82f1c 100644 --- a/src/engine/platform/bubsyswsg.cpp +++ b/src/engine/platform/bubsyswsg.cpp @@ -110,6 +110,9 @@ void DivPlatformBubSysWSG::tick(bool sysTick) { if (!chan[i].keyOff) chan[i].keyOn=true; } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].active) { if (chan[i].ws.tick()) { updateWave(i); diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 4c3cc32e4..12ec3f5f9 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -181,6 +181,9 @@ void DivPlatformC64::tick(bool sysTick) { chan[i].wave=chan[i].std.wave.val; rWrite(i*7+4,(chan[i].wave<<4)|(chan[i].ring<<2)|(chan[i].sync<<1)|(int)(chan[i].active)); } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].std.ex1.had) { filtControl=chan[i].std.ex1.val&15; updateFilter(); diff --git a/src/engine/platform/fds.cpp b/src/engine/platform/fds.cpp index 16e24f130..c581c516e 100644 --- a/src/engine/platform/fds.cpp +++ b/src/engine/platform/fds.cpp @@ -107,21 +107,11 @@ void DivPlatformFDS::tick(bool sysTick) { rWrite(0x4080,0x80|chan[i].outVol); } if (chan[i].std.arp.had) { - if (i==3) { // noise + if (!chan[i].inPorta) { if (chan[i].std.arp.mode) { - chan[i].baseFreq=chan[i].std.arp.val; + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val); } else { - chan[i].baseFreq=chan[i].note+chan[i].std.arp.val; - } - if (chan[i].baseFreq>255) chan[i].baseFreq=255; - if (chan[i].baseFreq<0) chan[i].baseFreq=0; - } else { - if (!chan[i].inPorta) { - if (chan[i].std.arp.mode) { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].std.arp.val); - } else { - chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val); - } + chan[i].baseFreq=NOTE_FREQUENCY(chan[i].note+chan[i].std.arp.val); } } chan[i].freqChanged=true; @@ -155,6 +145,9 @@ void DivPlatformFDS::tick(bool sysTick) { //if (!chan[i].keyOff) chan[i].keyOn=true; } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].active) { if (ws.tick()) { updateWave(); diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index c28478a3a..d3bb28e5e 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -192,6 +192,9 @@ void DivPlatformGB::tick(bool sysTick) { if (!chan[i].keyOff) chan[i].keyOn=true; } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { chan[i].keyOn=true; diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index bcca663ec..1385c62cf 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -258,6 +258,10 @@ void DivPlatformGenesis::tick(bool sysTick) { } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } + if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { chan[i].keyOn=true; diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index a62f0d458..16d3f15ea 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -171,6 +171,10 @@ void DivPlatformLynx::tick(bool sysTick) { } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } + if (chan[i].freqChanged) { if (chan[i].lfsr >= 0) { WRITE_LFSR(i, (chan[i].lfsr&0xff)); diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 3c7f3dcab..696ae6d21 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -123,6 +123,9 @@ void DivPlatformMMC5::tick(bool sysTick) { chan[i].duty=chan[i].std.duty.val; rWrite(0x5000+i*4,0x30|chan[i].outVol|((chan[i].duty&3)<<6)); } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { chan[i].freqChanged=true; diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index 6a1eb60e0..a9634fa95 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -261,6 +261,9 @@ void DivPlatformN163::tick(bool sysTick) { } } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].std.ex1.had) { if (chan[i].waveLen!=(chan[i].std.ex1.val&0xfc)) { chan[i].waveLen=chan[i].std.ex1.val&0xfc; diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 7e291446f..e4bfbca9b 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -195,6 +195,9 @@ void DivPlatformNES::tick(bool sysTick) { chan[i].freqChanged=true; } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].sweepChanged) { chan[i].sweepChanged=false; if (i==0) { diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index e73ca41e4..7050e0007 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -269,6 +269,10 @@ void DivPlatformOPL::tick(bool sysTick) { } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } + if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { chan[i].keyOn=true; diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index cb6ceba83..d94d1e26d 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -145,6 +145,10 @@ void DivPlatformOPLL::tick(bool sysTick) { } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } + if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { chan[i].keyOn=true; diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index cff5e534a..2c248db09 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -196,6 +196,9 @@ void DivPlatformPCE::tick(bool sysTick) { if (!chan[i].keyOff) chan[i].keyOn=true; } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].active) { if (chan[i].ws.tick() || (chan[i].std.phaseReset.had && chan[i].std.phaseReset.val==1)) { updateWave(i); diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index 8e1705f50..e7062d213 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -186,6 +186,9 @@ void DivPlatformPCSpeaker::tick(bool sysTick) { chan[i].freqChanged=true; } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)-1+chan[i].std.pitch.val; if (chan[i].freq<0) chan[i].freq=0; diff --git a/src/engine/platform/pet.cpp b/src/engine/platform/pet.cpp index 0fe4523db..47bb2e3d4 100644 --- a/src/engine/platform/pet.cpp +++ b/src/engine/platform/pet.cpp @@ -112,6 +112,9 @@ void DivPlatformPET::tick(bool sysTick) { rWrite(10,chan.wave); } } + if (chan.std.pitch.had) { + chan.freqChanged=true; + } if (chan.freqChanged || chan.keyOn || chan.keyOff) { chan.freq=parent->calcFreq(chan.baseFreq,chan.pitch,true)+chan.std.pitch.val; if (chan.freq>257) chan.freq=257; diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 601ea0ea9..338870109 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -326,6 +326,9 @@ void DivPlatformQSound::tick(bool sysTick) { chan[i].freqChanged=true; } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { //DivInstrument* ins=parent->getIns(chan[i].ins); chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false)+chan[i].std.pitch.val; diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index ca91800c2..0e06c3388 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -166,6 +166,9 @@ void DivPlatformSAA1099::tick(bool sysTick) { if (chan[i].std.wave.had) { chan[i].psgMode=chan[i].std.wave.val&3; } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].std.ex1.had) { saaEnv[i/3]=chan[i].std.ex1.val; rWrite(0x18+(i/3),saaEnv[i/3]); diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 97ff900ae..79d7179a2 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -99,6 +99,10 @@ void DivPlatformSegaPCM::tick(bool sysTick) { chan[i].freqChanged=true; } } + + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } /*if (chan[i].keyOn || chan[i].keyOff) { chan[i].keyOff=false; }*/ diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index acd2c0726..d755e84f6 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -98,6 +98,9 @@ void DivPlatformSMS::tick(bool sysTick) { } } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } } for (int i=0; i<3; i++) { if (chan[i].freqChanged) { diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 99d819b1f..3b4a955ea 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -173,6 +173,9 @@ void DivPlatformSwan::tick(bool sysTick) { chan[i].ws.changeWave1(chan[i].wave); } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].active) { sndCtrl|=(1<calcFreq(chan[i].baseFreq,chan[i].pitch,false,8)+chan[i].std.pitch.val; if (chan[i].freq>65535) chan[i].freq=65535; diff --git a/src/engine/platform/vic20.cpp b/src/engine/platform/vic20.cpp index 7817cd839..44aba9670 100644 --- a/src/engine/platform/vic20.cpp +++ b/src/engine/platform/vic20.cpp @@ -119,6 +119,9 @@ void DivPlatformVIC20::tick(bool sysTick) { chan[i].keyOn=true; } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val; if (i<3) { diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index 048b42cdb..d8b37d92f 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -178,6 +178,9 @@ void DivPlatformVRC6::tick(bool sysTick) { chWrite(i,0,(chan[i].outVol&0xf)|((chan[i].duty&7)<<4)); } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { if (i==2) { // sawtooth chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)-1+chan[i].std.pitch.val; diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index df6682adb..229d8eab6 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -372,6 +372,9 @@ void DivPlatformX1_010::tick(bool sysTick) { } } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } if (chan[i].std.ex1.had) { bool nextEnable=(chan[i].std.ex1.val&1); if (nextEnable!=(chan[i].env.flag.envEnable)) { diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 3d6c8ed29..6f4a1e46c 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -408,6 +408,10 @@ void DivPlatformYM2610::tick(bool sysTick) { } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } + if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { chan[i].keyOn=true; diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index aeadeae47..04bc096a9 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -472,6 +472,10 @@ void DivPlatformYM2610B::tick(bool sysTick) { } } + if (chan[i].std.pitch.had) { + chan[i].freqChanged=true; + } + if (chan[i].std.phaseReset.had) { if (chan[i].std.phaseReset.val==1) { chan[i].keyOn=true; From d16d1260cb1abe2f918cbe15596d1e4e3e713f8c Mon Sep 17 00:00:00 2001 From: Natt Akuma Date: Sat, 16 Apr 2022 22:54:01 +0700 Subject: [PATCH 21/77] VGM: Support ROM data in the second chip --- src/engine/vgmOps.cpp | 110 ++++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 48 deletions(-) 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 From 330171edc31dc9d7c0a82e2e9c44ae025e4275a7 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 16 Apr 2022 13:13:19 -0500 Subject: [PATCH 22/77] GUI: add "note preview behavior" setting --- TODO.md | 5 +++++ src/gui/gui.cpp | 8 ++++++++ src/gui/gui.h | 2 ++ src/gui/settings.cpp | 17 +++++++++++++++++ 4 files changed, 32 insertions(+) diff --git a/TODO.md b/TODO.md index d9817937e..04b724e0a 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,11 @@ # to-do for 0.6pre1 - panning macro + - single macro for hard-panned chips + - two macros for soft-panned ones - pitch macro + - relative mode + - test - piano/input pad - note input via piano - input pad @@ -43,3 +47,4 @@ - settings: OK/Cancel buttons should be always visible - Apply button in settings - better FM chip names (number and codename) +- find and replace diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index b37726059..44de597bd 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1960,6 +1960,7 @@ int _processEvent(void* instance, SDL_Event* event) { int FurnaceGUI::processEvent(SDL_Event* ev) { if (ev->type==SDL_KEYDOWN) { if (!ev->key.repeat && !wantCaptureKeyboard && (ev->key.keysym.mod&(~(KMOD_NUM|KMOD_CAPS|KMOD_SCROLL)))==0) { + if (settings.notePreviewBehavior==0) return 1; switch (curWindow) { case GUI_WINDOW_SAMPLE_EDIT: case GUI_WINDOW_SAMPLE_LIST: @@ -1991,6 +1992,13 @@ int FurnaceGUI::processEvent(SDL_Event* ev) { break; case GUI_WINDOW_ORDERS: // ignore here break; + case GUI_WINDOW_PATTERN: + if (settings.notePreviewBehavior==1) { + if (cursor.xFine!=0) break; + } else if (settings.notePreviewBehavior==2) { + if (edit && cursor.xFine!=0) break; + } + // fall-through default: try { int key=noteKeys.at(ev->key.keysym.scancode); diff --git a/src/gui/gui.h b/src/gui/gui.h index eaab6df43..447708b12 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -819,6 +819,7 @@ class FurnaceGUI { int oplStandardWaveNames; int cursorMoveNoScroll; int lowLatency; + int notePreviewBehavior; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -891,6 +892,7 @@ class FurnaceGUI { oplStandardWaveNames(0), cursorMoveNoScroll(0), lowLatency(0), + notePreviewBehavior(1), maxUndoSteps(100), mainFontPath(""), patFontPath(""), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index f4d62a81d..5bf76160e 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -301,6 +301,20 @@ void FurnaceGUI::drawSettings() { settings.sysFileDialog=sysFileDialogB; } + ImGui::Text("Note preview behavioe:"); + if (ImGui::RadioButton("Never##npb0",settings.notePreviewBehavior==0)) { + settings.notePreviewBehavior=0; + } + if (ImGui::RadioButton("When cursor is in Note column##npb1",settings.notePreviewBehavior==1)) { + settings.notePreviewBehavior=1; + } + if (ImGui::RadioButton("When cursor is in Note column or not in edit mode##npb2",settings.notePreviewBehavior==2)) { + settings.notePreviewBehavior=2; + } + if (ImGui::RadioButton("Always##npb3",settings.notePreviewBehavior==3)) { + settings.notePreviewBehavior=3; + } + ImGui::Text("Wrap pattern cursor horizontally:"); if (ImGui::RadioButton("No##wrapH0",settings.wrapHorizontal==0)) { settings.wrapHorizontal=0; @@ -1609,6 +1623,7 @@ void FurnaceGUI::syncSettings() { settings.oplStandardWaveNames=e->getConfInt("oplStandardWaveNames",0); settings.cursorMoveNoScroll=e->getConfInt("cursorMoveNoScroll",0); settings.lowLatency=e->getConfInt("lowLatency",0); + settings.notePreviewBehavior=e->getConfInt("notePreviewBehavior",1); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -1670,6 +1685,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.oplStandardWaveNames,0,1); clampSetting(settings.cursorMoveNoScroll,0,1); clampSetting(settings.lowLatency,0,1); + clampSetting(settings.notePreviewBehavior,0,3); // keybinds for (int i=0; isetConf("oplStandardWaveNames",settings.oplStandardWaveNames); e->setConf("cursorMoveNoScroll",settings.cursorMoveNoScroll); e->setConf("lowLatency",settings.lowLatency); + e->setConf("notePreviewBehavior",settings.notePreviewBehavior); // colors for (int i=0; i Date: Sat, 16 Apr 2022 14:12:55 -0500 Subject: [PATCH 23/77] use nightly.link for builds --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index f8ea1aec5..1eac106d2 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ this is a multi-system chiptune tracker. check out the [Releases](https://github.com/tildearrow/furnace/releases) page. available for Windows, macOS and Linux (AppImage). +[see here](https://nightly.link/tildearrow/furnace/workflows/build/master) for unstable developer builds. + ## features - supports the following systems: @@ -64,6 +66,8 @@ some people have provided packages for Unix/Unix-like distributions. here's a li [![Build furnace](https://github.com/tildearrow/furnace/actions/workflows/build.yml/badge.svg)](https://github.com/tildearrow/furnace/actions/workflows/build.yml) +if you can't download these artifacts (because GitHub requires you to be logged in), [go here](https://nightly.link/tildearrow/furnace/workflows/build/master) instead. + **NOTE: do not download the project's source as a .zip or .tar.gz as these do not include the project's submodules which are necessary to proceed with building. please instead use Git as shown below.** ## dependencies From 8669e2cddcdfa3b4f45f5479c6ea0e41c9e54b02 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 16 Apr 2022 17:24:40 -0500 Subject: [PATCH 24/77] GUI: a better look for panning macro --- src/gui/insEdit.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 50f93de2e..b54ccd136 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -175,6 +175,10 @@ const char* n163UpdateBits[8]={ "now", "every waveform changed", NULL }; +const char* panBits[3]={ + "left", "right", NULL +}; + const char* oneBit[2]={ "on", NULL }; @@ -2717,8 +2721,10 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_SAA1099) ex1Max=8; int panMax=0; + bool panSingle=false; if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_GB || ins->type==DIV_INS_OPZ || ins->type==DIV_INS_VERA) { panMax=1; + panSingle=true; } if (ins->type==DIV_INS_AMIGA) { panMax=127; @@ -2746,8 +2752,12 @@ void FurnaceGUI::drawInsEdit() { NORMAL_MACRO(ins->std.waveMacro,0,waveMax,"wave",waveLabel,(bitMode && ins->type!=DIV_INS_PET)?64:160,ins->std.waveMacro.open,bitMode,waveNames,false,NULL,0,0,0,((ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930)?1:0),false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_WAVE],mmlString[3],0,waveMax,NULL,false); } if (panMax>0) { - NORMAL_MACRO(ins->std.panLMacro,0,panMax,"panL","Panning (left)",(31+panMax),ins->std.panLMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false); - NORMAL_MACRO(ins->std.panRMacro,0,panMax,"panR","Panning (right)",(31+panMax),ins->std.panRMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[14],0,panMax,NULL,false); + if (panSingle) { + NORMAL_MACRO(ins->std.panLMacro,0,2,"panL","Panning",32,ins->std.panLMacro.open,true,panBits,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false); + } else { + NORMAL_MACRO(ins->std.panLMacro,0,panMax,"panL","Panning (left)",(31+panMax),ins->std.panLMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[13],0,panMax,NULL,false); + NORMAL_MACRO(ins->std.panRMacro,0,panMax,"panR","Panning (right)",(31+panMax),ins->std.panRMacro.open,false,NULL,false,NULL,0,0,0,0,false,0,macroDummyMode,uiColors[GUI_COLOR_MACRO_OTHER],mmlString[14],0,panMax,NULL,false); + } } NORMAL_MACRO(ins->std.pitchMacro,pitchMacroScroll,pitchMacroScroll+160,"pitch","Pitch",160,ins->std.pitchMacro.open,false,NULL,true,&pitchMacroScroll,-2048,2047,0,0,true,1,macroAbsoluteMode,uiColors[GUI_COLOR_MACRO_PITCH],mmlString[15],-2048,2047,NULL,!ins->std.pitchMacro.mode); if (ins->type==DIV_INS_FM || From dd8df45519854761dd702e5c35722cdc8420545a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 16 Apr 2022 18:01:12 -0500 Subject: [PATCH 25/77] update format.md with more clarifications --- papers/format.md | 58 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/papers/format.md b/papers/format.md index 2f4037a06..7775e9ea3 100644 --- a/papers/format.md +++ b/papers/format.md @@ -274,6 +274,19 @@ size | description # instrument +notes: + +- the entire instrument is stored, regardless of instrument type. +- the macro range varies depending on the instrument type. +- "macro open" indicates whether the macro is collapsed or not in the instrument editor. +- FM operator order is: + - 1/3/2/4 (internal order) for OPN, OPM, OPZ and OPL 4-op + - 1/2/?/? (? = unused) for OPL 2-op and OPLL +- meaning of extended macros varies depending on instrument type. +- meaning of panning macros varies depending on instrument type: + - for hard-panned chips (e.g. FM and Game Boy): left panning is 2-bit panning macro (left/right) + - otherwise both left and right panning macros are used + ``` size | description -----|------------------------------------ @@ -282,17 +295,39 @@ size | description 2 | format version (see header) 1 | instrument type | - 0: standard - | - 1: FM + | - 1: FM (OPM/OPN) | - 2: Game Boy | - 3: C64 | - 4: Amiga/sample + | - 5: PC Engine + | - 6: AY-3-8910 + | - 7: AY8930 + | - 8: TIA + | - 9: SAA1099 + | - 10: VIC + | - 11: PET + | - 12: VRC6 + | - 13: OPLL + | - 14: OPL + | - 15: FDS + | - 16: Virtual Boy + | - 17: Namco 163 + | - 18: SCC + | - 19: OPZ + | - 20: POKEY + | - 21: PC Speaker + | - 22: WonderSwan + | - 23: Lynx + | - 24: VERA + | - 25: X1-010 + | - 26: VRC6 (saw) 1 | reserved STR | instrument name --- | **FM instrument data** - 1 | alg + 1 | alg (SUS on OPLL) 1 | feedback - 1 | fms - 1 | ams + 1 | fms (DC on OPLL) + 1 | ams (DM on OPLL) 1 | operator count | - this is either 2 or 4, and is ignored on non-OPL systems. | - always read 4 ops regardless of this value. @@ -314,10 +349,12 @@ size | description 1 | dt 1 | d2r 1 | ssgEnv - 1 | dam - 1 | dvb - 1 | egt - 1 | ksl + | - bit 4: on (EG-S on OPLL) + | - bit 0-3: envelope type + 1 | dam (for YMU759 compat; REV on OPZ) + 1 | dvb (for YMU759 compat; FINE on OPZ) + 1 | egt (for YMU759 compat; FixedFreq on OPZ) + 1 | ksl (EGShift on OPZ) 1 | sus 1 | vib 1 | ws @@ -690,15 +727,18 @@ size | description | - 10: A# | - 11: B | - 12: C (of next octave) + | - this is actually a leftover of the .dmf format. | - 100: note off | - 100: note release | - 100: macro release | - octave | - this is an signed char stored in a short. | - therefore octave value 255 is actually octave -1. + | - yep, another leftover of the .dmf format... | - instrument | - volume - | - effect and effect data... + | - effect and effect data (× effect columns) + | - for note/octave, if both values are 0 then it means empty. | - for instrument, volume, effect and effect data, a value of -1 means empty. STR | pattern name (>=51) ``` From ef6e63239c5651b5386651dd14d98f4829e2388f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 16 Apr 2022 18:35:25 -0500 Subject: [PATCH 26/77] GUI: introduce power-saving mode --- src/gui/gui.cpp | 9 +++++++++ src/gui/gui.h | 4 ++++ src/gui/osc.cpp | 9 ++++++++- src/gui/pattern.cpp | 1 + src/gui/settings.cpp | 20 +++++++++++++++++++- 5 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 44de597bd..b2d1e5c94 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2038,7 +2038,15 @@ bool FurnaceGUI::loop() { while (!quit) { SDL_Event ev; + if (e->isPlaying()) { + WAKE_UP; + } + if (--drawHalt<=0) { + drawHalt=0; + if (settings.powerSave) SDL_WaitEventTimeout(NULL,500); + } while (SDL_PollEvent(&ev)) { + WAKE_UP; ImGui_ImplSDL2_ProcessEvent(&ev); switch (ev.type) { case SDL_MOUSEMOTION: { @@ -3425,6 +3433,7 @@ FurnaceGUI::FurnaceGUI(): wantCaptureKeyboard(false), displayNew(false), vgmExportVersion(0x171), + drawHalt(10), curFileDialog(GUI_FILE_OPEN), warnAction(GUI_WARN_OPEN), postWarnAction(GUI_WARN_GENERIC), diff --git a/src/gui/gui.h b/src/gui/gui.h index 447708b12..b6613e9df 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -41,6 +41,7 @@ #define unimportant(x) if (x) {handleUnimportant} #define MARK_MODIFIED modified=true; +#define WAKE_UP drawHalt=16; #define TOGGLE_COLOR(x) ((x)?uiColors[GUI_COLOR_TOGGLE_ON]:uiColors[GUI_COLOR_TOGGLE_OFF]) @@ -715,6 +716,7 @@ class FurnaceGUI { bool displayNew; bool willExport[32]; int vgmExportVersion; + int drawHalt; FurnaceGUIFileDialogs curFileDialog; FurnaceGUIWarnings warnAction; @@ -820,6 +822,7 @@ class FurnaceGUI { int cursorMoveNoScroll; int lowLatency; int notePreviewBehavior; + int powerSave; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -893,6 +896,7 @@ class FurnaceGUI { cursorMoveNoScroll(0), lowLatency(0), notePreviewBehavior(1), + powerSave(1), maxUndoSteps(100), mainFontPath(""), patFontPath(""), diff --git a/src/gui/osc.cpp b/src/gui/osc.cpp index 266dfa3bf..030a84e9c 100644 --- a/src/gui/osc.cpp +++ b/src/gui/osc.cpp @@ -49,12 +49,19 @@ void FurnaceGUI::readOsc() { for (int i=0; i<512; i++) { int pos=(readPos+(i*total/512))&0x7fff; oscValues[i]=(e->oscBuf[0][pos]+e->oscBuf[1][pos])*0.5f; + if (oscValues[i]>0.001f || oscValues[i]<-0.001f) { + WAKE_UP; + } } float peakDecay=0.05f*60.0f*ImGui::GetIO().DeltaTime; for (int i=0; i<2; i++) { peak[i]*=1.0-peakDecay; - if (peak[i]<0.0001) peak[i]=0.0; + if (peak[i]<0.0001) { + peak[i]=0.0; + } else { + WAKE_UP; + } float newPeak=peak[i]; for (int j=0; jgetConfInt("cursorMoveNoScroll",0); settings.lowLatency=e->getConfInt("lowLatency",0); settings.notePreviewBehavior=e->getConfInt("notePreviewBehavior",1); + settings.powerSave=e->getConfInt("powerSave",POWER_SAVE_DEFAULT); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -1686,6 +1702,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.cursorMoveNoScroll,0,1); clampSetting(settings.lowLatency,0,1); clampSetting(settings.notePreviewBehavior,0,3); + clampSetting(settings.powerSave,0,1); // keybinds for (int i=0; isetConf("cursorMoveNoScroll",settings.cursorMoveNoScroll); e->setConf("lowLatency",settings.lowLatency); e->setConf("notePreviewBehavior",settings.notePreviewBehavior); + e->setConf("powerSave",settings.powerSave); // colors for (int i=0; i Date: Sat, 16 Apr 2022 18:35:35 -0500 Subject: [PATCH 27/77] YM2151: implement panning macro i think --- src/engine/platform/arcade.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 2935bad06..f4311e29e 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -264,6 +264,16 @@ void DivPlatformArcade::tick(bool sysTick) { rWrite(0x1b,chan[i].std.wave.val&3); } + if (chan[i].std.panL.had) { + chan[i].chVolL=(chan[i].std.panL.val&2)>>1; + chan[i].chVolR=chan[i].std.panL.val&1; + if (isMuted[i]) { + rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); + } else { + rWrite(chanOffs[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)|((chan[i].chVolL&1)<<6)|((chan[i].chVolR&1)<<7)); + } + } + if (chan[i].std.pitch.had) { chan[i].freqChanged=true; } From 6450a5323a3c0760dc74e53303621046a751115e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 16 Apr 2022 22:26:41 -0500 Subject: [PATCH 28/77] fix preview of sample instruments --- src/engine/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 04029c46b..6d0d4df0e 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1971,7 +1971,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) { } do { - if ((ins==-1 || getPreferInsType(finalChan)==getIns(ins)->type) && chan[finalChan].midiNote==-1) { + if ((ins==-1 || getPreferInsType(finalChan)==getIns(ins)->type || getIns(ins)->type==DIV_INS_AMIGA) && chan[finalChan].midiNote==-1) { chan[finalChan].midiNote=note; pendingNotes.push(DivNoteEvent(finalChan,ins,note,vol,true)); break; From 523adfac86fc91efc48b35ff815a70afdf1c09c8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 16 Apr 2022 22:28:14 -0500 Subject: [PATCH 29/77] GUI: fix sample up/down actions not changing wavef orm --- src/gui/doAction.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 25b4afe6d..cd4dda075 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -559,12 +559,14 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_SAMPLE_LIST_ADD: curSample=e->addSample(); + updateSampleTex=true; MARK_MODIFIED; break; case GUI_ACTION_SAMPLE_LIST_DUPLICATE: if (curSample>=0 && curSample<(int)e->song.sample.size()) { DivSample* prevSample=e->getSample(curSample); curSample=e->addSample(); + updateSampleTex=true; e->lockEngine([this,prevSample]() { DivSample* sample=e->getSample(curSample); if (sample!=NULL) { @@ -591,16 +593,23 @@ void FurnaceGUI::doAction(int what) { if (curSample>=0 && curSample<(int)e->song.sample.size()) openFileDialog(GUI_FILE_SAMPLE_SAVE); break; case GUI_ACTION_SAMPLE_LIST_MOVE_UP: - if (e->moveSampleUp(curSample)) curSample--; + if (e->moveSampleUp(curSample)) { + curSample--; + updateSampleTex=true; + } break; case GUI_ACTION_SAMPLE_LIST_MOVE_DOWN: - if (e->moveSampleDown(curSample)) curSample++; + if (e->moveSampleDown(curSample)) { + curSample++; + updateSampleTex=true; + } break; case GUI_ACTION_SAMPLE_LIST_DELETE: e->delSample(curSample); MARK_MODIFIED; if (curSample>=(int)e->song.sample.size()) { curSample--; + updateSampleTex=true; } break; case GUI_ACTION_SAMPLE_LIST_EDIT: @@ -608,9 +617,11 @@ void FurnaceGUI::doAction(int what) { break; case GUI_ACTION_SAMPLE_LIST_UP: if (--curSample<0) curSample=0; + updateSampleTex=true; break; case GUI_ACTION_SAMPLE_LIST_DOWN: if (++curSample>=(int)e->song.sample.size()) curSample=((int)e->song.sample.size())-1; + updateSampleTex=true; break; case GUI_ACTION_SAMPLE_LIST_PREVIEW: e->previewSample(curSample); From 42e84541432574b7b21e771a643aa650dbeefd31 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 16 Apr 2022 22:53:40 -0500 Subject: [PATCH 30/77] ADSR test area --- src/gui/debugWindow.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 31830681f..06184c0ba 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -226,6 +226,26 @@ void FurnaceGUI::drawDebug() { } ImGui::TreePop(); } + if (ImGui::TreeNode("ADSR Test Area")) { + static int tl, ar, dr, d2r, sl, rr, sus, egt, algOrGlobalSus, instType; + static float maxArDr, maxTl; + ImGui::Text("This window was done out of frustration"); + drawFMEnv(tl,ar,dr,d2r,rr,sl,sus,egt,algOrGlobalSus,maxTl,maxArDr,ImVec2(200.0f*dpiScale,100.0f*dpiScale),instType); + + ImGui::InputInt("tl",&tl); + ImGui::InputInt("ar",&ar); + ImGui::InputInt("dr",&dr); + ImGui::InputInt("d2r",&d2r); + ImGui::InputInt("sl",&sl); + ImGui::InputInt("rr",&rr); + ImGui::InputInt("sus",&sus); + ImGui::InputInt("egt",&egt); + ImGui::InputInt("algOrGlobalSus",&algOrGlobalSus); + ImGui::InputInt("instType",&instType); + ImGui::InputFloat("maxArDr",&maxArDr); + ImGui::InputFloat("maxTl",&maxTl); + ImGui::TreePop(); + } if (ImGui::TreeNode("User Interface")) { if (ImGui::Button("Inspect")) { inspectorOpen=!inspectorOpen; From 99d57bf342fe765205c93128fbb71fddeef22fdf Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 16 Apr 2022 23:43:49 -0500 Subject: [PATCH 31/77] GUI: C64 envelope view --- src/gui/insEdit.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index b54ccd136..730d1695e 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2277,6 +2277,8 @@ void FurnaceGUI::drawInsEdit() { P(CWSliderScalar("Release",ImGuiDataType_U8,&ins->c64.r,&_ZERO,&_FIFTEEN)); rightClickable P(CWSliderScalar("Duty",ImGuiDataType_U16,&ins->c64.duty,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE)); rightClickable + drawFMEnv(0,16-ins->c64.a,16-ins->c64.d,15-ins->c64.r,15-ins->c64.r,15-ins->c64.s,0,0,0,15,16,ImVec2(ImGui::GetContentRegionAvail().x,100.0f*dpiScale),ins->type); + bool ringMod=ins->c64.ringMod; if (ImGui::Checkbox("Ring Modulation",&ringMod)) { PARAMETER ins->c64.ringMod=ringMod; From 003c9c323505f46a12fee9d31a2aa8a4596f167f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 16 Apr 2022 23:58:29 -0500 Subject: [PATCH 32/77] GUI: prepare for GB envelope view --- src/gui/gui.h | 1 + src/gui/insEdit.cpp | 23 +++++++++++++++++++++++ src/gui/settings.cpp | 10 +++++++--- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index b6613e9df..36b6a8893 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1078,6 +1078,7 @@ class FurnaceGUI { void drawWaveform(unsigned char type, bool opz, const ImVec2& size); void drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, const ImVec2& size); void drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, unsigned char sus, unsigned char egt, unsigned char algOrGlobalSus, float maxTl, float maxArDr, const ImVec2& size, unsigned short instType); + void drawGBEnv(unsigned char vol, unsigned char len, unsigned char sLen, bool dir, const ImVec2& size); void drawSysConf(int i); // these ones offer ctrl-wheel fine value changes. diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 730d1695e..a58feea87 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1002,6 +1002,27 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, } } +void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char sLen, bool dir, const ImVec2& size) { + //ImDrawList* dl=ImGui::GetWindowDrawList(); + ImGuiWindow* window=ImGui::GetCurrentWindow(); + + ImVec2 minArea=window->DC.CursorPos; + ImVec2 maxArea=ImVec2( + minArea.x+size.x, + minArea.y+size.y + ); + ImRect rect=ImRect(minArea,maxArea); + ImGuiStyle& style=ImGui::GetStyle(); + //ImU32 color=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ENVELOPE]); + //ImU32 colorS=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ENVELOPE_SUS_GUIDE]); // Sustain horiz/vert line color + ImGui::ItemSize(size,style.FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID("alg"))) { + ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding); + + // TODO: this whole thing + } +} + #define P(x) if (x) { \ MARK_MODIFIED; \ e->notifyInsChange(curIns); \ @@ -2242,6 +2263,8 @@ void FurnaceGUI::drawInsEdit() { goesUp=false; ins->gb.envDir=goesUp; } + + drawGBEnv(ins->gb.envVol,ins->gb.envLen,ins->gb.soundLen,ins->gb.envDir,ImVec2(ImGui::GetContentRegionAvail().x,100.0f*dpiScale)); ImGui::EndTabItem(); } if (ins->type==DIV_INS_C64) if (ImGui::BeginTabItem("C64")) { diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 2e23f2f78..5e0bdbad6 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1082,15 +1082,19 @@ void FurnaceGUI::drawSettings() { UI_COLOR_CONFIG(GUI_COLOR_ORDER_INACTIVE,"Inactive patterns"); ImGui::TreePop(); } + if (ImGui::TreeNode("Envelope View")) { + UI_COLOR_CONFIG(GUI_COLOR_FM_ENVELOPE,"Envelope"); + UI_COLOR_CONFIG(GUI_COLOR_FM_ENVELOPE_SUS_GUIDE,"Sustain guide"); + UI_COLOR_CONFIG(GUI_COLOR_FM_ENVELOPE_RELEASE,"Release"); + + ImGui::TreePop(); + } if (ImGui::TreeNode("FM Editor")) { UI_COLOR_CONFIG(GUI_COLOR_FM_ALG_BG,"Algorithm background"); UI_COLOR_CONFIG(GUI_COLOR_FM_ALG_LINE,"Algorithm lines"); UI_COLOR_CONFIG(GUI_COLOR_FM_MOD,"Modulator"); UI_COLOR_CONFIG(GUI_COLOR_FM_CAR,"Carrier"); - UI_COLOR_CONFIG(GUI_COLOR_FM_ENVELOPE,"Envelope"); - UI_COLOR_CONFIG(GUI_COLOR_FM_ENVELOPE_SUS_GUIDE,"Sustain guide"); - UI_COLOR_CONFIG(GUI_COLOR_FM_ENVELOPE_RELEASE,"Release"); UI_COLOR_CONFIG(GUI_COLOR_FM_SSG,"SSG-EG"); UI_COLOR_CONFIG(GUI_COLOR_FM_WAVE,"Waveform"); From d1fadf1076e61b57139c750f2df7972a098691c5 Mon Sep 17 00:00:00 2001 From: James Alan Nguyen Date: Sun, 17 Apr 2022 15:54:00 +1000 Subject: [PATCH 33/77] Address review comments take 2 --- src/engine/fileOpsIns.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/engine/fileOpsIns.cpp b/src/engine/fileOpsIns.cpp index b1e5b3974..f9eaab38b 100644 --- a/src/engine/fileOpsIns.cpp +++ b/src/engine/fileOpsIns.cpp @@ -101,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(lastError.c_str()); + logE("premature end of file"); delete ins; return; } @@ -160,7 +160,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE(lastError.c_str()); + logE("premature end of file"); delete ins; return; } @@ -352,7 +352,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector& ret, St } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE(lastError.c_str()); + logE("premature end of file"); delete ins; return; } @@ -387,7 +387,7 @@ void DivEngine::loadTFI(SafeReader& reader, std::vector& ret, St } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE(lastError.c_str()); + logE("premature end of file"); delete ins; return; } @@ -429,7 +429,7 @@ void DivEngine::loadVGI(SafeReader& reader, std::vector& ret, St } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE(lastError.c_str()); + logE("premature end of file"); delete ins; return; } @@ -496,7 +496,7 @@ void DivEngine::loadS3I(SafeReader& reader, std::vector& ret, St reader.seek(21, SEEK_CUR); } else { lastError = "S3I PCM samples currently not supported."; - logE(lastError.c_str()); + logE("S3I PCM samples currently not supported."); } ins->name = reader.readString(28); ins->name = (ins->name.length() == 0) ? stripPath : ins->name; @@ -504,12 +504,12 @@ void DivEngine::loadS3I(SafeReader& reader, std::vector& ret, St int s3i_signature = reader.readI(); if (s3i_signature != 0x49524353) { - warnings = "S3I signature invalid."; - logW(lastError.c_str()); + addWarning("S3I signature invalid."); + logW("S3I signature invalid."); }; } catch (EndOfFileException& e) { lastError = "premature end of file"; - logE(lastError.c_str()); + logE("premature end of file"); delete ins; return; } @@ -630,7 +630,7 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector& ret, St } catch (EndOfFileException& e) { lastError = "premature end of file"; - logE(lastError.c_str()); + logE("premature end of file"); delete ins; } } @@ -712,7 +712,7 @@ void DivEngine::loadBNK(SafeReader& reader, std::vector& ret, St } catch (EndOfFileException& e) { lastError = "premature end of file"; - logE(lastError.c_str()); + logE("premature end of file"); for (int i = readCount; i >= 0; --i) { delete insList[i]; } @@ -722,7 +722,7 @@ void DivEngine::loadBNK(SafeReader& reader, std::vector& ret, St } else { // assume GEMS BNK for now. lastError = "GEMS BNK currently not supported."; - logE(lastError.c_str()); + logE("GEMS BNK currently not supported."); } if (!is_failed) { @@ -797,7 +797,7 @@ void DivEngine::loadFF(SafeReader& reader, std::vector& ret, Str } } catch (EndOfFileException& e) { lastError = "premature end of file"; - logE(lastError.c_str()); + logE("premature end of file"); for (int i = readCount; i >= 0; --i) { delete insList[i]; } @@ -818,7 +818,7 @@ void DivEngine::loadOPM(SafeReader& reader, std::vector& ret, St } catch (EndOfFileException& e) { lastError="premature end of file"; - logE(lastError.c_str()); + logE("premature end of file"); return; } } @@ -916,7 +916,7 @@ std::vector DivEngine::instrumentFromFile(const char* path) { } } catch (EndOfFileException& e) { lastError="premature end of file"; - logE(lastError.c_str()); + logE("premature end of file"); delete ins; delete[] buf; return ret; From 768419f46121c9267cbcbb7690e0e6a592e58e7f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 17 Apr 2022 01:15:34 -0500 Subject: [PATCH 34/77] GUI: implement GB envelope view --- src/gui/insEdit.cpp | 47 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index a58feea87..dca41f17f 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -943,7 +943,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, ImU32 colorR=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ENVELOPE_RELEASE]); // Relsease triangle ImU32 colorS=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ENVELOPE_SUS_GUIDE]); // Sustain horiz/vert line color ImGui::ItemSize(size,style.FramePadding.y); - if (ImGui::ItemAdd(rect,ImGui::GetID("alg"))) { + if (ImGui::ItemAdd(rect,ImGui::GetID("fmEnv"))) { ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding); //Adjust for OPLL global sustain setting @@ -1003,7 +1003,7 @@ void FurnaceGUI::drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, } void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char sLen, bool dir, const ImVec2& size) { - //ImDrawList* dl=ImGui::GetWindowDrawList(); + ImDrawList* dl=ImGui::GetWindowDrawList(); ImGuiWindow* window=ImGui::GetCurrentWindow(); ImVec2 minArea=window->DC.CursorPos; @@ -1013,13 +1013,50 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s ); ImRect rect=ImRect(minArea,maxArea); ImGuiStyle& style=ImGui::GetStyle(); - //ImU32 color=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ENVELOPE]); + ImU32 color=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ENVELOPE]); //ImU32 colorS=ImGui::GetColorU32(uiColors[GUI_COLOR_FM_ENVELOPE_SUS_GUIDE]); // Sustain horiz/vert line color ImGui::ItemSize(size,style.FramePadding.y); - if (ImGui::ItemAdd(rect,ImGui::GetID("alg"))) { + if (ImGui::ItemAdd(rect,ImGui::GetID("gbEnv"))) { ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding); + + float volY=1.0-((float)vol/15.0); + float lenPos=(sLen>62)?1.0:((float)sLen/384.0); + float envEndPoint=((float)len/7.0)*((float)(dir?(15-vol):vol)/15.0); - // TODO: this whole thing + ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.0,volY)); + ImVec2 pos2; + if (dir) { + if (len>0) { + if (lenPos0) { + if (lenPos0 || sLen<63)?((dir && sLen>62)?0.0:1.0):volY)); + + addAALine(dl,pos1,pos2,color); + if (lenPos>=envEndPoint && sLen<63 && dir) { + pos3=ImLerp(rect.Min,rect.Max,ImVec2(lenPos,0.0)); + addAALine(dl,pos2,pos3,color); + ImVec2 pos4=ImLerp(rect.Min,rect.Max,ImVec2(lenPos,1.0)); + addAALine(dl,pos3,pos4,color); + } else { + addAALine(dl,pos2,pos3,color); + } } } From 211a4b182181961221f7c76dee4c95fcdc7cf382 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 17 Apr 2022 01:37:33 -0500 Subject: [PATCH 35/77] C64: fix portamento not working... --- src/engine/platform/c64.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 12ec3f5f9..02473c80c 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -169,7 +169,7 @@ void DivPlatformC64::tick(bool sysTick) { if (sysTick) { if (chan[i].testWhen>0) { if (--chan[i].testWhen<1) { - if (!chan[i].resetMask) { + if (!chan[i].resetMask && !chan[i].inPorta) { rWrite(i*7+5,0); rWrite(i*7+6,0); rWrite(i*7+4,(chan[i].wave<<4)|8|(chan[i].ring<<2)|(chan[i].sync<<1)); @@ -344,7 +344,7 @@ int DivPlatformC64::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) { + if (parent->song.resetMacroOnPorta || !chan[c.chan].inPorta) { chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); chan[c.chan].keyOn=true; } From 0952d1b2f927785fc159d31d45d7841a1f3294b8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 17 Apr 2022 01:54:42 -0500 Subject: [PATCH 36/77] GUI: add a full-screen option --- src/gui/gui.cpp | 20 +++++++++++++++++--- src/gui/gui.h | 2 +- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 7f8f0d729..30b90793e 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #define _USE_MATH_DEFINES #include "gui.h" #include "util.h" @@ -2475,6 +2476,10 @@ bool FurnaceGUI::loop() { ImGui::EndMenu(); } if (ImGui::BeginMenu("settings")) { + if (ImGui::MenuItem("full screen",NULL,fullScreen)) { + fullScreen=!fullScreen; + SDL_SetWindowFullscreen(sdlWin,fullScreen?(SDL_WINDOW_FULLSCREEN|SDL_WINDOW_FULLSCREEN_DESKTOP):0); + } if (ImGui::MenuItem("lock layout",NULL,lockLayout)) { lockLayout=!lockLayout; } @@ -3235,6 +3240,7 @@ bool FurnaceGUI::init() { tempoView=e->getConfBool("tempoView",true); waveHex=e->getConfBool("waveHex",false); lockLayout=e->getConfBool("lockLayout",false); + fullScreen=e->getConfBool("fullScreen",false); syncSettings(); @@ -3258,7 +3264,7 @@ bool FurnaceGUI::init() { SDL_Init(SDL_INIT_VIDEO); - sdlWin=SDL_CreateWindow("Furnace",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,scrW*dpiScale,scrH*dpiScale,SDL_WINDOW_RESIZABLE|SDL_WINDOW_ALLOW_HIGHDPI); + sdlWin=SDL_CreateWindow("Furnace",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,scrW*dpiScale,scrH*dpiScale,SDL_WINDOW_RESIZABLE|SDL_WINDOW_ALLOW_HIGHDPI|(fullScreen?SDL_WINDOW_FULLSCREEN_DESKTOP:0)); if (sdlWin==NULL) { logE("could not open window! %s",SDL_GetError()); return false; @@ -3269,12 +3275,18 @@ bool FurnaceGUI::init() { SDL_GetDisplayDPI(SDL_GetWindowDisplayIndex(sdlWin),&dpiScaleF,NULL,NULL); dpiScale=round(dpiScaleF/96.0f); if (dpiScale<1) dpiScale=1; - if (dpiScale!=1) SDL_SetWindowSize(sdlWin,scrW*dpiScale,scrH*dpiScale); + if (dpiScale!=1) { + if (!fullScreen) { + SDL_SetWindowSize(sdlWin,scrW*dpiScale,scrH*dpiScale); + } + } if (SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(sdlWin),&displaySize)==0) { if (scrW>displaySize.w/dpiScale) scrW=(displaySize.w/dpiScale)-32; if (scrH>displaySize.h/dpiScale) scrH=(displaySize.h/dpiScale)-32; - SDL_SetWindowSize(sdlWin,scrW*dpiScale,scrH*dpiScale); + if (!fullScreen) { + SDL_SetWindowSize(sdlWin,scrW*dpiScale,scrH*dpiScale); + } } } #endif @@ -3402,6 +3414,7 @@ bool FurnaceGUI::finish() { e->setConf("tempoView",tempoView); e->setConf("waveHex",waveHex); e->setConf("lockLayout",lockLayout); + e->setConf("fullScreen",fullScreen); for (int i=0; i Date: Sun, 17 Apr 2022 01:57:50 -0500 Subject: [PATCH 37/77] GUI: add toggle full-screen keybind --- src/gui/doAction.cpp | 4 ++++ src/gui/gui.cpp | 5 ++--- src/gui/gui.h | 1 + src/gui/guiConst.cpp | 1 + src/gui/settings.cpp | 1 + 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index cd4dda075..b68d684d3 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -136,6 +136,10 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_FOLLOW_PATTERN: followPattern=!followPattern; break; + case GUI_ACTION_FULLSCREEN: + fullScreen=!fullScreen; + SDL_SetWindowFullscreen(sdlWin,fullScreen?(SDL_WINDOW_FULLSCREEN|SDL_WINDOW_FULLSCREEN_DESKTOP):0); + break; case GUI_ACTION_PANIC: e->syncReset(); break; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 30b90793e..fab19120b 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2476,9 +2476,8 @@ bool FurnaceGUI::loop() { ImGui::EndMenu(); } if (ImGui::BeginMenu("settings")) { - if (ImGui::MenuItem("full screen",NULL,fullScreen)) { - fullScreen=!fullScreen; - SDL_SetWindowFullscreen(sdlWin,fullScreen?(SDL_WINDOW_FULLSCREEN|SDL_WINDOW_FULLSCREEN_DESKTOP):0); + if (ImGui::MenuItem("full screen",BIND_FOR(GUI_ACTION_FULLSCREEN),fullScreen)) { + doAction(GUI_ACTION_FULLSCREEN); } if (ImGui::MenuItem("lock layout",NULL,lockLayout)) { lockLayout=!lockLayout; diff --git a/src/gui/gui.h b/src/gui/gui.h index 4743a0002..b193e39a5 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -297,6 +297,7 @@ enum FurnaceGUIActions { GUI_ACTION_REPEAT_PATTERN, GUI_ACTION_FOLLOW_ORDERS, GUI_ACTION_FOLLOW_PATTERN, + GUI_ACTION_FULLSCREEN, GUI_ACTION_PANIC, GUI_ACTION_WINDOW_EDIT_CONTROLS, diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 10b004421..7cc173c52 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -167,6 +167,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("REPEAT_PATTERN", "Toggle repeat pattern", 0), D("FOLLOW_ORDERS", "Follow orders", 0), D("FOLLOW_PATTERN", "Follow pattern", 0), + D("FULLSCREEN", "Toggle full-screen", FURKMOD_ALT|SDLK_RETURN), D("PANIC", "Panic", SDLK_F12), D("WINDOW_EDIT_CONTROLS", "Edit Controls", 0), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index be0805f3a..7ead6c204 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1249,6 +1249,7 @@ void FurnaceGUI::drawSettings() { UI_KEYBIND_CONFIG(GUI_ACTION_REPEAT_PATTERN); UI_KEYBIND_CONFIG(GUI_ACTION_FOLLOW_ORDERS); UI_KEYBIND_CONFIG(GUI_ACTION_FOLLOW_PATTERN); + UI_KEYBIND_CONFIG(GUI_ACTION_FULLSCREEN); UI_KEYBIND_CONFIG(GUI_ACTION_PANIC); KEYBIND_CONFIG_END; From 53994cebbdfd3744b249352c401512f8a7436b62 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 17 Apr 2022 02:08:19 -0500 Subject: [PATCH 38/77] GUI: new default key for full-screen --- src/gui/guiConst.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 7cc173c52..a0b3c17c4 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -167,7 +167,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("REPEAT_PATTERN", "Toggle repeat pattern", 0), D("FOLLOW_ORDERS", "Follow orders", 0), D("FOLLOW_PATTERN", "Follow pattern", 0), - D("FULLSCREEN", "Toggle full-screen", FURKMOD_ALT|SDLK_RETURN), + D("FULLSCREEN", "Toggle full-screen", SDLK_F11), D("PANIC", "Panic", SDLK_F12), D("WINDOW_EDIT_CONTROLS", "Edit Controls", 0), From 0258342324eb59ad2e9d7be8dd901d0663994d7c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 17 Apr 2022 02:08:53 -0500 Subject: [PATCH 39/77] M S V C --- src/gui/gui.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index fab19120b..f3ab5a327 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -17,7 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #define _USE_MATH_DEFINES #include "gui.h" #include "util.h" From c9324e04bd10cb1d1f27b313598b1a090ea96f07 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 17 Apr 2022 02:51:03 -0500 Subject: [PATCH 40/77] GUI: vertical C64 envelope editor --- src/gui/insEdit.cpp | 47 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index dca41f17f..d3f297d40 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2331,13 +2331,48 @@ void FurnaceGUI::drawInsEdit() { } ImGui::PopStyleColor(); - P(CWSliderScalar("Attack",ImGuiDataType_U8,&ins->c64.a,&_ZERO,&_FIFTEEN)); rightClickable - P(CWSliderScalar("Decay",ImGuiDataType_U8,&ins->c64.d,&_ZERO,&_FIFTEEN)); rightClickable - P(CWSliderScalar("Sustain",ImGuiDataType_U8,&ins->c64.s,&_ZERO,&_FIFTEEN)); rightClickable - P(CWSliderScalar("Release",ImGuiDataType_U8,&ins->c64.r,&_ZERO,&_FIFTEEN)); rightClickable - P(CWSliderScalar("Duty",ImGuiDataType_U16,&ins->c64.duty,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE)); rightClickable + ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale); - drawFMEnv(0,16-ins->c64.a,16-ins->c64.d,15-ins->c64.r,15-ins->c64.r,15-ins->c64.s,0,0,0,15,16,ImVec2(ImGui::GetContentRegionAvail().x,100.0f*dpiScale),ins->type); + if (ImGui::BeginTable("C64EnvParams",5,ImGuiTableFlags_NoHostExtendX)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,sliderSize.x); + ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + CENTER_TEXT("A"); + ImGui::TextUnformatted("A"); + ImGui::TableNextColumn(); + CENTER_TEXT("D"); + ImGui::TextUnformatted("D"); + ImGui::TableNextColumn(); + CENTER_TEXT("S"); + ImGui::TextUnformatted("S"); + ImGui::TableNextColumn(); + CENTER_TEXT("R"); + ImGui::TextUnformatted("R"); + ImGui::TableNextColumn(); + CENTER_TEXT("Envelope"); + ImGui::TextUnformatted("Envelope"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Attack",sliderSize,ImGuiDataType_U8,&ins->c64.a,&_ZERO,&_FIFTEEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Decay",sliderSize,ImGuiDataType_U8,&ins->c64.d,&_ZERO,&_FIFTEEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Sustain",sliderSize,ImGuiDataType_U8,&ins->c64.s,&_ZERO,&_FIFTEEN)); + ImGui::TableNextColumn(); + P(CWVSliderScalar("##Release",sliderSize,ImGuiDataType_U8,&ins->c64.r,&_ZERO,&_FIFTEEN)); + ImGui::TableNextColumn(); + drawFMEnv(0,16-ins->c64.a,16-ins->c64.d,15-ins->c64.r,15-ins->c64.r,15-ins->c64.s,0,0,0,15,16,ImVec2(ImGui::GetContentRegionAvail().x,sliderSize.y),ins->type); + + ImGui::EndTable(); + } + + P(CWSliderScalar("Duty",ImGuiDataType_U16,&ins->c64.duty,&_ZERO,&_FOUR_THOUSAND_NINETY_FIVE)); rightClickable bool ringMod=ins->c64.ringMod; if (ImGui::Checkbox("Ring Modulation",&ringMod)) { PARAMETER From 5e7a4eae16ed7a82a499855d87326f77c9a67d80 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 17 Apr 2022 05:01:54 -0500 Subject: [PATCH 41/77] VERA: finally proper volume --- src/engine/platform/vera.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 99da6062e..99c6f8822 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -114,8 +114,8 @@ void DivPlatformVERA::acquire(short* bufL, short* bufR, size_t start, size_t len psg_render(psg,buf[0],buf[1],curLen); pcm_render(pcm,buf[2],buf[3],curLen); for (int i=0; i>1))/2); - bufR[pos]=(short)(((int)buf[1][i]+(buf[3][i]>>1))/2); + bufL[pos]=(short)(((int)buf[0][i]+buf[2][i])/2); + bufR[pos]=(short)(((int)buf[1][i]+buf[3][i])/2); pos++; } len-=curLen; @@ -377,7 +377,7 @@ void DivPlatformVERA::muteChannel(int ch, bool mute) { } float DivPlatformVERA::getPostAmp() { - return 4.0f; + return 8.0f; } bool DivPlatformVERA::isStereo() { From fc8a130c71529059bca416b76392faa6925dce72 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 17 Apr 2022 14:15:57 -0500 Subject: [PATCH 42/77] implement panning macro except for QSound --- src/engine/platform/gb.cpp | 5 +++++ src/engine/platform/genesis.cpp | 5 +++++ src/engine/platform/lynx.cpp | 14 ++++++++++++++ src/engine/platform/opl.cpp | 6 +++++- src/engine/platform/pce.cpp | 11 +++++++++++ src/engine/platform/saa.cpp | 20 ++++++++++++++++++++ src/engine/platform/segapcm.cpp | 24 ++++++++++++++++++++++-- src/engine/platform/swan.cpp | 11 +++++++++++ src/engine/platform/vera.cpp | 6 ++++++ src/engine/platform/x1_010.cpp | 10 ++++++++++ src/engine/platform/ym2610.cpp | 5 +++++ src/engine/platform/ym2610b.cpp | 5 +++++ src/gui/insEdit.cpp | 4 ++-- 13 files changed, 121 insertions(+), 5 deletions(-) diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index d3bb28e5e..eb7b6881e 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -192,6 +192,11 @@ void DivPlatformGB::tick(bool sysTick) { if (!chan[i].keyOff) chan[i].keyOn=true; } } + if (chan[i].std.panL.had) { + lastPan&=~(0x11<>1); + } + if (chan[i].std.pitch.had) { chan[i].freqChanged=true; } @@ -286,7 +290,7 @@ void DivPlatformOPL::tick(bool sysTick) { chan[i].state.fb=chan[i].std.fb.val; } - if (chan[i].std.alg.had || chan[i].std.fb.had) { + if (chan[i].std.alg.had || chan[i].std.fb.had || (oplType==3 && chan[i].std.panL.had)) { if (isMuted[i]) { rWrite(chanMap[i]+ADDR_LR_FB_ALG,(chan[i].state.alg&1)|(chan[i].state.fb<<1)); if (ops==4) { diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index 2c248db09..e1cbb6808 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -196,6 +196,17 @@ void DivPlatformPCE::tick(bool sysTick) { if (!chan[i].keyOff) chan[i].keyOn=true; } } + if (chan[i].std.panL.had) { + chan[i].pan&=0x0f; + chan[i].pan|=(chan[i].std.panL.val&15)<<4; + } + if (chan[i].std.panR.had) { + chan[i].pan&=0xf0; + chan[i].pan|=chan[i].std.panR.val&15; + } + if (chan[i].std.panL.had || chan[i].std.panR.had) { + chWrite(i,0x05,isMuted[i]?0:chan[i].pan); + } if (chan[i].std.pitch.had) { chan[i].freqChanged=true; } diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index 0e06c3388..47b698051 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -166,6 +166,26 @@ void DivPlatformSAA1099::tick(bool sysTick) { if (chan[i].std.wave.had) { chan[i].psgMode=chan[i].std.wave.val&3; } + if (chan[i].std.panL.had) { + chan[i].pan&=0x0f; + chan[i].pan|=(chan[i].std.panL.val&15)<<4; + } + + if (chan[i].std.panR.had) { + chan[i].pan&=0xf0; + chan[i].pan|=chan[i].std.panR.val&15; + } + if (chan[i].std.panL.had || chan[i].std.panR.had) { + if (isMuted[i]) { + rWrite(i,0); + } else { + if (chan[i].std.vol.had) { + if (chan[i].active) rWrite(i,applyPan(chan[i].outVol&15,chan[i].pan)); + } else { + if (chan[i].active) rWrite(i,applyPan(chan[i].vol&15,chan[i].pan)); + } + } + } if (chan[i].std.pitch.had) { chan[i].freqChanged=true; } diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 79d7179a2..700924476 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -80,9 +80,10 @@ void DivPlatformSegaPCM::tick(bool sysTick) { for (int i=0; i<16; i++) { chan[i].std.next(); - if (chan[i].std.vol.had) { + // TODO: fix + /*if (chan[i].std.vol.had) { chan[i].outVol=(chan[i].vol*MIN(127,chan[i].std.vol.val))/127; - } + }*/ if (chan[i].std.arp.had) { if (!chan[i].inPorta) { @@ -99,6 +100,20 @@ void DivPlatformSegaPCM::tick(bool sysTick) { chan[i].freqChanged=true; } } + + if (chan[i].std.panL.had) { + chan[i].chVolL=chan[i].std.panL.val&127; + if (dumpWrites) { + addWrite(0x10002+(i<<3),chan[i].chVolL); + } + } + + if (chan[i].std.panR.had) { + chan[i].chVolR=chan[i].std.panR.val&127; + if (dumpWrites) { + addWrite(0x10003+(i<<3),chan[i].chVolR); + } + } if (chan[i].std.pitch.had) { chan[i].freqChanged=true; @@ -143,14 +158,17 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { if (dumpWrites) { addWrite(0x10086+(c.chan<<3),3); } + chan[c.chan].std.init(NULL); break; } chan[c.chan].pcm.pos=0; if (c.value!=DIV_NOTE_NULL) { + chan[c.chan].note=c.value; chan[c.chan].baseFreq=(c.value<<6); chan[c.chan].freqChanged=true; } chan[c.chan].furnacePCM=true; + chan[c.chan].std.init(ins); if (dumpWrites) { // Sega PCM writes DivSample* s=parent->getSample(chan[c.chan].pcm.sample); addWrite(0x10086+(c.chan<<3),3+((s->offSegaPCM>>16)<<3)); @@ -167,6 +185,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { } } } else { + chan[c.chan].std.init(NULL); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; } @@ -208,6 +227,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { chan[c.chan].keyOff=true; chan[c.chan].keyOn=false; chan[c.chan].active=false; + chan[c.chan].std.init(NULL); break; case DIV_CMD_NOTE_OFF_ENV: chan[c.chan].keyOff=true; diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 3b4a955ea..22790c641 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -173,6 +173,17 @@ void DivPlatformSwan::tick(bool sysTick) { chan[i].ws.changeWave1(chan[i].wave); } } + if (chan[i].std.panL.had) { + chan[i].pan&=0x0f; + chan[i].pan|=(chan[i].std.panL.val&15)<<4; + } + if (chan[i].std.panR.had) { + chan[i].pan&=0xf0; + chan[i].pan|=chan[i].std.panR.val&15; + } + if (chan[i].std.panL.had || chan[i].std.panR.had) { + calcAndWriteOutVol(i,chan[i].std.vol.will?chan[i].std.vol.val:15); + } if (chan[i].std.pitch.had) { chan[i].freqChanged=true; } diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 99c6f8822..89cccb99d 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -184,6 +184,12 @@ void DivPlatformVERA::tick(bool sysTick) { if (chan[i].std.wave.had) { rWriteHi(i,3,chan[i].std.wave.val); } + if (i<16) { + if (chan[i].std.panL.had) { + chan[i].pan=chan[i].std.panL.val&3; + rWriteHi(i,2,isMuted[i]?0:chan[i].pan); + } + } if (chan[i].std.pitch.had) { chan[i].freqChanged=true; } diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index 229d8eab6..9c9b3e20d 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -372,6 +372,16 @@ void DivPlatformX1_010::tick(bool sysTick) { } } } + if (chan[i].std.panL.had) { + chan[i].pan&=0x0f; + chan[i].pan|=(chan[i].std.panL.val&15)<<4; + chan[i].envChanged=true; + } + if (chan[i].std.panR.had) { + chan[i].pan&=0xf0; + chan[i].pan|=chan[i].std.panR.val&15; + chan[i].envChanged=true; + } if (chan[i].std.pitch.had) { chan[i].freqChanged=true; } diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 6f4a1e46c..f955303d3 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -408,6 +408,11 @@ void DivPlatformYM2610::tick(bool sysTick) { } } + if (chan[i].std.panL.had) { + chan[i].pan=chan[i].std.panL.val&3; + rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + } + if (chan[i].std.pitch.had) { chan[i].freqChanged=true; } diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 04bc096a9..75855f4fc 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -472,6 +472,11 @@ void DivPlatformYM2610B::tick(bool sysTick) { } } + if (chan[i].std.panL.had) { + chan[i].pan=chan[i].std.panL.val&3; + rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4)); + } + if (chan[i].std.pitch.had) { chan[i].freqChanged=true; } diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index d3f297d40..995cc6e31 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -176,7 +176,7 @@ const char* n163UpdateBits[8]={ }; const char* panBits[3]={ - "left", "right", NULL + "right", "left", NULL }; const char* oneBit[2]={ @@ -2826,7 +2826,7 @@ void FurnaceGUI::drawInsEdit() { if (ins->type==DIV_INS_AMIGA) { panMax=127; } - if (ins->type==DIV_INS_X1_010 || ins->type==DIV_INS_PCE) { + if (ins->type==DIV_INS_X1_010 || ins->type==DIV_INS_PCE || ins->type==DIV_INS_MIKEY || ins->type==DIV_INS_SAA1099) { panMax=15; } From b8c790bf79df15d66aa9379c5acc9a742d79149e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 18 Apr 2022 00:52:29 -0500 Subject: [PATCH 43/77] dev84 - new compat flag and store macro modes --- TODO.md | 3 +-- src/engine/engine.h | 4 ++-- src/engine/fileOps.cpp | 13 ++++++++++-- src/engine/instrument.cpp | 44 +++++++++++++++++++++++++++++++++++++++ src/engine/song.h | 4 +++- src/gui/compatFlags.cpp | 4 ++++ 6 files changed, 65 insertions(+), 7 deletions(-) diff --git a/TODO.md b/TODO.md index 04b724e0a..b6d059502 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,7 @@ # to-do for 0.6pre1 - panning macro - - single macro for hard-panned chips - - two macros for soft-panned ones + - QSound? - pitch macro - relative mode - test diff --git a/src/engine/engine.h b/src/engine/engine.h index 3ec530f87..114d06d4c 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -42,8 +42,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev83" -#define DIV_ENGINE_VERSION 83 +#define DIV_VERSION "dev84" +#define DIV_ENGINE_VERSION 84 // for imports #define DIV_VERSION_MOD 0xff01 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 183ff81a1..aee7de71f 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -990,6 +990,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { ds.ignoreDACModeOutsideIntendedChannel=true; ds.e1e2AlsoTakePriority=false; } + if (ds.version<84) { + ds.newSegaPCM=false; + } ds.isDMF=false; reader.readS(); // reserved @@ -1334,7 +1337,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { reader.readC(); reader.readC(); } - for (int i=0; i<23; i++) { + if (ds.version>=84) { + ds.newSegaPCM=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<22; i++) { reader.readC(); } } @@ -2274,7 +2282,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(song.sharedExtStat); w->writeC(song.ignoreDACModeOutsideIntendedChannel); w->writeC(song.e1e2AlsoTakePriority); - for (int i=0; i<23; i++) { + w->writeC(song.newSegaPCM); + for (int i=0; i<22; i++) { w->writeC(0); } diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index b5ed40890..273af9bf7 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -482,6 +482,27 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(ws.param2); w->writeC(ws.param3); w->writeC(ws.param4); + + // other macro modes + w->writeC(std.volMacro.mode); + w->writeC(std.dutyMacro.mode); + w->writeC(std.waveMacro.mode); + w->writeC(std.pitchMacro.mode); + w->writeC(std.ex1Macro.mode); + w->writeC(std.ex2Macro.mode); + w->writeC(std.ex3Macro.mode); + w->writeC(std.algMacro.mode); + w->writeC(std.fbMacro.mode); + w->writeC(std.fmsMacro.mode); + w->writeC(std.amsMacro.mode); + w->writeC(std.panLMacro.mode); + w->writeC(std.panRMacro.mode); + w->writeC(std.phaseResetMacro.mode); + w->writeC(std.ex4Macro.mode); + w->writeC(std.ex5Macro.mode); + w->writeC(std.ex6Macro.mode); + w->writeC(std.ex7Macro.mode); + w->writeC(std.ex8Macro.mode); } DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { @@ -954,6 +975,29 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { ws.param4=reader.readC(); } + // other macro modes + if (version>=84) { + std.volMacro.mode=reader.readC(); + std.dutyMacro.mode=reader.readC(); + std.waveMacro.mode=reader.readC(); + std.pitchMacro.mode=reader.readC(); + std.ex1Macro.mode=reader.readC(); + std.ex2Macro.mode=reader.readC(); + std.ex3Macro.mode=reader.readC(); + std.algMacro.mode=reader.readC(); + std.fbMacro.mode=reader.readC(); + std.fmsMacro.mode=reader.readC(); + std.amsMacro.mode=reader.readC(); + std.panLMacro.mode=reader.readC(); + std.panRMacro.mode=reader.readC(); + std.phaseResetMacro.mode=reader.readC(); + std.ex4Macro.mode=reader.readC(); + std.ex5Macro.mode=reader.readC(); + std.ex6Macro.mode=reader.readC(); + std.ex7Macro.mode=reader.readC(); + std.ex8Macro.mode=reader.readC(); + } + return DIV_DATA_SUCCESS; } diff --git a/src/engine/song.h b/src/engine/song.h index 6cda7c533..81c0cb8a8 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -323,6 +323,7 @@ struct DivSong { bool sharedExtStat; bool ignoreDACModeOutsideIntendedChannel; bool e1e2AlsoTakePriority; + bool newSegaPCM; DivOrders orders; std::vector ins; @@ -404,7 +405,8 @@ struct DivSong { gbInsAffectsEnvelope(true), sharedExtStat(true), ignoreDACModeOutsideIntendedChannel(false), - e1e2AlsoTakePriority(false) { + e1e2AlsoTakePriority(false), + newSegaPCM(true) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; systemVol[i]=64; diff --git a/src/gui/compatFlags.cpp b/src/gui/compatFlags.cpp index 8a45741f8..d2035ff70 100644 --- a/src/gui/compatFlags.cpp +++ b/src/gui/compatFlags.cpp @@ -166,6 +166,10 @@ void FurnaceGUI::drawCompatFlags() { if (ImGui::IsItemHovered()) { ImGui::SetTooltip("behavior changed in 0.6"); } + ImGui::Checkbox("New SegaPCM features (macros and better panning)",&e->song.newSegaPCM); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("behavior changed in 0.6"); + } } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS; ImGui::End(); From 744c5982e12ef1c7dc4f0a628cd42770f779aa26 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 18 Apr 2022 01:31:03 -0500 Subject: [PATCH 44/77] bring on backward-cpp cross your fingers --- .gitmodules | 3 +++ CMakeLists.txt | 2 +- extern/backward | 1 + src/main.cpp | 4 ++++ 4 files changed, 9 insertions(+), 1 deletion(-) create mode 160000 extern/backward diff --git a/.gitmodules b/.gitmodules index d63fd70b5..a1c7da6d6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "extern/Nuked-OPL3"] path = extern/Nuked-OPL3 url = https://github.com/nukeykt/Nuked-OPL3.git +[submodule "extern/backward"] + path = extern/backward + url = https://github.com/bombela/backward-cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 498f3df69..3d6b9834e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -442,7 +442,7 @@ else() endif() if (WIN32) - list(APPEND DEPENDENCIES_LIBRARIES shlwapi) + list(APPEND DEPENDENCIES_LIBRARIES shlwapi imagehlp msvcr90) if (NOT MSVC) list(APPEND DEPENDENCIES_LIBRARIES -static) endif() diff --git a/extern/backward b/extern/backward new file mode 160000 index 000000000..5ffb2c879 --- /dev/null +++ b/extern/backward @@ -0,0 +1 @@ +Subproject commit 5ffb2c879ebdbea3bdb8477c671e32b1c984beaa diff --git a/src/main.cpp b/src/main.cpp index 8f41b10cb..29018b8d5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -39,6 +39,8 @@ #include "gui/gui.h" #endif +#include "../extern/backward/backward.hpp" + DivEngine e; #ifdef HAVE_GUI @@ -251,6 +253,8 @@ int main(int argc, char** argv) { outName=""; vgmOutName=""; + backward::SignalHandling crashHandler; + initParams(); // parse arguments From 4b0ffcafe834ccdf83e3ecc29fcecd1f8e209e8c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 18 Apr 2022 01:40:26 -0500 Subject: [PATCH 45/77] take 2 --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 29018b8d5..d7c2c194e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,6 +17,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "../extern/backward/backward.hpp" + #include #include #include @@ -39,8 +41,6 @@ #include "gui/gui.h" #endif -#include "../extern/backward/backward.hpp" - DivEngine e; #ifdef HAVE_GUI From 70ff71af44deb19f8d4d35e95e11d82e13f311b5 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 18 Apr 2022 01:49:28 -0500 Subject: [PATCH 46/77] take 3 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d6b9834e..9147beb66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -442,9 +442,9 @@ else() endif() if (WIN32) - list(APPEND DEPENDENCIES_LIBRARIES shlwapi imagehlp msvcr90) + list(APPEND DEPENDENCIES_LIBRARIES shlwapi imagehlp) if (NOT MSVC) - list(APPEND DEPENDENCIES_LIBRARIES -static) + list(APPEND DEPENDENCIES_LIBRARIES msvcr90 -static) endif() endif() From 925b1c21798791cdf081070b2938f00d78a22f32 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 18 Apr 2022 01:56:26 -0500 Subject: [PATCH 47/77] i'm done here --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 293c4cd0f..13ef95c74 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -187,6 +187,8 @@ jobs: export USE_WAE=ON export CMAKE_EXTRA_ARGS=() if [ '${{ matrix.config.compiler }}' == 'msvc' ]; then + # 1. Go to hell + export USE_WAE=OFF CMAKE_EXTRA_ARGS+=('-DCMAKE_GENERATOR_PLATFORM=${{ steps.windows-identify.outputs.msvc-target }}') # Force static linking From d4f58cb6ea6538bed96a612b60643477169e732f Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 18 Apr 2022 02:09:37 -0500 Subject: [PATCH 48/77] the final take (hopefully) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9147beb66..c8278959b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -444,7 +444,7 @@ endif() if (WIN32) list(APPEND DEPENDENCIES_LIBRARIES shlwapi imagehlp) if (NOT MSVC) - list(APPEND DEPENDENCIES_LIBRARIES msvcr90 -static) + list(APPEND DEPENDENCIES_LIBRARIES msvcr90 dbghelp -static) endif() endif() From eafbec6cfcd176a7b2320e342bf1b50c34e47cfa Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 18 Apr 2022 02:16:57 -0500 Subject: [PATCH 49/77] really what the heck --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c8278959b..950dc4ad5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -444,7 +444,7 @@ endif() if (WIN32) list(APPEND DEPENDENCIES_LIBRARIES shlwapi imagehlp) if (NOT MSVC) - list(APPEND DEPENDENCIES_LIBRARIES msvcr90 dbghelp -static) + list(APPEND DEPENDENCIES_LIBRARIES msvcr90 psapi -static) endif() endif() From 4d6fe8f0eae746dc200ec7d9bd2f974880b5a310 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 18 Apr 2022 03:15:39 -0500 Subject: [PATCH 50/77] get rid of backward thanks for the waste of time --- .gitmodules | 3 --- extern/backward | 1 - 2 files changed, 4 deletions(-) delete mode 160000 extern/backward diff --git a/.gitmodules b/.gitmodules index a1c7da6d6..d63fd70b5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,6 +22,3 @@ [submodule "extern/Nuked-OPL3"] path = extern/Nuked-OPL3 url = https://github.com/nukeykt/Nuked-OPL3.git -[submodule "extern/backward"] - path = extern/backward - url = https://github.com/bombela/backward-cpp diff --git a/extern/backward b/extern/backward deleted file mode 160000 index 5ffb2c879..000000000 --- a/extern/backward +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5ffb2c879ebdbea3bdb8477c671e32b1c984beaa From cc08dd895b43a698193ab3c1b956eb970dc28730 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 18 Apr 2022 03:17:11 -0500 Subject: [PATCH 51/77] get rid of backward completely for real --- CMakeLists.txt | 4 ++-- src/main.cpp | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 950dc4ad5..498f3df69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -442,9 +442,9 @@ else() endif() if (WIN32) - list(APPEND DEPENDENCIES_LIBRARIES shlwapi imagehlp) + list(APPEND DEPENDENCIES_LIBRARIES shlwapi) if (NOT MSVC) - list(APPEND DEPENDENCIES_LIBRARIES msvcr90 psapi -static) + list(APPEND DEPENDENCIES_LIBRARIES -static) endif() endif() diff --git a/src/main.cpp b/src/main.cpp index d7c2c194e..4a3e9d0e2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,8 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "../extern/backward/backward.hpp" - #include #include #include @@ -242,6 +240,7 @@ void initParams() { } // TODO: CoInitializeEx on Windows? +// TODO: add crash log int main(int argc, char** argv) { initLog(); #if !(defined(__APPLE__) || defined(_WIN32)) @@ -253,8 +252,6 @@ int main(int argc, char** argv) { outName=""; vgmOutName=""; - backward::SignalHandling crashHandler; - initParams(); // parse arguments From afa59a27ff0567a2c608e4a6f5f8a1e98a617008 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 18 Apr 2022 04:16:59 -0500 Subject: [PATCH 52/77] fix note preview for ADPCM-A --- src/engine/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 6d0d4df0e..88f50da92 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1971,7 +1971,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) { } do { - if ((ins==-1 || getPreferInsType(finalChan)==getIns(ins)->type || getIns(ins)->type==DIV_INS_AMIGA) && chan[finalChan].midiNote==-1) { + if ((ins==-1 || getChannelType(finalChan)==4 || getPreferInsType(finalChan)==getIns(ins)->type || getIns(ins)->type==DIV_INS_AMIGA) && chan[finalChan].midiNote==-1) { chan[finalChan].midiNote=note; pendingNotes.push(DivNoteEvent(finalChan,ins,note,vol,true)); break; From a4ff0c3876970b11e39208daeff60817a3cf2999 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 18 Apr 2022 04:18:33 -0500 Subject: [PATCH 53/77] GUI: fix relative/fixed toggle label being wrong --- src/gui/insEdit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 995cc6e31..baca9469e 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1082,7 +1082,7 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s } \ if (macroMode) { \ bool modeVal=macro.mode; \ - if (ImGui::Checkbox("Relative##IMacroMode_" macroName,&modeVal)) { \ + if (ImGui::Checkbox("Fixed##IMacroMode_" macroName,&modeVal)) { \ macro.mode=modeVal; \ } \ } \ @@ -1176,7 +1176,7 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s } \ if (macroMode) { \ bool modeVal=macro.mode; \ - if (ImGui::Checkbox("Relative##IOPMacroMode_" macroName,&modeVal)) { \ + if (ImGui::Checkbox("Fixed##IOPMacroMode_" macroName,&modeVal)) { \ macro.mode=modeVal; \ } \ } \ From cc5013f3dc8c33f9f508e7b165a7d1f41f6cd5df Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 18 Apr 2022 04:42:51 -0500 Subject: [PATCH 54/77] possibly fix OPl3 per-channel audio export --- src/engine/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 88f50da92..2597e1191 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -397,7 +397,7 @@ void DivEngine::runExportThread() { if (getChannelType(i)==5) { i++; while (true) { - if (++i>=chans) break; + if (i>=chans) break; if (getChannelType(i)!=5) break; } i--; From f550bd82ddc24c509feae47fb2e5d02e728a84a4 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 18 Apr 2022 16:21:00 -0500 Subject: [PATCH 55/77] possibly fix #373 --- src/engine/platform/amiga.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 104e66d45..6d015db48 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -108,7 +108,9 @@ void DivPlatformAmiga::acquire(short* bufL, short* bufR, size_t start, size_t le } else { DivSample* s=parent->getSample(chan[i].sample); if (s->samples>0) { - writeAudDat(s->data8[chan[i].audPos++]); + if (chan[i].audPossamples) { + writeAudDat(s->data8[chan[i].audPos++]); + } if (chan[i].audPos>=s->samples || chan[i].audPos>=131071) { if (s->loopStart>=0 && s->loopStart<(int)s->samples) { chan[i].audPos=s->loopStart; From 7767881ca7b4c214304e36e49c4e98913dbc0709 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 19 Apr 2022 13:59:17 -0500 Subject: [PATCH 56/77] VRC6: fix saw column not yielding saw type ins fixes #374 --- src/engine/sysDef.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 084504fe1..acd3cff25 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -1123,7 +1123,7 @@ const DivInstrumentType chanPrefType[47][28]={ {DIV_INS_VIC, DIV_INS_VIC, DIV_INS_VIC, DIV_INS_VIC}, // VIC-20 {DIV_INS_PET}, // PET {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, // SNES/N163/RF5C68 - {DIV_INS_VRC6, DIV_INS_VRC6, DIV_INS_VRC6}, // VRC6 + {DIV_INS_VRC6, DIV_INS_VRC6, DIV_INS_VRC6_SAW}, // VRC6 {DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL}, // OPLL/VRC7 {DIV_INS_FDS}, // FDS {DIV_INS_STD, DIV_INS_STD, DIV_INS_AMIGA}, // MMC5 From b6026e76c538f680fbf6de75b4ef4d3e5a35d87b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 19 Apr 2022 18:10:43 -0500 Subject: [PATCH 57/77] SMS: fix noise pitch being odd on linear pitch off issue #379 --- src/engine/platform/sms.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index d755e84f6..da31e4784 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -23,8 +23,6 @@ #define rWrite(v) {if (!skipRegisterWrites) {sn->write(v); if (dumpWrites) {addWrite(0x200,v);}}} -#define CHIP_DIVIDER 64 - const char* regCheatSheetSN[]={ "DATA", "0", NULL @@ -55,6 +53,8 @@ int DivPlatformSMS::acquireOne() { void DivPlatformSMS::tick(bool sysTick) { for (int i=0; i<4; i++) { + int CHIP_DIVIDER=64; + if (i==3 && isRealSN) CHIP_DIVIDER=60; chan[i].std.next(); if (chan[i].std.vol.had) { chan[i].outVol=MIN(15,chan[i].std.vol.val)-(15-(chan[i].vol&15)); @@ -119,8 +119,7 @@ void DivPlatformSMS::tick(bool sysTick) { } } if (chan[3].freqChanged || updateSNMode) { - // seems arbitrary huh? - chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch-1-(isRealSN?127:0),true)+chan[3].std.pitch.val; + chan[3].freq=parent->calcFreq(chan[3].baseFreq,chan[3].pitch,true)+chan[3].std.pitch.val; if (chan[3].freq>1023) chan[3].freq=1023; if (chan[3].actualNote>0x5d) chan[3].freq=0x01; if (snNoiseMode&2) { // take period from channel 3 @@ -164,6 +163,8 @@ void DivPlatformSMS::tick(bool sysTick) { } int DivPlatformSMS::dispatch(DivCommand c) { + int CHIP_DIVIDER=64; + if (c.chan==3 && isRealSN) CHIP_DIVIDER=60; switch (c.cmd) { case DIV_CMD_NOTE_ON: if (c.value!=DIV_NOTE_NULL) { From d4380e152451dab453c776aedcc865ad436704c8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 19 Apr 2022 18:44:05 -0500 Subject: [PATCH 58/77] GUI: add an effect list window --- CMakeLists.txt | 1 + src/engine/engine.cpp | 7 ++-- src/engine/engine.h | 2 +- src/gui/doAction.cpp | 9 ++++++ src/gui/effectList.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++ src/gui/gui.cpp | 9 +++++- src/gui/gui.h | 9 ++++-- src/gui/guiConst.cpp | 57 ++++++++++++++++++++++++++++++++- src/gui/guiConst.h | 4 ++- src/gui/log.cpp | 1 + src/gui/pattern.cpp | 54 ------------------------------- 11 files changed, 161 insertions(+), 65 deletions(-) create mode 100644 src/gui/effectList.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 498f3df69..623b6cc35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -393,6 +393,7 @@ src/gui/debugWindow.cpp src/gui/doAction.cpp src/gui/editing.cpp src/gui/editControls.cpp +src/gui/effectList.cpp src/gui/insEdit.cpp src/gui/log.cpp src/gui/mixer.cpp diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 2597e1191..488b4bf63 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -41,7 +41,7 @@ void process(void* u, float** in, float** out, int inChans, int outChans, unsign ((DivEngine*)u)->nextBuf(in,out,inChans,outChans,size); } -const char* DivEngine::getEffectDesc(unsigned char effect, int chan) { +const char* DivEngine::getEffectDesc(unsigned char effect, int chan, bool notNull) { switch (effect) { case 0x00: return "00xy: Arpeggio"; @@ -116,14 +116,13 @@ const char* DivEngine::getEffectDesc(unsigned char effect, int chan) { default: if ((effect&0xf0)==0x90) { return "9xxx: Set sample offset*256"; - } - else if (chan>=0 && chan=0 && changetEffectName(effect); if (ret!=NULL) return ret; } break; } - return "Invalid effect"; + return notNull?"Invalid effect":NULL; } void DivEngine::walkSong(int& loopOrder, int& loopRow, int& loopEnd) { diff --git a/src/engine/engine.h b/src/engine/engine.h index 114d06d4c..efcbb21b0 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -402,7 +402,7 @@ class DivEngine { int getTotalChannelCount(); // get effect description - const char* getEffectDesc(unsigned char effect, int chan); + const char* getEffectDesc(unsigned char effect, int chan, bool notNull=false); // get channel type // - 0: FM diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index b68d684d3..fc0dbef90 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -213,6 +213,9 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_WINDOW_LOG: nextWindow=GUI_WINDOW_LOG; break; + case GUI_ACTION_WINDOW_EFFECT_LIST: + nextWindow=GUI_WINDOW_EFFECT_LIST; + break; case GUI_ACTION_COLLAPSE_WINDOW: collapseWindow=true; @@ -285,6 +288,12 @@ void FurnaceGUI::doAction(int what) { case GUI_WINDOW_REGISTER_VIEW: regViewOpen=false; break; + case GUI_WINDOW_LOG: + logOpen=false; + break; + case GUI_WINDOW_EFFECT_LIST: + effectListOpen=false; + break; default: break; } diff --git a/src/gui/effectList.cpp b/src/gui/effectList.cpp new file mode 100644 index 000000000..c64966a43 --- /dev/null +++ b/src/gui/effectList.cpp @@ -0,0 +1,73 @@ +#include "gui.h" +#include "guiConst.h" +#include + +void FurnaceGUI::drawEffectList() { + if (nextWindow==GUI_WINDOW_EFFECT_LIST) { + effectListOpen=true; + ImGui::SetNextWindowFocus(); + nextWindow=GUI_WINDOW_NOTHING; + } + if (!effectListOpen) return; + if (ImGui::Begin("Effect List",&effectListOpen)) { + ImGui::Text("System at cursor: %s",e->getSystemName(e->sysOfChan[cursor.xCoarse])); + if (ImGui::BeginTable("effectList",2)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::Text("Name"); + ImGui::TableNextColumn(); + ImGui::Text("Description"); + + const char* prevName=NULL; + for (int i=0; i<256; i++) { + const char* name=e->getEffectDesc(i,cursor.xCoarse); + if (name==prevName) { + continue; + } + prevName=name; + if (name!=NULL) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::PushFont(patFont); + if (i<0x10) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[i]]); + } else if (i<0x20) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]); + } else if (i<0x30) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY]); + } else if (i<0x48) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]); + } else if (i<0x90) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); + } else if (i<0xa0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_MISC]); + } else if (i<0xc0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); + } else if (i<0xd0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SPEED]); + } else if (i<0xe0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); + } else { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[extFxColors[i-0xe0]]); + } + ImGui::Text("%c%c%c%c",name[0],name[1],name[2],name[3]); + ImGui::PopStyleColor(); + ImGui::PopFont(); + + ImGui::TableNextColumn(); + if (strlen(name)>6) { + ImGui::TextWrapped("%s",&name[6]); + } else { + ImGui::Text("ERROR"); + } + } + } + ImGui::EndTable(); + } + } + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EFFECT_LIST; + ImGui::End(); +} \ No newline at end of file diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index f3ab5a327..63e0594d0 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2523,6 +2523,7 @@ bool FurnaceGUI::loop() { ImGui::EndMenu(); } if (ImGui::BeginMenu("help")) { + if (ImGui::MenuItem("effect list",BIND_FOR(GUI_ACTION_WINDOW_EFFECT_LIST),effectListOpen)) effectListOpen=!effectListOpen; if (ImGui::MenuItem("debug menu",BIND_FOR(GUI_ACTION_WINDOW_DEBUG))) debugOpen=!debugOpen; if (ImGui::MenuItem("panic",BIND_FOR(GUI_ACTION_PANIC))) e->syncReset(); if (ImGui::MenuItem("about...",BIND_FOR(GUI_ACTION_WINDOW_ABOUT))) { @@ -2581,7 +2582,7 @@ bool FurnaceGUI::loop() { default: // effect int actualCursor=((cursor.xFine+1)&(~1)); if (p->data[cursor.y][actualCursor]>-1) { - info=e->getEffectDesc(p->data[cursor.y][actualCursor],cursor.xCoarse); + info=e->getEffectDesc(p->data[cursor.y][actualCursor],cursor.xCoarse,true); hasInfo=true; } break; @@ -2626,6 +2627,7 @@ bool FurnaceGUI::loop() { drawChannels(); drawRegView(); drawLog(); + drawEffectList(); if (inspectorOpen) ImGui::ShowMetricsWindow(&inspectorOpen); @@ -3234,6 +3236,7 @@ bool FurnaceGUI::init() { channelsOpen=e->getConfBool("channelsOpen",false); regViewOpen=e->getConfBool("regViewOpen",false); logOpen=e->getConfBool("logOpen",false); + effectListOpen=e->getConfBool("effectListOpen",false); tempoView=e->getConfBool("tempoView",true); waveHex=e->getConfBool("waveHex",false); @@ -3404,6 +3407,7 @@ bool FurnaceGUI::finish() { e->setConf("channelsOpen",channelsOpen); e->setConf("regViewOpen",regViewOpen); e->setConf("logOpen",logOpen); + e->setConf("effectListOpen",effectListOpen); // commit last window size e->setConf("lastWindowWidth",scrW); @@ -3510,6 +3514,7 @@ FurnaceGUI::FurnaceGUI(): channelsOpen(false), regViewOpen(false), logOpen(false), + effectListOpen(false), /* editControlsDocked(false), ordersDocked(false), @@ -3534,6 +3539,8 @@ FurnaceGUI::FurnaceGUI(): notesDocked(false), channelsDocked(false), regViewDocked(false), + logDocked(false), + effectListDocked(false), */ selecting(false), curNibble(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index b193e39a5..88ced6b69 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -225,7 +225,8 @@ enum FurnaceGUIWindows { GUI_WINDOW_NOTES, GUI_WINDOW_CHANNELS, GUI_WINDOW_REGISTER_VIEW, - GUI_WINDOW_LOG + GUI_WINDOW_LOG, + GUI_WINDOW_EFFECT_LIST }; enum FurnaceGUIFileDialogs { @@ -323,6 +324,7 @@ enum FurnaceGUIActions { GUI_ACTION_WINDOW_CHANNELS, GUI_ACTION_WINDOW_REGISTER_VIEW, GUI_ACTION_WINDOW_LOG, + GUI_ACTION_WINDOW_EFFECT_LIST, GUI_ACTION_COLLAPSE_WINDOW, GUI_ACTION_CLOSE_WINDOW, @@ -915,13 +917,13 @@ class FurnaceGUI { bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen; bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen; bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen; - bool pianoOpen, notesOpen, channelsOpen, regViewOpen, logOpen; + bool pianoOpen, notesOpen, channelsOpen, regViewOpen, logOpen, effectListOpen; /* there ought to be a better way... bool editControlsDocked, ordersDocked, insListDocked, songInfoDocked, patternDocked, insEditDocked; bool waveListDocked, waveEditDocked, sampleListDocked, sampleEditDocked, aboutDocked, settingsDocked; bool mixerDocked, debugDocked, inspectorDocked, oscDocked, volMeterDocked, statsDocked, compatFlagsDocked; - bool pianoDocked, notesDocked, channelsDocked, regViewDocked; + bool pianoDocked, notesDocked, channelsDocked, regViewDocked, logDocked, effectListDocked; */ SelectionPoint selStart, selEnd, cursor; @@ -1128,6 +1130,7 @@ class FurnaceGUI { void drawDebug(); void drawNewSong(); void drawLog(); + void drawEffectList(); void parseKeybinds(); void promptKey(int which); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index a0b3c17c4..99068e95f 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -18,8 +18,8 @@ */ // guiConst: constants used in the GUI like arrays, strings and other stuff -#include "guiConst.h" #include "gui.h" +#include "guiConst.h" #include "../engine/song.h" const int opOrder[4]={ @@ -138,6 +138,60 @@ const char* resampleStrats[]={ "best possible" }; +const FurnaceGUIColors fxColors[16]={ + GUI_COLOR_PATTERN_EFFECT_MISC, // 00 + GUI_COLOR_PATTERN_EFFECT_PITCH, // 01 + GUI_COLOR_PATTERN_EFFECT_PITCH, // 02 + GUI_COLOR_PATTERN_EFFECT_PITCH, // 03 + GUI_COLOR_PATTERN_EFFECT_PITCH, // 04 + GUI_COLOR_PATTERN_EFFECT_VOLUME, // 05 + GUI_COLOR_PATTERN_EFFECT_VOLUME, // 06 + GUI_COLOR_PATTERN_EFFECT_VOLUME, // 07 + GUI_COLOR_PATTERN_EFFECT_PANNING, // 08 + GUI_COLOR_PATTERN_EFFECT_SPEED, // 09 + GUI_COLOR_PATTERN_EFFECT_VOLUME, // 0A + GUI_COLOR_PATTERN_EFFECT_SONG, // 0B + GUI_COLOR_PATTERN_EFFECT_TIME, // 0C + GUI_COLOR_PATTERN_EFFECT_SONG, // 0D + GUI_COLOR_PATTERN_EFFECT_INVALID, // 0E + GUI_COLOR_PATTERN_EFFECT_SPEED, // 0F +}; + +const FurnaceGUIColors extFxColors[32]={ + GUI_COLOR_PATTERN_EFFECT_MISC, // E0 + GUI_COLOR_PATTERN_EFFECT_PITCH, // E1 + GUI_COLOR_PATTERN_EFFECT_PITCH, // E2 + GUI_COLOR_PATTERN_EFFECT_MISC, // E3 + GUI_COLOR_PATTERN_EFFECT_MISC, // E4 + GUI_COLOR_PATTERN_EFFECT_PITCH, // E5 + GUI_COLOR_PATTERN_EFFECT_INVALID, // E6 + GUI_COLOR_PATTERN_EFFECT_INVALID, // E7 + GUI_COLOR_PATTERN_EFFECT_INVALID, // E8 + GUI_COLOR_PATTERN_EFFECT_INVALID, // E9 + GUI_COLOR_PATTERN_EFFECT_MISC, // EA + GUI_COLOR_PATTERN_EFFECT_MISC, // EB + GUI_COLOR_PATTERN_EFFECT_TIME, // EC + GUI_COLOR_PATTERN_EFFECT_TIME, // ED + GUI_COLOR_PATTERN_EFFECT_SONG, // EE + GUI_COLOR_PATTERN_EFFECT_SONG, // EF + GUI_COLOR_PATTERN_EFFECT_SPEED, // F0 + GUI_COLOR_PATTERN_EFFECT_PITCH, // F1 + GUI_COLOR_PATTERN_EFFECT_PITCH, // F2 + GUI_COLOR_PATTERN_EFFECT_VOLUME, // F3 + GUI_COLOR_PATTERN_EFFECT_VOLUME, // F4 + GUI_COLOR_PATTERN_EFFECT_INVALID, // F5 + GUI_COLOR_PATTERN_EFFECT_INVALID, // F6 + GUI_COLOR_PATTERN_EFFECT_INVALID, // F7 + GUI_COLOR_PATTERN_EFFECT_VOLUME, // F8 + GUI_COLOR_PATTERN_EFFECT_VOLUME, // F9 + GUI_COLOR_PATTERN_EFFECT_VOLUME, // FA + GUI_COLOR_PATTERN_EFFECT_INVALID, // FB + GUI_COLOR_PATTERN_EFFECT_INVALID, // FC + GUI_COLOR_PATTERN_EFFECT_INVALID, // FD + GUI_COLOR_PATTERN_EFFECT_INVALID, // FE + GUI_COLOR_PATTERN_EFFECT_SONG, // FF +}; + #define D FurnaceGUIActionDef #define NOT_AN_ACTION -1 @@ -193,6 +247,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("WINDOW_CHANNELS", "Channels", 0), D("WINDOW_REGISTER_VIEW", "Register View", 0), D("WINDOW_LOG", "Log Viewer", 0), + D("EFFECT_LIST", "Effect List", 0), D("COLLAPSE_WINDOW", "Collapse/expand current window", 0), D("CLOSE_WINDOW", "Close current window", FURKMOD_SHIFT|SDLK_ESCAPE), diff --git a/src/gui/guiConst.h b/src/gui/guiConst.h index 93dd143a0..c0a8cd6c3 100644 --- a/src/gui/guiConst.h +++ b/src/gui/guiConst.h @@ -46,4 +46,6 @@ extern const int availableSystems[]; extern const FurnaceGUIActionDef guiActions[]; extern const FurnaceGUIColorDef guiColors[]; extern const int altValues[24]; -extern const int vgmVersions[6]; \ No newline at end of file +extern const int vgmVersions[6]; +extern const FurnaceGUIColors fxColors[16]; +extern const FurnaceGUIColors extFxColors[32]; \ No newline at end of file diff --git a/src/gui/log.cpp b/src/gui/log.cpp index 7dc6bf8d8..b5f4d3556 100644 --- a/src/gui/log.cpp +++ b/src/gui/log.cpp @@ -92,5 +92,6 @@ void FurnaceGUI::drawLog() { ImGui::EndTable(); } } + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_LOG; ImGui::End(); } diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index ab0eec099..6f357bd8b 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -27,60 +27,6 @@ #include "guiConst.h" #include -const FurnaceGUIColors fxColors[16]={ - GUI_COLOR_PATTERN_EFFECT_MISC, // 00 - GUI_COLOR_PATTERN_EFFECT_PITCH, // 01 - GUI_COLOR_PATTERN_EFFECT_PITCH, // 02 - GUI_COLOR_PATTERN_EFFECT_PITCH, // 03 - GUI_COLOR_PATTERN_EFFECT_PITCH, // 04 - GUI_COLOR_PATTERN_EFFECT_VOLUME, // 05 - GUI_COLOR_PATTERN_EFFECT_VOLUME, // 06 - GUI_COLOR_PATTERN_EFFECT_VOLUME, // 07 - GUI_COLOR_PATTERN_EFFECT_PANNING, // 08 - GUI_COLOR_PATTERN_EFFECT_SPEED, // 09 - GUI_COLOR_PATTERN_EFFECT_VOLUME, // 0A - GUI_COLOR_PATTERN_EFFECT_SONG, // 0B - GUI_COLOR_PATTERN_EFFECT_TIME, // 0C - GUI_COLOR_PATTERN_EFFECT_SONG, // 0D - GUI_COLOR_PATTERN_EFFECT_INVALID, // 0E - GUI_COLOR_PATTERN_EFFECT_SPEED, // 0F -}; - -const FurnaceGUIColors extFxColors[32]={ - GUI_COLOR_PATTERN_EFFECT_MISC, // E0 - GUI_COLOR_PATTERN_EFFECT_PITCH, // E1 - GUI_COLOR_PATTERN_EFFECT_PITCH, // E2 - GUI_COLOR_PATTERN_EFFECT_MISC, // E3 - GUI_COLOR_PATTERN_EFFECT_MISC, // E4 - GUI_COLOR_PATTERN_EFFECT_PITCH, // E5 - GUI_COLOR_PATTERN_EFFECT_INVALID, // E6 - GUI_COLOR_PATTERN_EFFECT_INVALID, // E7 - GUI_COLOR_PATTERN_EFFECT_INVALID, // E8 - GUI_COLOR_PATTERN_EFFECT_INVALID, // E9 - GUI_COLOR_PATTERN_EFFECT_MISC, // EA - GUI_COLOR_PATTERN_EFFECT_MISC, // EB - GUI_COLOR_PATTERN_EFFECT_TIME, // EC - GUI_COLOR_PATTERN_EFFECT_TIME, // ED - GUI_COLOR_PATTERN_EFFECT_SONG, // EE - GUI_COLOR_PATTERN_EFFECT_SONG, // EF - GUI_COLOR_PATTERN_EFFECT_SPEED, // F0 - GUI_COLOR_PATTERN_EFFECT_PITCH, // F1 - GUI_COLOR_PATTERN_EFFECT_PITCH, // F2 - GUI_COLOR_PATTERN_EFFECT_VOLUME, // F3 - GUI_COLOR_PATTERN_EFFECT_VOLUME, // F4 - GUI_COLOR_PATTERN_EFFECT_INVALID, // F5 - GUI_COLOR_PATTERN_EFFECT_INVALID, // F6 - GUI_COLOR_PATTERN_EFFECT_INVALID, // F7 - GUI_COLOR_PATTERN_EFFECT_VOLUME, // F8 - GUI_COLOR_PATTERN_EFFECT_VOLUME, // F9 - GUI_COLOR_PATTERN_EFFECT_VOLUME, // FA - GUI_COLOR_PATTERN_EFFECT_INVALID, // FB - GUI_COLOR_PATTERN_EFFECT_INVALID, // FC - GUI_COLOR_PATTERN_EFFECT_INVALID, // FD - GUI_COLOR_PATTERN_EFFECT_INVALID, // FE - GUI_COLOR_PATTERN_EFFECT_SONG, // FF -}; - inline float randRange(float min, float max) { return min+((float)rand()/(float)RAND_MAX)*(max-min); } From 1a81c6c3e7d7936417f8889cb1745d21211acc2e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 19 Apr 2022 21:55:13 -0500 Subject: [PATCH 59/77] VRC6: saw volume 63 --- src/engine/platform/vrc6.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index d8b37d92f..a35ed995b 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -434,9 +434,9 @@ void DivPlatformVRC6::reset() { chan[i]=DivPlatformVRC6::Channel(); chan[i].std.setEngine(parent); } - // a poll may be necessary to decide the default - chan[2].vol=30; - chan[2].outVol=30; + // HELP + chan[2].vol=63; + chan[2].outVol=63; if (dumpWrites) { addWrite(0xffffffff,0); } From dac623157471d95c872eae9cdd40e7338f6f0492 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 19 Apr 2022 21:55:23 -0500 Subject: [PATCH 60/77] GUI: fix about screen in power saving mode --- src/gui/about.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/about.cpp b/src/gui/about.cpp index c15f3268c..ce543f5f4 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -214,6 +214,8 @@ void FurnaceGUI::drawAbout() { while (aboutHue>1) aboutHue--; while (aboutSin>=2400) aboutSin-=2400; if (aboutScroll>(42*aboutCount+scrH)) aboutScroll=-20; + + WAKE_UP; } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_ABOUT; ImGui::End(); From ce5f3fd94ef5cf726bd7bccf1f486082e353bbab Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 20 Apr 2022 20:38:20 +0900 Subject: [PATCH 61/77] Further fix looped sample preview --- src/gui/sampleEdit.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/sampleEdit.cpp b/src/gui/sampleEdit.cpp index 9919c069f..802e10bc5 100644 --- a/src/gui/sampleEdit.cpp +++ b/src/gui/sampleEdit.cpp @@ -1137,7 +1137,8 @@ void FurnaceGUI::drawSampleEdit() { ImU32 centerLineColor=ImAlphaBlendColors(bgColor,ImGui::GetColorU32(ImGuiCol_PlotLines,0.25)); for (int i=0; iloopStart>=0 && sample->loopStart<(int)sample->samples && ((j+samplePos)*sampleZoom)>sample->loopStart) { + int scaledPos=samplePos+(j*sampleZoom); + if (sample->loopStart>=0 && sample->loopStart<(int)sample->samples && scaledPos>=sample->loopStart) { data[i*availX+j]=bgColorLoop; } else { data[i*availX+j]=bgColor; From 5630b69e64fd041c3c9d16ffe475c5e606b8641a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 20 Apr 2022 15:29:07 -0500 Subject: [PATCH 62/77] GUI: fix selection being visible in dummy row area --- src/gui/gui.h | 2 +- src/gui/pattern.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index 88ced6b69..bea900687 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1101,7 +1101,7 @@ class FurnaceGUI { float calcBPM(int s1, int s2, float hz); - void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache); + void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache, bool inhibitSel); void actualWaveList(); void actualSampleList(); diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index 6f357bd8b..3b45cd27b 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -32,9 +32,9 @@ inline float randRange(float min, float max) { } // draw a pattern row -inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache) { +inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache, bool inhibitSel) { static char id[32]; - bool selectedRow=(i>=sel1.y && i<=sel2.y); + bool selectedRow=(i>=sel1.y && i<=sel2.y && !inhibitSel); ImGui::TableNextRow(0,lineHeight); ImGui::TableNextColumn(); float cursorPosY=ImGui::GetCursorPos().y-ImGui::GetScrollY(); @@ -559,7 +559,7 @@ void FurnaceGUI::drawPattern() { patCache[i]=e->song.pat[i].getPattern(e->song.orders.ord[i][ord-1],true); } for (int i=0; isong.patLen+i-dummyRows+1,e->isPlaying(),lineHeight,chans,ord-1,patCache); + patternRow(e->song.patLen+i-dummyRows+1,e->isPlaying(),lineHeight,chans,ord-1,patCache,true); } } else { for (int i=0; isong.pat[i].getPattern(e->song.orders.ord[i][ord],true); } for (int i=0; isong.patLen; i++) { - patternRow(i,e->isPlaying(),lineHeight,chans,ord,patCache); + patternRow(i,e->isPlaying(),lineHeight,chans,ord,patCache,false); } // next pattern ImGui::BeginDisabled(); @@ -582,7 +582,7 @@ void FurnaceGUI::drawPattern() { patCache[i]=e->song.pat[i].getPattern(e->song.orders.ord[i][ord+1],true); } for (int i=0; i<=dummyRows; i++) { - patternRow(i,e->isPlaying(),lineHeight,chans,ord+1,patCache); + patternRow(i,e->isPlaying(),lineHeight,chans,ord+1,patCache,true); } } else { for (int i=0; i<=dummyRows; i++) { From 79fa8f1d02afb73972bfc63fd2d326fedc0bb336 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Apr 2022 02:24:06 -0500 Subject: [PATCH 63/77] better default instrument for OPL/OPLL no longer silence --- src/engine/engine.cpp | 20 +++++++++++++++++--- src/engine/engine.h | 3 ++- src/engine/platform/amiga.cpp | 8 ++++---- src/engine/platform/arcade.cpp | 2 +- src/engine/platform/ay.cpp | 4 ++-- src/engine/platform/ay8930.cpp | 4 ++-- src/engine/platform/bubsyswsg.cpp | 6 +++--- src/engine/platform/c64.cpp | 12 ++++++------ src/engine/platform/fds.cpp | 4 ++-- src/engine/platform/gb.cpp | 12 ++++++------ src/engine/platform/genesis.cpp | 2 +- src/engine/platform/genesisext.cpp | 2 +- src/engine/platform/lynx.cpp | 6 +++--- src/engine/platform/mmc5.cpp | 6 +++--- src/engine/platform/n163.cpp | 4 ++-- src/engine/platform/nes.cpp | 6 +++--- src/engine/platform/opl.cpp | 2 +- src/engine/platform/opll.cpp | 2 +- src/engine/platform/pce.cpp | 6 +++--- src/engine/platform/pcspkr.cpp | 4 ++-- src/engine/platform/pet.cpp | 4 ++-- src/engine/platform/qsound.cpp | 6 +++--- src/engine/platform/saa.cpp | 4 ++-- src/engine/platform/segapcm.cpp | 2 +- src/engine/platform/sms.cpp | 6 +++--- src/engine/platform/swan.cpp | 6 +++--- src/engine/platform/tia.cpp | 4 ++-- src/engine/platform/tx81z.cpp | 2 +- src/engine/platform/vera.cpp | 6 +++--- src/engine/platform/vic20.cpp | 4 ++-- src/engine/platform/vrc6.cpp | 6 +++--- src/engine/platform/x1_010.cpp | 4 ++-- src/engine/platform/ym2610.cpp | 6 +++--- src/engine/platform/ym2610b.cpp | 6 +++--- src/engine/platform/ym2610bext.cpp | 14 +++++++------- src/engine/platform/ym2610ext.cpp | 14 +++++++------- src/engine/song.h | 17 ++++++++++++++++- 37 files changed, 128 insertions(+), 98 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 488b4bf63..98cd8454c 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -738,8 +738,22 @@ String DivEngine::getWarnings() { return warnings; } -DivInstrument* DivEngine::getIns(int index) { - if (index<0 || index>=song.insLen) return &song.nullIns; +DivInstrument* DivEngine::getIns(int index, DivInstrumentType fallbackType) { + if (index<0 || index>=song.insLen) { + switch (fallbackType) { + case DIV_INS_OPLL: + logV("returning the OPLL null instrument"); + return &song.nullInsOPLL; + break; + case DIV_INS_OPL: + logV("returning the OPL null instrument"); + return &song.nullInsOPL; + break; + default: + break; + } + return &song.nullIns; + } return song.ins[index]; } @@ -1970,7 +1984,7 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) { } do { - if ((ins==-1 || getChannelType(finalChan)==4 || getPreferInsType(finalChan)==getIns(ins)->type || getIns(ins)->type==DIV_INS_AMIGA) && chan[finalChan].midiNote==-1) { + if ((ins<0 || ins>=song.insLen || getChannelType(finalChan)==4 || getPreferInsType(finalChan)==getIns(ins)->type || getIns(ins)->type==DIV_INS_AMIGA) && chan[finalChan].midiNote==-1) { chan[finalChan].midiNote=note; pendingNotes.push(DivNoteEvent(finalChan,ins,note,vol,true)); break; diff --git a/src/engine/engine.h b/src/engine/engine.h index efcbb21b0..515b9c590 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -19,6 +19,7 @@ #ifndef _ENGINE_H #define _ENGINE_H +#include "instrument.h" #include "song.h" #include "dispatch.h" #include "dataErrors.h" @@ -309,7 +310,7 @@ class DivEngine { void runExportThread(); void nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size); - DivInstrument* getIns(int index); + DivInstrument* getIns(int index, DivInstrumentType fallbackType=DIV_INS_FM); DivWavetable* getWave(int index); DivSample* getSample(int index); // start fresh diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 6d015db48..1212b15d0 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -206,7 +206,7 @@ void DivPlatformAmiga::tick(bool sysTick) { } } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - //DivInstrument* ins=parent->getIns(chan[i].ins); + //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA); chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val; if (chan[i].freq>4095) chan[i].freq=4095; if (chan[i].freq<0) chan[i].freq=0; @@ -224,7 +224,7 @@ void DivPlatformAmiga::tick(bool sysTick) { int DivPlatformAmiga::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); double off=1.0; if (ins->amiga.useWave) { chan[c.chan].useWave=true; @@ -314,7 +314,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) { chan[c.chan].ws.changeWave1(chan[c.chan].wave); break; case DIV_CMD_NOTE_PORTA: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); chan[c.chan].sample=ins->amiga.initSample; double off=1.0; if (!chan[c.chan].useWave && chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { @@ -364,7 +364,7 @@ int DivPlatformAmiga::dispatch(DivCommand c) { } case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index f4311e29e..6be50b6e4 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -446,7 +446,7 @@ void DivPlatformArcade::muteChannel(int ch, bool mute) { int DivPlatformArcade::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 25f49e950..4ba384832 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -294,7 +294,7 @@ void DivPlatformAY8910::tick(bool sysTick) { int DivPlatformAY8910::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; @@ -457,7 +457,7 @@ int DivPlatformAY8910::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AY)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index e4fa30dc4..640b495b3 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -318,7 +318,7 @@ void DivPlatformAY8930::tick(bool sysTick) { int DivPlatformAY8930::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AY8930); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; @@ -482,7 +482,7 @@ int DivPlatformAY8930::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AY8930)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/bubsyswsg.cpp b/src/engine/platform/bubsyswsg.cpp index 569e82f1c..6783bc336 100644 --- a/src/engine/platform/bubsyswsg.cpp +++ b/src/engine/platform/bubsyswsg.cpp @@ -119,7 +119,7 @@ void DivPlatformBubSysWSG::tick(bool sysTick) { } } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - //DivInstrument* ins=parent->getIns(chan[i].ins); + //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_SCC); chan[i].freq=0x1000-parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val; if (chan[i].freq<0) chan[i].freq=0; if (chan[i].freq>4095) chan[i].freq=4095; @@ -142,7 +142,7 @@ void DivPlatformBubSysWSG::tick(bool sysTick) { int DivPlatformBubSysWSG::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SCC); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; @@ -228,7 +228,7 @@ int DivPlatformBubSysWSG::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SCC)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/c64.cpp b/src/engine/platform/c64.cpp index 02473c80c..604dcfe33 100644 --- a/src/engine/platform/c64.cpp +++ b/src/engine/platform/c64.cpp @@ -126,7 +126,7 @@ void DivPlatformC64::tick(bool sysTick) { for (int i=0; i<3; i++) { chan[i].std.next(); if (chan[i].std.vol.had) { - DivInstrument* ins=parent->getIns(chan[i].ins); + DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_C64); if (ins->c64.volIsCutoff) { if (ins->c64.filterIsAbs) { filtCut=MIN(2047,chan[i].std.vol.val); @@ -157,7 +157,7 @@ void DivPlatformC64::tick(bool sysTick) { } } if (chan[i].std.duty.had) { - DivInstrument* ins=parent->getIns(chan[i].ins); + DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_C64); if (ins->c64.dutyIsAbs) { chan[i].duty=chan[i].std.duty.val; } else { @@ -223,7 +223,7 @@ void DivPlatformC64::tick(bool sysTick) { int DivPlatformC64::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_C64); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].freqChanged=true; @@ -345,7 +345,7 @@ int DivPlatformC64::dispatch(DivCommand c) { case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta || !chan[c.chan].inPorta) { - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_C64)); chan[c.chan].keyOn=true; } } @@ -383,7 +383,7 @@ int DivPlatformC64::dispatch(DivCommand c) { break; case DIV_CMD_C64_FILTER_RESET: if (c.value&15) { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_C64); if (ins->c64.initFilter) { filtCut=ins->c64.cut; updateFilter(); @@ -393,7 +393,7 @@ int DivPlatformC64::dispatch(DivCommand c) { break; case DIV_CMD_C64_DUTY_RESET: if (c.value&15) { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_C64); chan[c.chan].duty=ins->c64.duty; rWrite(c.chan*7+2,chan[c.chan].duty&0xff); rWrite(c.chan*7+3,chan[c.chan].duty>>8); diff --git a/src/engine/platform/fds.cpp b/src/engine/platform/fds.cpp index c581c516e..2c3512137 100644 --- a/src/engine/platform/fds.cpp +++ b/src/engine/platform/fds.cpp @@ -198,7 +198,7 @@ void DivPlatformFDS::tick(bool sysTick) { int DivPlatformFDS::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FDS); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].freqChanged=true; @@ -358,7 +358,7 @@ int DivPlatformFDS::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_FDS)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/gb.cpp b/src/engine/platform/gb.cpp index eb7b6881e..b9668d58a 100644 --- a/src/engine/platform/gb.cpp +++ b/src/engine/platform/gb.cpp @@ -176,7 +176,7 @@ void DivPlatformGB::tick(bool sysTick) { } if (chan[i].std.duty.had) { chan[i].duty=chan[i].std.duty.val; - DivInstrument* ins=parent->getIns(chan[i].ins); + DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_GB); if (i!=2) { rWrite(16+i*5+1,((chan[i].duty&3)<<6)|(63-(ins->gb.soundLen&63))); } else { @@ -220,7 +220,7 @@ void DivPlatformGB::tick(bool sysTick) { } } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - DivInstrument* ins=parent->getIns(chan[i].ins); + DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_GB); if (i==3) { // noise int ntPos=chan[i].baseFreq; if (ntPos<0) ntPos=0; @@ -269,7 +269,7 @@ void DivPlatformGB::muteChannel(int ch, bool mute) { int DivPlatformGB::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_GB); if (c.value!=DIV_NOTE_NULL) { if (c.chan==3) { // noise chan[c.chan].baseFreq=c.value; @@ -306,7 +306,7 @@ int DivPlatformGB::dispatch(DivCommand c) { chan[c.chan].ins=c.value; chan[c.chan].insChanged=true; if (c.chan!=2) { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_GB); chan[c.chan].vol=ins->gb.envVol; if (parent->song.gbInsAffectsEnvelope) { rWrite(16+c.chan*5+2,((chan[c.chan].vol<<4))|(ins->gb.envLen&7)|((ins->gb.envDir&1)<<3)); @@ -360,7 +360,7 @@ int DivPlatformGB::dispatch(DivCommand c) { chan[c.chan].duty=c.value; if (c.chan!=2) { chan[c.chan].freqChanged=true; - rWrite(16+c.chan*5+1,((chan[c.chan].duty&3)<<6)|(63-(parent->getIns(chan[c.chan].ins)->gb.soundLen&63))); + rWrite(16+c.chan*5+1,((chan[c.chan].duty&3)<<6)|(63-(parent->getIns(chan[c.chan].ins,DIV_INS_GB)->gb.soundLen&63))); } break; case DIV_CMD_PANNING: { @@ -379,7 +379,7 @@ int DivPlatformGB::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_GB)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 210a50e74..81fcdefe5 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -484,7 +484,7 @@ void DivPlatformGenesis::muteChannel(int ch, bool mute) { int DivPlatformGenesis::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); if (c.chan==5) { if (ins->type==DIV_INS_AMIGA) { dacMode=1; diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index 403c1a8cf..f0369370c 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -37,7 +37,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { int ordch=orderedOps[ch]; switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(opChan[ch].ins); + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); if (opChan[ch].insChanged) { chan[2].state.alg=ins->fm.alg; diff --git a/src/engine/platform/lynx.cpp b/src/engine/platform/lynx.cpp index c51c6a068..4c688103c 100644 --- a/src/engine/platform/lynx.cpp +++ b/src/engine/platform/lynx.cpp @@ -224,7 +224,7 @@ int DivPlatformLynx::dispatch(DivCommand c) { } chan[c.chan].active=true; WRITE_VOLUME(c.chan,(isMuted[c.chan]?0:(chan[c.chan].vol&127))); - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY)); break; case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; @@ -241,7 +241,7 @@ int DivPlatformLynx::dispatch(DivCommand c) { break; case DIV_CMD_INSTRUMENT: chan[c.chan].ins=c.value; - //chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + //chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY)); break; case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { @@ -297,7 +297,7 @@ int DivPlatformLynx::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_MIKEY)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/mmc5.cpp b/src/engine/platform/mmc5.cpp index 696ae6d21..cf1ea36d6 100644 --- a/src/engine/platform/mmc5.cpp +++ b/src/engine/platform/mmc5.cpp @@ -177,7 +177,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: if (c.chan==2) { // PCM - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_STD); if (ins->type==DIV_INS_AMIGA) { dacSample=ins->amiga.initSample; if (dacSample<0 || dacSample>=parent->song.sampleLen) { @@ -227,7 +227,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); rWrite(0x5000+c.chan*4,0x30|chan[c.chan].vol|((chan[c.chan].duty&3)<<6)); break; case DIV_CMD_NOTE_OFF: @@ -305,7 +305,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/n163.cpp b/src/engine/platform/n163.cpp index a9634fa95..a00d4d05d 100644 --- a/src/engine/platform/n163.cpp +++ b/src/engine/platform/n163.cpp @@ -374,7 +374,7 @@ void DivPlatformN163::tick(bool sysTick) { int DivPlatformN163::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_N163); if (chan[c.chan].insChanged) { chan[c.chan].wave=ins->n163.wave; chan[c.chan].ws.changeWave1(chan[c.chan].wave); @@ -546,7 +546,7 @@ int DivPlatformN163::dispatch(DivCommand c) { case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { if (parent->song.resetMacroOnPorta) { - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_N163)); chan[c.chan].keyOn=true; } } diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index e4bfbca9b..f855648b9 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -271,7 +271,7 @@ int DivPlatformNES::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: if (c.chan==4) { // PCM - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_STD); if (ins->type==DIV_INS_AMIGA) { dacSample=ins->amiga.initSample; if (dacSample<0 || dacSample>=parent->song.sampleLen) { @@ -325,7 +325,7 @@ int DivPlatformNES::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); if (c.chan==2) { rWrite(0x4000+c.chan*4,0xff); } else { @@ -428,7 +428,7 @@ int DivPlatformNES::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 96b0d23b5..ef9adecfc 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -535,7 +535,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { } switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPL); if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index d94d1e26d..a02bc8de2 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -365,7 +365,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { if (c.chan>=9 && !properDrums) return 0; - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPLL); if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; } diff --git a/src/engine/platform/pce.cpp b/src/engine/platform/pce.cpp index e1cbb6808..016b3b3c4 100644 --- a/src/engine/platform/pce.cpp +++ b/src/engine/platform/pce.cpp @@ -216,7 +216,7 @@ void DivPlatformPCE::tick(bool sysTick) { } } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - //DivInstrument* ins=parent->getIns(chan[i].ins); + //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_PCE); chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,true)+chan[i].std.pitch.val; if (chan[i].furnaceDac) { double off=1.0; @@ -251,7 +251,7 @@ void DivPlatformPCE::tick(bool sysTick) { int DivPlatformPCE::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_PCE); if (ins->type==DIV_INS_AMIGA) { chan[c.chan].pcm=true; } else if (chan[c.chan].furnaceDac) { @@ -429,7 +429,7 @@ int DivPlatformPCE::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_PCE)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index e7062d213..b34d16f24 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -217,7 +217,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER)); break; case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; @@ -282,7 +282,7 @@ int DivPlatformPCSpeaker::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_BEEPER)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/pet.cpp b/src/engine/platform/pet.cpp index 47bb2e3d4..0e83e9d21 100644 --- a/src/engine/platform/pet.cpp +++ b/src/engine/platform/pet.cpp @@ -138,7 +138,7 @@ void DivPlatformPET::tick(bool sysTick) { int DivPlatformPET::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan.ins); + DivInstrument* ins=parent->getIns(chan.ins,DIV_INS_PET); if (c.value!=DIV_NOTE_NULL) { chan.baseFreq=NOTE_PERIODIC(c.value); chan.freqChanged=true; @@ -213,7 +213,7 @@ int DivPlatformPET::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan.active && c.value2) { - if (parent->song.resetMacroOnPorta) chan.std.init(parent->getIns(chan.ins)); + if (parent->song.resetMacroOnPorta) chan.std.init(parent->getIns(chan.ins,DIV_INS_PET)); } chan.inPorta=c.value; break; diff --git a/src/engine/platform/qsound.cpp b/src/engine/platform/qsound.cpp index 338870109..b5d194ffc 100644 --- a/src/engine/platform/qsound.cpp +++ b/src/engine/platform/qsound.cpp @@ -330,7 +330,7 @@ void DivPlatformQSound::tick(bool sysTick) { chan[i].freqChanged=true; } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - //DivInstrument* ins=parent->getIns(chan[i].ins); + //DivInstrument* ins=parent->getIns(chan[i].ins,DIV_INS_AMIGA); chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false)+chan[i].std.pitch.val; if (chan[i].freq>0xffff) chan[i].freq=0xffff; if (chan[i].keyOn) { @@ -363,7 +363,7 @@ void DivPlatformQSound::tick(bool sysTick) { int DivPlatformQSound::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); chan[c.chan].sample=ins->amiga.initSample; double off=1.0; if (chan[c.chan].sample>=0 && chan[c.chan].samplesong.sampleLen) { @@ -487,7 +487,7 @@ int DivPlatformQSound::dispatch(DivCommand c) { } case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/saa.cpp b/src/engine/platform/saa.cpp index 47b698051..f21c7d5b4 100644 --- a/src/engine/platform/saa.cpp +++ b/src/engine/platform/saa.cpp @@ -249,7 +249,7 @@ void DivPlatformSAA1099::tick(bool sysTick) { int DivPlatformSAA1099::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SAA1099); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; @@ -356,7 +356,7 @@ int DivPlatformSAA1099::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SAA1099)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/segapcm.cpp b/src/engine/platform/segapcm.cpp index 700924476..a7db708a2 100644 --- a/src/engine/platform/segapcm.cpp +++ b/src/engine/platform/segapcm.cpp @@ -149,7 +149,7 @@ void DivPlatformSegaPCM::muteChannel(int ch, bool mute) { int DivPlatformSegaPCM::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA); if (skipRegisterWrites) break; if (ins->type==DIV_INS_AMIGA) { chan[c.chan].pcm.sample=ins->amiga.initSample; diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index da31e4784..af339f6e2 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -175,7 +175,7 @@ int DivPlatformSMS::dispatch(DivCommand c) { } chan[c.chan].active=true; rWrite(0x90|c.chan<<5|(isMuted[c.chan]?15:(15-(chan[c.chan].vol&15)))); - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); break; case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; @@ -188,7 +188,7 @@ int DivPlatformSMS::dispatch(DivCommand c) { break; case DIV_CMD_INSTRUMENT: chan[c.chan].ins=c.value; - //chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + //chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); break; case DIV_CMD_VOLUME: if (chan[c.chan].vol!=c.value) { @@ -244,7 +244,7 @@ int DivPlatformSMS::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_STD)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/swan.cpp b/src/engine/platform/swan.cpp index 22790c641..b8f9a40dc 100644 --- a/src/engine/platform/swan.cpp +++ b/src/engine/platform/swan.cpp @@ -147,7 +147,7 @@ void DivPlatformSwan::tick(bool sysTick) { chan[i].std.next(); if (chan[i].std.vol.had) { int env=chan[i].std.vol.val; - if(parent->getIns(chan[i].ins)->type==DIV_INS_AMIGA) { + if(parent->getIns(chan[i].ins,DIV_INS_SWAN)->type==DIV_INS_AMIGA) { env=MIN(env/4,15); } calcAndWriteOutVol(i,env); @@ -240,7 +240,7 @@ void DivPlatformSwan::tick(bool sysTick) { int DivPlatformSwan::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_SWAN); if (c.chan==1) { if (ins->type==DIV_INS_AMIGA) { pcm=true; @@ -415,7 +415,7 @@ int DivPlatformSwan::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_SWAN)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/tia.cpp b/src/engine/platform/tia.cpp index 86b5e6be1..cc5151f03 100644 --- a/src/engine/platform/tia.cpp +++ b/src/engine/platform/tia.cpp @@ -154,7 +154,7 @@ void DivPlatformTIA::tick(bool sysTick) { int DivPlatformTIA::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_TIA); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=c.value<<8; chan[c.chan].freqChanged=true; @@ -248,7 +248,7 @@ int DivPlatformTIA::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_TIA)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 98f68a54b..712335818 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -424,7 +424,7 @@ void DivPlatformTX81Z::muteChannel(int ch, bool mute) { int DivPlatformTX81Z::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_OPZ); if (chan[c.chan].insChanged) { chan[c.chan].state=ins->fm; diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index 89cccb99d..63415a0c1 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -237,7 +237,7 @@ int DivPlatformVERA::dispatch(DivCommand c) { if(c.chan<16) { rWriteLo(c.chan,2,chan[c.chan].vol) } else { - chan[16].pcm.sample=parent->getIns(chan[16].ins)->amiga.initSample; + chan[16].pcm.sample=parent->getIns(chan[16].ins,DIV_INS_VERA)->amiga.initSample; if (chan[16].pcm.sample<0 || chan[16].pcm.sample>=parent->song.sampleLen) { chan[16].pcm.sample=-1; } @@ -259,7 +259,7 @@ int DivPlatformVERA::dispatch(DivCommand c) { chan[c.chan].note=c.value; } chan[c.chan].active=true; - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VERA)); break; case DIV_CMD_NOTE_OFF: chan[c.chan].active=false; @@ -327,7 +327,7 @@ int DivPlatformVERA::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VERA)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/vic20.cpp b/src/engine/platform/vic20.cpp index 44aba9670..aa787672b 100644 --- a/src/engine/platform/vic20.cpp +++ b/src/engine/platform/vic20.cpp @@ -158,7 +158,7 @@ void DivPlatformVIC20::tick(bool sysTick) { int DivPlatformVIC20::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_VIC); if (c.value!=DIV_NOTE_NULL) { chan[c.chan].baseFreq=NOTE_PERIODIC(c.value); chan[c.chan].freqChanged=true; @@ -232,7 +232,7 @@ int DivPlatformVIC20::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VIC)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/vrc6.cpp b/src/engine/platform/vrc6.cpp index a35ed995b..56e95948c 100644 --- a/src/engine/platform/vrc6.cpp +++ b/src/engine/platform/vrc6.cpp @@ -220,7 +220,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: if (c.chan!=2) { // pulse wave - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_VRC6); if (ins->type==DIV_INS_AMIGA) { chan[c.chan].pcm=true; } else if (chan[c.chan].furnaceDac) { @@ -284,7 +284,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) { } chan[c.chan].active=true; chan[c.chan].keyOn=true; - chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6)); if (!isMuted[c.chan]) { if (c.chan==2) { // sawtooth chWrite(c.chan,0,chan[c.chan].vol); @@ -380,7 +380,7 @@ int DivPlatformVRC6::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_VRC6)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/x1_010.cpp b/src/engine/platform/x1_010.cpp index 9c9b3e20d..f1498709f 100644 --- a/src/engine/platform/x1_010.cpp +++ b/src/engine/platform/x1_010.cpp @@ -525,7 +525,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { chWrite(c.chan,0,0); // reset previous note - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_X1_010); if ((ins->type==DIV_INS_AMIGA) || chan[c.chan].pcm) { if (ins->type==DIV_INS_AMIGA) { chan[c.chan].furnacePCM=true; @@ -703,7 +703,7 @@ int DivPlatformX1_010::dispatch(DivCommand c) { break; case DIV_CMD_PRE_PORTA: if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_X1_010)); } chan[c.chan].inPorta=c.value; break; diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index f955303d3..04338d265 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -635,7 +635,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { if (c.chan>12) { // ADPCM-B - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); if (ins->type==DIV_INS_AMIGA) { chan[c.chan].furnacePCM=true; } else { @@ -718,7 +718,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { immWrite(0x100,0x00|(1<<(c.chan-7))); break; } - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].std.init(ins); if (c.chan<4) { if (!chan[c.chan].std.vol.will) { @@ -981,7 +981,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { case DIV_CMD_PRE_PORTA: if (c.chan>3) { if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_FM)); } } chan[c.chan].inPorta=c.value; diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 75855f4fc..a250e04ce 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -698,7 +698,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { switch (c.cmd) { case DIV_CMD_NOTE_ON: { if (c.chan>14) { // ADPCM-B - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); if (ins->type==DIV_INS_AMIGA) { chan[c.chan].furnacePCM=true; } else { @@ -781,7 +781,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { immWrite(0x100,0x00|(1<<(c.chan-9))); break; } - DivInstrument* ins=parent->getIns(chan[c.chan].ins); + DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM); chan[c.chan].std.init(ins); if (c.chan<6) { if (!chan[c.chan].std.vol.will) { @@ -1044,7 +1044,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { case DIV_CMD_PRE_PORTA: if (c.chan>5) { if (chan[c.chan].active && c.value2) { - if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins)); + if (parent->song.resetMacroOnPorta) chan[c.chan].std.init(parent->getIns(chan[c.chan].ins,DIV_INS_FM)); } } chan[c.chan].inPorta=c.value; diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index 496a308e0..74794a7d7 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -36,7 +36,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { int ordch=orderedOps[ch]; switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(opChan[ch].ins); + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; @@ -78,7 +78,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: { opChan[ch].vol=c.value; - DivInstrument* ins=parent->getIns(opChan[ch].ins); + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; if (isOpMuted[ch]) { @@ -104,7 +104,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { } else { opChan[ch].pan=((c.value&15)>0)|(((c.value>>4)>0)<<1); } - DivInstrument* ins=parent->getIns(opChan[ch].ins); + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); if (parent->song.sharedExtStat) { for (int i=0; i<4; i++) { if (ch==i) continue; @@ -159,14 +159,14 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { } case DIV_CMD_FM_MULT: { // TODO unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; - DivInstrument* ins=parent->getIns(opChan[ch].ins); + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]]; rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4)); break; } case DIV_CMD_FM_TL: { // TODO unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]]; - DivInstrument* ins=parent->getIns(opChan[ch].ins); + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); if (isOutput[ins->fm.alg][c.value]) { rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127)); } else { @@ -175,7 +175,7 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) { break; } case DIV_CMD_FM_AR: { - DivInstrument* ins=parent->getIns(opChan[ch].ins); + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); if (c.value<0) { for (int i=0; i<4; i++) { DivInstrumentFM::Operator op=ins->fm.op[i]; @@ -268,7 +268,7 @@ void DivPlatformYM2610BExt::muteChannel(int ch, bool mute) { isOpMuted[ch-2]=mute; int ordch=orderedOps[ch-2]; - DivInstrument* ins=parent->getIns(opChan[ch-2].ins); + DivInstrument* ins=parent->getIns(opChan[ch-2].ins,DIV_INS_FM); unsigned short baseAddr=chanOffs[2]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; if (isOpMuted[ch-2]) { diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index dc4625080..df9b43511 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -36,7 +36,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { int ordch=orderedOps[ch]; switch (c.cmd) { case DIV_CMD_NOTE_ON: { - DivInstrument* ins=parent->getIns(opChan[ch].ins); + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); unsigned short baseAddr=chanOffs[1]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; @@ -78,7 +78,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { break; case DIV_CMD_VOLUME: { opChan[ch].vol=c.value; - DivInstrument* ins=parent->getIns(opChan[ch].ins); + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); unsigned short baseAddr=chanOffs[1]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; if (isOpMuted[ch]) { @@ -104,7 +104,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { } else { opChan[ch].pan=((c.value&15)>0)|(((c.value>>4)>0)<<1); } - DivInstrument* ins=parent->getIns(opChan[ch].ins); + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); if (parent->song.sharedExtStat) { for (int i=0; i<4; i++) { if (ch==i) continue; @@ -159,14 +159,14 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { } case DIV_CMD_FM_MULT: { // TODO unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; - DivInstrument* ins=parent->getIns(opChan[ch].ins); + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]]; rWrite(baseAddr+0x30,(c.value2&15)|(dtTable[op.dt&7]<<4)); break; } case DIV_CMD_FM_TL: { // TODO unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]]; - DivInstrument* ins=parent->getIns(opChan[ch].ins); + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); if (isOutput[ins->fm.alg][c.value]) { rWrite(baseAddr+0x40,127-(((127-c.value2)*(opChan[ch].vol&0x7f))/127)); } else { @@ -175,7 +175,7 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) { break; } case DIV_CMD_FM_AR: { - DivInstrument* ins=parent->getIns(opChan[ch].ins); + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); if (c.value<0) { for (int i=0; i<4; i++) { DivInstrumentFM::Operator op=ins->fm.op[i]; @@ -268,7 +268,7 @@ void DivPlatformYM2610Ext::muteChannel(int ch, bool mute) { isOpMuted[ch-1]=mute; int ordch=orderedOps[ch-1]; - DivInstrument* ins=parent->getIns(opChan[ch].ins); + DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM); unsigned short baseAddr=chanOffs[1]|opOffs[ordch]; DivInstrumentFM::Operator op=ins->fm.op[ordch]; if (isOpMuted[ch]) { diff --git a/src/engine/song.h b/src/engine/song.h index 81c0cb8a8..82d219338 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -334,7 +334,7 @@ struct DivSong { bool chanShow[DIV_MAX_CHANS]; bool chanCollapse[DIV_MAX_CHANS]; - DivInstrument nullIns; + DivInstrument nullIns, nullInsOPLL, nullInsOPL; DivWavetable nullWave; DivSample nullSample; @@ -419,6 +419,21 @@ struct DivSong { } system[0]=DIV_SYSTEM_YM2612; system[1]=DIV_SYSTEM_SMS; + + nullInsOPLL.fm.opllPreset=7; + nullInsOPLL.fm.op[1].tl=0; + + nullInsOPL.fm.alg=0; + nullInsOPL.fm.fb=7; + nullInsOPL.fm.op[0].dr=2; + nullInsOPL.fm.op[0].rr=7; + nullInsOPL.fm.op[0].tl=22; + nullInsOPL.fm.op[0].ksl=1; + nullInsOPL.fm.op[0].mult=3; + nullInsOPL.fm.op[1].tl=0; + nullInsOPL.fm.op[1].dr=3; + nullInsOPL.fm.op[1].rr=12; + nullInsOPL.fm.op[1].mult=1; } }; From 4195715dc0fa69f14a50b1a512c27e40fe396aa1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Apr 2022 02:29:20 -0500 Subject: [PATCH 64/77] use good default instrument when adding ins --- src/engine/engine.cpp | 15 ++++++++++++--- src/engine/song.h | 2 ++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 98cd8454c..905ba8aa5 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -742,11 +742,9 @@ DivInstrument* DivEngine::getIns(int index, DivInstrumentType fallbackType) { if (index<0 || index>=song.insLen) { switch (fallbackType) { case DIV_INS_OPLL: - logV("returning the OPLL null instrument"); return &song.nullInsOPLL; break; case DIV_INS_OPL: - logV("returning the OPL null instrument"); return &song.nullInsOPL; break; default: @@ -1310,8 +1308,19 @@ int DivEngine::addInstrument(int refChan) { BUSY_BEGIN; DivInstrument* ins=new DivInstrument; int insCount=(int)song.ins.size(); + DivInstrumentType prefType=getPreferInsType(refChan); + switch (prefType) { + case DIV_INS_OPLL: + *ins=song.nullInsOPLL; + break; + case DIV_INS_OPL: + *ins=song.nullInsOPL; + break; + default: + break; + } ins->name=fmt::sprintf("Instrument %d",insCount); - ins->type=getPreferInsType(refChan); + ins->type=prefType; saveLock.lock(); song.ins.push_back(ins); song.insLen=insCount+1; diff --git a/src/engine/song.h b/src/engine/song.h index 82d219338..20b17ae60 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -422,6 +422,7 @@ struct DivSong { nullInsOPLL.fm.opllPreset=7; nullInsOPLL.fm.op[1].tl=0; + nullInsOPLL.name="This is a bug! Report!"; nullInsOPL.fm.alg=0; nullInsOPL.fm.fb=7; @@ -434,6 +435,7 @@ struct DivSong { nullInsOPL.fm.op[1].dr=3; nullInsOPL.fm.op[1].rr=12; nullInsOPL.fm.op[1].mult=1; + nullInsOPL.name="This is a bug! Report!"; } }; From 06a69a20e89ff1e1be3d89282c1b3037dc9d8c64 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Apr 2022 02:35:50 -0500 Subject: [PATCH 65/77] GUI: add "absorb" instrument input mode --- src/gui/gui.cpp | 3 +++ src/gui/gui.h | 2 ++ src/gui/settings.cpp | 8 ++++++++ 3 files changed, 13 insertions(+) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 63e0594d0..068eb11d5 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -954,6 +954,9 @@ void FurnaceGUI::valueInput(int num, bool direct, int target) { pat->data[cursor.y][target]=(int)e->song.ins.size()-1; } } + if (settings.absorbInsInput) { + curIns=pat->data[cursor.y][target]; + } makeUndo(GUI_UNDO_PATTERN_EDIT); if (direct) { curNibble=false; diff --git a/src/gui/gui.h b/src/gui/gui.h index bea900687..6db3c4a23 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -826,6 +826,7 @@ class FurnaceGUI { int lowLatency; int notePreviewBehavior; int powerSave; + int absorbInsInput; unsigned int maxUndoSteps; String mainFontPath; String patFontPath; @@ -900,6 +901,7 @@ class FurnaceGUI { lowLatency(0), notePreviewBehavior(1), powerSave(1), + absorbInsInput(0), maxUndoSteps(100), mainFontPath(""), patFontPath(""), diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 7ead6c204..f1cd27a36 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -258,6 +258,11 @@ void FurnaceGUI::drawSettings() { settings.stepOnDelete=stepOnDeleteB; } + bool absorbInsInputB=settings.absorbInsInput; + if (ImGui::Checkbox("Change current instrument when changing instrument column (absorb)",&absorbInsInputB)) { + settings.absorbInsInput=absorbInsInputB; + } + bool effectDeletionAltersValueB=settings.effectDeletionAltersValue; if (ImGui::Checkbox("Delete effect value when deleting effect",&effectDeletionAltersValueB)) { settings.effectDeletionAltersValue=effectDeletionAltersValueB; @@ -1645,6 +1650,7 @@ void FurnaceGUI::syncSettings() { settings.lowLatency=e->getConfInt("lowLatency",0); settings.notePreviewBehavior=e->getConfInt("notePreviewBehavior",1); settings.powerSave=e->getConfInt("powerSave",POWER_SAVE_DEFAULT); + settings.absorbInsInput=e->getConfInt("absorbInsInput",0); clampSetting(settings.mainFontSize,2,96); clampSetting(settings.patFontSize,2,96); @@ -1708,6 +1714,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.lowLatency,0,1); clampSetting(settings.notePreviewBehavior,0,3); clampSetting(settings.powerSave,0,1); + clampSetting(settings.absorbInsInput,0,1); // keybinds for (int i=0; isetConf("lowLatency",settings.lowLatency); e->setConf("notePreviewBehavior",settings.notePreviewBehavior); e->setConf("powerSave",settings.powerSave); + e->setConf("absorbInsInput",settings.absorbInsInput); // colors for (int i=0; i Date: Thu, 21 Apr 2022 02:35:57 -0500 Subject: [PATCH 66/77] update to-do list --- TODO.md | 1 - 1 file changed, 1 deletion(-) diff --git a/TODO.md b/TODO.md index b6d059502..03e465ce6 100644 --- a/TODO.md +++ b/TODO.md @@ -26,7 +26,6 @@ - rewrite the system name detection function anyway - add nightly.link - scroll instrument/wave/sample list when selecting item -- "absorb" mode for instrument input - when this happens, current instrument is set to the input value - unified data view - separate "transpose note" and "transpose value" - see next point - volume commands should work on Game Boy From dba9482cee12e7eaf7709e7109808b8b0aef870e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Apr 2022 02:53:09 -0500 Subject: [PATCH 67/77] GUI: add a "none" option to instrument list --- src/gui/dataList.cpp | 244 ++++++++++++++++++++++--------------------- 1 file changed, 125 insertions(+), 119 deletions(-) diff --git a/src/gui/dataList.cpp b/src/gui/dataList.cpp index 8a02c40e3..671eb451e 100644 --- a/src/gui/dataList.cpp +++ b/src/gui/dataList.cpp @@ -72,126 +72,132 @@ void FurnaceGUI::drawInsList() { ImGui::Indent(); } - for (int i=0; i<(int)e->song.ins.size(); i++) { - DivInstrument* ins=e->song.ins[i]; - String name; - switch (ins->type) { - case DIV_INS_FM: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_FM]); - name=fmt::sprintf(ICON_FA_AREA_CHART " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_STD: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_STD]); - name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_GB: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_GB]); - name=fmt::sprintf(ICON_FA_GAMEPAD " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_C64: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_C64]); - name=fmt::sprintf(ICON_FA_KEYBOARD_O " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_AMIGA: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_AMIGA]); - name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_PCE: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_PCE]); - name=fmt::sprintf(ICON_FA_ID_BADGE " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_AY: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_AY]); - name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_AY8930: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_AY8930]); - name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_TIA: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_TIA]); - name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_SAA1099: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_SAA1099]); - name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_VIC: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_VIC]); - name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_PET: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_PET]); - name=fmt::sprintf(ICON_FA_SQUARE " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_VRC6: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_VRC6]); - name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_VRC6_SAW: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_VRC6_SAW]); - name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_OPLL: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPLL]); - name=fmt::sprintf(ICON_FA_AREA_CHART " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_OPL: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPL]); - name=fmt::sprintf(ICON_FA_AREA_CHART " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_FDS: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_FDS]); - name=fmt::sprintf(ICON_FA_FLOPPY_O " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_VBOY: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_VBOY]); - name=fmt::sprintf(ICON_FA_BINOCULARS " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_N163: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_N163]); - name=fmt::sprintf(ICON_FA_CALCULATOR " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_SCC: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_SCC]); - name=fmt::sprintf(ICON_FA_CALCULATOR " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_OPZ: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPZ]); - name=fmt::sprintf(ICON_FA_AREA_CHART " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_POKEY: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_POKEY]); - name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_BEEPER: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_BEEPER]); - name=fmt::sprintf(ICON_FA_SQUARE " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_SWAN: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_SWAN]); - name=fmt::sprintf(ICON_FA_GAMEPAD " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_MIKEY: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_MIKEY]); - name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_VERA: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_VERA]); - name=fmt::sprintf(ICON_FA_KEYBOARD_O " %.2X: %s##_INS%d",i,ins->name,i); - break; - case DIV_INS_X1_010: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_X1_010]); - name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); - break; - default: - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_UNKNOWN]); - name=fmt::sprintf(ICON_FA_QUESTION " %.2X: %s##_INS%d",i,ins->name,i); - break; + for (int i=-1; i<(int)e->song.ins.size(); i++) { + String name=ICON_FA_CIRCLE_O " - None -"; + const char* insType="Bug!"; + if (i>=0) { + DivInstrument* ins=e->song.ins[i]; + insType=(ins->type>DIV_INS_MAX)?"Unknown":insTypes[ins->type]; + switch (ins->type) { + case DIV_INS_FM: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_FM]); + name=fmt::sprintf(ICON_FA_AREA_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_STD: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_STD]); + name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_GB: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_GB]); + name=fmt::sprintf(ICON_FA_GAMEPAD " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_C64: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_C64]); + name=fmt::sprintf(ICON_FA_KEYBOARD_O " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_AMIGA: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_AMIGA]); + name=fmt::sprintf(ICON_FA_VOLUME_UP " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_PCE: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_PCE]); + name=fmt::sprintf(ICON_FA_ID_BADGE " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_AY: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_AY]); + name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_AY8930: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_AY8930]); + name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_TIA: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_TIA]); + name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_SAA1099: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_SAA1099]); + name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_VIC: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_VIC]); + name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_PET: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_PET]); + name=fmt::sprintf(ICON_FA_SQUARE " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_VRC6: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_VRC6]); + name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_VRC6_SAW: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_VRC6_SAW]); + name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_OPLL: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPLL]); + name=fmt::sprintf(ICON_FA_AREA_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_OPL: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPL]); + name=fmt::sprintf(ICON_FA_AREA_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_FDS: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_FDS]); + name=fmt::sprintf(ICON_FA_FLOPPY_O " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_VBOY: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_VBOY]); + name=fmt::sprintf(ICON_FA_BINOCULARS " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_N163: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_N163]); + name=fmt::sprintf(ICON_FA_CALCULATOR " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_SCC: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_SCC]); + name=fmt::sprintf(ICON_FA_CALCULATOR " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_OPZ: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_OPZ]); + name=fmt::sprintf(ICON_FA_AREA_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_POKEY: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_POKEY]); + name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_BEEPER: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_BEEPER]); + name=fmt::sprintf(ICON_FA_SQUARE " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_SWAN: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_SWAN]); + name=fmt::sprintf(ICON_FA_GAMEPAD " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_MIKEY: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_MIKEY]); + name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_VERA: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_VERA]); + name=fmt::sprintf(ICON_FA_KEYBOARD_O " %.2X: %s##_INS%d",i,ins->name,i); + break; + case DIV_INS_X1_010: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_X1_010]); + name=fmt::sprintf(ICON_FA_BAR_CHART " %.2X: %s##_INS%d",i,ins->name,i); + break; + default: + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_INSTR_UNKNOWN]); + name=fmt::sprintf(ICON_FA_QUESTION " %.2X: %s##_INS%d",i,ins->name,i); + break; + } + } else { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_TEXT]); } ImGui::TableNextRow(); ImGui::TableNextColumn(); - if (ImGui::Selectable(name.c_str(),curIns==i)) { + if (ImGui::Selectable(name.c_str(),(i==-1)?(curIns<0 || curIns>=e->song.insLen):(curIns==i))) { curIns=i; } if (settings.insFocusesPattern && patternOpen && ImGui::IsItemActivated()) { @@ -199,8 +205,8 @@ void FurnaceGUI::drawInsList() { curIns=i; } ImGui::PopStyleColor(); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("%s",(ins->type>DIV_INS_MAX)?"Unknown":insTypes[ins->type]); + if (ImGui::IsItemHovered() && i>=0) { + ImGui::SetTooltip("%s",insType); if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { insEditOpen=true; nextWindow=GUI_WINDOW_INS_EDIT; From bfdfac004fe261239004662898b2b0bf8c1fee27 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Apr 2022 03:22:01 -0500 Subject: [PATCH 68/77] GUI: fix ins 0 being inserted on blank song --- TODO.md | 1 - src/gui/gui.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/TODO.md b/TODO.md index 03e465ce6..7204a6d12 100644 --- a/TODO.md +++ b/TODO.md @@ -21,7 +21,6 @@ - ability to customize startup system - store system presets in new file - Game Boy envelope macro/sequence -- Game Boy envelope view - option to display chip names instead of "multi-system" on title bar - rewrite the system name detection function anyway - add nightly.link diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 068eb11d5..8993a7d76 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -915,6 +915,7 @@ void FurnaceGUI::noteInput(int num, int key, int vol) { } pat->data[cursor.y][1]=(unsigned char)pat->data[cursor.y][1]; if (latchIns==-2) { + if (curIns>=(int)e->song.ins.size()) curIns=-1; pat->data[cursor.y][2]=curIns; } else if (latchIns!=-1 && !e->song.ins.empty()) { pat->data[cursor.y][2]=MIN(((int)e->song.ins.size())-1,latchIns); From 21c4d09c06a76092befbd89e6ce1ba4cf7e18f94 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Apr 2022 03:26:34 -0500 Subject: [PATCH 69/77] GUI: "none" instrument should not remove inscolumn --- src/gui/gui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 8993a7d76..689e26385 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -916,7 +916,9 @@ void FurnaceGUI::noteInput(int num, int key, int vol) { pat->data[cursor.y][1]=(unsigned char)pat->data[cursor.y][1]; if (latchIns==-2) { if (curIns>=(int)e->song.ins.size()) curIns=-1; - pat->data[cursor.y][2]=curIns; + if (curIns>=0) { + pat->data[cursor.y][2]=curIns; + } } else if (latchIns!=-1 && !e->song.ins.empty()) { pat->data[cursor.y][2]=MIN(((int)e->song.ins.size())-1,latchIns); } From bc235ed4943fcc3887e99a38202328ba41565ef7 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Apr 2022 03:45:06 -0500 Subject: [PATCH 70/77] GUI: prepare for separate operation mask --- src/gui/editing.cpp | 46 ++++++++++++++++++++++----------------------- src/gui/gui.cpp | 25 ++++++++++-------------- src/gui/gui.h | 12 +++++++++++- 3 files changed, 44 insertions(+), 39 deletions(-) diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index bd17e20ab..ce1cb21c2 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -177,17 +177,17 @@ void FurnaceGUI::doSelectAll() { } } -#define maskOut(x) \ +#define maskOut(m,x) \ if (x==0) { \ - if (!opMaskNote) continue; \ + if (!m.note) continue; \ } else if (x==1) { \ - if (!opMaskIns) continue; \ + if (!m.ins) continue; \ } else if (x==2) { \ - if (!opMaskVol) continue; \ + if (!m.vol) continue; \ } else if (((x)&1)==0) { \ - if (!opMaskEffectVal) continue; \ + if (!m.effectVal) continue; \ } else if (((x)&1)==1) { \ - if (!opMaskEffect) continue; \ + if (!m.effect) continue; \ } void FurnaceGUI::doDelete() { @@ -201,7 +201,7 @@ void FurnaceGUI::doDelete() { if (!e->song.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsedata[j][iFine]=0; @@ -238,7 +238,7 @@ void FurnaceGUI::doPullDelete() { if (!e->song.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsesong.patLen; j++) { if (jsong.patLen-1) { if (iFine==0) { @@ -270,7 +270,7 @@ void FurnaceGUI::doInsert() { if (!e->song.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsesong.patLen-1; j>=selStart.y; j--) { if (j==selStart.y) { if (iFine==0) { @@ -302,7 +302,7 @@ void FurnaceGUI::doTranspose(int amount) { if (!e->song.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsedata[j][0]; @@ -469,7 +469,7 @@ void FurnaceGUI::doPaste(PasteMode mode) { note[2]=line[charPos++]; note[3]=0; - if (iFine==0 && !opMaskNote) { + if (iFine==0 && !opMask.note) { iFine++; continue; } @@ -498,22 +498,22 @@ void FurnaceGUI::doPaste(PasteMode mode) { note[2]=0; if (iFine==1) { - if (!opMaskIns) { + if (!opMask.ins) { iFine++; continue; } } else if (iFine==2) { - if (!opMaskVol) { + if (!opMask.vol) { iFine++; continue; } } else if ((iFine&1)==0) { - if (!opMaskEffectVal) { + if (!opMask.effectVal) { iFine++; continue; } } else if ((iFine&1)==1) { - if (!opMaskEffect) { + if (!opMask.effect) { iFine++; continue; } @@ -589,7 +589,7 @@ void FurnaceGUI::doInterpolate() { if (!e->song.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsesong.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsesong.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsesong.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsesong.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsesong.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsedata[j][0]; @@ -825,7 +825,7 @@ void FurnaceGUI::doCollapse(int divider) { if (!e->song.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsedata[j][0]; @@ -882,7 +882,7 @@ void FurnaceGUI::doExpand(int multiplier) { if (!e->song.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsedata[j][0]; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 689e26385..83dbdce7b 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1798,30 +1798,30 @@ void FurnaceGUI::editOptions(bool topMenu) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_ACTIVE]); - if (ImGui::Selectable(opMaskNote?"C-4##opMaskNote":"---##opMaskNote",opMaskNote,ImGuiSelectableFlags_DontClosePopups)) { - opMaskNote=!opMaskNote; + if (ImGui::Selectable(opMask.note?"C-4##opMaskNote":"---##opMaskNote",opMask.note,ImGuiSelectableFlags_DontClosePopups)) { + opMask.note=!opMask.note; } ImGui::PopStyleColor(); ImGui::TableNextColumn(); ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_INS]); - if (ImGui::Selectable(opMaskIns?"01##opMaskIns":"--##opMaskIns",opMaskIns,ImGuiSelectableFlags_DontClosePopups)) { - opMaskIns=!opMaskIns; + if (ImGui::Selectable(opMask.ins?"01##opMaskIns":"--##opMaskIns",opMask.ins,ImGuiSelectableFlags_DontClosePopups)) { + opMask.ins=!opMask.ins; } ImGui::PopStyleColor(); ImGui::TableNextColumn(); ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_VOLUME_MAX]); - if (ImGui::Selectable(opMaskVol?"7F##opMaskVol":"--##opMaskVol",opMaskVol,ImGuiSelectableFlags_DontClosePopups)) { - opMaskVol=!opMaskVol; + if (ImGui::Selectable(opMask.vol?"7F##opMaskVol":"--##opMaskVol",opMask.vol,ImGuiSelectableFlags_DontClosePopups)) { + opMask.vol=!opMask.vol; } ImGui::PopStyleColor(); ImGui::TableNextColumn(); ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_PITCH]); - if (ImGui::Selectable(opMaskEffect?"04##opMaskEffect":"--##opMaskEffect",opMaskEffect,ImGuiSelectableFlags_DontClosePopups)) { - opMaskEffect=!opMaskEffect; + if (ImGui::Selectable(opMask.effect?"04##opMaskEffect":"--##opMaskEffect",opMask.effect,ImGuiSelectableFlags_DontClosePopups)) { + opMask.effect=!opMask.effect; } ImGui::TableNextColumn(); - if (ImGui::Selectable(opMaskEffectVal?"72##opMaskEffectVal":"--##opMaskEffectVal",opMaskEffectVal,ImGuiSelectableFlags_DontClosePopups)) { - opMaskEffectVal=!opMaskEffectVal; + if (ImGui::Selectable(opMask.effectVal?"72##opMaskEffectVal":"--##opMaskEffectVal",opMask.effectVal,ImGuiSelectableFlags_DontClosePopups)) { + opMask.effectVal=!opMask.effectVal; } ImGui::PopStyleColor(); ImGui::EndTable(); @@ -3565,11 +3565,6 @@ FurnaceGUI::FurnaceGUI(): curWindow(GUI_WINDOW_NOTHING), nextWindow(GUI_WINDOW_NOTHING), nextDesc(NULL), - opMaskNote(true), - opMaskIns(true), - opMaskVol(true), - opMaskEffect(true), - opMaskEffectVal(true), latchNote(-1), latchIns(-2), latchVol(-1), diff --git a/src/gui/gui.h b/src/gui/gui.h index 6db3c4a23..eaf52dc72 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -683,6 +683,16 @@ struct Particle { lifeSpeed(lS) {} }; +struct OperationMask { + bool note, ins, vol, effect, effectVal; + OperationMask(): + note(true), + ins(true), + vol(true), + effect(true), + effectVal(true) {} +}; + struct FurnaceGUISysDef { const char* name; std::vector definition; @@ -937,7 +947,7 @@ class FurnaceGUI { float patChanSlideY[DIV_MAX_CHANS+1]; const int* nextDesc; - bool opMaskNote, opMaskIns, opMaskVol, opMaskEffect, opMaskEffectVal; + OperationMask opMask; short latchNote, latchIns, latchVol, latchEffect, latchEffectVal; // bit 31: ctrl From 521bb9c16a79cbc19b9595c112489df686c484af Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Apr 2022 16:01:46 -0500 Subject: [PATCH 71/77] GUI: add missing FDS preset --- src/gui/presets.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 5dd3b693d..d6e439a68 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -726,6 +726,13 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Famicom Disk System", { + DIV_SYSTEM_NES, 64, 0, 0, + DIV_SYSTEM_FDS, 64, 0, 0, + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "Commodore 64 (6581 SID)", { DIV_SYSTEM_C64_6581, 64, 0, 1, From 023761373db3656ebd5e547c7742091e095ff3af Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Apr 2022 17:32:28 -0500 Subject: [PATCH 72/77] GUI: separate operation masks also separate note/value transpose commands --- TODO.md | 3 +- src/gui/doAction.cpp | 20 ++++-- src/gui/editing.cpp | 36 +++++----- src/gui/gui.cpp | 164 ++++++++++++++++++++++++++++++++----------- src/gui/gui.h | 10 ++- src/gui/guiConst.cpp | 4 ++ 6 files changed, 170 insertions(+), 67 deletions(-) diff --git a/TODO.md b/TODO.md index 7204a6d12..f9230306d 100644 --- a/TODO.md +++ b/TODO.md @@ -26,14 +26,13 @@ - add nightly.link - scroll instrument/wave/sample list when selecting item - unified data view -- separate "transpose note" and "transpose value" - see next point - volume commands should work on Game Boy - macro editor menu - refactor sysDef.cpp - add another FM editor layout - try to find out why does VSlider not accept keyboard input - finish lock layout -- note input latch! and separate edit masks +- note input latch! - if macros have release, note off should release them - add "don't scroll on cursor movement" option - add ability to select entire row when clicking on row number diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index fc0dbef90..c12df2fe4 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -301,16 +301,28 @@ void FurnaceGUI::doAction(int what) { break; case GUI_ACTION_PAT_NOTE_UP: - doTranspose(1); + doTranspose(1,opMaskTransposeNote); break; case GUI_ACTION_PAT_NOTE_DOWN: - doTranspose(-1); + doTranspose(-1,opMaskTransposeNote); break; case GUI_ACTION_PAT_OCTAVE_UP: - doTranspose(12); + doTranspose(12,opMaskTransposeNote); break; case GUI_ACTION_PAT_OCTAVE_DOWN: - doTranspose(-12); + doTranspose(-12,opMaskTransposeNote); + break; + case GUI_ACTION_PAT_VALUE_UP: + doTranspose(1,opMaskTransposeValue); + break; + case GUI_ACTION_PAT_VALUE_DOWN: + doTranspose(-1,opMaskTransposeValue); + break; + case GUI_ACTION_PAT_VALUE_UP_COARSE: + doTranspose(16,opMaskTransposeValue); + break; + case GUI_ACTION_PAT_VALUE_DOWN_COARSE: + doTranspose(-16,opMaskTransposeValue); break; case GUI_ACTION_PAT_SELECT_ALL: doSelectAll(); diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index ce1cb21c2..106ec61b1 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -201,7 +201,7 @@ void FurnaceGUI::doDelete() { if (!e->song.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsedata[j][iFine]=0; @@ -238,7 +238,7 @@ void FurnaceGUI::doPullDelete() { if (!e->song.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsesong.patLen; j++) { if (jsong.patLen-1) { if (iFine==0) { @@ -270,7 +270,7 @@ void FurnaceGUI::doInsert() { if (!e->song.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsesong.patLen-1; j>=selStart.y; j--) { if (j==selStart.y) { if (iFine==0) { @@ -291,7 +291,7 @@ void FurnaceGUI::doInsert() { makeUndo(GUI_UNDO_PATTERN_PUSH); } -void FurnaceGUI::doTranspose(int amount) { +void FurnaceGUI::doTranspose(int amount, OperationMask& mask) { finishSelection(); prepareUndo(GUI_UNDO_PATTERN_DELETE); curNibble=false; @@ -302,7 +302,7 @@ void FurnaceGUI::doTranspose(int amount) { if (!e->song.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsedata[j][0]; @@ -469,7 +469,7 @@ void FurnaceGUI::doPaste(PasteMode mode) { note[2]=line[charPos++]; note[3]=0; - if (iFine==0 && !opMask.note) { + if (iFine==0 && !opMaskPaste.note) { iFine++; continue; } @@ -498,22 +498,22 @@ void FurnaceGUI::doPaste(PasteMode mode) { note[2]=0; if (iFine==1) { - if (!opMask.ins) { + if (!opMaskPaste.ins) { iFine++; continue; } } else if (iFine==2) { - if (!opMask.vol) { + if (!opMaskPaste.vol) { iFine++; continue; } } else if ((iFine&1)==0) { - if (!opMask.effectVal) { + if (!opMaskPaste.effectVal) { iFine++; continue; } } else if ((iFine&1)==1) { - if (!opMask.effect) { + if (!opMaskPaste.effect) { iFine++; continue; } @@ -589,7 +589,7 @@ void FurnaceGUI::doInterpolate() { if (!e->song.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsesong.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsesong.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsesong.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsesong.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsesong.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsedata[j][0]; @@ -825,7 +825,7 @@ void FurnaceGUI::doCollapse(int divider) { if (!e->song.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsedata[j][0]; @@ -882,7 +882,7 @@ void FurnaceGUI::doExpand(int multiplier) { if (!e->song.chanShow[iCoarse]) continue; DivPattern* pat=e->song.pat[iCoarse].getPattern(e->song.orders.ord[iCoarse][curOrder],true); for (; iFine<3+e->song.pat[iCoarse].effectRows*2 && (iCoarsedata[j][0]; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 83dbdce7b..09709b50b 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1772,6 +1772,44 @@ void FurnaceGUI::processDrags(int dragX, int dragY) { fileName+=fallback; \ } +#define drawOpMask(m) \ + ImGui::PushFont(patFont); \ + ImGui::PushID("om_" #m); \ + if (ImGui::BeginTable("opMaskTable",5,ImGuiTableFlags_Borders|ImGuiTableFlags_SizingFixedFit|ImGuiTableFlags_NoHostExtendX)) { \ + ImGui::TableNextRow(); \ + ImGui::TableNextColumn(); \ + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_ACTIVE]); \ + if (ImGui::Selectable(m.note?"C-4##opMaskNote":"---##opMaskNote",m.note,ImGuiSelectableFlags_DontClosePopups)) { \ + m.note=!m.note; \ + } \ + ImGui::PopStyleColor(); \ + ImGui::TableNextColumn(); \ + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_INS]); \ + if (ImGui::Selectable(m.ins?"01##opMaskIns":"--##opMaskIns",m.ins,ImGuiSelectableFlags_DontClosePopups)) { \ + m.ins=!m.ins; \ + } \ + ImGui::PopStyleColor(); \ + ImGui::TableNextColumn(); \ + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_VOLUME_MAX]); \ + if (ImGui::Selectable(m.vol?"7F##opMaskVol":"--##opMaskVol",m.vol,ImGuiSelectableFlags_DontClosePopups)) { \ + m.vol=!m.vol; \ + } \ + ImGui::PopStyleColor(); \ + ImGui::TableNextColumn(); \ + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_PITCH]); \ + if (ImGui::Selectable(m.effect?"04##opMaskEffect":"--##opMaskEffect",m.effect,ImGuiSelectableFlags_DontClosePopups)) { \ + m.effect=!m.effect; \ + } \ + ImGui::TableNextColumn(); \ + if (ImGui::Selectable(m.effectVal?"72##opMaskEffectVal":"--##opMaskEffectVal",m.effectVal,ImGuiSelectableFlags_DontClosePopups)) { \ + m.effectVal=!m.effectVal; \ + } \ + ImGui::PopStyleColor(); \ + ImGui::EndTable(); \ + } \ + ImGui::PopID(); \ + ImGui::PopFont(); + void FurnaceGUI::editOptions(bool topMenu) { char id[4096]; if (ImGui::MenuItem("cut",BIND_FOR(GUI_ACTION_PAT_CUT))) doCopy(true); @@ -1790,43 +1828,61 @@ void FurnaceGUI::editOptions(bool topMenu) { } ImGui::Separator(); - ImGui::Text("operation mask"); - ImGui::SameLine(); + if (ImGui::BeginMenu("operation mask...")) { + drawOpMask(opMaskDelete); + ImGui::SameLine(); + ImGui::Text("delete"); - ImGui::PushFont(patFont); - if (ImGui::BeginTable("opMaskTable",5,ImGuiTableFlags_Borders|ImGuiTableFlags_SizingFixedFit|ImGuiTableFlags_NoHostExtendX)) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_ACTIVE]); - if (ImGui::Selectable(opMask.note?"C-4##opMaskNote":"---##opMaskNote",opMask.note,ImGuiSelectableFlags_DontClosePopups)) { - opMask.note=!opMask.note; - } - ImGui::PopStyleColor(); - ImGui::TableNextColumn(); - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_INS]); - if (ImGui::Selectable(opMask.ins?"01##opMaskIns":"--##opMaskIns",opMask.ins,ImGuiSelectableFlags_DontClosePopups)) { - opMask.ins=!opMask.ins; - } - ImGui::PopStyleColor(); - ImGui::TableNextColumn(); - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_VOLUME_MAX]); - if (ImGui::Selectable(opMask.vol?"7F##opMaskVol":"--##opMaskVol",opMask.vol,ImGuiSelectableFlags_DontClosePopups)) { - opMask.vol=!opMask.vol; - } - ImGui::PopStyleColor(); - ImGui::TableNextColumn(); - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_PITCH]); - if (ImGui::Selectable(opMask.effect?"04##opMaskEffect":"--##opMaskEffect",opMask.effect,ImGuiSelectableFlags_DontClosePopups)) { - opMask.effect=!opMask.effect; - } - ImGui::TableNextColumn(); - if (ImGui::Selectable(opMask.effectVal?"72##opMaskEffectVal":"--##opMaskEffectVal",opMask.effectVal,ImGuiSelectableFlags_DontClosePopups)) { - opMask.effectVal=!opMask.effectVal; - } - ImGui::PopStyleColor(); - ImGui::EndTable(); + drawOpMask(opMaskPullDelete); + ImGui::SameLine(); + ImGui::Text("pull delete"); + + drawOpMask(opMaskInsert); + ImGui::SameLine(); + ImGui::Text("insert"); + + drawOpMask(opMaskPaste); + ImGui::SameLine(); + ImGui::Text("paste"); + + drawOpMask(opMaskTransposeNote); + ImGui::SameLine(); + ImGui::Text("transpose (note)"); + + drawOpMask(opMaskTransposeValue); + ImGui::SameLine(); + ImGui::Text("transpose (value)"); + + drawOpMask(opMaskInterpolate); + ImGui::SameLine(); + ImGui::Text("interpolate"); + + drawOpMask(opMaskFade); + ImGui::SameLine(); + ImGui::Text("fade"); + + drawOpMask(opMaskInvertVal); + ImGui::SameLine(); + ImGui::Text("invert values"); + + drawOpMask(opMaskScale); + ImGui::SameLine(); + ImGui::Text("scale"); + + drawOpMask(opMaskRandomize); + ImGui::SameLine(); + ImGui::Text("randomize"); + + drawOpMask(opMaskFlip); + ImGui::SameLine(); + ImGui::Text("flip"); + + drawOpMask(opMaskCollapseExpand); + ImGui::SameLine(); + ImGui::Text("collapse/expand"); + + ImGui::EndMenu(); } - ImGui::PopFont(); ImGui::Text("input latch"); if (ImGui::MenuItem("set latch",BIND_FOR(GUI_ACTION_PAT_LATCH))) { @@ -1834,17 +1890,31 @@ void FurnaceGUI::editOptions(bool topMenu) { } ImGui::Separator(); - if (ImGui::MenuItem("note up",BIND_FOR(GUI_ACTION_PAT_NOTE_UP))) doTranspose(1); - if (ImGui::MenuItem("note down",BIND_FOR(GUI_ACTION_PAT_NOTE_DOWN))) doTranspose(-1); - if (ImGui::MenuItem("octave up",BIND_FOR(GUI_ACTION_PAT_OCTAVE_UP))) doTranspose(12); - if (ImGui::MenuItem("octave down",BIND_FOR(GUI_ACTION_PAT_OCTAVE_DOWN))) doTranspose(-12); + if (ImGui::MenuItem("note up",BIND_FOR(GUI_ACTION_PAT_NOTE_UP))) doTranspose(1,opMaskTransposeNote); + if (ImGui::MenuItem("note down",BIND_FOR(GUI_ACTION_PAT_NOTE_DOWN))) doTranspose(-1,opMaskTransposeNote); + if (ImGui::MenuItem("octave up",BIND_FOR(GUI_ACTION_PAT_OCTAVE_UP))) doTranspose(12,opMaskTransposeNote); + if (ImGui::MenuItem("octave down",BIND_FOR(GUI_ACTION_PAT_OCTAVE_DOWN))) doTranspose(-12,opMaskTransposeNote); + ImGui::Separator(); + if (ImGui::MenuItem("values up",BIND_FOR(GUI_ACTION_PAT_VALUE_UP))) doTranspose(1,opMaskTransposeValue); + if (ImGui::MenuItem("values down",BIND_FOR(GUI_ACTION_PAT_VALUE_DOWN))) doTranspose(-1,opMaskTransposeValue); + if (ImGui::MenuItem("values up (+16)",BIND_FOR(GUI_ACTION_PAT_VALUE_UP_COARSE))) doTranspose(16,opMaskTransposeValue); + if (ImGui::MenuItem("values down (-16)",BIND_FOR(GUI_ACTION_PAT_VALUE_DOWN_COARSE))) doTranspose(-16,opMaskTransposeValue); + ImGui::Separator(); + ImGui::Text("transpose"); + ImGui::SameLine(); + ImGui::SetNextItemWidth(120.0f*dpiScale); if (ImGui::InputInt("##TransposeAmount",&transposeAmount,1,1)) { if (transposeAmount<-96) transposeAmount=-96; if (transposeAmount>96) transposeAmount=96; } ImGui::SameLine(); - if (ImGui::Button("Transpose")) { - doTranspose(transposeAmount); + if (ImGui::Button("Notes")) { + doTranspose(transposeAmount,opMaskTransposeNote); + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Values")) { + doTranspose(transposeAmount,opMaskTransposeNote); ImGui::CloseCurrentPopup(); } @@ -3699,6 +3769,18 @@ FurnaceGUI::FurnaceGUI(): peak[0]=0; peak[1]=0; + opMaskTransposeNote.note=true; + opMaskTransposeNote.ins=false; + opMaskTransposeNote.vol=false; + opMaskTransposeNote.effect=false; + opMaskTransposeNote.effectVal=false; + + opMaskTransposeValue.note=false; + opMaskTransposeValue.ins=true; + opMaskTransposeValue.vol=true; + opMaskTransposeValue.effect=true; + opMaskTransposeValue.effectVal=true; + memset(actionKeys,0,GUI_ACTION_MAX*sizeof(int)); memset(patChanX,0,sizeof(float)*(DIV_MAX_CHANS+1)); diff --git a/src/gui/gui.h b/src/gui/gui.h index eaf52dc72..328ad6a71 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -335,6 +335,10 @@ enum FurnaceGUIActions { GUI_ACTION_PAT_NOTE_DOWN, GUI_ACTION_PAT_OCTAVE_UP, GUI_ACTION_PAT_OCTAVE_DOWN, + GUI_ACTION_PAT_VALUE_UP, + GUI_ACTION_PAT_VALUE_DOWN, + GUI_ACTION_PAT_VALUE_UP_COARSE, + GUI_ACTION_PAT_VALUE_DOWN_COARSE, GUI_ACTION_PAT_SELECT_ALL, GUI_ACTION_PAT_CUT, GUI_ACTION_PAT_COPY, @@ -947,7 +951,9 @@ class FurnaceGUI { float patChanSlideY[DIV_MAX_CHANS+1]; const int* nextDesc; - OperationMask opMask; + OperationMask opMaskDelete, opMaskPullDelete, opMaskInsert, opMaskPaste, opMaskTransposeNote, opMaskTransposeValue; + OperationMask opMaskInterpolate, opMaskFade, opMaskInvertVal, opMaskScale; + OperationMask opMaskRandomize, opMaskFlip, opMaskCollapseExpand; short latchNote, latchIns, latchVol, latchEffect, latchEffectVal; // bit 31: ctrl @@ -1178,7 +1184,7 @@ class FurnaceGUI { void doDelete(); void doPullDelete(); void doInsert(); - void doTranspose(int amount); + void doTranspose(int amount, OperationMask& mask); void doCopy(bool cut); void doPaste(PasteMode mode=GUI_PASTE_MODE_NORMAL); void doChangeIns(int ins); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 99068e95f..b5d437072 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -258,6 +258,10 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("PAT_NOTE_DOWN", "Transpose (-1)", FURKMOD_CMD|SDLK_F1), D("PAT_OCTAVE_UP", "Transpose (+1 octave)", FURKMOD_CMD|SDLK_F4), D("PAT_OCTAVE_DOWN", "Transpose (-1 octave)", FURKMOD_CMD|SDLK_F3), + D("PAT_VALUE_UP", "Increase values (+1)", FURKMOD_CMD|FURKMOD_SHIFT|SDLK_F2), + D("PAT_VALUE_DOWN", "Increase values (-1)", FURKMOD_CMD|FURKMOD_SHIFT|SDLK_F1), + D("PAT_VALUE_UP_COARSE", "Increase values (+16)", FURKMOD_CMD|FURKMOD_SHIFT|SDLK_F4), + D("PAT_VALUE_DOWN_COARSE", "Increase values (-16)", FURKMOD_CMD|FURKMOD_SHIFT|SDLK_F3), D("PAT_SELECT_ALL", "Select all", FURKMOD_CMD|SDLK_a), D("PAT_CUT", "Cut", FURKMOD_CMD|SDLK_x), D("PAT_COPY", "Copy", FURKMOD_CMD|SDLK_c), From 741062242511465db7e7cc50b9bcc33a690aece0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Apr 2022 17:39:13 -0500 Subject: [PATCH 73/77] GUI: min ins selector width fix --- src/gui/insEdit.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index baca9469e..7879d966e 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1346,6 +1346,7 @@ void FurnaceGUI::drawInsEdit() { ImGui::TableNextRow(); ImGui::TableNextColumn(); String insIndex=fmt::sprintf("%.2X",curIns); + ImGui::SetNextItemWidth(72.0f*dpiScale); if (ImGui::BeginCombo("##InsSelect",insIndex.c_str())) { String name; for (size_t i=0; isong.ins.size(); i++) { From 50deead11a1707a24f6b19e63dc48e5bbe0e64c7 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Apr 2022 18:10:59 -0500 Subject: [PATCH 74/77] GUI: prepare for note input latch UI --- src/gui/gui.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++++++++- src/gui/gui.h | 4 +-- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 09709b50b..dba51591f 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1812,6 +1812,7 @@ void FurnaceGUI::processDrags(int dragX, int dragY) { void FurnaceGUI::editOptions(bool topMenu) { char id[4096]; + editOptsVisible=true; if (ImGui::MenuItem("cut",BIND_FOR(GUI_ACTION_PAT_CUT))) doCopy(true); if (ImGui::MenuItem("copy",BIND_FOR(GUI_ACTION_PAT_COPY))) doCopy(false); if (ImGui::MenuItem("paste",BIND_FOR(GUI_ACTION_PAT_PASTE))) doPaste(); @@ -1885,7 +1886,68 @@ void FurnaceGUI::editOptions(bool topMenu) { } ImGui::Text("input latch"); - if (ImGui::MenuItem("set latch",BIND_FOR(GUI_ACTION_PAT_LATCH))) { + if (ImGui::BeginTable("opMaskTable",5,ImGuiTableFlags_Borders|ImGuiTableFlags_SizingFixedFit|ImGuiTableFlags_NoHostExtendX)) { + static char id[64]; + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_ACTIVE]); + ImGui::Text("C-4"); + ImGui::PopStyleColor(); + ImGui::TableNextColumn(); + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_INS]); + if (latchIns==-2) { + strcpy(id,"&&##LatchIns"); + } else if (latchIns==-1) { + strcpy(id,"..##LatchIns"); + } else { + snprintf(id,63,"%.2x##LatchIns",latchIns&0xff); + } + if (ImGui::Selectable(id,latchTarget==1,ImGuiSelectableFlags_DontClosePopups)) { + latchTarget=1; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("&&: selected instrument\n..: no instrument"); + } + ImGui::PopStyleColor(); + ImGui::TableNextColumn(); + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_VOLUME_MAX]); + if (latchVol==-1) { + strcpy(id,"..##LatchVol"); + } else { + snprintf(id,63,"%.2x##LatchVol",latchVol&0xff); + } + if (ImGui::Selectable(id,latchTarget==2,ImGuiSelectableFlags_DontClosePopups)) { + latchTarget=2; + } + ImGui::PopStyleColor(); + ImGui::TableNextColumn(); + if (latchEffect==-1) { + strcpy(id,"..##LatchFX"); + } else { + snprintf(id,63,"%.2x##LatchFX",latchEffect&0xff); + } + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_PITCH]); + if (ImGui::Selectable(id,latchTarget==3,ImGuiSelectableFlags_DontClosePopups)) { + latchTarget=3; + } + ImGui::TableNextColumn(); + if (latchEffectVal==-1) { + strcpy(id,"..##LatchFXV"); + } else { + snprintf(id,63,"%.2x##LatchFXV",latchEffectVal&0xff); + } + if (ImGui::Selectable(id,latchTarget==4,ImGuiSelectableFlags_DontClosePopups)) { + latchTarget=4; + } + ImGui::PopStyleColor(); + ImGui::EndTable(); + } + ImGui::SameLine(); + if (ImGui::Button("Set")) { + // TODO + } + ImGui::SameLine(); + if (ImGui::Button("Clear")) { // TODO } ImGui::Separator(); @@ -2400,6 +2462,7 @@ bool FurnaceGUI::loop() { ImGui::NewFrame(); curWindow=GUI_WINDOW_NOTHING; + editOptsVisible=false; ImGui::BeginMainMenuBar(); if (ImGui::BeginMenu("file")) { @@ -3266,6 +3329,10 @@ bool FurnaceGUI::loop() { willCommit=false; } + if (!editOptsVisible) { + latchTarget=0; + } + if (SDL_GetWindowFlags(sdlWin)&SDL_WINDOW_MINIMIZED) { SDL_Delay(100); } @@ -3564,6 +3631,7 @@ FurnaceGUI::FurnaceGUI(): extraChannelButtons(0), patNameTarget(-1), newSongCategory(0), + latchTarget(0), wheelX(0), wheelY(0), editControlsOpen(true), @@ -3632,6 +3700,7 @@ FurnaceGUI::FurnaceGUI(): tempoView(true), waveHex(false), lockLayout(false), + editOptsVisible(false), curWindow(GUI_WINDOW_NOTHING), nextWindow(GUI_WINDOW_NOTHING), nextDesc(NULL), diff --git a/src/gui/gui.h b/src/gui/gui.h index 328ad6a71..2bd286362 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -927,7 +927,7 @@ class FurnaceGUI { char finalLayoutPath[4096]; int curIns, curWave, curSample, curOctave, curOrder, oldRow, oldOrder, oldOrder1, editStep, exportLoops, soloChan, soloTimeout, orderEditMode, orderCursor; - int loopOrder, loopRow, loopEnd, isClipping, extraChannelButtons, patNameTarget, newSongCategory; + int loopOrder, loopRow, loopEnd, isClipping, extraChannelButtons, patNameTarget, newSongCategory, latchTarget; int wheelX, wheelY; bool editControlsOpen, ordersOpen, insListOpen, songInfoOpen, patternOpen, insEditOpen; @@ -944,7 +944,7 @@ class FurnaceGUI { SelectionPoint selStart, selEnd, cursor; bool selecting, curNibble, orderNibble, followOrders, followPattern, changeAllOrders; - bool collapseWindow, demandScrollX, fancyPattern, wantPatName, firstFrame, tempoView, waveHex, lockLayout; + bool collapseWindow, demandScrollX, fancyPattern, wantPatName, firstFrame, tempoView, waveHex, lockLayout, editOptsVisible; FurnaceGUIWindows curWindow, nextWindow; float peak[2]; float patChanX[DIV_MAX_CHANS+1]; From bd58059261008afd1133f5050a0cf78c0b15c866 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Apr 2022 18:11:34 -0500 Subject: [PATCH 75/77] GUI: transpose value does not transpose effect ID --- src/gui/gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index dba51591f..388ac9645 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3847,7 +3847,7 @@ FurnaceGUI::FurnaceGUI(): opMaskTransposeValue.note=false; opMaskTransposeValue.ins=true; opMaskTransposeValue.vol=true; - opMaskTransposeValue.effect=true; + opMaskTransposeValue.effect=false; opMaskTransposeValue.effectVal=true; memset(actionKeys,0,GUI_ACTION_MAX*sizeof(int)); From 2278c1a465bb65b9ea4046e032e5f5186f71bdff Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 21 Apr 2022 18:30:32 -0500 Subject: [PATCH 76/77] GUI: partially implement note input latch UI --- src/gui/gui.cpp | 115 +++++++++++++++++++++++++++++++++++++++++++++--- src/gui/gui.h | 2 +- 2 files changed, 110 insertions(+), 7 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 388ac9645..880d6bc57 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #define _USE_MATH_DEFINES #include "gui.h" #include "util.h" @@ -1018,6 +1019,15 @@ void FurnaceGUI::valueInput(int num, bool direct, int target) { } } +#define changeLatch(x) \ + if (x<0) x=0; \ + if (!latchNibble && !settings.pushNibble) x=0; \ + x=(x<<4)|num; \ + latchNibble=!latchNibble; \ + if (!latchNibble) { \ + if (++latchTarget>4) latchTarget=0; \ + } + void FurnaceGUI::keyDown(SDL_Event& ev) { if (ImGuiFileDialog::Instance()->IsOpened()) return; if (aboutOpen) return; @@ -1059,6 +1069,45 @@ void FurnaceGUI::keyDown(SDL_Event& ev) { return; } + if (latchTarget) { + if (mapped==SDLK_DELETE || mapped==SDLK_BACKSPACE) { + switch (latchTarget) { + case 1: + latchIns=-1; + break; + case 2: + latchVol=-1; + break; + case 3: + latchEffect=-1; + break; + case 4: + latchEffectVal=-1; + break; + } + } else { + try { + int num=valueKeys.at(ev.key.keysym.sym); + switch (latchTarget) { + case 1: // instrument + changeLatch(latchIns); + break; + case 2: // volume + changeLatch(latchVol); + break; + case 3: // effect + changeLatch(latchEffect); + break; + case 4: // effect value + changeLatch(latchEffectVal); + break; + } + } catch (std::out_of_range& e) { + } + } + return; + } + // PER-WINDOW KEYS switch (curWindow) { case GUI_WINDOW_PATTERN: @@ -1904,9 +1953,15 @@ void FurnaceGUI::editOptions(bool topMenu) { } if (ImGui::Selectable(id,latchTarget==1,ImGuiSelectableFlags_DontClosePopups)) { latchTarget=1; + latchNibble=false; + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + latchIns=-2; } if (ImGui::IsItemHovered()) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_TEXT]); ImGui::SetTooltip("&&: selected instrument\n..: no instrument"); + ImGui::PopStyleColor(); } ImGui::PopStyleColor(); ImGui::TableNextColumn(); @@ -1918,17 +1973,48 @@ void FurnaceGUI::editOptions(bool topMenu) { } if (ImGui::Selectable(id,latchTarget==2,ImGuiSelectableFlags_DontClosePopups)) { latchTarget=2; + latchNibble=false; + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + latchVol=-1; } ImGui::PopStyleColor(); ImGui::TableNextColumn(); if (latchEffect==-1) { strcpy(id,"..##LatchFX"); + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_INACTIVE]); } else { - snprintf(id,63,"%.2x##LatchFX",latchEffect&0xff); + const unsigned char data=latchEffect; + snprintf(id,63,"%.2x##LatchFX",data); + if (data<0x10) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[data]]); + } else if (data<0x20) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]); + } else if (data<0x30) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY]); + } else if (data<0x48) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY]); + } else if (data<0x90) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); + } else if (data<0xa0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_MISC]); + } else if (data<0xc0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); + } else if (data<0xd0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_SPEED]); + } else if (data<0xe0) { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]); + } else { + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[extFxColors[data-0xe0]]); + } } - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_PITCH]); + if (ImGui::Selectable(id,latchTarget==3,ImGuiSelectableFlags_DontClosePopups)) { latchTarget=3; + latchNibble=false; + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + latchEffect=-1; } ImGui::TableNextColumn(); if (latchEffectVal==-1) { @@ -1938,17 +2024,32 @@ void FurnaceGUI::editOptions(bool topMenu) { } if (ImGui::Selectable(id,latchTarget==4,ImGuiSelectableFlags_DontClosePopups)) { latchTarget=4; + latchNibble=false; + } + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { + latchEffectVal=-1; } ImGui::PopStyleColor(); ImGui::EndTable(); } ImGui::SameLine(); if (ImGui::Button("Set")) { - // TODO + DivPattern* pat=e->song.pat[cursor.xCoarse].getPattern(e->song.orders.ord[cursor.xCoarse][curOrder],true); + latchIns=pat->data[cursor.y][2]; + latchVol=pat->data[cursor.y][3]; + latchEffect=pat->data[cursor.y][4]; + latchEffectVal=pat->data[cursor.y][5]; + latchTarget=0; + latchNibble=false; } ImGui::SameLine(); - if (ImGui::Button("Clear")) { - // TODO + if (ImGui::Button("Reset")) { + latchIns=-2; + latchVol=-1; + latchEffect=-1; + latchEffectVal=-1; + latchTarget=0; + latchNibble=false; } ImGui::Separator(); @@ -2097,7 +2198,7 @@ int _processEvent(void* instance, SDL_Event* event) { int FurnaceGUI::processEvent(SDL_Event* ev) { if (ev->type==SDL_KEYDOWN) { - if (!ev->key.repeat && !wantCaptureKeyboard && (ev->key.keysym.mod&(~(KMOD_NUM|KMOD_CAPS|KMOD_SCROLL)))==0) { + if (!ev->key.repeat && latchTarget==0 && !wantCaptureKeyboard && (ev->key.keysym.mod&(~(KMOD_NUM|KMOD_CAPS|KMOD_SCROLL)))==0) { if (settings.notePreviewBehavior==0) return 1; switch (curWindow) { case GUI_WINDOW_SAMPLE_EDIT: @@ -3331,6 +3432,7 @@ bool FurnaceGUI::loop() { if (!editOptsVisible) { latchTarget=0; + latchNibble=false; } if (SDL_GetWindowFlags(sdlWin)&SDL_WINDOW_MINIMIZED) { @@ -3701,6 +3803,7 @@ FurnaceGUI::FurnaceGUI(): waveHex(false), lockLayout(false), editOptsVisible(false), + latchNibble(false), curWindow(GUI_WINDOW_NOTHING), nextWindow(GUI_WINDOW_NOTHING), nextDesc(NULL), diff --git a/src/gui/gui.h b/src/gui/gui.h index 2bd286362..6c50a914a 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -944,7 +944,7 @@ class FurnaceGUI { SelectionPoint selStart, selEnd, cursor; bool selecting, curNibble, orderNibble, followOrders, followPattern, changeAllOrders; - bool collapseWindow, demandScrollX, fancyPattern, wantPatName, firstFrame, tempoView, waveHex, lockLayout, editOptsVisible; + bool collapseWindow, demandScrollX, fancyPattern, wantPatName, firstFrame, tempoView, waveHex, lockLayout, editOptsVisible, latchNibble; FurnaceGUIWindows curWindow, nextWindow; float peak[2]; float patChanX[DIV_MAX_CHANS+1]; From 9c8d1223894544763463abeef1624299ee5c4f09 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 22 Apr 2022 01:27:27 -0500 Subject: [PATCH 77/77] GUI: use pattern font for input latch --- TODO.md | 1 - src/gui/gui.cpp | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index f9230306d..4c200e02a 100644 --- a/TODO.md +++ b/TODO.md @@ -32,7 +32,6 @@ - add another FM editor layout - try to find out why does VSlider not accept keyboard input - finish lock layout -- note input latch! - if macros have release, note off should release them - add "don't scroll on cursor movement" option - add ability to select entire row when clicking on row number diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 880d6bc57..009952a63 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -1935,7 +1935,8 @@ void FurnaceGUI::editOptions(bool topMenu) { } ImGui::Text("input latch"); - if (ImGui::BeginTable("opMaskTable",5,ImGuiTableFlags_Borders|ImGuiTableFlags_SizingFixedFit|ImGuiTableFlags_NoHostExtendX)) { + ImGui::PushFont(patFont); + if (ImGui::BeginTable("inputLatchTable",5,ImGuiTableFlags_Borders|ImGuiTableFlags_SizingFixedFit|ImGuiTableFlags_NoHostExtendX)) { static char id[64]; ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -2032,6 +2033,7 @@ void FurnaceGUI::editOptions(bool topMenu) { ImGui::PopStyleColor(); ImGui::EndTable(); } + ImGui::PopFont(); ImGui::SameLine(); if (ImGui::Button("Set")) { DivPattern* pat=e->song.pat[cursor.xCoarse].getPattern(e->song.orders.ord[cursor.xCoarse][curOrder],true);