aboutsummaryrefslogtreecommitdiff
path: root/utils/gen_adldata/gen_adldata.cc
diff options
context:
space:
mode:
authorWohlstand <admin@wohlnet.ru>2017-10-20 04:28:53 +0300
committerWohlstand <admin@wohlnet.ru>2017-10-20 04:28:53 +0300
commiteb45a7913d83fe2a3dc03033230950e78fb9755d (patch)
treed7318e79b08404f293fb99bb22e0ed202e07d890 /utils/gen_adldata/gen_adldata.cc
parente95cde9fea4f9daf3e19492021b8a153acae0404 (diff)
downloadlibADLMIDI-eb45a7913d83fe2a3dc03033230950e78fb9755d.tar.gz
libADLMIDI-eb45a7913d83fe2a3dc03033230950e78fb9755d.tar.bz2
libADLMIDI-eb45a7913d83fe2a3dc03033230950e78fb9755d.zip
Added CMake support
Diffstat (limited to 'utils/gen_adldata/gen_adldata.cc')
-rw-r--r--utils/gen_adldata/gen_adldata.cc506
1 files changed, 506 insertions, 0 deletions
diff --git a/utils/gen_adldata/gen_adldata.cc b/utils/gen_adldata/gen_adldata.cc
new file mode 100644
index 0000000..6c77a12
--- /dev/null
+++ b/utils/gen_adldata/gen_adldata.cc
@@ -0,0 +1,506 @@
+//#ifdef __MINGW32__
+//typedef struct vswprintf {} swprintf;
+//#endif
+#include <cstdio>
+#include <string>
+#include <cstring>
+
+#include "ini/ini_processing.h"
+
+#include "progs_cache.h"
+#include "measurer.h"
+
+#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"
+
+int main(int argc, char**argv)
+{
+ if(argc == 1)
+ {
+ printf("Usage:\n"
+ "\n"
+ "bin/gen_adldata src/adldata.cpp\n"
+ "\n");
+ return 1;
+ }
+
+ const char *outFile_s = argv[1];
+
+ FILE *outFile = fopen(outFile_s, "w");
+ if(!outFile)
+ {
+ fprintf(stderr, "Can't open %s file for write!\n", outFile_s);
+ return 1;
+ }
+
+ fprintf(outFile, "\
+#include \"adldata.hh\"\n\
+\n\
+/* THIS OPL-3 FM INSTRUMENT DATA IS AUTOMATICALLY GENERATED\n\
+ * FROM A NUMBER OF SOURCES, MOSTLY PC GAMES.\n\
+ * PREPROCESSED, CONVERTED, AND POSTPROCESSED OFF-SCREEN.\n\
+ */\n\
+");
+ {
+ IniProcessing ini;
+ if(!ini.open("banks.ini"))
+ {
+ fprintf(stderr, "Can't open banks.ini!\n");
+ return 1;
+ }
+
+ uint32_t banks_count;
+ ini.beginGroup("General");
+ ini.read("banks", banks_count, 0);
+ ini.endGroup();
+
+ if(!banks_count)
+ {
+ fprintf(stderr, "Zero count of banks found in banks.ini!\n");
+ return 1;
+ }
+
+ for(uint32_t bank = 0; bank < banks_count; bank++)
+ {
+ if(!ini.beginGroup(std::string("bank-") + std::to_string(bank)))
+ {
+ fprintf(stderr, "Failed to find bank %u!\n", bank);
+ return 1;
+ }
+ std::string bank_name;
+ std::string filepath;
+ std::string filepath_d;
+ std::string prefix;
+ std::string prefix_d;
+ std::string filter_m;
+ std::string filter_p;
+ std::string format;
+
+ ini.read("name", bank_name, "Untitled");
+ ini.read("format", format, "Unknown");
+ ini.read("file", filepath, "");
+ ini.read("file-p", filepath_d, "");
+ ini.read("prefix", prefix, "");
+ ini.read("prefix-p", prefix_d, "");
+ ini.read("filter-m", filter_m, "");
+ ini.read("filter-p", filter_p, "");
+
+ if(filepath.empty())
+ {
+ fprintf(stderr, "Failed to load bank %u, file is empty!\n", bank);
+ return 1;
+ }
+
+ banknames.push_back(bank_name);
+
+ //printf("Loading %s...\n", filepath.c_str());
+
+ if(format == "AIL")
+ {
+ if(!LoadMiles(filepath.c_str(), bank, prefix.c_str()))
+ {
+ fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());
+ return 1;
+ }
+ }
+ else
+ if(format == "Bisqwit")
+ {
+ if(!LoadBisqwit(filepath.c_str(), bank, prefix.c_str()))
+ {
+ fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());
+ return 1;
+ }
+ }
+ else
+ if(format == "WOPL")
+ {
+ if(!LoadWopl(filepath.c_str(), bank, prefix.c_str()))
+ {
+ fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());
+ return 1;
+ }
+ }
+ else
+ if(format == "OP2")
+ {
+ if(!LoadDoom(filepath.c_str(), bank, prefix.c_str()))
+ {
+ fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());
+ return 1;
+ }
+ }
+ else
+ if(format == "TMB")
+ {
+ if(!LoadTMB(filepath.c_str(), bank, prefix.c_str()))
+ {
+ fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());
+ return 1;
+ }
+ }
+ else
+ if(format == "Junglevision")
+ {
+ if(!LoadJunglevision(filepath.c_str(), bank, prefix.c_str()))
+ {
+ fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());
+ return 1;
+ }
+ }
+ else
+ if(format == "AdLibGold")
+ {
+ if(!LoadBNK2(filepath.c_str(), bank, prefix.c_str(), filter_m, filter_p))
+ {
+ fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());
+ return 1;
+ }
+ }
+ else
+ if(format == "HMI")
+ {
+ if(!LoadBNK(filepath.c_str(), bank, prefix.c_str(), false, false))
+ {
+ 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))
+ {
+ fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());
+ return 1;
+ }
+ }
+ }
+ else
+ if(format == "IBK")
+ {
+ if(!LoadIBK(filepath.c_str(), bank, prefix.c_str(), false))
+ {
+ fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());
+ return 1;
+ }
+ if(!filepath_d.empty())
+ {
+ //printf("Loading %s... \n", filepath_d.c_str());
+ if(!LoadIBK(filepath_d.c_str(),bank, prefix_d.c_str(), true))
+ {
+ fprintf(stderr, "Failed to load bank %u, file %s!\n", bank, filepath.c_str());
+ return 1;
+ }
+ }
+ }
+ else
+ {
+ fprintf(stderr, "Failed to load bank %u, file %s!\nUnknown format type %s\n",
+ bank,
+ filepath.c_str(),
+ format.c_str());
+ return 1;
+ }
+
+
+ ini.endGroup();
+ }
+
+ printf("Loaded %u banks!\n", banks_count);
+ fflush(stdout);
+ }
+
+ #if 0
+ for(unsigned a = 0; a < 36 * 8; ++a)
+ {
+ if((1 << (a % 8)) > maxvalues[a / 8]) continue;
+
+ const std::map<unsigned, unsigned> &data = Correlate[a];
+ if(data.empty()) continue;
+ std::vector< std::pair<unsigned, unsigned> > correlations;
+ for(std::map<unsigned, unsigned>::const_iterator
+ i = data.begin();
+ i != data.end();
+ ++i)
+ {
+ correlations.push_back(std::make_pair(i->second, i->first));
+ }
+ std::sort(correlations.begin(), correlations.end());
+ fprintf(outFile, "Byte %2u bit %u=mask %02X:\n", a / 8, a % 8, 1 << (a % 8));
+ for(size_t c = 0; c < correlations.size() && c < 10; ++c)
+ {
+ unsigned count = correlations[correlations.size() - 1 - c ].first;
+ unsigned index = correlations[correlations.size() - 1 - c ].second;
+ fprintf(outFile, "\tAdldata index %u, bit %u=mask %02X (%u matches)\n",
+ index / 8, index % 8, 1 << (index % 8), count);
+ }
+ }
+ #endif
+
+ printf("Writing raw instrument data...\n");
+ fflush(stdout);
+ {
+ 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;
+ 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);
+
+ 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);
+
+ 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;
+ }
+ fprintf(outFile, " }, // %u: %s\n", (unsigned)c, names.c_str());
+ }
+ }
+ fprintf(outFile, "};\n");
+ }
+
+ /*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"
+ "} adlins[] =\n");*/
+
+ fprintf(outFile, "const struct adlinsdata adlins[%u] =\n", (unsigned)instab.size());
+ fprintf(outFile, "{\n");
+
+ MeasureThreaded measureCounter;
+ {
+ std::printf("Beginning to generate measures data... (Hardware concurrency: %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");
+ }
+
+ std::printf("Writing generated measure data...\n");
+ std::fflush(stdout);
+
+ std::vector<unsigned> adlins_flags;
+
+ 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;
+ //DurationInfo info = MeasureDurations(i->first);
+ MeasureThreaded::DurationInfoCache::iterator indo_i = measureCounter.m_durationInfo.find(i->first);
+ DurationInfo info = indo_i->second;
+ {
+ if(info.peak_amplitude_time == 0)
+ {
+ fprintf(outFile,
+ " // Amplitude begins at %6.1f,\n"
+ " // fades to 20%% at %.1fs, keyoff fades to 20%% in %.1fs.\n",
+ info.begin_amplitude,
+ info.quarter_amplitude_time / double(info.interval),
+ info.keyoff_out_time / double(info.interval));
+ }
+ else
+ {
+ fprintf(outFile,
+ " // Amplitude begins at %6.1f, peaks %6.1f at %.1fs,\n"
+ " // fades to 20%% at %.1fs, keyoff fades to 20%% in %.1fs.\n",
+ info.begin_amplitude,
+ info.peak_amplitude_value,
+ info.peak_amplitude_time / double(info.interval),
+ info.quarter_amplitude_time / double(info.interval),
+ info.keyoff_out_time / double(info.interval));
+ }
+ }
+
+ unsigned flags = (i->first.pseudo4op ? 1 : 0) | (info.nosound ? 2 : 0);
+
+ fprintf(outFile, " {");
+ fprintf(outFile, "%4d,%4d,%3d, %d, %6ld,%6ld,%lf",
+ (unsigned) i->first.insno1,
+ (unsigned) i->first.insno2,
+ (int)(i->first.notenum),
+ flags,
+ info.ms_sound_kon,
+ info.ms_sound_koff,
+ i->first.voice2_fine_tune);
+ 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;
+ }
+ fprintf(outFile, " }, // %u: %s\n\n", (unsigned)c, names.c_str());
+ fflush(outFile);
+ adlins_flags.push_back(flags);
+ }
+ fprintf(outFile, "};\n\n");
+
+
+ printf("Writing banks data...\n");
+ fflush(stdout);
+
+ //fprintf(outFile, "static const unsigned short banks[][256] =\n");
+ #ifdef HARD_BANKS
+ const unsigned bankcount = sizeof(banknames) / sizeof(*banknames);
+ #else
+ const size_t bankcount = banknames.size();
+ #endif
+
+ size_t nosound = InsertNoSoundIns();
+
+ std::map<size_t, std::vector<size_t> > bank_data;
+ for(size_t bank = 0; bank < bankcount; ++bank)
+ {
+ //bool redundant = true;
+ std::vector<size_t> data(256);
+ for(size_t p = 0; p < 256; ++p)
+ {
+ size_t v = progs[bank][p];
+ if(v == 0 || (adlins_flags[v - 1] & 2))
+ v = nosound; // Blank.in
+ else
+ v -= 1;
+ data[p] = v;
+ }
+ bank_data[bank] = data;
+ }
+ std::set<size_t> listed;
+
+ fprintf(outFile,
+ "\n\n//Returns total number of generated banks\n"
+ "int maxAdlBanks()\n"
+ "{"
+ " return %u;\n"
+ "}\n\n"
+ "const char* const banknames[%u] =\n", (unsigned int)bankcount, (unsigned int)bankcount);
+ fprintf(outFile, "{\n");
+ for(unsigned bank = 0; bank < bankcount; ++bank)
+ fprintf(outFile, " \"%s\",\n", banknames[bank].c_str());
+ fprintf(outFile, "};\n");
+
+ fprintf(outFile, "const unsigned short banks[%u][256] =\n", (unsigned int)bankcount);
+ fprintf(outFile, "{\n");
+ for(unsigned bank = 0; bank < bankcount; ++bank)
+ {
+ fprintf(outFile, " { // bank %u, %s\n", bank, banknames[bank].c_str());
+ bool redundant = true;
+ for(unsigned p = 0; p < 256; ++p)
+ {
+ size_t v = bank_data[bank][p];
+ if(listed.find(v) == listed.end())
+ {
+ listed.insert(v);
+ redundant = false;
+ }
+ fprintf(outFile, "%4d,", (unsigned int)v);
+ if(p % 16 == 15) fprintf(outFile, "\n");
+ }
+ fprintf(outFile, " },\n");
+ if(redundant)
+ {
+ fprintf(outFile, " // Bank %u defines nothing new.\n", bank);
+ for(unsigned refbank = 0; refbank < bank; ++refbank)
+ {
+ bool match = true;
+ for(unsigned p = 0; p < 256; ++p)
+ if(bank_data[bank][p] != nosound
+ && bank_data[bank][p] != bank_data[refbank][p])
+ {
+ match = false;
+ break;
+ }
+ if(match)
+ fprintf(outFile, " // Bank %u is just a subset of bank %u!\n",
+ bank, refbank);
+ }
+ }
+ }
+
+ fprintf(outFile, "};\n");
+ fflush(outFile);
+ fclose(outFile);
+
+ printf("Generation of ADLMIDI data has been completed!\n");
+ fflush(stdout);
+}