aboutsummaryrefslogtreecommitdiff
path: root/utils/gen_adldata
diff options
context:
space:
mode:
Diffstat (limited to 'utils/gen_adldata')
-rw-r--r--utils/gen_adldata/CMakeLists.txt25
-rw-r--r--utils/gen_adldata/file_formats/common.h27
-rw-r--r--utils/gen_adldata/file_formats/load_ail.h161
-rw-r--r--utils/gen_adldata/file_formats/load_bisqwit.h46
-rw-r--r--utils/gen_adldata/file_formats/load_bnk.h37
-rw-r--r--utils/gen_adldata/file_formats/load_bnk2.h62
-rw-r--r--utils/gen_adldata/file_formats/load_ea.h61
-rw-r--r--utils/gen_adldata/file_formats/load_ibk.h42
-rw-r--r--utils/gen_adldata/file_formats/load_jv.h43
-rw-r--r--utils/gen_adldata/file_formats/load_op2.h46
-rw-r--r--utils/gen_adldata/file_formats/load_tmb.h40
-rw-r--r--utils/gen_adldata/file_formats/load_wopl.h87
-rw-r--r--utils/gen_adldata/gen_adldata.cc202
-rw-r--r--utils/gen_adldata/measurer.cpp790
-rw-r--r--utils/gen_adldata/measurer.h23
-rw-r--r--utils/gen_adldata/progs_cache.cpp571
-rw-r--r--utils/gen_adldata/progs_cache.h346
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