diff options
Diffstat (limited to 'utils')
| -rw-r--r-- | utils/gen_adldata/CMakeLists.txt | 25 | ||||
| -rw-r--r-- | utils/gen_adldata/file_formats/common.h | 27 | ||||
| -rw-r--r-- | utils/gen_adldata/file_formats/load_ail.h | 161 | ||||
| -rw-r--r-- | utils/gen_adldata/file_formats/load_bisqwit.h | 46 | ||||
| -rw-r--r-- | utils/gen_adldata/file_formats/load_bnk.h | 37 | ||||
| -rw-r--r-- | utils/gen_adldata/file_formats/load_bnk2.h | 62 | ||||
| -rw-r--r-- | utils/gen_adldata/file_formats/load_ea.h | 61 | ||||
| -rw-r--r-- | utils/gen_adldata/file_formats/load_ibk.h | 42 | ||||
| -rw-r--r-- | utils/gen_adldata/file_formats/load_jv.h | 43 | ||||
| -rw-r--r-- | utils/gen_adldata/file_formats/load_op2.h | 46 | ||||
| -rw-r--r-- | utils/gen_adldata/file_formats/load_tmb.h | 40 | ||||
| -rw-r--r-- | utils/gen_adldata/file_formats/load_wopl.h | 87 | ||||
| -rw-r--r-- | utils/gen_adldata/gen_adldata.cc | 202 | ||||
| -rw-r--r-- | utils/gen_adldata/measurer.cpp | 790 | ||||
| -rw-r--r-- | utils/gen_adldata/measurer.h | 23 | ||||
| -rw-r--r-- | utils/gen_adldata/progs_cache.cpp | 571 | ||||
| -rw-r--r-- | utils/gen_adldata/progs_cache.h | 346 | 
17 files changed, 2126 insertions, 483 deletions
| diff --git a/utils/gen_adldata/CMakeLists.txt b/utils/gen_adldata/CMakeLists.txt index a3be516..7939d5b 100644 --- a/utils/gen_adldata/CMakeLists.txt +++ b/utils/gen_adldata/CMakeLists.txt @@ -19,6 +19,22 @@ list(APPEND GEN_ADLDATA_SRC      ini/ini_processing.cpp  ) +option(WITH_GENADLDATA_DEEPDEBUG "Enable deep debug mode of gen_adldata with dumping every voice into WAV file" OFF) +if(WITH_GENADLDATA_DEEPDEBUG) +    add_definitions(-DGEN_ADLDATA_DEEP_DEBUG) +    list(APPEND GEN_ADLDATA_SRC +        ../midiplay/wave_writer.c +    ) +    file(GLOB WAV_FILES ${libADLMIDI_SOURCE_DIR}/fm_banks/_deep_debug/*.wav) +    if(WAV_FILES) +        file(REMOVE ${WAV_FILES}) +    endif() +    add_custom_target(gen_adldata_deepdebug_prepare ALL +        COMMAND ${CMAKE_COMMAND} -E make_directory ${libADLMIDI_SOURCE_DIR}/fm_banks/_deep_debug +        COMMAND ${CMAKE_COMMAND} -E remove ${libADLMIDI_SOURCE_DIR}/fm_banks/adldata-cache-x.dat +    ) +endif() +  if(USE_DOSBOX_EMULATOR)      set(HAS_EMULATOR TRUE)      list(APPEND GEN_ADLDATA_SRC @@ -53,6 +69,15 @@ endif()  set_nopie(gen_adldata) +if(WITH_GENADLDATA_DEEPDEBUG) +    add_dependencies(gen_adldata gen_adldata_deepdebug_prepare) +endif() + +option(WITH_GENADLDATA_PROGRESS "Enable progress printing in gen_adldata" OFF) +if(WITH_GENADLDATA_PROGRESS OR WITH_GENADLDATA_DEEPDEBUG) +    target_compile_options(gen_adldata PUBLIC "-DADL_GENDATA_PRINT_PROGRESS") +endif() +  if(WITH_GENADLDATA_COMMENTS)      target_compile_options(gen_adldata PUBLIC "-DADLDATA_WITH_COMMENTS")  endif() diff --git a/utils/gen_adldata/file_formats/common.h b/utils/gen_adldata/file_formats/common.h index d06059e..a03ca5d 100644 --- a/utils/gen_adldata/file_formats/common.h +++ b/utils/gen_adldata/file_formats/common.h @@ -18,6 +18,14 @@ inline int16_t toSint16BE(const uint8_t *arr)      return num;  } +inline int16_t toSint16LE(const uint8_t *arr) +{ +    int16_t num = *reinterpret_cast<const int8_t *>(&arr[1]); +    num *= 1 << 8; +    num |= static_cast<int16_t>(arr[0]) & 0x00FF; +    return num; +} +  inline uint16_t toUint16LE(const uint8_t *arr)  {      uint16_t num = arr[0]; @@ -25,4 +33,23 @@ inline uint16_t toUint16LE(const uint8_t *arr)      return num;  } +inline uint32_t toUint32LE(const uint8_t *arr) +{ +    uint32_t num = arr[0]; +    num |= (static_cast<uint32_t>(arr[1] << 8)  & 0x0000FF00); +    num |= (static_cast<uint32_t>(arr[2] << 16) & 0x00FF0000); +    num |= (static_cast<uint32_t>(arr[3] << 24) & 0xFF000000); +    return num; +} + +inline int32_t toSint32LE(const uint8_t *arr) +{ +    int32_t num = *reinterpret_cast<const int8_t *>(&arr[3]); +    num *= 1 << 24; +    num |= (static_cast<int32_t>(arr[2]) << 16) & 0x00FF0000; +    num |= (static_cast<int32_t>(arr[1]) << 8) & 0x0000FF00; +    num |= static_cast<int32_t>(arr[0]) & 0x000000FF; +    return num; +} +  #endif // COMMON_H diff --git a/utils/gen_adldata/file_formats/load_ail.h b/utils/gen_adldata/file_formats/load_ail.h index 80ca8ad..abeda95 100644 --- a/utils/gen_adldata/file_formats/load_ail.h +++ b/utils/gen_adldata/file_formats/load_ail.h @@ -3,8 +3,17 @@  #include "../progs_cache.h"  #include "../midi_inst_list.h" +#include "common.h" -static bool LoadMiles(const char *fn, unsigned bank, const char *prefix) +struct GTL_Head // GTL file header entry structure +{ +    uint8_t  patch  = 0; +    uint8_t  bank   = 0; +    uint32_t offset = 0; +}; + +bool BankFormats::LoadMiles(BanksDump &db, const char *fn, unsigned bank, +                            const std::string &bankTitle, const char *prefix)  {      #ifdef HARD_BANKS      writeIni("AIL", fn, prefix, bank, INI_Both); @@ -13,7 +22,7 @@ static bool LoadMiles(const char *fn, unsigned bank, const char *prefix)      if(!fp)          return false;      std::fseek(fp, 0, SEEK_END); -    std::vector<unsigned char> data(size_t(std::ftell(fp))); +    std::vector<uint8_t> data(size_t(std::ftell(fp)));      std::rewind(fp);      if(std::fread(&data[0], 1, data.size(), fp) != data.size())      { @@ -22,33 +31,74 @@ static bool LoadMiles(const char *fn, unsigned bank, const char *prefix)      }      std::fclose(fp); -    for(unsigned a = 0; a < 2000; ++a) +    GTL_Head head; +    std::vector<GTL_Head> heads; +    uint_fast8_t   max_bank_number = 0; +    heads.reserve(256); +    uint8_t *data_pos = data.data(); +    uint8_t *data_end = data.data() + data.size(); +    do      { -        unsigned gm_patch  = data[a * 6 + 0]; -        unsigned gm_bank = data[a * 6 + 1]; -        unsigned offset    = *(unsigned *)&data[a * 6 + 2]; +        if((data_end - data_pos) < 6) +            return false; -        if(gm_patch == 0xFF) +        head.patch = data_pos[0]; +        head.bank  = data_pos[1]; +        head.offset = toUint32LE(data_pos + 2); + +        if((head.patch == 0xFF) || (head.bank == 0xFF))              break; -        int gmno = gm_bank == 0x7F ? int(gm_patch + 0x80) : int(gm_patch); -        int midi_index = gmno < 128 ? gmno -                         : gmno < 128 + 35 ? -1 -                         : gmno < 128 + 88 ? gmno - 35 -                         : -1; -        unsigned length = data[offset] + data[offset + 1] * 256; -        signed char notenum = ((signed char)data[offset + 2]); +        if(head.patch > 127)//Patch ID is more than 127 +            return false; + +        if((head.bank != 0x7F) && (head.bank > max_bank_number) ) +            max_bank_number = head.bank; -        /*printf("%02X %02X %08X ", gmnumber,gmnumber2, offset); -        for(unsigned b=0; b<length; ++b) +        heads.push_back(head); +        data_pos += 6; +    } +    while(data_pos < data_end); + +    size_t bankDb = db.initBank(bank, bankTitle, BanksDump::BankEntry::SETUP_AIL); + +    std::vector<BanksDump::MidiBank> bnkMelodic; +    bnkMelodic.resize(max_bank_number + 1, BanksDump::MidiBank()); +    BanksDump::MidiBank              bnkPercussion; + +    { +        uint8_t bank_lsb_counter = 0; +        uint8_t bank_msb_counter = 0; +        for(BanksDump::MidiBank &b : bnkMelodic)          { -            if(b > 3 && (b-3)%11 == 0) printf("\n                        "); -            printf("%02X ", data[offset+b]); +            b.lsb = bank_lsb_counter++; +            b.msb = bank_msb_counter; +            if(bank_lsb_counter == 0) +                bank_msb_counter++;          } -        printf("\n");*/ +    } -        if(gm_bank != 0 && gm_bank != 0x7F) -            continue; +    uint32_t totalInsts = static_cast<uint32_t>(heads.size()); +    for(uint32_t i = 0; i < totalInsts; i++) +    { +        GTL_Head &h = heads[i]; +        bool isPerc = (h.bank == 0x7F); +        // int  gmPatchId = isPerc ? h.patch : (h.patch + (h.bank * 128)); +        unsigned offset = h.offset; + +        BanksDump::MidiBank &bnk = isPerc ? bnkPercussion : bnkMelodic[h.bank]; + +        int gmno = isPerc ? int(h.patch + 0x80) : int(h.patch); +//        int midi_index = gmno < 128 ? gmno +//                         : gmno < 128 + 35 ? -1 +//                         : gmno < 128 + 88 ? gmno - 35 +//                         : -1; + +        unsigned length = data[offset] + data[offset + 1] * 256; +        signed char notenum = ((signed char)data[offset + 2]); + +        BanksDump::InstrumentEntry inst; +        BanksDump::Operator ops[5];          char name2[512];          sprintf(name2, "%s%c%u", prefix, @@ -57,31 +107,44 @@ static bool LoadMiles(const char *fn, unsigned bank, const char *prefix)          insdata tmp[200];          const unsigned inscount = (length - 3) / 11; -        bool twoOp = (inscount == 1); +//        bool twoOp = (inscount == 1);          for(unsigned i = 0; i < inscount; ++i)          { +            if(i >= 2) +                break;              unsigned o = offset + 3 + i * 11;              tmp[i].finetune = (gmno < 128 && i == 0) ? notenum : 0;              tmp[i].diff = (i == 1); -            tmp[i].data[0] = data[o + 0]; // 20 -            tmp[i].data[8] = data[o + 1]; // 40 (vol) -            tmp[i].data[2] = data[o + 2]; // 60 -            tmp[i].data[4] = data[o + 3]; // 80 -            tmp[i].data[6] = data[o + 4]; // E0 -            tmp[i].data[1] = data[o + 6]; // 23 -            tmp[i].data[9] = data[o + 7]; // 43 (vol) -            tmp[i].data[3] = data[o + 8]; // 63 -            tmp[i].data[5] = data[o + 9]; // 83 -            tmp[i].data[7] = data[o + 10]; // E3 + +            uint8_t temp[11] = {0}; +            if(o < data.size()) +            { +                size_t count = data.size() - o; +                count = (count > sizeof(temp)) ? sizeof(temp) : count; +                std::memcpy(temp, &data[o], count); +            } + +            tmp[i].data[0] = temp[0]; // 20 +            tmp[i].data[8] = temp[1]; // 40 (vol) +            tmp[i].data[2] = temp[2]; // 60 +            tmp[i].data[4] = temp[3]; // 80 +            tmp[i].data[6] = temp[4]; // E0 +            tmp[i].data[1] = temp[6]; // 23 +            tmp[i].data[9] = temp[7]; // 43 (vol) +            tmp[i].data[3] = temp[8]; // 63 +            tmp[i].data[5] = temp[9]; // 83 +            tmp[i].data[7] = temp[10]; // E3              unsigned fb_c = data[offset + 3 + 5];              tmp[i].data[10] = uint8_t(fb_c);              if(i == 1)              { +                inst.instFlags |= BanksDump::InstrumentEntry::WOPL_Ins_4op;                  tmp[0].data[10] = fb_c & 0x0F;                  tmp[1].data[10] = uint8_t((fb_c & 0x0E) | (fb_c >> 7));              } +            db.toOps(tmp[i], ops, i * 2);          }          if(inscount <= 2) @@ -93,19 +156,33 @@ static bool LoadMiles(const char *fn, unsigned bank, const char *prefix)              tmp2.voice2_fine_tune = 0.0;              tmp2.midi_velocity_offset = 0;              tmp2.rhythmModeDrum = 0; -            std::string name; -            if(midi_index >= 0) name = std::string(1, '\377') + MidiInsName[midi_index]; -            size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2, twoOp); -            SetBank(bank, (unsigned int)gmno, resno); +//            std::string name; +//            if(midi_index >= 0) name = std::string(1, '\377') + MidiInsName[midi_index]; +//            if(h.bank == 0 || h.bank == 0x7F) +//            { +//                size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2, twoOp); +//                SetBank(bank, (unsigned int)gmno, resno); +//            } +            //--------------------------------------------------------------- +            inst.percussionKeyNumber = isPerc ? static_cast<uint_fast8_t>(notenum) : 0; +            inst.noteOffset1 = isPerc ? 0 : notenum; +            unsigned fb_c = data[offset + 3 + 5]; +            inst.fbConn = (static_cast<uint_fast16_t>(fb_c & 0x0F)) | +                          (static_cast<uint_fast16_t>((fb_c & 0x0E) | (fb_c >> 7)) << 8); +            db.addInstrument(bnk, h.patch, inst, ops, fn);          }      } -    AdlBankSetup setup; -    setup.volumeModel = VOLUME_Generic; -    setup.deepTremolo = true; -    setup.deepVibrato = true; -    setup.scaleModulators = false; -    SetBankSetup(bank, setup); +//    AdlBankSetup setup; +//    setup.volumeModel = VOLUME_Generic; +//    setup.deepTremolo = true; +//    setup.deepVibrato = true; +//    setup.scaleModulators = false; +//    SetBankSetup(bank, setup); + +    for(auto &b : bnkMelodic) +        db.addMidiBank(bankDb, false, b); +    db.addMidiBank(bankDb, true, bnkPercussion);      return true;  } diff --git a/utils/gen_adldata/file_formats/load_bisqwit.h b/utils/gen_adldata/file_formats/load_bisqwit.h index 9749a76..2c803dd 100644 --- a/utils/gen_adldata/file_formats/load_bisqwit.h +++ b/utils/gen_adldata/file_formats/load_bisqwit.h @@ -4,7 +4,7 @@  #include "../progs_cache.h"  #include "../midi_inst_list.h" -static bool LoadBisqwit(const char *fn, unsigned bank, const char *prefix) +bool BankFormats::LoadBisqwit(BanksDump &db, const char *fn, unsigned bank, const std::string &bankTitle, const char *prefix)  {      #ifdef HARD_BANKS      writeIni("Bisqwit", fn, prefix, bank, INI_Both); @@ -13,14 +13,25 @@ static bool LoadBisqwit(const char *fn, unsigned bank, const char *prefix)      if(!fp)          return false; -    for(uint32_t a = 0; a < 256; ++a) +    size_t bankDb = db.initBank(bank, bankTitle, BanksDump::BankEntry::SETUP_Generic); +    BanksDump::MidiBank bnkMelodique; +    BanksDump::MidiBank bnkPercussion; + +    for(uint32_t a = 0, patchId = 0; a < 256; ++a, patchId++)      {          //unsigned offset = a * 25;          uint32_t gmno = a; +        bool isPercussion = gmno >= 128;          int32_t midi_index = gmno < 128 ? int32_t(gmno)                           : gmno < 128 + 35 ? -1                           : gmno < 128 + 88 ? int32_t(gmno - 35)                           : -1; +        if(patchId == 128) +            patchId = 0; + +        BanksDump::MidiBank &bnk = isPercussion ? bnkPercussion : bnkMelodique; +        BanksDump::InstrumentEntry inst; +        BanksDump::Operator ops[5];          struct ins tmp2;          tmp2.notenum = (uint8_t)std::fgetc(fp); @@ -47,17 +58,32 @@ static bool LoadBisqwit(const char *fn, unsigned bank, const char *prefix)          tmp[1].diff = (tmp[0] != tmp[1]);          tmp2.real4op = tmp[1].diff; -        size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2, (tmp[0] == tmp[1])); -        SetBank(bank, gmno, resno); +//        size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2, (tmp[0] == tmp[1])); +//        SetBank(bank, gmno, resno); + +        db.toOps(tmp[0], ops, 0); +        if(tmp[0] != tmp[1]) +        { +            inst.instFlags |= BanksDump::InstrumentEntry::WOPL_Ins_4op; +            db.toOps(tmp[1], ops, 2); +        } + +        inst.fbConn = uint_fast16_t(tmp[0].data[10]) | (uint_fast16_t(tmp[1].data[10]) << 8); +        inst.percussionKeyNumber = a >= 128 ? tmp2.notenum : 0; +        inst.noteOffset1 = a < 128 ? tmp2.notenum : 0; +        db.addInstrument(bnk, patchId, inst, ops, fn);      }      std::fclose(fp); -    AdlBankSetup setup; -    setup.volumeModel = VOLUME_Generic; -    setup.deepTremolo = true; -    setup.deepVibrato = true; -    setup.scaleModulators = false; -    SetBankSetup(bank, setup); +    db.addMidiBank(bankDb, false, bnkMelodique); +    db.addMidiBank(bankDb, true, bnkPercussion); + +//    AdlBankSetup setup; +//    setup.volumeModel = VOLUME_Generic; +//    setup.deepTremolo = true; +//    setup.deepVibrato = true; +//    setup.scaleModulators = false; +//    SetBankSetup(bank, setup);      return true;  } diff --git a/utils/gen_adldata/file_formats/load_bnk.h b/utils/gen_adldata/file_formats/load_bnk.h index f1412ba..4021831 100644 --- a/utils/gen_adldata/file_formats/load_bnk.h +++ b/utils/gen_adldata/file_formats/load_bnk.h @@ -7,7 +7,9 @@  #include <cstdint>  #include <string> -static bool LoadBNK(const char *fn, unsigned bank, const char *prefix, bool is_fat, bool percussive) +bool BankFormats::LoadBNK(BanksDump &db, const char *fn, unsigned bank, +                          const std::string &bankTitle, const char *prefix, +                          bool is_fat, bool percussive)  {      #ifdef HARD_BANKS      writeIni("HMI", fn, prefix, bank, percussive ? INI_Drums : INI_Melodic); @@ -25,6 +27,9 @@ static bool LoadBNK(const char *fn, unsigned bank, const char *prefix, bool is_f      }      std::fclose(fp); +    size_t bankDb = db.initBank(bank, bankTitle, BanksDump::BankEntry::SETUP_Generic); +    BanksDump::MidiBank bnk; +      /*printf("%s:\n", fn);*/      //unsigned short version = *(short*)&data[0]; // major,minor (2 bytes)      //                                             "ADLIB-"    (6 bytes) @@ -80,6 +85,9 @@ static bool LoadBNK(const char *fn, unsigned bank, const char *prefix, bool is_f          else              sprintf(name2, "%s%u", prefix, n); +        BanksDump::InstrumentEntry inst; +        BanksDump::Operator ops[5]; +          insdata tmp;          tmp.data[0] = uint8_t(                        (op1[ 9] << 7) // TREMOLO FLAG @@ -115,16 +123,21 @@ static bool LoadBNK(const char *fn, unsigned bank, const char *prefix, bool is_f          if(is_fat) tmp.data[10] ^= 1; -        size_t resno = InsertIns(tmp, tmp2, std::string(1, '\377') + name, name2); +        db.toOps(tmp, ops, 0); +        inst.percussionKeyNumber = is_fat ? voice_num : (percussive ? usage_flag : 0); +        inst.setFbConn(op1[2] * 2 + op1[12]); + +//        size_t resno = InsertIns(tmp, tmp2, std::string(1, '\377') + name, name2);          if(!is_fat)          { -            SetBank(bank, (unsigned int)gmno, resno); +//            SetBank(bank, (unsigned int)gmno, resno); +            db.addInstrument(bnk, n & 127, inst, ops, fn);          }          else          { -            if(name[2] == 'O' || name[1] == 'M') SetBank(bank + 0, (unsigned int)gmno, resno); -            if(name[2] == 'S' || name[1] == 'M') SetBank(bank + 1, (unsigned int)gmno, resno); +//            if(name[2] == 'O' || name[1] == 'M') SetBank(bank + 0, (unsigned int)gmno, resno); +//            if(name[2] == 'S' || name[1] == 'M') SetBank(bank + 1, (unsigned int)gmno, resno);          }          /* @@ -151,12 +164,14 @@ static bool LoadBNK(const char *fn, unsigned bank, const char *prefix, bool is_f          */      } -    AdlBankSetup setup; -    setup.volumeModel = VOLUME_Generic; -    setup.deepTremolo = false; -    setup.deepVibrato = false; -    setup.scaleModulators = false; -    SetBankSetup(bank, setup); +    db.addMidiBank(bankDb, percussive, bnk); + +//    AdlBankSetup setup; +//    setup.volumeModel = VOLUME_Generic; +//    setup.deepTremolo = false; +//    setup.deepVibrato = false; +//    setup.scaleModulators = false; +//    SetBankSetup(bank, setup);      return true;  } diff --git a/utils/gen_adldata/file_formats/load_bnk2.h b/utils/gen_adldata/file_formats/load_bnk2.h index 072712c..fc36dd2 100644 --- a/utils/gen_adldata/file_formats/load_bnk2.h +++ b/utils/gen_adldata/file_formats/load_bnk2.h @@ -8,9 +8,10 @@ inline int stdstoi(const std::string& str)      return std::atoi(str.c_str());  } -static bool LoadBNK2(const char *fn, unsigned bank, const char *prefix, -                     const std::string &melo_filter, -                     const std::string &perc_filter) +bool BankFormats::LoadBNK2(BanksDump &db, const char *fn, unsigned bank, +                           const std::string &bankTitle, const char *prefix, +                           const std::string &melo_filter, +                           const std::string &perc_filter)  {      #ifdef HARD_BANKS      writeIni("AdLibGold", fn, prefix, bank, INI_Both, melo_filter.c_str(), perc_filter.c_str()); @@ -28,6 +29,10 @@ static bool LoadBNK2(const char *fn, unsigned bank, const char *prefix,      }      std::fclose(fp); +    size_t bankDb = db.initBank(bank, bankTitle, BanksDump::BankEntry::SETUP_Generic); +    BanksDump::MidiBank bnkMelodic; +    BanksDump::MidiBank bnkPercussion; +      unsigned short ins_entries = *(unsigned short *)&data[28 + 2 + 10];      unsigned char *records = &data[48]; @@ -47,13 +52,24 @@ static bool LoadBNK2(const char *fn, unsigned bank, const char *prefix,          }          int gmno = 0; +        int patchId = 0; +        bool isPercussion = false;          if(name.substr(0, melo_filter.size()) == melo_filter) -            gmno = stdstoi(name.substr(melo_filter.size())); +        { +            gmno = patchId = stdstoi(name.substr(melo_filter.size())); +            isPercussion = false; +        }          else if(name.substr(0, perc_filter.size()) == perc_filter) -            gmno = stdstoi(name.substr(perc_filter.size())) + 128; +        { +            patchId = stdstoi(name.substr(perc_filter.size())); +            gmno = patchId + 128; +            isPercussion = true; +        }          else              continue; +        BanksDump::MidiBank &bnk = isPercussion ? bnkPercussion : bnkMelodic; +          const unsigned char *insdata = &data[size_t(offset2)];          const unsigned char *ops[4] = { insdata + 0, insdata + 6, insdata + 12, insdata + 18 };          unsigned char C4xxxFFFC = insdata[24]; @@ -64,6 +80,9 @@ static bool LoadBNK2(const char *fn, unsigned bank, const char *prefix,          char name2[512];          sprintf(name2, "%s%c%u", prefix, (gmno & 128) ? 'P' : 'M', gmno & 127); +        BanksDump::InstrumentEntry inst; +        BanksDump::Operator opsD[5]; +          struct insdata tmp[2];          for(unsigned a = 0; a < 2; ++a)          { @@ -79,6 +98,7 @@ static bool LoadBNK2(const char *fn, unsigned bank, const char *prefix,              tmp[a].data[9] = ops[a * 2 + 1][1];              tmp[a].finetune = (int8_t)TTTTTTTT;              tmp[a].diff = false; +            db.toOps(tmp[a], opsD, a * 2);          }          tmp[0].data[10] = C4xxxFFFC & 0x0F;          tmp[1].data[10] = (tmp[0].data[10] & 0x0E) | (C4xxxFFFC >> 7); @@ -91,28 +111,40 @@ static bool LoadBNK2(const char *fn, unsigned bank, const char *prefix,          tmp2.midi_velocity_offset = 0;          tmp2.rhythmModeDrum = 0; +        inst.setFbConn(C4xxxFFFC & 0x0F, (tmp[0].data[10] & 0x0E) | (C4xxxFFFC >> 7)); +        inst.noteOffset1 = (int8_t)TTTTTTTT; +        inst.percussionKeyNumber = (gmno & 128) ? 35 : 0; +          if(xxP24NNN & 8)          {              // dual-op              tmp2.real4op = true;              tmp[1].diff = true; -            size_t resno = InsertIns(tmp[0], tmp[1], tmp2, std::string(1, '\377') + name, name2); -            SetBank(bank, (unsigned int)gmno, resno); +//            size_t resno = InsertIns(tmp[0], tmp[1], tmp2, std::string(1, '\377') + name, name2); +//            SetBank(bank, (unsigned int)gmno, resno); + +            inst.instFlags |= BanksDump::InstrumentEntry::WOPL_Ins_4op; +            db.addInstrument(bnk, patchId, inst, opsD, fn);          }          else          {              // single-op -            size_t resno = InsertIns(tmp[0], tmp2, std::string(1, '\377') + name, name2); -            SetBank(bank, (unsigned int)gmno, resno); +//            size_t resno = InsertIns(tmp[0], tmp2, std::string(1, '\377') + name, name2); +//            SetBank(bank, (unsigned int)gmno, resno); + +            db.addInstrument(bnk, patchId, inst, opsD, fn);          }      } -    AdlBankSetup setup; -    setup.volumeModel = VOLUME_Generic; -    setup.deepTremolo = false; -    setup.deepVibrato = false; -    setup.scaleModulators = false; -    SetBankSetup(bank, setup); +    db.addMidiBank(bankDb, false, bnkMelodic); +    db.addMidiBank(bankDb, true, bnkPercussion); + +//    AdlBankSetup setup; +//    setup.volumeModel = VOLUME_Generic; +//    setup.deepTremolo = false; +//    setup.deepVibrato = false; +//    setup.scaleModulators = false; +//    SetBankSetup(bank, setup);      return true;  } diff --git a/utils/gen_adldata/file_formats/load_ea.h b/utils/gen_adldata/file_formats/load_ea.h index c217c09..0e2d294 100644 --- a/utils/gen_adldata/file_formats/load_ea.h +++ b/utils/gen_adldata/file_formats/load_ea.h @@ -4,17 +4,22 @@  #include "../progs_cache.h"  #include "../midi_inst_list.h" -static bool LoadEA(const char *fn, unsigned bank, const char *prefix) +bool BankFormats::LoadEA(BanksDump &db, const char *fn, unsigned bank, +                         const std::string &bankTitle, const char *prefix)  {      FILE *fp = std::fopen(fn, "rb");      if(!fp)          return false; +    size_t bankDb = db.initBank(bank, bankTitle, BanksDump::BankEntry::SETUP_CMF); +    BanksDump::MidiBank bnkMelodic = db.midiBanks[db.banks[0].melodic[0]]; +    BanksDump::MidiBank bnkPercussion = db.midiBanks[db.banks[0].percussion[0]]; +      // Copy all instruments from bank 0 -    for(unsigned gmno = 0; gmno < 128; ++gmno) -        progs[bank][gmno] = progs[0][gmno]; -    for(unsigned gmno = 35; gmno < 80; ++gmno) -        progs[bank][0x80 + gmno] = progs[0][0x80 + gmno]; +//    for(unsigned gmno = 0; gmno < 128; ++gmno) +//        progs[bank][gmno] = progs[0][gmno]; +//    for(unsigned gmno = 35; gmno < 80; ++gmno) +//        progs[bank][0x80 + gmno] = progs[0][0x80 + gmno];      uint16_t sources[20 + 8];      // Copy also the unused instruments @@ -61,6 +66,9 @@ static bool LoadEA(const char *fn, unsigned bank, const char *prefix)              return false;          } +        BanksDump::InstrumentEntry inst; +        BanksDump::Operator ops[5]; +          insdata tmp;          tmp.data[0] = bytes[0]; // reg 0x20: modulator AM/VIG/EG/KSR          tmp.data[8] = bytes[1]; // reg 0x40: modulator ksl/attenuation @@ -82,12 +90,16 @@ static bool LoadEA(const char *fn, unsigned bank, const char *prefix)          tmp.data[6] = 0;        // reg 0xE0: modulator, never seems to be set          tmp.data[7] = 0;        // reg 0xE0: carrier,   never seems to be set -        ins tmp2{}; +        ins tmp2;          tmp2.notenum   = 0;          tmp2.pseudo4op = false;          tmp2.real4op = false;          tmp2.rhythmModeDrum = 0; +        db.toOps(tmp, ops, 0); +        inst.setFbConn(bytes[8]); +        inst.noteOffset1 = int8_t(bytes[9] + 12); +          std::string name;          char name2[512];          if(gmno < 20) @@ -98,42 +110,55 @@ static bool LoadEA(const char *fn, unsigned bank, const char *prefix)          {              snprintf(name2, 512, "%sunk%04X", prefix, offset);          } -        size_t resno = InsertIns(tmp, tmp2, std::string(1, '\377') + name, name2); -        SetBank(bank, gmno, resno); +//        size_t resno = InsertIns(tmp, tmp2, std::string(1, '\377') + name, name2); +//        SetBank(bank, gmno, resno); + +        db.addInstrument(bnkMelodic, gmno, inst, ops, fn);          if(gmno == 10)          {              /*tmp.finetune=0;*/ tmp2.notenum = 0x49; -            SetBank(bank, 0x80 + 0x36, InsertIns(tmp, tmp2, std::string(1, '\377') + MidiInsName[0x80 + 0x36 - 35], std::string(1, '\377') + prefix + "P54")); +//            SetBank(bank, 0x80 + 0x36, InsertIns(tmp, tmp2, std::string(1, '\377') + MidiInsName[0x80 + 0x36 - 35], std::string(1, '\377') + prefix + "P54")); +            inst.percussionKeyNumber = 0x49; +            db.addInstrument(bnkPercussion, 0x36, inst, ops, fn);          }          if(gmno == 18)          {              /*tmp.finetune=0;*/ tmp2.notenum = 0x17; -            SetBank(bank, 0x80 + 0x2A, InsertIns(tmp, tmp2, std::string(1, '\377') + MidiInsName[0x80 + 0x2A - 35], std::string(1, '\377') + prefix + "P42")); +//            SetBank(bank, 0x80 + 0x2A, InsertIns(tmp, tmp2, std::string(1, '\377') + MidiInsName[0x80 + 0x2A - 35], std::string(1, '\377') + prefix + "P42")); +            inst.percussionKeyNumber = 0x17; +            db.addInstrument(bnkPercussion, 0x2A, inst, ops, fn);          }          if(gmno == 16)          {              /*tmp.finetune=0;*/ tmp2.notenum = 0x0C; -            SetBank(bank, 0x80 + 0x24, InsertIns(tmp, tmp2, std::string(1, '\377') + MidiInsName[0x80 + 0x24 - 35], std::string(1, '\377') + prefix + "P36")); +//            SetBank(bank, 0x80 + 0x24, InsertIns(tmp, tmp2, std::string(1, '\377') + MidiInsName[0x80 + 0x24 - 35], std::string(1, '\377') + prefix + "P36")); +            inst.percussionKeyNumber = 0x0C; +            db.addInstrument(bnkPercussion, 0x24, inst, ops, fn);          }          if(gmno == 17)          {              /*tmp.finetune=0;*/ tmp2.notenum = 0x01; -            SetBank(bank, 0x80 + 0x26, InsertIns(tmp, tmp2, std::string(1, '\377') + MidiInsName[0x80 + 0x26 - 35], std::string(1, '\377') + prefix + "P38")); +//            SetBank(bank, 0x80 + 0x26, InsertIns(tmp, tmp2, std::string(1, '\377') + MidiInsName[0x80 + 0x26 - 35], std::string(1, '\377') + prefix + "P38")); +            inst.percussionKeyNumber = 0x01; +            db.addInstrument(bnkPercussion, 0x26, inst, ops, fn);          }      }      std::fclose(fp); -    AdlBankSetup setup; -    setup.volumeModel = VOLUME_CMF; -    setup.deepTremolo = false; -    setup.deepVibrato = false; -    setup.scaleModulators = false; -    SetBankSetup(bank, setup); +//    AdlBankSetup setup; +//    setup.volumeModel = VOLUME_CMF; +//    setup.deepTremolo = false; +//    setup.deepVibrato = false; +//    setup.scaleModulators = false; +//    SetBankSetup(bank, setup); + +    db.addMidiBank(bankDb, false, bnkMelodic); +    db.addMidiBank(bankDb, true, bnkPercussion);      return true;  } diff --git a/utils/gen_adldata/file_formats/load_ibk.h b/utils/gen_adldata/file_formats/load_ibk.h index 28177c7..6ae907e 100644 --- a/utils/gen_adldata/file_formats/load_ibk.h +++ b/utils/gen_adldata/file_formats/load_ibk.h @@ -3,7 +3,9 @@  #include "../progs_cache.h" -static bool LoadIBK(const char *fn, unsigned bank, const char *prefix, bool percussive, bool noRhythmMode = false) +bool BankFormats::LoadIBK(BanksDump &db, const char *fn, unsigned bank, +                          const std::string &bankTitle, const char *prefix, +                          bool percussive, bool noRhythmMode)  {      #ifdef HARD_BANKS      writeIni("IBK", fn, prefix, bank, percussive ? INI_Drums : INI_Melodic); @@ -21,6 +23,9 @@ static bool LoadIBK(const char *fn, unsigned bank, const char *prefix, bool perc      }      std::fclose(fp); +    size_t bankDb = db.initBank(bank, bankTitle, BanksDump::BankEntry::SETUP_Generic); +    BanksDump::MidiBank bnk; +      unsigned offs1_base = 0x804, offs1_len = 9;      unsigned offs2_base = 0x004, offs2_len = 16; @@ -43,6 +48,9 @@ static bool LoadIBK(const char *fn, unsigned bank, const char *prefix, bool perc          sprintf(name2, "%s%c%u", prefix,                  (gmno < 128 ? 'M' : 'P'), gmno & 127); +        BanksDump::InstrumentEntry inst; +        BanksDump::Operator ops[5]; +          insdata tmp;          tmp.data[0] = data[offset2 + 0];          tmp.data[1] = data[offset2 + 1]; @@ -66,6 +74,11 @@ static bool LoadIBK(const char *fn, unsigned bank, const char *prefix, bool perc          tmp2.voice2_fine_tune = 0.0;          tmp2.midi_velocity_offset = 0; +        db.toOps(tmp, ops, 0); +        inst.noteOffset1 = percussive ? 0 : data[offset2 + 12]; +        inst.percussionKeyNumber = percussive ? data[offset2 + 13] : 0; +        inst.setFbConn(data[offset2 + 10]); +          tmp2.rhythmModeDrum = 0;          if(percussive && !noRhythmMode)          { @@ -74,36 +87,45 @@ static bool LoadIBK(const char *fn, unsigned bank, const char *prefix, bool perc              {              case 6:                  tmp2.rhythmModeDrum = ins::Flag_RM_BassDrum; +                inst.instFlags |= BanksDump::InstrumentEntry::WOPL_RM_BassDrum;                  break;              case 7:                  tmp2.rhythmModeDrum = ins::Flag_RM_Snare; +                inst.instFlags |= BanksDump::InstrumentEntry::WOPL_RM_Snare;                  break;              case 8:                  tmp2.rhythmModeDrum = ins::Flag_RM_TomTom; +                inst.instFlags |= BanksDump::InstrumentEntry::WOPL_RM_TomTom;                  break;              case 9:                  tmp2.rhythmModeDrum = ins::Flag_RM_Cymbal; +                inst.instFlags |= BanksDump::InstrumentEntry::WOPL_RM_Cymbal;                  break;              case 10:                  tmp2.rhythmModeDrum = ins::Flag_RM_HiHat; +                inst.instFlags |= BanksDump::InstrumentEntry::WOPL_RM_HiHat;                  break;              default:                  // IBK logic: make non-percussion instrument be silent -                tmp = MakeNoSoundIns(); +//                tmp = MakeNoSoundIns();                  break;              }          } -        size_t resno = InsertIns(tmp, tmp2, std::string(1, '\377') + name, name2); -        SetBank(bank, (unsigned int)gmno, resno); +//        size_t resno = InsertIns(tmp, tmp2, std::string(1, '\377') + name, name2); +//        SetBank(bank, (unsigned int)gmno, resno); + +        db.addInstrument(bnk, a, inst, ops, fn);      } -    AdlBankSetup setup; -    setup.volumeModel = VOLUME_Generic; -    setup.deepTremolo = false; -    setup.deepVibrato = false; -    setup.scaleModulators = false; -    SetBankSetup(bank, setup); +    db.addMidiBank(bankDb, percussive, bnk); + +//    AdlBankSetup setup; +//    setup.volumeModel = VOLUME_Generic; +//    setup.deepTremolo = false; +//    setup.deepVibrato = false; +//    setup.scaleModulators = false; +//    SetBankSetup(bank, setup);      return true;  } diff --git a/utils/gen_adldata/file_formats/load_jv.h b/utils/gen_adldata/file_formats/load_jv.h index a498bb6..1cb6a16 100644 --- a/utils/gen_adldata/file_formats/load_jv.h +++ b/utils/gen_adldata/file_formats/load_jv.h @@ -4,7 +4,7 @@  #include "../progs_cache.h"  #include "../midi_inst_list.h" -static bool LoadJunglevision(const char *fn, unsigned bank, const char *prefix) +bool BankFormats::LoadJunglevision(BanksDump &db, const char *fn, unsigned bank, const std::string &bankTitle, const char *prefix)  {      #ifdef HARD_BANKS      writeIni("Junglevision", fn, prefix, bank, INI_Both); @@ -22,6 +22,10 @@ static bool LoadJunglevision(const char *fn, unsigned bank, const char *prefix)      }      std::fclose(fp); +    size_t bankDb = db.initBank(bank, bankTitle, BanksDump::BankEntry::SETUP_Win9X); +    BanksDump::MidiBank bnkMelodique; +    BanksDump::MidiBank bnkPercussion; +      uint16_t ins_count  = uint16_t(data[0x20] + (data[0x21] << 8));      uint16_t drum_count = uint16_t(data[0x22] + (data[0x23] << 8));      uint16_t first_ins  = uint16_t(data[0x24] + (data[0x25] << 8)); @@ -38,6 +42,12 @@ static bool LoadJunglevision(const char *fn, unsigned bank, const char *prefix)                           : gmno < 128 + 88 ? int(gmno - 35)                           : -1; +        bool isPercussion = a >= ins_count; +        size_t patchId = (a < ins_count) ? (a + first_ins) : ((a - ins_count) + first_drum); +        BanksDump::MidiBank &bnk = isPercussion ? bnkPercussion : bnkMelodique; +        BanksDump::InstrumentEntry inst; +        BanksDump::Operator ops[5]; +          insdata tmp[2];          tmp[0].data[0] = data[offset + 2]; @@ -83,6 +93,13 @@ static bool LoadJunglevision(const char *fn, unsigned bank, const char *prefix)              tmp[1].finetune -= 12;          } +        if(data[offset] != 0) +            inst.instFlags |= BanksDump::InstrumentEntry::WOPL_Ins_4op; +        inst.percussionKeyNumber = data[offset + 1]; +        inst.setFbConn(data[offset + 7], data[offset + 7 + 11]); +        db.toOps(tmp[0], ops, 0); +        db.toOps(tmp[1], ops, 2); +          std::string name;          if(midi_index >= 0) name = std::string(1, '\377') + MidiInsName[midi_index]; @@ -92,22 +109,26 @@ static bool LoadJunglevision(const char *fn, unsigned bank, const char *prefix)          if(!data[offset])          { -            size_t resno = InsertIns(tmp[0], tmp2, name, name2); -            SetBank(bank, gmno, resno); +//            size_t resno = InsertIns(tmp[0], tmp2, name, name2); +//            SetBank(bank, gmno, resno);          }          else // Double instrument          { -            size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2); -            SetBank(bank, gmno, resno); +//            size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2); +//            SetBank(bank, gmno, resno);          } +        db.addInstrument(bnk, patchId, inst, ops, fn);      } -    AdlBankSetup setup; -    setup.volumeModel = VOLUME_9X; -    setup.deepTremolo = true; -    setup.deepVibrato = true; -    setup.scaleModulators = false; -    SetBankSetup(bank, setup); +    db.addMidiBank(bankDb, false, bnkMelodique); +    db.addMidiBank(bankDb, true, bnkPercussion); + +//    AdlBankSetup setup; +//    setup.volumeModel = VOLUME_9X; +//    setup.deepTremolo = true; +//    setup.deepVibrato = true; +//    setup.scaleModulators = false; +//    SetBankSetup(bank, setup);      return true;  } diff --git a/utils/gen_adldata/file_formats/load_op2.h b/utils/gen_adldata/file_formats/load_op2.h index 86f1377..494655d 100644 --- a/utils/gen_adldata/file_formats/load_op2.h +++ b/utils/gen_adldata/file_formats/load_op2.h @@ -49,7 +49,7 @@ struct Doom_opl_instr  #endif -static bool LoadDoom(const char *fn, unsigned bank, const char *prefix) +bool BankFormats::LoadDoom(BanksDump &db, const char *fn, unsigned bank, const std::string &bankTitle, const char *prefix)  {      #ifdef HARD_BANKS      writeIni("OP2", fn, prefix, bank, INI_Both); @@ -68,11 +68,17 @@ static bool LoadDoom(const char *fn, unsigned bank, const char *prefix)      }      std::fclose(fp); +    size_t bankDb = db.initBank(bank, bankTitle, BanksDump::BankEntry::SETUP_DMX); +    BanksDump::MidiBank bnkMelodique; +    BanksDump::MidiBank bnkPercussion; +      for(unsigned a = 0; a < 175; ++a)      {          const size_t offset1 = 0x18A4 + a * 32;          const size_t offset2 = 8      + a * 36; - +        BanksDump::MidiBank &bnk = a < 128 ? bnkMelodique : bnkPercussion; +        BanksDump::InstrumentEntry inst; +        BanksDump::Operator ops[5];          std::string name;          for(unsigned p = 0; p < 32; ++p)              if(data[offset1] != '\0') @@ -80,6 +86,7 @@ static bool LoadDoom(const char *fn, unsigned bank, const char *prefix)          //printf("%3d %3d %3d %8s: ", a,b,c, name.c_str());          int gmno = int(a < 128 ? a : ((a | 128) + 35)); +        size_t patchId = a < 128 ? a : ((a - 128) + 35);          char name2[512];          snprintf(name2, 512, "%s%c%u", prefix, (gmno < 128 ? 'M' : 'P'), gmno & 127); @@ -104,6 +111,8 @@ static bool LoadDoom(const char *fn, unsigned bank, const char *prefix)              tmp[index].data[9] = src.scale_2 | src.level_2;              tmp[index].data[10] = src.feedback;              tmp[index].finetune = int8_t(src.basenote + 12); +            inst.fbConn |= (uint_fast16_t(src.feedback) << (a == 1 ? 8 : 0)); +            db.toOps(tmp[index], ops, index * 2);          }          struct ins tmp2;          tmp2.notenum  = ins.note; @@ -120,10 +129,18 @@ static bool LoadDoom(const char *fn, unsigned bank, const char *prefix)              tmp[1].finetune -= 12;          } +        inst.noteOffset1 = int8_t(tmp[0].finetune); +        inst.noteOffset2 = int8_t(tmp[1].finetune); + +        if((ins.flags & FL_DOUBLE_VOICE) != 0) +            inst.instFlags |= BanksDump::InstrumentEntry::WOPL_Ins_4op | BanksDump::InstrumentEntry::WOPL_Ins_Pseudo4op; +        inst.percussionKeyNumber = tmp2.notenum; +        inst.secondVoiceDetune = static_cast<char>(static_cast<int>(ins.finetune) - 128); +          if(!(ins.flags & FL_DOUBLE_VOICE))          { -            size_t resno = InsertIns(tmp[0], tmp2, std::string(1, '\377') + name, name2); -            SetBank(bank, (unsigned int)gmno, resno); +//            size_t resno = InsertIns(tmp[0], tmp2, std::string(1, '\377') + name, name2); +//            SetBank(bank, (unsigned int)gmno, resno);          }          else // Double instrument          { @@ -131,10 +148,12 @@ static bool LoadDoom(const char *fn, unsigned bank, const char *prefix)              // Simulate behavior of DMX second voice detune              tmp2.voice2_fine_tune = (double)((ins.finetune >> 1) - 64) / 32.0;              //printf("/*DOOM FINE TUNE (flags %000X instrument is %d) IS %d -> %lf*/\n", ins.flags, a, ins.finetune, tmp2.fine_tune); -            size_t resno = InsertIns(tmp[0], tmp[1], tmp2, std::string(1, '\377') + name, name2); -            SetBank(bank, (unsigned int)gmno, resno); +//            size_t resno = InsertIns(tmp[0], tmp[1], tmp2, std::string(1, '\377') + name, name2); +//            SetBank(bank, (unsigned int)gmno, resno);          } +        db.addInstrument(bnk, patchId, inst, ops, fn); +          /*const Doom_OPL2instrument& A = ins.patchdata[0];          const Doom_OPL2instrument& B = ins.patchdata[1];          printf( @@ -156,12 +175,15 @@ static bool LoadDoom(const char *fn, unsigned bank, const char *prefix)          printf("------------------------------------------------------------\n");*/      } -    AdlBankSetup setup; -    setup.volumeModel = VOLUME_DMX; -    setup.deepTremolo = false; -    setup.deepVibrato = false; -    setup.scaleModulators = false; -    SetBankSetup(bank, setup); +    db.addMidiBank(bankDb, false, bnkMelodique); +    db.addMidiBank(bankDb, true, bnkPercussion); + +//    AdlBankSetup setup; +//    setup.volumeModel = VOLUME_DMX; +//    setup.deepTremolo = false; +//    setup.deepVibrato = false; +//    setup.scaleModulators = false; +//    SetBankSetup(bank, setup);      return true;  } diff --git a/utils/gen_adldata/file_formats/load_tmb.h b/utils/gen_adldata/file_formats/load_tmb.h index 4417b02..e0b0e31 100644 --- a/utils/gen_adldata/file_formats/load_tmb.h +++ b/utils/gen_adldata/file_formats/load_tmb.h @@ -4,7 +4,7 @@  #include "../progs_cache.h"  #include "../midi_inst_list.h" -static bool LoadTMB(const char *fn, unsigned bank, const char *prefix) +bool BankFormats::LoadTMB(BanksDump &db, const char *fn, unsigned bank, const std::string &bankTitle, const char *prefix)  {      #ifdef HARD_BANKS      writeIni("TMB", fn, prefix, bank, INI_Both); @@ -22,7 +22,11 @@ static bool LoadTMB(const char *fn, unsigned bank, const char *prefix)      }      std::fclose(fp); -    for(unsigned a = 0; a < 256; ++a) +    size_t bankDb = db.initBank(bank, bankTitle, BanksDump::BankEntry::SETUP_Apogee); +    BanksDump::MidiBank bnkMelodique; +    BanksDump::MidiBank bnkPercussion; + +    for(unsigned a = 0, patchId = 0; a < 256; ++a, patchId++)      {          unsigned offset = a * 0x0D;          unsigned gmno = a; @@ -30,6 +34,12 @@ static bool LoadTMB(const char *fn, unsigned bank, const char *prefix)                           : gmno < 128 + 35 ? -1                           : gmno < 128 + 88 ? int(gmno - 35)                           : -1; +        if(patchId == 128) +            patchId = 0; +        bool isPercussion = a >= 128; +        BanksDump::MidiBank &bnk = isPercussion ? bnkPercussion : bnkMelodique; +        BanksDump::InstrumentEntry inst; +        BanksDump::Operator ops[5];          insdata tmp; @@ -55,6 +65,11 @@ static bool LoadTMB(const char *fn, unsigned bank, const char *prefix)          tmp2.midi_velocity_offset = (int8_t)data[offset + 12];          tmp2.rhythmModeDrum = 0; +        inst.percussionKeyNumber = data[offset + 11]; +        inst.midiVelocityOffset = (int8_t)data[offset + 12]; +        inst.fbConn = data[offset + 10]; +        db.toOps(tmp, ops, 0); +          std::string name;          if(midi_index >= 0) name = std::string(1, '\377') + MidiInsName[midi_index]; @@ -62,16 +77,21 @@ static bool LoadTMB(const char *fn, unsigned bank, const char *prefix)          sprintf(name2, "%s%c%u", prefix,                  (gmno < 128 ? 'M' : 'P'), gmno & 127); -        size_t resno = InsertIns(tmp, tmp2, name, name2); -        SetBank(bank, gmno, resno); +//        size_t resno = InsertIns(tmp, tmp2, name, name2); +//        SetBank(bank, gmno, resno); + +        db.addInstrument(bnk, patchId, inst, ops, fn);      } -    AdlBankSetup setup; -    setup.volumeModel = VOLUME_APOGEE; -    setup.deepTremolo = false; -    setup.deepVibrato = false; -    setup.scaleModulators = false; -    SetBankSetup(bank, setup); +    db.addMidiBank(bankDb, false, bnkMelodique); +    db.addMidiBank(bankDb, true, bnkPercussion); + +//    AdlBankSetup setup; +//    setup.volumeModel = VOLUME_APOGEE; +//    setup.deepTremolo = false; +//    setup.deepVibrato = false; +//    setup.scaleModulators = false; +//    SetBankSetup(bank, setup);      return true;  } diff --git a/utils/gen_adldata/file_formats/load_wopl.h b/utils/gen_adldata/file_formats/load_wopl.h index d0c01d3..a60cbc4 100644 --- a/utils/gen_adldata/file_formats/load_wopl.h +++ b/utils/gen_adldata/file_formats/load_wopl.h @@ -18,7 +18,7 @@ enum class WOPL_Flags      WOPL_RhythmModeMask = 0x38,  }; -static bool LoadWopl(const char *fn, unsigned bank, const char *prefix) +bool BankFormats::LoadWopl(BanksDump &db, const char *fn, unsigned bank, const std::string bankTitle, const char *prefix)  {      FILE *fp = std::fopen(fn, "rb");      if(!fp) @@ -27,6 +27,7 @@ static bool LoadWopl(const char *fn, unsigned bank, const char *prefix)          std::fflush(stderr);          return false;      } +      std::fseek(fp, 0, SEEK_END);      std::vector<unsigned char> data(size_t(std::ftell(fp)));      std::rewind(fp); @@ -57,11 +58,13 @@ static bool LoadWopl(const char *fn, unsigned bank, const char *prefix)      uint16_t mbanks_count = toUint16BE((const uint8_t *)data.data() + 0x0d);      uint16_t pbanks_count = toUint16BE((const uint8_t *)data.data() + 0x0f); -    AdlBankSetup setup; -    setup.deepTremolo = (data[0x11] & 0x01) != 0; -    setup.deepVibrato = (data[0x11] & 0x02) != 0; -    setup.volumeModel = (int)data[0x12]; -    setup.scaleModulators  = false; +//    AdlBankSetup setup; +//    setup.deepTremolo = (data[0x11] & 0x01) != 0; +//    setup.deepVibrato = (data[0x11] & 0x02) != 0; +//    setup.volumeModel = (int)data[0x12]; +//    setup.scaleModulators  = false; + +    size_t bankDb = db.initBank(bank, bankTitle, static_cast<uint_fast16_t>((static_cast<unsigned>(data[0x11]) << 8) | static_cast<unsigned>(data[0x12])));      // Validate file format by size calculation      if(version == 1) @@ -91,28 +94,51 @@ static bool LoadWopl(const char *fn, unsigned bank, const char *prefix)      uint32_t melodic_offset = 0;      uint32_t percussion_offset = 0; +    uint32_t melodic_meta_offset = 0; +    uint32_t percussion_meta_offset = 0; +      if(version < 2) +    {          melodic_offset = 0x13; +        melodic_meta_offset = 0; +    }      else +    {          melodic_offset = 0x13 + 34 * mbanks_count + 34 * pbanks_count; +        melodic_meta_offset = 0x13; +        percussion_meta_offset = 0x13 + 34 * mbanks_count; +    }      percussion_offset = melodic_offset + (insSize * 128 * mbanks_count); -    uint32_t root_offsets[2] = {melodic_offset, percussion_offset}; +    uint32_t root_sizes[2]  =   {mbanks_count, pbanks_count}; +    uint32_t root_offsets[2] =  {melodic_offset, percussion_offset}; +    uint32_t root_meta_offsets[2] =  {melodic_meta_offset, percussion_meta_offset};      for(size_t bset = 0; bset < 2; bset++)      {          bool is_percussion = (bset == 1); -        for(uint32_t bankno = 0; bankno < 1; bankno++) // only first melodic bank (Until multi-banks support will be implemented) +        for(uint32_t bankno = 0; bankno < root_sizes[bset]; bankno++) // only first melodic bank (Until multi-banks support will be implemented)          {              uint32_t bank_offset = root_offsets[bset] + (bankno * insSize * 128); +            BanksDump::MidiBank bnk; +            if(version >= 2) +            { +                uint32_t meta_offset = root_meta_offsets[bset] + (bankno * 34); +                bnk.lsb = data[meta_offset + 32 + 0]; +                bnk.msb = data[meta_offset + 32 + 1]; +            } +              for(uint32_t i = 0; i < 128; i++)              {                  uint32_t offset = bank_offset + uint32_t(i * insSize);                  std::string name;                  insdata tmp[2]; +                BanksDump::InstrumentEntry inst; +                BanksDump::Operator ops[5]; +                  name.resize(32);                  std::memcpy(&name[0], data.data() + offset, 32);                  name.resize(std::strlen(&name[0])); @@ -160,6 +186,9 @@ static bool LoadWopl(const char *fn, unsigned bank, const char *prefix)                   * Those fields are made for hot-loading while runtime, but not                   * for generation of embedded banks database.                   */ +                db.toOps(tmp[0], ops, 0); +                db.toOps(tmp[1], ops, 2); +                  tmp[0].finetune = int8_t(toSint16BE((const uint8_t *)data.data() + offset + 32));                  tmp[1].finetune = int8_t(toSint16BE((const uint8_t *)data.data() + offset + 34)); @@ -175,6 +204,21 @@ static bool LoadWopl(const char *fn, unsigned bank, const char *prefix)                  tmp2.rhythmModeDrum = (flags & (uint8_t)WOPL_Flags::WOPL_RhythmModeMask);                  tmp[0].diff = false;                  tmp[1].diff = real4op && !tmp2.pseudo4op; +                //---------------- +                inst.instFlags = flags; +                inst.percussionKeyNumber = is_percussion ? data[offset + 38] : 0; +                inst.noteOffset1 = int8_t(toSint16BE((const uint8_t *)data.data() + offset + 32)); +                inst.noteOffset2 = int8_t(toSint16BE((const uint8_t *)data.data() + offset + 34)); +                inst.secondVoiceDetune = static_cast<int_fast8_t>(data[offset + 37]); +                inst.midiVelocityOffset = static_cast<int_fast8_t>(data[offset + 36]); +                inst.fbConn = (static_cast<uint_fast16_t>(data[offset + 40])) | +                              (static_cast<uint_fast16_t>(data[offset + 41]) << 8); +                if(version >= 2) +                { +                    inst.delay_on_ms = toUint16BE((const uint8_t *)data.data() + offset + 62); +                    inst.delay_off_ms = toUint16BE((const uint8_t *)data.data() + offset + 64); +                } +                //----------------                  int8_t fine_tune = (int8_t)data[offset + 37];                  if(fine_tune != 0) @@ -210,21 +254,26 @@ static bool LoadWopl(const char *fn, unsigned bank, const char *prefix)                  else                      snprintf(name2, 512, "%sM%u", prefix, i); -                if(!real4op && !tmp2.pseudo4op) -                { -                    size_t resno = InsertIns(tmp[0], tmp2, name, name2); -                    SetBank(bank, gmno, resno); -                } -                else -                { -                    size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2); -                    SetBank(bank, gmno, resno); -                } +//                if(bankno == 0) +//                { +//                    if(!real4op && !tmp2.pseudo4op) +//                    { +//                        size_t resno = InsertIns(tmp[0], tmp2, name, name2); +//                        SetBank(bank, gmno, resno); +//                    } +//                    else +//                    { +//                        size_t resno = InsertIns(tmp[0], tmp[1], tmp2, name, name2); +//                        SetBank(bank, gmno, resno); +//                    } +//                } +                db.addInstrument(bnk, i, inst, ops, fn);              } +            db.addMidiBank(bankDb, is_percussion, bnk);          }      } -    SetBankSetup(bank, setup); +//    SetBankSetup(bank, setup);      return true;  } diff --git a/utils/gen_adldata/gen_adldata.cc b/utils/gen_adldata/gen_adldata.cc index 7cb4528..e62ddf2 100644 --- a/utils/gen_adldata/gen_adldata.cc +++ b/utils/gen_adldata/gen_adldata.cc @@ -15,17 +15,6 @@  #include "midi_inst_list.h" -#include "file_formats/load_ail.h" -#include "file_formats/load_bisqwit.h" -#include "file_formats/load_bnk2.h" -#include "file_formats/load_bnk.h" -#include "file_formats/load_ibk.h" -#include "file_formats/load_jv.h" -#include "file_formats/load_op2.h" -#include "file_formats/load_tmb.h" -#include "file_formats/load_wopl.h" -#include "file_formats/load_ea.h" -  int main(int argc, char**argv)  {      if(argc == 1) @@ -39,13 +28,18 @@ int main(int argc, char**argv)      const char *outFile_s = argv[1]; +#if 0      FILE *outFile = std::fopen(outFile_s, "w");      if(!outFile)      {          std::fprintf(stderr, "Can't open %s file for write!\n", outFile_s);          return 1;      } +#endif + +    BanksDump db; +#if 0      std::fprintf(outFile, "\  #include \"adldata.hh\"\n\  \n\ @@ -54,6 +48,9 @@ int main(int argc, char**argv)   * PREPROCESSED, CONVERTED, AND POSTPROCESSED OFF-SCREEN.\n\   */\n\  "); +#endif + +      {          IniProcessing ini;          if(!ini.open("banks.ini")) @@ -106,13 +103,13 @@ int main(int argc, char**argv)                  return 1;              } -            banknames.push_back(bank_name); +//            banknames.push_back(bank_name);              //printf("Loading %s...\n", filepath.c_str());              if(format == "AIL")              { -                if(!LoadMiles(filepath.c_str(), bank, prefix.c_str())) +                if(!BankFormats::LoadMiles(db, filepath.c_str(), bank, bank_name, prefix.c_str()))                  {                      std::fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());                      return 1; @@ -121,7 +118,7 @@ int main(int argc, char**argv)              else              if(format == "Bisqwit")              { -                if(!LoadBisqwit(filepath.c_str(), bank, prefix.c_str())) +                if(!BankFormats::LoadBisqwit(db, filepath.c_str(), bank, bank_name, prefix.c_str()))                  {                      std::fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());                      return 1; @@ -130,7 +127,7 @@ int main(int argc, char**argv)              else              if(format == "WOPL")              { -                if(!LoadWopl(filepath.c_str(), bank, prefix.c_str())) +                if(!BankFormats::LoadWopl(db, filepath.c_str(), bank, bank_name, prefix.c_str()))                  {                      std::fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());                      return 1; @@ -139,7 +136,7 @@ int main(int argc, char**argv)              else              if(format == "OP2")              { -                if(!LoadDoom(filepath.c_str(), bank, prefix.c_str())) +                if(!BankFormats::LoadDoom(db, filepath.c_str(), bank, bank_name, prefix.c_str()))                  {                      std::fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());                      return 1; @@ -148,7 +145,7 @@ int main(int argc, char**argv)              else              if(format == "EA")              { -                if(!LoadEA(filepath.c_str(), bank, prefix.c_str())) +                if(!BankFormats::LoadEA(db, filepath.c_str(), bank, bank_name, prefix.c_str()))                  {                      std::fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());                      return 1; @@ -157,7 +154,7 @@ int main(int argc, char**argv)              else              if(format == "TMB")              { -                if(!LoadTMB(filepath.c_str(), bank, prefix.c_str())) +                if(!BankFormats::LoadTMB(db, filepath.c_str(), bank, bank_name, prefix.c_str()))                  {                      std::fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());                      return 1; @@ -166,7 +163,7 @@ int main(int argc, char**argv)              else              if(format == "Junglevision")              { -                if(!LoadJunglevision(filepath.c_str(), bank, prefix.c_str())) +                if(!BankFormats::LoadJunglevision(db, filepath.c_str(), bank, bank_name, prefix.c_str()))                  {                      std::fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());                      return 1; @@ -175,7 +172,7 @@ int main(int argc, char**argv)              else              if(format == "AdLibGold")              { -                if(!LoadBNK2(filepath.c_str(), bank, prefix.c_str(), filter_m, filter_p)) +                if(!BankFormats::LoadBNK2(db, filepath.c_str(), bank, bank_name, prefix.c_str(), filter_m, filter_p))                  {                      std::fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());                      return 1; @@ -184,14 +181,14 @@ int main(int argc, char**argv)              else              if(format == "HMI")              { -                if(!LoadBNK(filepath.c_str(),  bank, prefix.c_str(),   false, false)) +                if(!BankFormats::LoadBNK(db, filepath.c_str(),  bank, bank_name, prefix.c_str(),   false, false))                  {                      std::fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());                      return 1;                  }                  if(!filepath_d.empty())                  { -                    if(!LoadBNK(filepath_d.c_str(),bank, prefix_d.c_str(), false, true)) +                    if(!BankFormats::LoadBNK(db, filepath_d.c_str(), bank, bank_name, prefix_d.c_str(), false, true))                      {                          std::fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());                          return 1; @@ -201,7 +198,7 @@ int main(int argc, char**argv)              else              if(format == "IBK")              { -                if(!LoadIBK(filepath.c_str(),  bank, prefix.c_str(),   false)) +                if(!BankFormats::LoadIBK(db, filepath.c_str(),  bank, bank_name, prefix.c_str(),   false))                  {                      std::fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());                      return 1; @@ -209,7 +206,7 @@ int main(int argc, char**argv)                  if(!filepath_d.empty())                  {                      //printf("Loading %s... \n", filepath_d.c_str()); -                    if(!LoadIBK(filepath_d.c_str(),bank, prefix_d.c_str(), true, noRhythmMode)) +                    if(!BankFormats::LoadIBK(db, filepath_d.c_str(),bank, bank_name, prefix_d.c_str(), true, noRhythmMode))                      {                          std::fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());                          return 1; @@ -260,117 +257,34 @@ int main(int argc, char**argv)      }      #endif -    std::printf("Writing raw instrument data...\n"); -    std::fflush(stdout); -    { -        std::fprintf(outFile, -                /* -                "static const struct\n" -                "{\n" -                "    unsigned modulator_E862, carrier_E862;  // See below\n" -                "    unsigned char modulator_40, carrier_40; // KSL/attenuation settings\n" -                "    unsigned char feedconn; // Feedback/connection bits for the channel\n" -                "    signed char finetune;   // Finetune\n" -                "} adl[] =\n"*/ -                "const adldata adl[%u] =\n" -                "{ //    ,---------+-------- Wave select settings\n" -                "  //    | ,-------ч-+------ Sustain/release rates\n" -                "  //    | | ,-----ч-ч-+---- Attack/decay rates\n" -                "  //    | | | ,---ч-ч-ч-+-- AM/VIB/EG/KSR/Multiple bits\n" -                "  //    | | | |   | | | |\n" -                "  //    | | | |   | | | |     ,----+-- KSL/attenuation settings\n" -                "  //    | | | |   | | | |     |    |    ,----- Feedback/connection bits\n" -                "  //    | | | |   | | | |     |    |    |    ,----- Fine tune\n\n" -                "  //    | | | |   | | | |     |    |    |    |\n" -                "  //    | | | |   | | | |     |    |    |    |\n", (unsigned)insdatatab.size()); - -        for(size_t b = insdatatab.size(), c = 0; c < b; ++c) -        { -            for(std::map<insdata, std::pair<size_t, std::set<std::string> > > -                ::const_iterator -                i = insdatatab.begin(); -                i != insdatatab.end(); -                ++i) -            { -                if(i->second.first != c) continue; -                std::fprintf(outFile, "    { "); - -                uint32_t carrier_E862 = -                    uint32_t(i->first.data[6] << 24) -                    + uint32_t(i->first.data[4] << 16) -                    + uint32_t(i->first.data[2] << 8) -                    + uint32_t(i->first.data[0] << 0); -                uint32_t modulator_E862 = -                    uint32_t(i->first.data[7] << 24) -                    + uint32_t(i->first.data[5] << 16) -                    + uint32_t(i->first.data[3] << 8) -                    + uint32_t(i->first.data[1] << 0); - -                std::fprintf(outFile, "0x%07X,0x%07X, 0x%02X,0x%02X, 0x%X, %+d", -                        carrier_E862, -                        modulator_E862, -                        i->first.data[8], -                        i->first.data[9], -                        i->first.data[10], -                        i->first.finetune); - -#ifdef ADLDATA_WITH_COMMENTS -                std::string names; -                for(std::set<std::string>::const_iterator -                    j = i->second.second.begin(); -                    j != i->second.second.end(); -                    ++j) -                { -                    if(!names.empty()) names += "; "; -                    if((*j)[0] == '\377') -                        names += j->substr(1); -                    else -                        names += *j; -                } -                std::fprintf(outFile, " }, // %u: %s\n", (unsigned)c, names.c_str()); -#else -                std::fprintf(outFile, " },\n"); -#endif -            } -        } -        std::fprintf(outFile, "};\n"); -    } - -    /*std::fprintf(outFile, "static const struct\n" -           "{\n" -           "    unsigned short adlno1, adlno2;\n" -           "    unsigned char tone;\n" -           "    unsigned char flags;\n" -           "    long ms_sound_kon;  // Number of milliseconds it produces sound;\n" -           "    long ms_sound_koff;\n" -           "    double voice2_fine_tune;\n" -           "} adlins[] =\n");*/ - -    std::fprintf(outFile, "const struct adlinsdata adlins[%u] =\n", (unsigned)instab.size()); -    std::fprintf(outFile, "{\n"); +//    std::printf("Writing raw instrument data...\n"); +//    std::fflush(stdout);      MeasureThreaded measureCounter; -    { -        std::printf("Beginning to generate measures data... (hardware concurrency of %d)\n", std::thread::hardware_concurrency()); -        std::fflush(stdout); -        measureCounter.LoadCache("fm_banks/adldata-cache.dat"); -        measureCounter.m_total = instab.size(); -        for(size_t b = instab.size(), c = 0; c < b; ++c) -        { -            for(std::map<ins, std::pair<size_t, std::set<std::string> > >::const_iterator i =  instab.begin(); i != instab.end(); ++i) -            { -                if(i->second.first != c) continue; -                measureCounter.run(i); -            } -        } -        std::fflush(stdout); -        measureCounter.waitAll(); -        measureCounter.SaveCache("fm_banks/adldata-cache.dat"); -    } +//#ifndef GEN_ADLDATA_DEEP_DEBUG // Skip slowest place to work with a debug +//    { +//        std::printf("Beginning to generate measures data... (hardware concurrency of %d)\n", std::thread::hardware_concurrency()); +//        std::fflush(stdout); +//        measureCounter.LoadCache("fm_banks/adldata-cache.dat"); +//        measureCounter.m_total = instab.size(); +//        for(size_t b = instab.size(), c = 0; c < b; ++c) +//        { +//            for(std::map<ins, std::pair<size_t, std::set<std::string> > >::const_iterator i =  instab.begin(); i != instab.end(); ++i) +//            { +//                if(i->second.first != c) continue; +//                measureCounter.run(i); +//            } +//        } +//        std::fflush(stdout); +//        measureCounter.waitAll(); +//        measureCounter.SaveCache("fm_banks/adldata-cache.dat"); +//    } +//#endif -    std::printf("Writing generated measure data...\n"); -    std::fflush(stdout); +//    std::printf("Writing generated measure data...\n"); +//    std::fflush(stdout); +#if 0      std::vector<unsigned> adlins_flags;      for(size_t b = instab.size(), c = 0; c < b; ++c) @@ -476,6 +390,7 @@ int main(int argc, char**argv)      }      std::set<size_t> listed; +      std::fprintf(outFile,              "\n\n//Returns total number of generated banks\n"              "int  maxAdlBanks()\n" @@ -538,6 +453,10 @@ int main(int argc, char**argv)  #endif      } +#endif + + +#if 0      std::fprintf(outFile, "};\n\n");      std::fflush(outFile); @@ -564,6 +483,27 @@ int main(int argc, char**argv)      std::fflush(outFile);      std::fclose(outFile); +#endif + +    { +        measureCounter.LoadCacheX("fm_banks/adldata-cache.dat"); +        measureCounter.m_durationInfo.clear(); +        measureCounter.m_cache_matches = 0; +        measureCounter.m_done = 0; +        measureCounter.m_total = db.instruments.size(); +        std::printf("Beginning to generate measures data... (hardware concurrency of %d)\n", std::thread::hardware_concurrency()); +        std::fflush(stdout); +        for(size_t b = 0; b < db.instruments.size(); ++b) +        { +            assert(db.instruments[b].instId == b); +            measureCounter.run(db, db.instruments[b]); +        } +        std::fflush(stdout); +        measureCounter.waitAll(); +        measureCounter.SaveCacheX("fm_banks/adldata-cache.dat"); +    } + +    db.exportBanks(std::string(outFile_s));      std::printf("Generation of ADLMIDI data has been completed!\n");      std::fflush(stdout); diff --git a/utils/gen_adldata/measurer.cpp b/utils/gen_adldata/measurer.cpp index 4f28671..b9738be 100644 --- a/utils/gen_adldata/measurer.cpp +++ b/utils/gen_adldata/measurer.cpp @@ -1,6 +1,11 @@  #include "measurer.h" +#include "file_formats/common.h"  #include <cmath> +#ifdef GEN_ADLDATA_DEEP_DEBUG +#include "../midiplay/wave_writer.h" +#endif +  #ifndef M_PI  #define M_PI    3.14159265358979323846  #endif @@ -16,6 +21,56 @@  #    include "../../src/chips/dosbox_opl3.h"  #endif +#define NUM_OF_CHANNELS                 23 +#define NUM_OF_RM_CHANNELS              5 + +//! Per-channel and per-operator registers map +static const uint16_t g_operatorsMap[(NUM_OF_CHANNELS + NUM_OF_RM_CHANNELS) * 2] = +{ +    // Channels 0-2 +    0x000, 0x003, 0x001, 0x004, 0x002, 0x005, // operators  0, 3,  1, 4,  2, 5 +    // Channels 3-5 +    0x008, 0x00B, 0x009, 0x00C, 0x00A, 0x00D, // operators  6, 9,  7,10,  8,11 +    // Channels 6-8 +    0x010, 0x013, 0x011, 0x014, 0x012, 0x015, // operators 12,15, 13,16, 14,17 +    // Same for second card +    0x100, 0x103, 0x101, 0x104, 0x102, 0x105, // operators 18,21, 19,22, 20,23 +    0x108, 0x10B, 0x109, 0x10C, 0x10A, 0x10D, // operators 24,27, 25,28, 26,29 +    0x110, 0x113, 0x111, 0x114, 0x112, 0x115, // operators 30,33, 31,34, 32,35 + +    //==For Rhythm-mode percussions +    // Channel 18 +    0x010, 0x013,  // operators 12,15 +    // Channel 19 +    0xFFF, 0x014,  // operator 16 +    // Channel 19 +    0x012, 0xFFF,  // operator 14 +    // Channel 19 +    0xFFF, 0x015,  // operator 17 +    // Channel 19 +    0x011, 0xFFF,  // operator 13 + +    //==For Rhythm-mode percussions in CMF, snare and cymbal operators has inverted! +    0x010, 0x013,  // operators 12,15 +    // Channel 19 +    0x014, 0xFFF,  // operator 16 +    // Channel 19 +    0x012, 0xFFF,  // operator 14 +    // Channel 19 +    0x015, 0xFFF,  // operator 17 +    // Channel 19 +    0x011, 0xFFF   // operator 13 +}; + +//! Channel map to regoster offsets +static const uint16_t g_channelsMap[NUM_OF_CHANNELS] = +{ +    0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, // 0..8 +    0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, // 9..17 (secondary set) +    0x006, 0x007, 0x008, 0x008, 0x008 // <- hw percussions, hihats and cymbals using tom-tom's channel as pitch source +}; + +  template <class T>  class AudioHistory  { @@ -87,94 +142,170 @@ struct TinySynth  {      OPLChipBase *m_chip;      unsigned m_notesNum; -    int m_notenum; -    int8_t m_fineTune; +    unsigned m_actualNotesNum; +    bool m_isReal4op; +    bool m_isPseudo4op; +    bool m_isRhythmMode; +    int m_playNoteNum; +    int8_t m_voice1Detune;      int16_t m_noteOffsets[2];      unsigned m_x[2]; +    bool m_isSilentGuess; + +    void writeReg(uint16_t addr, uint8_t data) +    { +        m_chip->writeReg(addr, data); +    } +      void resetChip()      { -        static const short initdata[(2 + 3 + 2 + 2) * 2] = +        static const short initdata[] =          { -            0x004, 96, 0x004, 128,      // Pulse timer -            0x105, 0, 0x105, 1, 0x105, 0, // Pulse OPL3 enable, leave disabled -            0x001, 32, 0x0BD, 0         // Enable wave & melodic +            0x004, 96, 0x004, 128,        // Pulse timer +            0x105, 0, 0x105, 1, 0x105, 0, // Pulse OPL3 enable +            0x001, 32, 0x105, 1           // Enable wave, OPL3 extensions          };          m_chip->setRate(g_outputRate); -        for(unsigned a = 0; a < 18; a += 2) -            m_chip->writeReg((uint16_t)initdata[a], (uint8_t)initdata[a + 1]); +        for(size_t a = 0; a < 18; ++a) +            writeReg(0xB0 + g_channelsMap[a], 0x00); +        for(unsigned a = 0; a < 14; a += 2) +            writeReg((uint16_t)initdata[a], (uint8_t)initdata[a + 1]);      } -    void setInstrument(const ins &in) +//    void setInstrument(const ins &in) +//    { +//        insdata rawData[2]; +//        bool found[2] = {false, false}; +//        for(InstrumentDataTab::const_iterator j = insdatatab.begin(); +//            j != insdatatab.end(); +//            ++j) +//        { +//            if(j->second.first == in.insno1) +//            { +//                rawData[0] = j->first; +//                found[0] = true; +//                if(found[1]) break; +//            } +//            if(j->second.first == in.insno2) +//            { +//                rawData[1] = j->first; +//                found[1] = true; +//                if(found[0]) break; +//            } +//        } + +//        std::memset(m_x, 0, sizeof(m_x)); +//        m_isRhythmMode = false; +//        m_playNoteNum = in.notenum >= 128 ? (in.notenum - 128) : in.notenum; +//        m_isReal4op = in.real4op && !in.pseudo4op; +//        m_isPseudo4op = in.pseudo4op; +//        if(m_playNoteNum == 0) +//            m_playNoteNum = 25; +//        m_notesNum = in.insno1 == in.insno2 ? 1 : 2; +//        m_actualNotesNum = (m_isReal4op ? 1 : m_notesNum); +//        m_voice1Detune = 0; +//        m_noteOffsets[0] = rawData[0].finetune; +//        m_noteOffsets[1] = rawData[1].finetune; +//        if(in.pseudo4op) +//            m_voice1Detune = in.voice2_fine_tune; +//        writeReg(0x104, in.real4op ? (1 << 6) - 1 : 0x00); + +//        //For cleaner measurement, disable tremolo and vibrato +//        rawData[0].data[0] &= 0x3F; +//        rawData[0].data[1] &= 0x3F; +//        rawData[1].data[0] &= 0x3F; +//        rawData[1].data[1] &= 0x3F; + +//        for(unsigned n = 0; n < m_notesNum; ++n) +//        { +//            static const unsigned char patchdata[11] = +//            {0x20, 0x23, 0x60, 0x63, 0x80, 0x83, 0xE0, 0xE3, 0x40, 0x43, 0xC0}; +//            for(unsigned a = 0; a < 10; ++a) +//                writeReg(patchdata[a] + n * 8, rawData[n].data[a]); +//            writeReg(patchdata[10] + n * 8, rawData[n].data[10] | 0x30); +//        } +//    } + +    void setInstrument(const BanksDump &db, const BanksDump::InstrumentEntry &ins)      { -        insdata rawData[2]; -        bool found[2] = {false, false}; -        for(InstrumentDataTab::const_iterator j = insdatatab.begin(); -            j != insdatatab.end(); -            ++j) +        bool isPseudo4ops = ((ins.instFlags & BanksDump::InstrumentEntry::WOPL_Ins_Pseudo4op) != 0); +        bool is4ops =       ((ins.instFlags & BanksDump::InstrumentEntry::WOPL_Ins_4op) != 0) && !isPseudo4ops; +        m_isRhythmMode = ((ins.instFlags & BanksDump::InstrumentEntry::WOPL_RhythmModeMask) != 0); +        size_t opsNum = (is4ops || isPseudo4ops) ? 4 : 2; +        BanksDump::Operator ops[4]; +        assert(ins.ops[0] >= 0); +        assert(ins.ops[1] >= 0); +        ops[0] = db.operators[ins.ops[0]]; +        ops[1] = db.operators[ins.ops[1]]; +        if(opsNum > 2)          { -            if(j->second.first == in.insno1) -            { -                rawData[0] = j->first; -                found[0] = true; -                if(found[1]) break; -            } -            if(j->second.first == in.insno2) -            { -                rawData[1] = j->first; -                found[1] = true; -                if(found[0]) break; -            } +            assert(ins.ops[2] >= 0); +            assert(ins.ops[3] >= 0); +            ops[2] = db.operators[ins.ops[2]]; +            ops[3] = db.operators[ins.ops[3]];          }          std::memset(m_x, 0, sizeof(m_x)); -        m_notenum = in.notenum >= 128 ? (in.notenum - 128) : in.notenum; -        if(m_notenum == 0) -            m_notenum = 25; -        m_notesNum = in.insno1 == in.insno2 ? 1 : 2; -        m_fineTune = 0; -        m_noteOffsets[0] = rawData[0].finetune; -        m_noteOffsets[1] = rawData[1].finetune; -        if(in.pseudo4op) -            m_fineTune = in.voice2_fine_tune; -        if(in.real4op) -        { -            m_chip->writeReg(0x105, 1); -            m_chip->writeReg(0x104, 0xFF); -        } - -        //For clearer measurement, disable tremolo and vibrato -        rawData[0].data[0] &= 0x3F; -        rawData[0].data[1] &= 0x3F; -        rawData[1].data[0] &= 0x3F; -        rawData[1].data[1] &= 0x3F; +        m_playNoteNum = ins.percussionKeyNumber >= 128 ? (ins.percussionKeyNumber - 128) : ins.percussionKeyNumber; +        m_isReal4op = is4ops; +        m_isPseudo4op = isPseudo4ops; +        if(m_playNoteNum == 0) +            m_playNoteNum = 25;//60; +        m_notesNum = opsNum / 2; +        m_actualNotesNum = (m_isReal4op ? 1 : m_notesNum); +        m_voice1Detune = 0; +        m_noteOffsets[0] = ins.noteOffset1; +        m_noteOffsets[1] = ins.noteOffset2; +        if(isPseudo4ops) +            m_voice1Detune = ins.secondVoiceDetune; +        writeReg(0x104, m_isReal4op ? 0x3F : 0x00); + +        //For cleaner measurement, disable tremolo and vibrato +        ops[0].d_E862 &= 0xFFFFFF3F; +        ops[1].d_E862 &= 0xFFFFFF3F; +        ops[2].d_E862 &= 0xFFFFFF3F; +        ops[3].d_E862 &= 0xFFFFFF3F;          for(unsigned n = 0; n < m_notesNum; ++n)          { -            static const unsigned char patchdata[11] = -            {0x20, 0x23, 0x60, 0x63, 0x80, 0x83, 0xE0, 0xE3, 0x40, 0x43, 0xC0}; -            for(unsigned a = 0; a < 10; ++a) -                m_chip->writeReg(patchdata[a] + n * 8, rawData[n].data[a]); -            m_chip->writeReg(patchdata[10] + n * 8, rawData[n].data[10] | 0x30); +            static const uint8_t data[4] = {0x20, 0x60, 0x80, 0xE0}; +            size_t opOffset = (n * 2); +            size_t opMapOffset = m_isReal4op ? (n * 6) : opOffset; +            uint16_t op1off = g_operatorsMap[opMapOffset + 0]; +            uint16_t op2off = g_operatorsMap[opMapOffset + 1]; +            uint_fast32_t x1 = ops[opOffset + 0].d_E862, y1 = ops[opOffset + 1].d_E862; +            uint_fast8_t  x2 = ops[opOffset + 0].d_40,   y2 = ops[opOffset + 1].d_40; +            uint_fast8_t  fbConn = (ins.fbConn >> (n * 8)) & 0xFF; + +            for(size_t a = 0; a < 4; ++a, x1 >>= 8, y1 >>= 8) +            { +                writeReg(data[a] + op1off, x1 & 0xFF); +                writeReg(data[a] + op2off, y1 & 0xFF); +            } +            writeReg(0xC0 + g_channelsMap[m_isReal4op ? (n * 3) : n], fbConn | 0x30); + +            writeReg(0x40 + op1off, x2 & 0xFF); +            writeReg(0x40 + op2off, y2 & 0xFF);          }      }      void noteOn()      {          std::memset(m_x, 0, sizeof(m_x)); -        for(unsigned n = 0; n < m_notesNum; ++n) +        for(unsigned n = 0; n < m_actualNotesNum; ++n)          { -            double hertz = 172.00093 * std::exp(0.057762265 * (m_notenum + m_noteOffsets[n])); +            double hertz = 172.00093 * std::exp(0.057762265 * (m_playNoteNum + m_noteOffsets[n]));              if(hertz > 131071)              {                  std::fprintf(stdout, "%s:%d:0: warning: Why does note %d + note-offset %d produce hertz %g?\n", __FILE__, __LINE__, -                             m_notenum, m_noteOffsets[n], hertz); +                             m_playNoteNum, m_noteOffsets[n], hertz);                  std::fflush(stdout);                  hertz = 131071;              } -            m_x[n] = 0x2000; +            m_x[n] = 0x2000u;              while(hertz >= 1023.5)              {                  hertz /= 2.0;    // Calculate octave @@ -183,16 +314,16 @@ struct TinySynth              m_x[n] += (unsigned int)(hertz + 0.5);              // Keyon the note -            m_chip->writeReg(0xA0 + n * 3, m_x[n] & 0xFF); -            m_chip->writeReg(0xB0 + n * 3, m_x[n] >> 8); +            writeReg(0xA0 + g_channelsMap[n], m_x[n] & 0xFF); +            writeReg(0xB0 + g_channelsMap[n], (m_x[n] >> 8) & 0xFF);          }      }      void noteOff()      {          // Keyoff the note -        for(unsigned n = 0; n < m_notesNum; ++n) -            m_chip->writeReg(0xB0 + n * 3, (m_x[n] >> 8) & 0xDF); +        for(unsigned n = 0; n < m_actualNotesNum; ++n) +            writeReg(0xB0 + g_channelsMap[n], (m_x[n] >> 8) & 0xDF);      }      void generate(int16_t *output, size_t frames) @@ -201,7 +332,7 @@ struct TinySynth      }  }; - +#if 0  DurationInfo MeasureDurations(const ins &in, OPLChipBase *chip)  {      AudioHistory<double> audioHistory; @@ -391,9 +522,280 @@ DurationInfo MeasureDurations(const ins &in, OPLChipBase *chip)      return result;  } +#endif + +DurationInfo MeasureDurations(BanksDump &db, const BanksDump::InstrumentEntry &ins, OPLChipBase *chip) +{ +    AudioHistory<double> audioHistory; + +    const unsigned interval             = 150; +    const unsigned samples_per_interval = g_outputRate / interval; + +    const double historyLength = 0.1;  // maximum duration to memorize (seconds) +    audioHistory.reset(std::ceil(historyLength * g_outputRate)); + +    std::unique_ptr<double[]> window; +    window.reset(new double[audioHistory.capacity()]); +    unsigned winsize = 0; +    TinySynth synth; +    synth.m_chip = chip; +    synth.resetChip(); +    synth.setInstrument(db, ins); +    synth.noteOn(); + +    if(synth.m_isRhythmMode) // Skip rhythm-mode check +    { +        DurationInfo result; +        std::memset(&result, 0, sizeof(DurationInfo)); +        result.ms_sound_kon = 1000; +        result.ms_sound_koff = 10; +        result.nosound = false; +        db.instruments[ins.instId].delay_on_ms = result.ms_sound_kon; +        db.instruments[ins.instId].delay_off_ms = result.ms_sound_koff; +        return result; +    } + +#ifdef GEN_ADLDATA_DEEP_DEBUG +    /*****************DEBUG******************/ +    char waveFileOut[80] = ""; +    std::snprintf(waveFileOut, 80, "fm_banks/_deep_debug/%04lu_%s_%u_an_%u_no.wav", +                  ins.instId, synth.m_isPseudo4op ? "pseudo4op" : +                              synth.m_isReal4op ? "4op" : "2op", +                  synth.m_actualNotesNum, +                  synth.m_notesNum); +    void *waveCtx = ctx_wave_open(g_outputRate, waveFileOut); +    ctx_wave_enable_stereo(waveCtx); +    /*****************DEBUG******************/ +#endif + +    /* For capturing */ +    const unsigned max_silent = 6; +    const unsigned max_on  = 40; +    const unsigned max_off = 60; + +    unsigned max_period_on = max_on * interval; +    unsigned max_period_off = max_off * interval; + +    const double min_coefficient_on = 0.008; +    const double min_coefficient_off = 0.2; + +    unsigned windows_passed_on = 0; +    unsigned windows_passed_off = 0; + +    /* For Analyze the results */ +    double begin_amplitude        = 0; +    double peak_amplitude_value   = 0; +    size_t peak_amplitude_time    = 0; +    size_t quarter_amplitude_time = max_period_on; +    bool   quarter_amplitude_time_found = false; +    size_t keyoff_out_time        = 0; +    bool   keyoff_out_time_found  = false; + +    const size_t audioBufferLength = 256; +    const size_t audioBufferSize = 2 * audioBufferLength; +    int16_t audioBuffer[audioBufferSize]; + +    // For up to 40 seconds, measure mean amplitude. +    double highest_sofar = 0; +    short sound_min = 0, sound_max = 0; + +    for(unsigned period = 0; period < max_period_on; ++period, ++windows_passed_on) +    { +        for(unsigned i = 0; i < samples_per_interval;) +        { +            size_t blocksize = samples_per_interval - i; +            blocksize = (blocksize < audioBufferLength) ? blocksize : audioBufferLength; +            synth.generate(audioBuffer, blocksize); +#ifdef GEN_ADLDATA_DEEP_DEBUG +            /***************DEBUG******************/ +            ctx_wave_write(waveCtx, audioBuffer, blocksize * 2); +            /***************DEBUG******************/ +#endif +            for (unsigned j = 0; j < blocksize; ++j) +            { +                int16_t s = audioBuffer[2 * j]; +                audioHistory.add(s); +                if(sound_min > s) sound_min = s; +                if(sound_max < s) sound_max = s; +            } +            i += blocksize; +        } + +        if(winsize != audioHistory.size()) +        { +            winsize = audioHistory.size(); +            HannWindow(window.get(), winsize); +        } + +        double rms = MeasureRMS(audioHistory.data(), window.get(), winsize); +        /* ======== Peak time detection ======== */ +        if(period == 0) +        { +            begin_amplitude = rms; +            peak_amplitude_value = rms; +            peak_amplitude_time = 0; +        } +        else if(rms > peak_amplitude_value) +        { +            peak_amplitude_value = rms; +            peak_amplitude_time  = period; +            // In next step, update the quater amplitude time +            quarter_amplitude_time_found = false; +        } +        else if(!quarter_amplitude_time_found && (rms <= peak_amplitude_value * min_coefficient_on)) +        { +            quarter_amplitude_time = period; +            quarter_amplitude_time_found = true; +        } +        /* ======== Peak time detection =END==== */ +        if(rms > highest_sofar) +            highest_sofar = rms; + +        if((period > max_silent * interval) && +           ( (rms < highest_sofar * min_coefficient_on) || (sound_min >= -1 && sound_max <= 1) ) +        ) +            break; +    } + +    if(!quarter_amplitude_time_found) +        quarter_amplitude_time = windows_passed_on; + +    if(windows_passed_on >= max_period_on) +    { +        // Just Keyoff the note +        synth.noteOff(); +    } +    else +    { +        // Reset the emulator and re-run the "ON" simulation until reaching the peak time +        synth.resetChip(); +        synth.setInstrument(db, ins); +        synth.noteOn(); + +        audioHistory.reset(std::ceil(historyLength * g_outputRate)); +        for(unsigned period = 0; +            ((period < peak_amplitude_time) || (period == 0)) && (period < max_period_on); +            ++period) +        { +            for(unsigned i = 0; i < samples_per_interval;) +            { +                size_t blocksize = samples_per_interval - i; +                blocksize = (blocksize < audioBufferLength) ? blocksize : audioBufferLength; +                synth.generate(audioBuffer, blocksize); +                for (unsigned j = 0; j < blocksize; ++j) +                    audioHistory.add(audioBuffer[2 * j]); +                i += blocksize; +            } +        } +        synth.noteOff(); +    } + +    // Now, for up to 60 seconds, measure mean amplitude. +    for(unsigned period = 0; period < max_period_off; ++period, ++windows_passed_off) +    { +        for(unsigned i = 0; i < samples_per_interval;) +        { +            size_t blocksize = samples_per_interval - i; +            blocksize = (blocksize < 256) ? blocksize : 256; +            synth.generate(audioBuffer, blocksize); +            for (unsigned j = 0; j < blocksize; ++j) +            { +                int16_t s = audioBuffer[2 * j]; +                audioHistory.add(s); +                if(sound_min > s) sound_min = s; +                if(sound_max < s) sound_max = s; +            } +            i += blocksize; +        } + +        if(winsize != audioHistory.size()) +        { +            winsize = audioHistory.size(); +            HannWindow(window.get(), winsize); +        } + +        double rms = MeasureRMS(audioHistory.data(), window.get(), winsize); +        /* ======== Find Key Off time ======== */ +        if(!keyoff_out_time_found && (rms <= peak_amplitude_value * min_coefficient_off)) +        { +            keyoff_out_time = period; +            keyoff_out_time_found = true; +        } +        /* ======== Find Key Off time ==END=== */ +        if(rms < highest_sofar * min_coefficient_off) +            break; + +        if((period > max_silent * interval) && (sound_min >= -1 && sound_max <= 1)) +            break; +    } + +    DurationInfo result; +    result.peak_amplitude_time = peak_amplitude_time; +    result.peak_amplitude_value = peak_amplitude_value; +    result.begin_amplitude = begin_amplitude; +    result.quarter_amplitude_time = (double)quarter_amplitude_time; +    result.keyoff_out_time = (double)keyoff_out_time; + +    result.ms_sound_kon  = (int64_t)(quarter_amplitude_time * 1000.0 / interval); +    result.ms_sound_koff = (int64_t)(keyoff_out_time        * 1000.0 / interval); +    result.nosound = (peak_amplitude_value < 0.5) || ((sound_min >= -19) && (sound_max <= 18)); + +    db.instruments[ins.instId].delay_on_ms = result.ms_sound_kon; +    db.instruments[ins.instId].delay_off_ms = result.ms_sound_koff; +    if(result.nosound) +        db.instruments[ins.instId].instFlags |= BanksDump::InstrumentEntry::WOPL_Ins_IsBlank; + +#ifdef GEN_ADLDATA_DEEP_DEBUG +    /***************DEBUG******************/ +    ctx_wave_close(waveCtx); +    /***************DEBUG******************/ +#endif +    { +        bool silent1 = result.nosound; +        bool silent2 = BanksDump::isSilent(db, ins); +        if(silent1 != silent2) +        { +            std::fprintf(stdout, +                         "\n\n%04lu - %s  AN=%u NN=%u -- con1=%lu, con2=%lu\n%s computed - %s actual (%g peak, %d<%d)\n\n", +                         ins.instId, synth.m_isPseudo4op ? "pseudo4op" : +                                     synth.m_isReal4op ? "4op" : "2op", +                         synth.m_actualNotesNum, +                         synth.m_notesNum, +                         (ins.fbConn) & 0x01, +                         (ins.fbConn >> 8) & 0x01, +                         silent2 ? "silent" : "sound", +                         silent1 ? "silent" : "sound", +                         peak_amplitude_value, +                         sound_min, +                         sound_max); +            for(auto &sss : ins.instMetas) +                std::fprintf(stdout, "%s\n", sss.c_str()); +            BanksDump::isSilent(db, ins, true); +            std::fprintf(stdout, "\n\n"); +            std::fflush(stdout); +//            assert(silent1 == silent2); +//            exit(1); +        } +    } + +    return result; +} + + +MeasureThreaded::MeasureThreaded() : +    m_semaphore(int(std::thread::hardware_concurrency()) * 2), +    m_done(0), +    m_cache_matches(0) +{ +    DosBoxOPL3::globalPreInit(); +} + +#if 0  void MeasureThreaded::LoadCache(const char *fileName)  { +    m_durationInfo.clear(); +      FILE *in = std::fopen(fileName, "rb");      if(!in)      { @@ -448,14 +850,29 @@ void MeasureThreaded::LoadCache(const char *fileName)          if(std::fread(&inval, 1, sizeof(uint64_t), in) != sizeof(uint64_t))              break;          inst.insno2 = inval; +        if(std::fread(&inst.instCache1.data, 1, 11, in) != 11) +            break; +        if(std::fread(&inst.instCache1.finetune, 1, 1, in) != 1) +            break; +        if(std::fread(&inst.instCache1.diff, 1, sizeof(bool), in) != sizeof(bool)) +            break; +        if(std::fread(&inst.instCache2.data, 1, 11, in) != 11) +            break; +        if(std::fread(&inst.instCache2.finetune, 1, 1, in) != 1) +            break; +        if(std::fread(&inst.instCache2.diff, 1, sizeof(bool), in) != sizeof(bool)) +            break; +          if(std::fread(&inst.notenum, 1, 1, in) != 1)              break;          if(std::fread(&inst.real4op, 1, 1, in) != 1)              break;          if(std::fread(&inst.pseudo4op, 1, 1, in) != 1)              break; -        if(std::fread(&inst.voice2_fine_tune, sizeof(double), 1, in) != 1) +        int64_t voice2detune = 0; +        if(std::fread(&voice2detune, sizeof(int64_t), 1, in) != 1)              break; +        inst.voice2_fine_tune = static_cast<double>(voice2detune) / 1000000.0;          //Instrument data          if(fread(found_f, 1, 2 * sizeof(bool), in) != sizeof(bool) * 2) @@ -534,18 +951,6 @@ void MeasureThreaded::LoadCache(const char *fileName)          }          //Duration data -        if(std::fread(&info.peak_amplitude_time, 1, sizeof(uint64_t), in) != sizeof(uint64_t)) -            break; -        if(std::fread(&info.peak_amplitude_value, 1, sizeof(double), in) != sizeof(double)) -            break; -        if(std::fread(&info.quarter_amplitude_time, 1, sizeof(double), in) != sizeof(double)) -            break; -        if(std::fread(&info.begin_amplitude, 1, sizeof(double), in) != sizeof(double)) -            break; -        if(std::fread(&info.interval, 1, sizeof(double), in) != sizeof(double)) -            break; -        if(std::fread(&info.keyoff_out_time, 1, sizeof(double), in) != sizeof(double)) -            break;          if(std::fread(&info.ms_sound_kon, 1, sizeof(int64_t), in) != sizeof(int64_t))              break;          if(std::fread(&info.ms_sound_koff, 1, sizeof(int64_t), in) != sizeof(int64_t)) @@ -579,10 +984,17 @@ void MeasureThreaded::SaveCache(const char *fileName)          fwrite(&outval, 1, sizeof(uint64_t), out);          outval = in.insno2;          fwrite(&outval, 1, sizeof(uint64_t), out); +        fwrite(&in.instCache1.data, 1, 11, out); +        fwrite(&in.instCache1.finetune, 1, 1, out); +        fwrite(&in.instCache1.diff, 1, sizeof(bool), out); +        fwrite(&in.instCache2.data, 1, 11, out); +        fwrite(&in.instCache2.finetune, 1, 1, out); +        fwrite(&in.instCache2.diff, 1, sizeof(bool), out);          fwrite(&in.notenum, 1, 1, out);          fwrite(&in.real4op, 1, 1, out);          fwrite(&in.pseudo4op, 1, 1, out); -        fwrite(&in.voice2_fine_tune, sizeof(double), 1, out); +        int64_t voice2detune = static_cast<int64_t>(in.voice2_fine_tune * 1000000.0); +        fwrite(&voice2detune, sizeof(int64_t), 1, out);          for(InstrumentDataTab::const_iterator j = insdatatab.begin(); j != insdatatab.end(); ++j)          { @@ -608,18 +1020,149 @@ void MeasureThreaded::SaveCache(const char *fileName)              fwrite(&id[i].diff, 1, sizeof(bool), out);          } -        fwrite(&it->second.peak_amplitude_time, 1, sizeof(uint64_t), out); -        fwrite(&it->second.peak_amplitude_value, 1, sizeof(double), out); -        fwrite(&it->second.quarter_amplitude_time, 1, sizeof(double), out); -        fwrite(&it->second.begin_amplitude, 1, sizeof(double), out); -        fwrite(&it->second.interval, 1, sizeof(double), out); -        fwrite(&it->second.keyoff_out_time, 1, sizeof(double), out);          fwrite(&it->second.ms_sound_kon, 1, sizeof(int64_t), out);          fwrite(&it->second.ms_sound_koff, 1, sizeof(int64_t), out);          fwrite(&it->second.nosound, 1, sizeof(bool), out);      }      std::fclose(out);  } +#endif + +void MeasureThreaded::LoadCacheX(const char *fileName) +{ +    m_durationInfoX.clear(); + +    FILE *in = std::fopen(fileName, "rb"); +    if(!in) +    { +        std::printf("Failed to load CacheX: file is not exists.\n" +               "Complete data will be generated from scratch.\n"); +        std::fflush(stdout); +        return; +    } + +    char magic[32]; +    if(std::fread(magic, 1, 32, in) != 32) +    { +        std::fclose(in); +        std::printf("Failed to load CacheX: can't read magic.\n" +               "Complete data will be generated from scratch.\n"); +        std::fflush(stdout); +        return; +    } + +    if(std::memcmp(magic, "ADLMIDI-DURATION-CACHE-FILE-V2.0", 32) != 0) +    { +        std::fclose(in); +        std::printf("Failed to load CacheX: magic missmatch.\n" +               "Complete data will be generated from scratch.\n"); +        std::fflush(stdout); +        return; +    } + +    uint_fast32_t itemsCount; +    uint8_t itemsCountA[4]; +    if(std::fread(itemsCountA, 1, 4, in) != 4) +    { +        std::fclose(in); +        std::printf("Failed to load CacheX: can't read cache size value.\n" +               "Complete data will be generated from scratch.\n"); +        std::fflush(stdout); +        return; +    } + +    itemsCount = static_cast<uint_fast32_t>(toUint32LE(itemsCountA)); + +    while(!std::feof(in) && itemsCount > 0) +    { +        OperatorsKey k; +        DurationInfo v; + +        uint8_t data_k[5]; + +        for(auto &kv : k) +        { +            uint8_t data[4]; +            auto ret = std::fread(data, 1, 4, in); +            if(ret != 4) +            { +                std::fclose(in); +                std::printf("Failed to load CacheX: unexpected end of file.\n" +                       "Complete data will be generated from scratch.\n"); +                std::fflush(stdout); +                return; +            } +            kv = static_cast<int_fast32_t>(toSint32LE(data)); +        } + +        auto ret = std::fread(data_k, 1, 5, in); +        if(ret != 5) +        { +            std::fclose(in); +            std::printf("Failed to load CacheX: unexpected end of file.\n" +                   "Complete data will be generated from scratch.\n"); +            std::fflush(stdout); +            return; +        } + +        v.ms_sound_kon  = static_cast<int_fast64_t>(toUint16LE(data_k + 0)); +        v.ms_sound_koff = static_cast<int_fast64_t>(toUint16LE(data_k + 2)); +        v.nosound = (data_k[4] == 0x01); + +        m_durationInfoX.insert({k, v}); +        itemsCount--; +    } + +    std::printf("CacheX loaded!\n"); +    std::fflush(stdout); + +    std::fclose(in); +} + +void MeasureThreaded::SaveCacheX(const char *fileName) +{ +    FILE *out = std::fopen(fileName, "wb"); +    std::fprintf(out, "ADLMIDI-DURATION-CACHE-FILE-V2.0"); + +    uint_fast32_t itemsCount = static_cast<uint_fast32_t>(m_durationInfoX.size()); +    uint8_t itemsCountA[4] = +    { +        static_cast<uint8_t>((itemsCount >>  0) & 0xFF), +        static_cast<uint8_t>((itemsCount >>  8) & 0xFF), +        static_cast<uint8_t>((itemsCount >> 16) & 0xFF), +        static_cast<uint8_t>((itemsCount >> 24) & 0xFF) +    }; +    std::fwrite(itemsCountA, 1, 4, out); + +    for(DurationInfoCacheX::iterator it = m_durationInfoX.begin(); it != m_durationInfoX.end(); it++) +    { +        const OperatorsKey &k = it->first; +        const DurationInfo &v = it->second; + +        uint8_t data_k[5] = +        { +            static_cast<uint8_t>((v.ms_sound_kon >>  0) & 0xFF), +            static_cast<uint8_t>((v.ms_sound_kon >>  8) & 0xFF), +            static_cast<uint8_t>((v.ms_sound_koff >> 0) & 0xFF), +            static_cast<uint8_t>((v.ms_sound_koff >> 8) & 0xFF), +            static_cast<uint8_t>(v.nosound ? 0x01 : 0x00) +        }; + +        for(auto &kv : k) +        { +            uint8_t data[4] = +            { +                static_cast<uint8_t>((kv >>  0) & 0xFF), +                static_cast<uint8_t>((kv >>  8) & 0xFF), +                static_cast<uint8_t>((kv >> 16) & 0xFF), +                static_cast<uint8_t>((kv >> 24) & 0xFF) +            }; +            std::fwrite(data, 1, 4, out); +        } +        std::fwrite(data_k, 1, 5, out); +    } +    std::fclose(out); +}  #ifdef ADL_GENDATA_PRINT_PROGRESS @@ -652,6 +1195,7 @@ void MeasureThreaded::printFinal()      std::fflush(stdout);  } +#if 0  void MeasureThreaded::run(InstrumentsData::const_iterator i)  {      m_semaphore.wait(); @@ -671,6 +1215,37 @@ void MeasureThreaded::run(InstrumentsData::const_iterator i)      destData *dd = new destData;      dd->i = i; +    dd->bd = nullptr; +    dd->bd_ins = nullptr; +    dd->myself = this; +    dd->start(); +    m_threads.push_back(dd); +#ifdef ADL_GENDATA_PRINT_PROGRESS +    printProgress(); +#endif +} +#endif + +void MeasureThreaded::run(BanksDump &bd, BanksDump::InstrumentEntry &e) +{ +    m_semaphore.wait(); +    if(m_threads.size() > 0) +    { +        for(std::vector<destData *>::iterator it = m_threads.begin(); it != m_threads.end();) +        { +            if(!(*it)->m_works) +            { +                delete(*it); +                it = m_threads.erase(it); +            } +            else +                it++; +        } +    } + +    destData *dd = new destData; +    dd->bd = &bd; +    dd->bd_ins = &e;      dd->myself = this;      dd->start();      m_threads.push_back(dd); @@ -702,18 +1277,57 @@ void MeasureThreaded::destData::callback(void *myself)      destData *s = reinterpret_cast<destData *>(myself);      DurationInfo info;      DosBoxOPL3 dosbox; -    DurationInfoCache::iterator cachedEntry = s->myself->m_durationInfo.find(s->i->first); +    // NukedOPL3 dosbox; -    if(cachedEntry != s->myself->m_durationInfo.end()) +    if(s->bd)      { -        s->myself->m_cache_matches++; -        goto endWork; +        OperatorsKey ok = {s->bd_ins->ops[0], s->bd_ins->ops[1], s->bd_ins->ops[2], s->bd_ins->ops[3], +                           static_cast<int_fast32_t>(s->bd_ins->fbConn), +                           s->bd_ins->noteOffset1, s->bd_ins->noteOffset2, +                           static_cast<int_fast32_t>(s->bd_ins->percussionKeyNumber), +                           static_cast<int_fast32_t>(s->bd_ins->instFlags), +                           static_cast<int_fast32_t>(s->bd_ins->secondVoiceDetune)}; +        s->myself->m_durationInfo_mx.lock(); +        DurationInfoCacheX::iterator cachedEntry = s->myself->m_durationInfoX.find(ok); +        bool atEnd = cachedEntry == s->myself->m_durationInfoX.end(); +        s->myself->m_durationInfo_mx.unlock(); + +        if(!atEnd) +        { +            const DurationInfo &di = cachedEntry->second; +            s->bd_ins->delay_on_ms = di.ms_sound_kon; +            s->bd_ins->delay_off_ms = di.ms_sound_koff; +            if(di.nosound) +                s->bd_ins->instFlags |= BanksDump::InstrumentEntry::WOPL_Ins_IsBlank; +            s->myself->m_cache_matches++; +            goto endWork; +        } +        info = MeasureDurations(*s->bd, *s->bd_ins, &dosbox); +        s->myself->m_durationInfo_mx.lock(); +        s->myself->m_durationInfoX.insert({ok, info}); +        s->myself->m_durationInfo_mx.unlock();      } +    else +    { +#if 0 +        const ins &ok = s->i->first; +        s->myself->m_durationInfo_mx.lock(); +        DurationInfoCache::iterator cachedEntry = s->myself->m_durationInfo.find(ok); +        bool atEnd = cachedEntry == s->myself->m_durationInfo.end(); +        s->myself->m_durationInfo_mx.unlock(); + +        if(!atEnd) +        { +            s->myself->m_cache_matches++; +            goto endWork; +        } -    info = MeasureDurations(s->i->first, &dosbox); -    s->myself->m_durationInfo_mx.lock(); -    s->myself->m_durationInfo.insert({s->i->first, info}); -    s->myself->m_durationInfo_mx.unlock(); +        info = MeasureDurations(ok, &dosbox); +        s->myself->m_durationInfo_mx.lock(); +        s->myself->m_durationInfo.insert({ok, info}); +        s->myself->m_durationInfo_mx.unlock(); +#endif +    }  endWork:      s->myself->m_semaphore.notify(); diff --git a/utils/gen_adldata/measurer.h b/utils/gen_adldata/measurer.h index 63475ca..f49b9bf 100644 --- a/utils/gen_adldata/measurer.h +++ b/utils/gen_adldata/measurer.h @@ -6,6 +6,7 @@  #include <mutex>  #include <condition_variable>  #include <thread> +#include <array>  #include "progs_cache.h" @@ -54,24 +55,28 @@ private:  struct MeasureThreaded  { +    typedef std::array<int_fast32_t, 10> OperatorsKey;      typedef std::map<ins, DurationInfo> DurationInfoCache; +    typedef std::map<OperatorsKey, DurationInfo> DurationInfoCacheX; -    MeasureThreaded() : -        m_semaphore(int(std::thread::hardware_concurrency()) * 2), -        m_done(0), -        m_cache_matches(0) -    {} +    MeasureThreaded();      Semaphore           m_semaphore;      std::mutex          m_durationInfo_mx;      DurationInfoCache   m_durationInfo; +    DurationInfoCacheX  m_durationInfoX;      std::atomic_bool    m_delete_tail;      size_t              m_total = 0;      std::atomic<size_t> m_done;      std::atomic<size_t> m_cache_matches; +#if 0      void LoadCache(const char *fileName);      void SaveCache(const char *fileName); +#endif + +    void LoadCacheX(const char *fileName); +    void SaveCacheX(const char *fileName);      struct destData      { @@ -85,6 +90,8 @@ struct MeasureThreaded          }          MeasureThreaded  *myself;          std::map<ins, std::pair<size_t, std::set<std::string> > >::const_iterator i; +        BanksDump *bd; +        BanksDump::InstrumentEntry *bd_ins;          std::thread       m_work;          std::atomic_bool  m_works; @@ -96,11 +103,17 @@ struct MeasureThreaded      void printProgress();      void printFinal(); +#if 0      void run(InstrumentsData::const_iterator i); +#endif +    void run(BanksDump &bd, BanksDump::InstrumentEntry &e);      void waitAll();  };  class OPLChipBase; +#if 0  extern DurationInfo MeasureDurations(const ins &in, OPLChipBase *chip); +#endif +extern DurationInfo MeasureDurations(const BanksDump &db, const BanksDump::InstrumentEntry &ins, OPLChipBase *chip);  #endif // MEASURER_H diff --git a/utils/gen_adldata/progs_cache.cpp b/utils/gen_adldata/progs_cache.cpp index 10124a8..73b05da 100644 --- a/utils/gen_adldata/progs_cache.cpp +++ b/utils/gen_adldata/progs_cache.cpp @@ -1,123 +1,550 @@  #include "progs_cache.h" -InstrumentDataTab insdatatab; +#include "file_formats/load_ail.h" +#include "file_formats/load_bisqwit.h" +#include "file_formats/load_bnk2.h" +#include "file_formats/load_bnk.h" +#include "file_formats/load_ibk.h" +#include "file_formats/load_jv.h" +#include "file_formats/load_op2.h" +#include "file_formats/load_tmb.h" +#include "file_formats/load_wopl.h" +#include "file_formats/load_ea.h" -InstrumentsData instab; -InstProgsData   progs; -BankSetupData   banksetup; +//InstrumentDataTab insdatatab; -std::vector<std::string> banknames; +//InstrumentsData instab; +//InstProgsData   progs; +//BankSetupData   banksetup; + +//std::vector<std::string> banknames;  //unsigned maxvalues[30] = { 0 }; -void SetBank(size_t bank, unsigned patch, size_t insno) +//void SetBank(size_t bank, unsigned patch, size_t insno) +//{ +//    progs[bank][patch] = insno + 1; +//} + +//void SetBankSetup(size_t bank, const AdlBankSetup &setup) +//{ +//    banksetup[bank] = setup; +//} + +//size_t InsertIns(const insdata &id, ins &in, const std::string &name, const std::string &name2) +//{ +//    return InsertIns(id, id, in, name, name2, true); +//} + +//size_t InsertIns( +//    const insdata &id, +//    const insdata &id2, +//    ins &in, +//    const std::string &name, +//    const std::string &name2, +//    bool oneVoice) +//{ +//    { +//        InstrumentDataTab::iterator i = insdatatab.lower_bound(id); + +//        size_t insno = ~size_t(0); +//        if(i == insdatatab.end() || i->first != id) +//        { +//            std::pair<insdata, std::pair<size_t, std::set<std::string> > > res; +//            res.first = id; +//            res.second.first = insdatatab.size(); +//            if(!name.empty()) res.second.second.insert(name); +//            if(!name2.empty()) res.second.second.insert(name2); +//            insdatatab.insert(i, res); +//            insno = res.second.first; +//        } +//        else +//        { +//            if(!name.empty()) i->second.second.insert(name); +//            if(!name2.empty()) i->second.second.insert(name2); +//            insno = i->second.first; +//        } + +//        in.insno1 = insno; +//        in.instCache1 = id; +//    } + +//    if(oneVoice || (id == id2)) +//    { +//        in.insno2 = in.insno1; +//        in.instCache2 = in.instCache1; +//    } +//    else +//    { +//        InstrumentDataTab::iterator i = insdatatab.lower_bound(id2); + +//        size_t insno2 = ~size_t(0); +//        if(i == insdatatab.end() || i->first != id2) +//        { +//            std::pair<insdata, std::pair<size_t, std::set<std::string> > > res; +//            res.first = id2; +//            res.second.first = insdatatab.size(); +//            if(!name.empty()) res.second.second.insert(name); +//            if(!name2.empty()) res.second.second.insert(name2); +//            insdatatab.insert(i, res); +//            insno2 = res.second.first; +//        } +//        else +//        { +//            if(!name.empty()) i->second.second.insert(name); +//            if(!name2.empty()) i->second.second.insert(name2); +//            insno2 = i->second.first; +//        } +//        in.insno2 = insno2; +//        in.instCache2 = id2; +//    } + +//    { +//        InstrumentsData::iterator i = instab.lower_bound(in); + +//        size_t resno = ~size_t(0); +//        if(i == instab.end() || i->first != in) +//        { +//            std::pair<ins, std::pair<size_t, std::set<std::string> > > res; +//            res.first = in; +//            res.second.first = instab.size(); +//            if(!name.empty()) res.second.second.insert(name); +//            if(!name2.empty()) res.second.second.insert(name2); +//            instab.insert(i, res); +//            resno = res.second.first; +//        } +//        else +//        { +//            if(!name.empty()) i->second.second.insert(name); +//            if(!name2.empty()) i->second.second.insert(name2); +//            resno = i->second.first; +//        } +//        return resno; +//    } +//} + +//// Create silent 'nosound' instrument +//size_t InsertNoSoundIns() +//{ +//    // { 0x0F70700,0x0F70710, 0xFF,0xFF, 0x0,+0 }, +//    insdata tmp1 = MakeNoSoundIns(); +//    struct ins tmp2; +//    return InsertIns(tmp1, tmp1, tmp2, "nosound", ""); +//} + +insdata MakeNoSoundIns()  { -    progs[bank][patch] = insno + 1; +    insdata nosnd; +    uint8_t d[] = {0x00, 0x10, 0x07, 0x07, 0xF7, 0xF7, 0x00, 0x00, 0xFF, 0xFF, 0x00}; +    std::memcpy(nosnd.data, d, 11); +    nosnd.finetune = 0; +    nosnd.diff = false; +    return nosnd;  } -void SetBankSetup(size_t bank, const AdlBankSetup &setup) + +void BanksDump::toOps(const insdata &inData, BanksDump::Operator *outData, size_t begin)  { -    banksetup[bank] = setup; +    outData[begin + 0].d_E862 = +            uint_fast32_t(inData.data[6] << 24) +          + uint_fast32_t(inData.data[4] << 16) +          + uint_fast32_t(inData.data[2] << 8) +          + uint_fast32_t(inData.data[0] << 0); +    outData[begin + 1].d_E862 = +            uint_fast32_t(inData.data[7] << 24) +          + uint_fast32_t(inData.data[5] << 16) +          + uint_fast32_t(inData.data[3] << 8) +          + uint_fast32_t(inData.data[1] << 0); +    outData[begin + 0].d_40 = inData.data[8]; +    outData[begin + 1].d_40 = inData.data[9];  } -size_t InsertIns(const insdata &id, ins &in, const std::string &name, const std::string &name2) +size_t BanksDump::initBank(size_t bankId, const std::string &title, uint_fast16_t bankSetup)  { -    return InsertIns(id, id, in, name, name2, true); +    for(size_t bID = 0; bID < banks.size(); bID++) +    { +        BankEntry &be = banks[bID]; +        if(bankId == be.bankId) +        { +            be.bankTitle = title; +            be.bankSetup = bankSetup; +            return bID; +        } +    } + +    size_t bankIndex = banks.size(); +    banks.emplace_back(); +    BankEntry &b = banks.back(); + +    b.bankId = bankId; +    b.bankTitle = title; +    b.bankSetup = bankSetup; +    return bankIndex;  } -size_t InsertIns( -    const insdata &id, -    const insdata &id2, -    ins &in, -    const std::string &name, -    const std::string &name2, -    bool oneVoice) +void BanksDump::addMidiBank(size_t bankId, bool percussion, BanksDump::MidiBank b)  { +    assert(bankId < banks.size()); +    BankEntry &be = banks[bankId]; + +    auto it = std::find(midiBanks.begin(), midiBanks.end(), b); +    if(it == midiBanks.end())      { -        InstrumentDataTab::iterator i = insdatatab.lower_bound(id); +        b.midiBankId = midiBanks.size(); +        midiBanks.push_back(b); +    } +    else +    { +        b.midiBankId = it->midiBankId; +    } + +    if(percussion) +        be.percussion.push_back(b.midiBankId); +    else +        be.melodic.push_back(b.midiBankId); +} -        size_t insno = ~size_t(0); -        if(i == insdatatab.end() || i->first != id) +void BanksDump::addInstrument(BanksDump::MidiBank &bank, size_t patchId, +                              BanksDump::InstrumentEntry e, +                              BanksDump::Operator *ops, +                              const std::string &meta) +{ +    assert(patchId < 128); +    size_t opsCount = ((e.instFlags & InstrumentEntry::WOPL_Ins_4op) != 0 || +            (e.instFlags & InstrumentEntry::WOPL_Ins_Pseudo4op) != 0) ? +                4 : 2; + +    if((e.instFlags & InstrumentEntry::WOPL_Ins_IsBlank) != 0) +    { +        bank.instruments[patchId] = -1; +        return; +    } + +    for(size_t op = 0; op < opsCount; op++) +    { +        Operator o = ops[op]; +        auto it = std::find(operators.begin(), operators.end(), o); +        if(it == operators.end())          { -            std::pair<insdata, std::pair<size_t, std::set<std::string> > > res; -            res.first = id; -            res.second.first = insdatatab.size(); -            if(!name.empty()) res.second.second.insert(name); -            if(!name2.empty()) res.second.second.insert(name2); -            insdatatab.insert(i, res); -            insno = res.second.first; +            o.opId = operators.size(); +            e.ops[op] = static_cast<int_fast32_t>(o.opId); +            operators.push_back(o);          }          else          { -            if(!name.empty()) i->second.second.insert(name); -            if(!name2.empty()) i->second.second.insert(name2); -            insno = i->second.first; +            e.ops[op] = static_cast<int_fast32_t>(it->opId);          } - -        in.insno1 = insno;      } -    if(oneVoice || (id == id2)) -        in.insno2 = in.insno1; +    auto it = std::find(instruments.begin(), instruments.end(), e); +    if(it == instruments.end()) +    { +        e.instId = instruments.size(); +        e.instMetas.push_back(meta + "_" + std::to_string(patchId)); +        instruments.push_back(e); +    }      else      { -        InstrumentDataTab::iterator i = insdatatab.lower_bound(id2); +        e.instId = it->instId; +        e.instMetas.push_back(meta + "_" + std::to_string(patchId)); +        it->instMetas.push_back(meta + "_" + std::to_string(patchId)); +    } +    bank.instruments[patchId] = static_cast<int_fast32_t>(e.instId); +} + +void BanksDump::exportBanks(const std::string &outPath, const std::string &headerName) +{ +    FILE *out = std::fopen(outPath.c_str(), "w"); + +    std::fprintf(out, "/**********************************************************\n" +                      "    This file is generated by `gen_adldata` automatically\n" +                      "                  Don't edit it directly!\n" +                      "        To modify content of this file, modify banks\n" +                      "          and re-run the `gen_adldata` build step.\n" +                      "***********************************************************/\n\n" +                      "#include \"%s\"\n\n\n", headerName.c_str()); -        size_t insno2 = ~size_t(0); -        if(i == insdatatab.end() || i->first != id2) +    std::fprintf(out, "const size_t g_embeddedBanksCount = %zu;\n\n", banks.size()); +    std::fprintf(out, "const BanksDump::BankEntry g_embeddedBanks[] =\n" +                      "{\n"); + +    std::vector<size_t> bankNumberLists; + +    for(const BankEntry &be : banks) +    { +        std::fprintf(out, "\t{0x%04lX, %zu, %zu, \"%s\", ", +                                   be.bankSetup, +                                   be.melodic.size(), +                                   be.percussion.size(), +                                   be.bankTitle.c_str()); + +        fprintf(out, "%zu, ", bankNumberLists.size()); // Use offset to point the common array of bank IDs +        for(const size_t &me : be.melodic) +            bankNumberLists.push_back(me); + +        fprintf(out, "%zu", bankNumberLists.size()); +        for(const size_t &me : be.percussion) +            bankNumberLists.push_back(me); + +        std::fprintf(out, "},\n"); +    } + +    std::fprintf(out, "};\n\n"); + +    std::fprintf(out, "const char* const g_embeddedBankNames[] =\n" +                      "{\n\t"); +    { +        bool commaNeeded = false; +        size_t operatorEntryCounter = 0; +        for(const BankEntry &be : banks)          { -            std::pair<insdata, std::pair<size_t, std::set<std::string> > > res; -            res.first = id2; -            res.second.first = insdatatab.size(); -            if(!name.empty()) res.second.second.insert(name); -            if(!name2.empty()) res.second.second.insert(name2); -            insdatatab.insert(i, res); -            insno2 = res.second.first; +            if(commaNeeded) +                std::fprintf(out, ", "); +            else +                commaNeeded = true; +            operatorEntryCounter++; +            if(operatorEntryCounter >= 25) +            { +                std::fprintf(out, "\n"); +                operatorEntryCounter = 0; +            } +            if(operatorEntryCounter == 0) +                std::fprintf(out, "\t"); +            std::fprintf(out, "g_embeddedBanks[%zu].title", be.bankId);          } -        else +        std::fprintf(out, ",\n\tNULL"); // Make a null entry as finalizer +    } +    std::fprintf(out, "\n};\n\n"); + +    std::fprintf(out, "const size_t g_embeddedBanksMidiIndex[] =\n" +                      "{"); +    { +        bool commaNeeded = false; +        for(const size_t &me : bankNumberLists)          { -            if(!name.empty()) i->second.second.insert(name); -            if(!name2.empty()) i->second.second.insert(name2); -            insno2 = i->second.first; +            if(commaNeeded) +                std::fprintf(out, ","); +            else +                commaNeeded = true; +            std::fprintf(out, "%zu", me);          } -        in.insno2 = insno2;      } +    std::fprintf(out, "};\n\n"); +    std::fprintf(out, "const BanksDump::MidiBank g_embeddedBanksMidi[] =\n" +                      "{\n"); +    for(const MidiBank &be : midiBanks)      { -        InstrumentsData::iterator i = instab.lower_bound(in); +        bool commaNeeded = true; +        std::fprintf(out, "\t{%u,%u,", be.msb, be.lsb); -        size_t resno = ~size_t(0); -        if(i == instab.end() || i->first != in) +        std::fprintf(out, "{"); +        commaNeeded = false; +        for(size_t i = 0; i < 128; i++)          { -            std::pair<ins, std::pair<size_t, std::set<std::string> > > res; -            res.first = in; -            res.second.first = instab.size(); -            if(!name.empty()) res.second.second.insert(name); -            if(!name2.empty()) res.second.second.insert(name2); -            instab.insert(i, res); -            resno = res.second.first; +            if(commaNeeded) +                std::fprintf(out, ","); +            else +                commaNeeded = true; +            std::fprintf(out, "%ld", be.instruments[i]);          } +        std::fprintf(out, "}"); + +        std::fprintf(out, "},\n"); +    } +    std::fprintf(out, "};\n\n"); + + +    std::fprintf(out, "const BanksDump::InstrumentEntry g_embeddedBanksInstruments[] =\n" +                      "{\n"); +    for(const InstrumentEntry &be : instruments) +    { +        size_t opsCount = ((be.instFlags & InstrumentEntry::WOPL_Ins_4op) != 0 || +                           (be.instFlags & InstrumentEntry::WOPL_Ins_Pseudo4op) != 0) ? 4 : 2; +        std::fprintf(out, "\t{%d,%d,%d,%u,%s%lX,%d,%s%lX,%s%lX,%s%lX,", +                     be.noteOffset1, +                     be.noteOffset2, +                     be.midiVelocityOffset, +                     be.percussionKeyNumber, +                     (be.instFlags == 0 ? "" : "0x"), be.instFlags, // for compactness, don't print "0x" when is zero +                     be.secondVoiceDetune, +                     (be.fbConn == 0 ? "" : "0x"), be.fbConn, +                     (be.delay_on_ms == 0 ? "" : "0x"), be.delay_on_ms, +                     (be.delay_off_ms == 0 ? "" : "0x"), be.delay_off_ms); + +        if(opsCount == 4) +            std::fprintf(out, "{%ld,%ld,%ld,%ld} ", +                         be.ops[0], be.ops[1], be.ops[2], be.ops[3]);          else +            std::fprintf(out, "{%ld,%ld}", +                         be.ops[0], be.ops[1]); + +        std::fprintf(out, "},\n"); +    } +    std::fprintf(out, "};\n\n"); + +    std::fprintf(out, "const BanksDump::Operator g_embeddedBanksOperators[] =\n" +                      "{\n"); +    size_t operatorEntryCounter = 0; +    for(const Operator &be : operators) +    { +        if(operatorEntryCounter == 0) +            std::fprintf(out, "\t"); +        std::fprintf(out, "{0x%07lX,%s%02lX},", +                     be.d_E862, +                     (be.d_40 == 0 ? "" : "0x"), be.d_40); +        operatorEntryCounter++; +        if(operatorEntryCounter >= 25)          { -            if(!name.empty()) i->second.second.insert(name); -            if(!name2.empty()) i->second.second.insert(name2); -            resno = i->second.first; +            std::fprintf(out, "\n"); +            operatorEntryCounter = 0;          } -        return resno;      } +    std::fprintf(out, "\n};\n\n"); + +    std::fclose(out);  } -// Create silent 'nosound' instrument -size_t InsertNoSoundIns() +struct OpCheckData +{ +    uint_fast8_t egEn; +    uint_fast8_t attack; +    uint_fast8_t decay; +    uint_fast8_t sustain; +    uint_fast8_t release; +    uint_fast8_t level; + +    void setData(uint_fast32_t d_E862, uint_fast32_t d_40) +    { +        egEn    = static_cast<uint_fast8_t>(((d_E862 & 0xFF) >> 5) & 0x01); +        decay   = static_cast<uint_fast8_t>((d_E862 >> 8)  & 0x0F); +        attack  = static_cast<uint_fast8_t>((d_E862 >> 12) & 0x0F); +        release = static_cast<uint_fast8_t>((d_E862 >> 16) & 0x0F); +        sustain = static_cast<uint_fast8_t>((d_E862 >> 20) & 0x0F); +        level   = static_cast<uint_fast8_t>(d_40 & 0x3F); +    } + +    bool isOpSilent(bool moreInfo) +    { +        // level=0x3f - silence +        // attack=0x00 - silence +        // attack=0x0F & sustain=0x0F & decay=0x0F - half-silence +        // attack=0x0F & decay=0x0F & release=0x00 & egOff - half-silence +        if(level == 0x3F) +        { +            if(moreInfo) +                std::fprintf(stdout, "== volume=0x3F ==\n"); +            return true; +        } +        if(attack == 0x00) +        { +            if(moreInfo) +                std::fprintf(stdout, "== attack=0x00 ==\n"); +            return true; +        } +        if(attack == 0x0F && sustain == 0x0F && decay == 0x0F) +        { +            if(moreInfo) +                std::fprintf(stdout, "== attack=0x0F, sustain=0x0F, decay=0x0F ==\n"); +            return true; +        } +        if(attack == 0x0F && decay == 0x0F && release == 0x00 && !egEn) +        { +            if(moreInfo) +                std::fprintf(stdout, "== attack=0x0F, decay=0x0F, release=0x00, !egEn ==\n"); +            return true; +        } +        return false; +    } +}; + +bool BanksDump::isSilent(const BanksDump &db, const BanksDump::InstrumentEntry &ins, bool moreInfo)  { -    // { 0x0F70700,0x0F70710, 0xFF,0xFF, 0x0,+0 }, -    insdata tmp1 = MakeNoSoundIns(); -    struct ins tmp2 = { 0, 0, 0, false, false, 0u, 0.0, 0}; -    return InsertIns(tmp1, tmp1, tmp2, "nosound", ""); +    bool isPseudo4ops = ((ins.instFlags & BanksDump::InstrumentEntry::WOPL_Ins_Pseudo4op) != 0); +    bool is4ops =       ((ins.instFlags & BanksDump::InstrumentEntry::WOPL_Ins_4op) != 0) && !isPseudo4ops; +    size_t opsNum = (is4ops || isPseudo4ops) ? 4 : 2; +    BanksDump::Operator ops[4]; +    assert(ins.ops[0] >= 0); +    assert(ins.ops[1] >= 0); +    ops[0] = db.operators[ins.ops[0]]; +    ops[1] = db.operators[ins.ops[1]]; +    if(opsNum > 2) +    { +        assert(ins.ops[2] >= 0); +        assert(ins.ops[3] >= 0); +        ops[2] = db.operators[ins.ops[2]]; +        ops[3] = db.operators[ins.ops[3]]; +    } +    return isSilent(ops, ins.fbConn, opsNum, isPseudo4ops, moreInfo);  } -insdata MakeNoSoundIns() +bool BanksDump::isSilent(const BanksDump::Operator *ops, uint_fast16_t fbConn, size_t countOps, bool pseudo4op, bool moreInfo)  { -    return { {0x00, 0x10, 0x07, 0x07, 0xF7, 0xF7, 0x00, 0x00, 0xFF, 0xFF, 0x00}, 0, false}; +    // TODO: Implement this completely!!! +    const uint_fast8_t conn1 = (fbConn) & 0x01; +    const uint_fast8_t conn2 = (fbConn >> 8) & 0x01; +    OpCheckData opd[4]; +    for(size_t i = 0; i < 4; i++) +        opd[i].setData(ops[i].d_E862, ops[i].d_40); + +    if(countOps == 2) +    { +        if(conn1 == 0) +        { +            if(opd[1].isOpSilent(moreInfo)) +                return true; +        } +        if(conn1 == 1) +        { +            if(opd[0].isOpSilent(moreInfo) && opd[1].isOpSilent(moreInfo)) +                return true; +        } +    } +    else if(countOps == 4 && pseudo4op) +    { +        bool silent1 = false; +        bool silent2 = false; +        if(conn1 == 0 && opd[1].isOpSilent(moreInfo)) +            silent1 = true; +        if(conn1 == 1 && opd[0].isOpSilent(moreInfo) && opd[1].isOpSilent(moreInfo)) +            silent1 = true; +        if(conn2 == 0 && opd[3].isOpSilent(moreInfo)) +            silent2 = true; +        if(conn2 == 1 && opd[2].isOpSilent(moreInfo) && opd[3].isOpSilent(moreInfo)) +            silent2 = true; +        if(silent1 && silent2) +            return true; +    } +    else if(countOps == 4 && !pseudo4op) +    { +        if(conn1 == 0 && conn2 == 0) // FM-FM [0, 0, 0, 1] +        { +            if(opd[3].isOpSilent(moreInfo)) +                return true; +        } + +        if(conn1 == 1 && conn2 == 0) // AM-FM [1, 0, 0, 1] +        { +            if(opd[0].isOpSilent(moreInfo) && opd[3].isOpSilent(moreInfo)) +                return true; +        } +        if(conn1 == 0 && conn2 == 1) // FM-AM [0, 1, 0, 1] +        { +            if(opd[1].isOpSilent(moreInfo) && opd[3].isOpSilent(moreInfo)) +                return true; +        } +        if(conn1 == 1 && conn2 == 1) // FM-AM [1, 0, 1, 1] +        { +            if(opd[0].isOpSilent(moreInfo) && opd[2].isOpSilent(moreInfo) && opd[3].isOpSilent(moreInfo)) +                return true; +        } +    } + +    return false;  } +void BanksDump::InstrumentEntry::setFbConn(uint_fast16_t fbConn1, uint_fast16_t fbConn2) +{ +    fbConn = (static_cast<uint_fast16_t>(fbConn1 & 0x0F)) | +             (static_cast<uint_fast16_t>(fbConn2 & 0x0F) << 8); +} diff --git a/utils/gen_adldata/progs_cache.h b/utils/gen_adldata/progs_cache.h index 28aaa19..10e29aa 100644 --- a/utils/gen_adldata/progs_cache.h +++ b/utils/gen_adldata/progs_cache.h @@ -12,12 +12,28 @@  #include <vector>  #include <limits>  #include <cmath> +#include <cstdint> +#include <cstdio> + +#include <cassert>  struct insdata  {      uint8_t         data[11];      int8_t          finetune;      bool            diff; +    explicit insdata() +    { +        std::memset(data, 0, 11); +        finetune = 0; +        diff = false; +    } +    insdata(const insdata &b) +    { +        std::memcpy(data, b.data, 11); +        finetune = b.finetune; +        diff = b.diff; +    }      bool operator==(const insdata &b) const      {          return (std::memcmp(data, b.data, 11) == 0) && (finetune == b.finetune) && (diff == b.diff); @@ -42,9 +58,9 @@ struct insdata  inline bool equal_approx(double const a, double const b)  { -    double const epsilon(std::numeric_limits<double>::epsilon() * 100); -    double const scale(1.0); -    return std::fabs(a - b) < epsilon * (scale + (std::max)(std::fabs(a), std::fabs(b))); +    int_fast64_t ai = static_cast<int_fast64_t>(a * 1000000.0); +    int_fast64_t bi = static_cast<int_fast64_t>(b * 1000000.0); +    return ai == bi;  }  struct ins @@ -55,18 +71,44 @@ struct ins             Flag_RM_Cymbal = 0x20, Flag_RM_HiHat = 0x28, Mask_RhythmMode = 0x38 };      size_t insno1, insno2; +    insdata instCache1, instCache2;      unsigned char notenum;      bool pseudo4op;      bool real4op;      uint32_t rhythmModeDrum;      double voice2_fine_tune;      int8_t midi_velocity_offset; +    explicit ins() : +        insno1(0), +        insno2(0), +        notenum(0), +        pseudo4op(false), +        real4op(false), +        rhythmModeDrum(false), +        voice2_fine_tune(0.0), +        midi_velocity_offset(0) +    {} + +    ins(const ins &o) : +        insno1(o.insno1), +        insno2(o.insno2), +        instCache1(o.instCache1), +        instCache2(o.instCache2), +        notenum(o.notenum), +        pseudo4op(o.pseudo4op), +        real4op(o.real4op), +        rhythmModeDrum(o.rhythmModeDrum), +        voice2_fine_tune(o.voice2_fine_tune), +        midi_velocity_offset(o.midi_velocity_offset) +    {}      bool operator==(const ins &b) const      {          return notenum == b.notenum                 && insno1 == b.insno1                 && insno2 == b.insno2 +               && instCache1 == b.instCache2 +               && instCache2 == b.instCache2                 && pseudo4op == b.pseudo4op                 && real4op == b.real4op                 && rhythmModeDrum == b.rhythmModeDrum @@ -77,6 +119,8 @@ struct ins      {          if(insno1 != b.insno1) return insno1 < b.insno1;          if(insno2 != b.insno2) return insno2 < b.insno2; +        if(instCache1 != b.instCache1) return instCache1 < b.instCache1; +        if(instCache2 != b.instCache2) return instCache2 < b.instCache2;          if(notenum != b.notenum) return notenum < b.notenum;          if(pseudo4op != b.pseudo4op) return pseudo4op < b.pseudo4op;          if(real4op != b.real4op) return real4op < b.real4op; @@ -100,44 +144,288 @@ enum VolumesModels      VOLUME_9X  }; -struct AdlBankSetup -{ -    int     volumeModel; -    bool    deepTremolo; -    bool    deepVibrato; -    bool    scaleModulators; -}; +//struct AdlBankSetup +//{ +//    int     volumeModel; +//    bool    deepTremolo; +//    bool    deepVibrato; +//    bool    scaleModulators; +//}; -typedef std::map<insdata, std::pair<size_t, std::set<std::string> > > InstrumentDataTab; -extern InstrumentDataTab insdatatab; +//typedef std::map<insdata, std::pair<size_t, std::set<std::string> > > InstrumentDataTab; +//extern InstrumentDataTab insdatatab; -typedef std::map<ins, std::pair<size_t, std::set<std::string> > > InstrumentsData; -extern InstrumentsData instab; +//typedef std::map<ins, std::pair<size_t, std::set<std::string> > > InstrumentsData; +//extern InstrumentsData instab; -typedef std::map<size_t, std::map<size_t, size_t> > InstProgsData; -extern InstProgsData progs; +//typedef std::map<size_t, std::map<size_t, size_t> > InstProgsData; +//extern InstProgsData progs; -typedef std::map<size_t, AdlBankSetup> BankSetupData; -extern BankSetupData banksetup; +//typedef std::map<size_t, AdlBankSetup> BankSetupData; +//extern BankSetupData banksetup; -extern std::vector<std::string> banknames; +//extern std::vector<std::string> banknames;  //static std::map<unsigned, std::map<unsigned, unsigned> > Correlate;  //extern unsigned maxvalues[30]; -void SetBank(size_t bank, unsigned patch, size_t insno); -void SetBankSetup(size_t bank, const AdlBankSetup &setup); +//void SetBank(size_t bank, unsigned patch, size_t insno); +//void SetBankSetup(size_t bank, const AdlBankSetup &setup); -/* 2op voice instrument */ -size_t InsertIns(const insdata &id, ins &in, -                 const std::string &name, const std::string &name2); +///* 2op voice instrument */ +//size_t InsertIns(const insdata &id, ins &in, +//                 const std::string &name, const std::string &name2); -/* 4op voice instrument or double-voice 2-op instrument */ -size_t InsertIns(const insdata &id, const insdata &id2, ins &in, -                 const std::string &name, const std::string &name2, -                 bool oneVoice = false); +///* 4op voice instrument or double-voice 2-op instrument */ +//size_t InsertIns(const insdata &id, const insdata &id2, ins &in, +//                 const std::string &name, const std::string &name2, +//                 bool oneVoice = false); -size_t InsertNoSoundIns(); +//size_t InsertNoSoundIns();  insdata MakeNoSoundIns(); + + + + + + + + +struct BanksDump +{ +    struct BankEntry +    { +        uint_fast32_t bankId = 0; +        std::string bankTitle = "Untitled"; + +        /* Global OPL flags */ +        typedef enum WOPLFileFlags +        { +            /* Enable Deep-Tremolo flag */ +            WOPL_FLAG_DEEP_TREMOLO = 0x01, +            /* Enable Deep-Vibrato flag */ +            WOPL_FLAG_DEEP_VIBRATO = 0x02 +        } WOPLFileFlags; + +        /* Volume scaling model implemented in the libADLMIDI */ +        typedef enum WOPL_VolumeModel +        { +            WOPL_VM_Generic = 0, +            WOPL_VM_Native, +            WOPL_VM_DMX, +            WOPL_VM_Apogee, +            WOPL_VM_Win9x +        } WOPL_VolumeModel; + +        /** +         * @brief Suggested bank setup in dependence from a driver that does use of this +         */ +        enum BankSetup +        { +            SETUP_Generic = 0x0300, +            SETUP_Win9X   = 0x0304, +            SETUP_DMX     = 0x0002, +            SETUP_Apogee  = 0x0003, +            SETUP_AIL     = 0x0300, +            SETUP_IBK     = 0x0301, +            SETUP_IMF     = 0x0200, +            SETUP_CMF     = 0x0201 +        }; + +        uint_fast16_t       bankSetup = SETUP_Generic; // 0xAABB, AA - OPL flags, BB - Volume model +        std::vector<size_t> melodic; +        std::vector<size_t> percussion; + +        explicit BankEntry() = default; + +        BankEntry(const BankEntry &o) +        { +            bankId = o.bankId; +            bankTitle = o.bankTitle; +            bankSetup = o.bankSetup; +            melodic = o.melodic; +            percussion = o.percussion; +        } + +        BankEntry(const BankEntry &&o) +        { +            bankId = std::move(o.bankId); +            bankTitle = std::move(o.bankTitle); +            bankSetup = std::move(o.bankSetup); +            melodic = std::move(o.melodic); +            percussion = std::move(o.percussion); +        } +    }; + +    struct MidiBank +    { +        uint_fast32_t midiBankId = 0; +        uint_fast8_t  msb = 0, lsb = 0; +        int_fast32_t  instruments[128]; + +        MidiBank() +        { +            for(size_t i = 0; i < 128; i++) +                instruments[i] = -1; +        } + +        MidiBank(const MidiBank &o) +        { +            midiBankId = o.midiBankId; +            msb = o.msb; +            lsb = o.lsb; +            std::memcpy(instruments, o.instruments, sizeof(int_fast32_t) * 128); +        } + +        bool operator==(const MidiBank &o) +        { +            if(msb != o.msb) +                return false; +            if(lsb != o.lsb) +                return false; +            if(std::memcmp(instruments, o.instruments, sizeof(int_fast32_t) * 128) != 0) +                return false; +            return true; +        } +        bool operator!=(const MidiBank &o) +        { +            return !operator==(o); +        } +    }; + +    struct InstrumentEntry +    { +        uint_fast32_t instId = 0; +        std::vector<std::string> instMetas; + +        typedef enum WOPL_InstrumentFlags +        { +            /* Is two-operator single-voice instrument (no flags) */ +            WOPL_Ins_2op        = 0x00, +            /* Is true four-operator instrument */ +            WOPL_Ins_4op        = 0x01, +            /* Is pseudo four-operator (two 2-operator voices) instrument */ +            WOPL_Ins_Pseudo4op  = 0x02, +            /* Is a blank instrument entry */ +            WOPL_Ins_IsBlank    = 0x04, + +            /* RythmMode flags mask */ +            WOPL_RhythmModeMask  = 0x38, + +            /* Mask of the flags range */ +            WOPL_Ins_ALL_MASK   = 0x07 +        } WOPL_InstrumentFlags; + +        typedef enum WOPL_RhythmMode +        { +            /* RythmMode: BassDrum */ +            WOPL_RM_BassDrum  = 0x08, +            /* RythmMode: Snare */ +            WOPL_RM_Snare     = 0x10, +            /* RythmMode: TomTom */ +            WOPL_RM_TomTom    = 0x18, +            /* RythmMode: Cymbell */ +            WOPL_RM_Cymbal   = 0x20, +            /* RythmMode: HiHat */ +            WOPL_RM_HiHat     = 0x28 +        } WOPL_RhythmMode; + +        int_fast8_t   noteOffset1 = 0; +        int_fast8_t   noteOffset2 = 0; +        int_fast8_t   midiVelocityOffset = 0; +        uint_fast8_t  percussionKeyNumber = 0; +        uint_fast32_t instFlags = 0; +        int_fast8_t   secondVoiceDetune = 0; +        /* +            2op: modulator1, carrier1, feedback1 +            2vo: modulator1, carrier1, modulator2, carrier2, feedback(1+2) +            4op: modulator1, carrier1, modulator2, carrier2, feedback1 +        */ +        //! Contains FeedBack-Connection for both operators 0xBBAA - AA - first, BB - second +        uint_fast16_t fbConn = 0; +        int_fast64_t delay_on_ms = 0; +        int_fast64_t delay_off_ms = 0; +        int_fast32_t ops[5] = {-1, -1, -1, -1, -1}; + +        void setFbConn(uint_fast16_t fbConn1, uint_fast16_t fbConn2 = 0x00); + +        bool operator==(const InstrumentEntry &o) +        { +            return ( +                (noteOffset1 == o.noteOffset1) && +                (noteOffset2 == o.noteOffset2) && +                (midiVelocityOffset == o.midiVelocityOffset) && +                (percussionKeyNumber == o.percussionKeyNumber) && +                (instFlags == o.instFlags) && +                (secondVoiceDetune == o.secondVoiceDetune) && +                (fbConn == o.fbConn) && +                (delay_on_ms == o.delay_on_ms) && +                (delay_off_ms == o.delay_off_ms) && +                (std::memcmp(ops, o.ops, sizeof(int_fast32_t) * 5) == 0) +            ); +        } +        bool operator!=(const InstrumentEntry &o) +        { +            return !operator==(o); +        } +    }; + +    struct Operator +    { +        uint_fast32_t opId = 0; +        uint_fast32_t d_E862 = 0; +        uint_fast32_t d_40 = 0; +        explicit Operator() {} +        Operator(const Operator &o) +        { +            opId = o.opId; +            d_E862 = o.d_E862; +            d_40 = o.d_40; +        } +        bool operator==(const Operator &o) +        { +            return ((d_E862 == o.d_E862) && (d_40 == o.d_40)); +        } +        bool operator!=(const Operator &o) +        { +            return !operator==(o); +        } +    }; + +    std::vector<BankEntry>       banks; +    std::vector<MidiBank>        midiBanks; +    std::vector<InstrumentEntry> instruments; +    std::vector<Operator>        operators; + +    static void toOps(const insdata &inData, Operator *outData, size_t begin = 0); +    //! WIP +    static bool isSilent(const BanksDump &db, const BanksDump::InstrumentEntry &ins, bool moreInfo = false); +    static bool isSilent(const Operator *ops, uint_fast16_t fbConn, size_t countOps = 2, bool pseudo4op = false, bool moreInfo = false); + +    size_t initBank(size_t bankId, const std::string &title, uint_fast16_t bankSetup); +    void addMidiBank(size_t bankId, bool percussion, MidiBank b); +    void addInstrument(MidiBank &bank, size_t patchId, InstrumentEntry e, Operator *ops, const std::string &meta = std::string()); +    void exportBanks(const std::string &outPath, const std::string &headerName = "adlmidi_db.h"); +}; + + +namespace BankFormats +{ + +bool LoadMiles(BanksDump &db, const char *fn, unsigned bank, const std::string &bankTitle, const char *prefix); +bool LoadBisqwit(BanksDump &db, const char *fn, unsigned bank, const std::string &bankTitle, const char *prefix); +bool LoadBNK(BanksDump &db, const char *fn, unsigned bank, const std::string &bankTitle, const char *prefix, bool is_fat, bool percussive); +bool LoadBNK2(BanksDump &db, const char *fn, unsigned bank, const std::string &bankTitle, const char *prefix, +                     const std::string &melo_filter, +                     const std::string &perc_filter); +bool LoadEA(BanksDump &db, const char *fn, unsigned bank, const std::string &bankTitle, const char *prefix); +bool LoadIBK(BanksDump &db, const char *fn, unsigned bank, const std::string &bankTitle, const char *prefix, bool percussive, bool noRhythmMode = false); +bool LoadJunglevision(BanksDump &db, const char *fn, unsigned bank, const std::string &bankTitle, const char *prefix); +bool LoadDoom(BanksDump &db, const char *fn, unsigned bank, const std::string &bankTitle, const char *prefix); +bool LoadTMB(BanksDump &db, const char *fn, unsigned bank, const std::string &bankTitle, const char *prefix); +bool LoadWopl(BanksDump &db, const char *fn, unsigned bank, const std::string bankTitle, const char *prefix); + +} +  #endif // PROGS_H |