aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/adlmidi-2/9x15.hpp10
-rw-r--r--utils/adlmidi-2/midiplay.cc3
-rw-r--r--utils/adlmidi-2/puzzlegame.cc2
-rwxr-xr-xutils/adlmidi-2/puzzlegame.hpp2
-rw-r--r--utils/dumpbank/dumpbank.cpp7
-rw-r--r--utils/dumpmiles/dumpmiles.cpp9
-rw-r--r--utils/gen_adldata/file_formats/load_ail.h1
-rw-r--r--utils/gen_adldata/file_formats/load_bisqwit.h1
-rw-r--r--utils/gen_adldata/file_formats/load_bnk.h4
-rw-r--r--utils/gen_adldata/file_formats/load_bnk2.h10
-rw-r--r--utils/gen_adldata/file_formats/load_ea.h5
-rw-r--r--utils/gen_adldata/file_formats/load_ibk.h1
-rw-r--r--utils/gen_adldata/file_formats/load_jv.h1
-rw-r--r--utils/gen_adldata/file_formats/load_op2.h3
-rw-r--r--utils/gen_adldata/file_formats/load_tmb.h1
-rw-r--r--utils/gen_adldata/file_formats/load_wopl.h9
-rw-r--r--utils/gen_adldata/gen_adldata.cc43
-rw-r--r--utils/gen_adldata/ini/ini_processing.cpp45
-rw-r--r--utils/gen_adldata/ini/ini_processing.h44
-rw-r--r--utils/gen_adldata/ini/ini_processing_variant.h50
-rw-r--r--utils/gen_adldata/measurer.cpp480
-rw-r--r--utils/gen_adldata/measurer.h3
-rw-r--r--utils/gen_adldata/progs_cache.cpp2
-rw-r--r--utils/gen_adldata/progs_cache.h4
-rw-r--r--utils/midiplay/adlmidiplay.cpp5
-rw-r--r--utils/vlc_codec/libadlmidi.c189
26 files changed, 553 insertions, 381 deletions
diff --git a/utils/adlmidi-2/9x15.hpp b/utils/adlmidi-2/9x15.hpp
index e535d49..76e0660 100644
--- a/utils/adlmidi-2/9x15.hpp
+++ b/utils/adlmidi-2/9x15.hpp
@@ -160,8 +160,8 @@ struct font9x15: public UIfontBase
virtual unsigned GetIndex(char32_t c) const { return ns_font9x15::unicode_to_bitmap_index[c]; }
};
-static UIfontBase* Getfont9x15()
-{
- static font9x15 f;
- return &f;
-}
+//static UIfontBase* Getfont9x15()
+//{
+// static font9x15 f;
+// return &f;
+//}
diff --git a/utils/adlmidi-2/midiplay.cc b/utils/adlmidi-2/midiplay.cc
index b670083..74806eb 100644
--- a/utils/adlmidi-2/midiplay.cc
+++ b/utils/adlmidi-2/midiplay.cc
@@ -1593,6 +1593,7 @@ int main(int argc, char **argv)
UI.Color(7);
std::fflush(stderr);
std::printf(
+ "\n\n"
"Usage: adlmidi <midifilename> [ <options> ] [ <banknumber> [ <numcards> [ <numfourops>] ] ]\n"
" adlmidi <midifilename> -1 To enter instrument tester\n"
" -p Enables adlib percussion instrument mode (use with CMF files)\n"
@@ -1758,7 +1759,7 @@ int main(int argc, char **argv)
if(argc >= 3)
{
- if(is_number(argv[2]))
+ if(is_number(argv[2]) || !strcmp(argv[2], "-1"))
{
int bankno = std::atoi(argv[2]);
if(bankno == -1)
diff --git a/utils/adlmidi-2/puzzlegame.cc b/utils/adlmidi-2/puzzlegame.cc
index e9d2b9b..f8fa57c 100644
--- a/utils/adlmidi-2/puzzlegame.cc
+++ b/utils/adlmidi-2/puzzlegame.cc
@@ -4,6 +4,8 @@
#include "input.hpp"
#include "puzzlegame.hpp"
+char ADLMIDI_PuzzleGame::peeked_input = 0;
+
unsigned long ADLMIDI_PuzzleGame::TimerRead()
{
static std::chrono::time_point<std::chrono::system_clock> begin = std::chrono::system_clock::now();
diff --git a/utils/adlmidi-2/puzzlegame.hpp b/utils/adlmidi-2/puzzlegame.hpp
index 03ad921..a35f1cb 100755
--- a/utils/adlmidi-2/puzzlegame.hpp
+++ b/utils/adlmidi-2/puzzlegame.hpp
@@ -36,7 +36,7 @@ namespace ADLMIDI_PuzzleGame
void Sound(unsigned/*freq*/, unsigned/*duration*/);
void PutCell(int x, int y, unsigned cell);
void ScreenPutString(const char* str, unsigned attr, unsigned column, unsigned row);
- static char peeked_input = 0;
+ extern char peeked_input;
bool kbhit();
char getch();
diff --git a/utils/dumpbank/dumpbank.cpp b/utils/dumpbank/dumpbank.cpp
index 84283e7..d2df74a 100644
--- a/utils/dumpbank/dumpbank.cpp
+++ b/utils/dumpbank/dumpbank.cpp
@@ -190,5 +190,12 @@ static void LoadBNK(const char* fn)
int main(int argc, const char* const* argv)
{
+ if(argc < 2)
+ {
+ std::printf("Usage: \n"
+ " %s filename.bnk\n"
+ "\n", argv[0]);
+ return 1;
+ }
LoadBNK(argv[1]);
}
diff --git a/utils/dumpmiles/dumpmiles.cpp b/utils/dumpmiles/dumpmiles.cpp
index 0c2d51b..a1a3816 100644
--- a/utils/dumpmiles/dumpmiles.cpp
+++ b/utils/dumpmiles/dumpmiles.cpp
@@ -49,5 +49,14 @@ static void LoadMiles(const char* fn)
int main(int argc, const char* const* argv)
{
+ if(argc < 2)
+ {
+ std::printf("Usage: \n"
+ " %s filename.opl\n"
+ "or:\n"
+ " %s filename.opl\n"
+ "\n", argv[0], argv[0]);
+ return 1;
+ }
LoadMiles(argv[1]);
}
diff --git a/utils/gen_adldata/file_formats/load_ail.h b/utils/gen_adldata/file_formats/load_ail.h
index a10ff92..e63b1d7 100644
--- a/utils/gen_adldata/file_formats/load_ail.h
+++ b/utils/gen_adldata/file_formats/load_ail.h
@@ -89,6 +89,7 @@ static bool LoadMiles(const char *fn, unsigned bank, const char *prefix)
struct ins tmp2;
tmp2.notenum = gmno < 128 ? 0 : (unsigned char)notenum;
tmp2.pseudo4op = false;
+ tmp2.real4op = (inscount > 1);
tmp2.voice2_fine_tune = 0.0;
std::string name;
if(midi_index >= 0) name = std::string(1, '\377') + MidiInsName[midi_index];
diff --git a/utils/gen_adldata/file_formats/load_bisqwit.h b/utils/gen_adldata/file_formats/load_bisqwit.h
index 015b0eb..f5f73dc 100644
--- a/utils/gen_adldata/file_formats/load_bisqwit.h
+++ b/utils/gen_adldata/file_formats/load_bisqwit.h
@@ -44,6 +44,7 @@ static bool LoadBisqwit(const char *fn, unsigned bank, const char *prefix)
(gmno < 128 ? 'M' : 'P'), gmno & 127);
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);
}
diff --git a/utils/gen_adldata/file_formats/load_bnk.h b/utils/gen_adldata/file_formats/load_bnk.h
index a41185a..aa7701f 100644
--- a/utils/gen_adldata/file_formats/load_bnk.h
+++ b/utils/gen_adldata/file_formats/load_bnk.h
@@ -69,7 +69,8 @@ static bool LoadBNK(const char *fn, unsigned bank, const char *prefix, bool is_f
if(name[2] == 'O'
|| name[2] == 'S')
{
- gmno = 128 + std::stoi(name.substr(3));
+ std::string n = name.substr(3);
+ gmno = 128 + std::atoi(n.c_str());
}
}
@@ -107,6 +108,7 @@ static bool LoadBNK(const char *fn, unsigned bank, const char *prefix, bool is_f
ins tmp2;
tmp2.notenum = is_fat ? voice_num : (percussive ? usage_flag : 0);
tmp2.pseudo4op = false;
+ tmp2.real4op = false;
tmp2.voice2_fine_tune = 0.0;
if(is_fat) tmp.data[10] ^= 1;
diff --git a/utils/gen_adldata/file_formats/load_bnk2.h b/utils/gen_adldata/file_formats/load_bnk2.h
index 1f3d4a1..4772da5 100644
--- a/utils/gen_adldata/file_formats/load_bnk2.h
+++ b/utils/gen_adldata/file_formats/load_bnk2.h
@@ -3,6 +3,11 @@
#include "../progs_cache.h"
+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)
@@ -43,9 +48,9 @@ static bool LoadBNK2(const char *fn, unsigned bank, const char *prefix,
int gmno = 0;
if(name.substr(0, melo_filter.size()) == melo_filter)
- gmno = std::stoi(name.substr(melo_filter.size()));
+ gmno = stdstoi(name.substr(melo_filter.size()));
else if(name.substr(0, perc_filter.size()) == perc_filter)
- gmno = std::stoi(name.substr(perc_filter.size())) + 128;
+ gmno = stdstoi(name.substr(perc_filter.size())) + 128;
else
continue;
@@ -81,6 +86,7 @@ static bool LoadBNK2(const char *fn, unsigned bank, const char *prefix,
ins tmp2;
tmp2.notenum = (gmno & 128) ? 35 : 0;
tmp2.pseudo4op = false;
+ tmp2.real4op = false;
tmp2.voice2_fine_tune = 0.0;
if(xxP24NNN & 8)
diff --git a/utils/gen_adldata/file_formats/load_ea.h b/utils/gen_adldata/file_formats/load_ea.h
index 5e0baa4..79367d9 100644
--- a/utils/gen_adldata/file_formats/load_ea.h
+++ b/utils/gen_adldata/file_formats/load_ea.h
@@ -85,16 +85,17 @@ static bool LoadEA(const char *fn, unsigned bank, const char *prefix)
ins tmp2{};
tmp2.notenum = 0;
tmp2.pseudo4op = false;
+ tmp2.real4op = false;
std::string name;
char name2[512];
if(gmno < 20)
{
- std::snprintf(name2, 512, "%sM%u", prefix, gmno);
+ snprintf(name2, 512, "%sM%u", prefix, gmno);
}
else
{
- std::snprintf(name2, 512, "%sunk%04X", prefix, offset);
+ snprintf(name2, 512, "%sunk%04X", prefix, offset);
}
size_t resno = InsertIns(tmp, tmp2, std::string(1, '\377') + name, name2);
SetBank(bank, gmno, resno);
diff --git a/utils/gen_adldata/file_formats/load_ibk.h b/utils/gen_adldata/file_formats/load_ibk.h
index bc03962..12fa520 100644
--- a/utils/gen_adldata/file_formats/load_ibk.h
+++ b/utils/gen_adldata/file_formats/load_ibk.h
@@ -61,6 +61,7 @@ static bool LoadIBK(const char *fn, unsigned bank, const char *prefix, bool perc
struct ins tmp2;
tmp2.notenum = gmno < 128 ? 0 : 35;
tmp2.pseudo4op = false;
+ tmp2.real4op = false;
tmp2.voice2_fine_tune = 0.0;
size_t resno = InsertIns(tmp, tmp2, std::string(1, '\377') + name, name2);
diff --git a/utils/gen_adldata/file_formats/load_jv.h b/utils/gen_adldata/file_formats/load_jv.h
index b79832f..35caead 100644
--- a/utils/gen_adldata/file_formats/load_jv.h
+++ b/utils/gen_adldata/file_formats/load_jv.h
@@ -71,6 +71,7 @@ static bool LoadJunglevision(const char *fn, unsigned bank, const char *prefix)
struct ins tmp2;
tmp2.notenum = data[offset + 1];
tmp2.pseudo4op = false;
+ tmp2.real4op = (data[offset] != 0);
tmp2.voice2_fine_tune = 0.0;
while(tmp2.notenum && tmp2.notenum < 20)
diff --git a/utils/gen_adldata/file_formats/load_op2.h b/utils/gen_adldata/file_formats/load_op2.h
index 8b7fec6..48b7eae 100644
--- a/utils/gen_adldata/file_formats/load_op2.h
+++ b/utils/gen_adldata/file_formats/load_op2.h
@@ -82,7 +82,7 @@ static bool LoadDoom(const char *fn, unsigned bank, const char *prefix)
int gmno = int(a < 128 ? a : ((a | 128) + 35));
char name2[512];
- std::snprintf(name2, 512, "%s%c%u", prefix, (gmno < 128 ? 'M' : 'P'), gmno & 127);
+ snprintf(name2, 512, "%s%c%u", prefix, (gmno < 128 ? 'M' : 'P'), gmno & 127);
Doom_opl_instr &ins = *(Doom_opl_instr *) &data[offset2];
@@ -108,6 +108,7 @@ static bool LoadDoom(const char *fn, unsigned bank, const char *prefix)
struct ins tmp2;
tmp2.notenum = ins.note;
tmp2.pseudo4op = false;
+ tmp2.real4op = false;
tmp2.voice2_fine_tune = 0.0;
while(tmp2.notenum && tmp2.notenum < 20)
{
diff --git a/utils/gen_adldata/file_formats/load_tmb.h b/utils/gen_adldata/file_formats/load_tmb.h
index ab1ff37..5b38433 100644
--- a/utils/gen_adldata/file_formats/load_tmb.h
+++ b/utils/gen_adldata/file_formats/load_tmb.h
@@ -50,6 +50,7 @@ static bool LoadTMB(const char *fn, unsigned bank, const char *prefix)
struct ins tmp2;
tmp2.notenum = data[offset + 11];
tmp2.pseudo4op = false;
+ tmp2.real4op = false;
tmp2.voice2_fine_tune = 0.0;
std::string name;
diff --git a/utils/gen_adldata/file_formats/load_wopl.h b/utils/gen_adldata/file_formats/load_wopl.h
index 26a2611..fe4865d 100644
--- a/utils/gen_adldata/file_formats/load_wopl.h
+++ b/utils/gen_adldata/file_formats/load_wopl.h
@@ -57,8 +57,8 @@ static bool LoadWopl(const char *fn, unsigned bank, const char *prefix)
uint16_t pbanks_count = toUint16BE((const uint8_t *)data.data() + 0x0f);
AdlBankSetup setup;
- setup.deepTremolo = (data[0x11] >> 0) & 0x01;
- setup.deepVibrato = (data[0x11] >> 1) & 0x01;
+ setup.deepTremolo = (data[0x11] & 0x01) != 0;
+ setup.deepVibrato = (data[0x11] & 0x02) != 0;
setup.volumeModel = (int)data[0x12];
setup.adLibPercussions = false;
setup.scaleModulators = false;
@@ -169,6 +169,7 @@ static bool LoadWopl(const char *fn, unsigned bank, const char *prefix)
tmp2.notenum = is_percussion ? data[offset + 38] : 0;
bool real4op = (flags & (uint8_t)WOPL_Flags::Mode_4op) != 0;
tmp2.pseudo4op = (flags & (uint8_t)WOPL_Flags::Mode_DoubleVoice) != 0;
+ tmp2.real4op = real4op && !tmp2.pseudo4op;
tmp2.voice2_fine_tune = 0;
tmp[0].diff = false;
tmp[1].diff = real4op && !tmp2.pseudo4op;
@@ -207,9 +208,9 @@ static bool LoadWopl(const char *fn, unsigned bank, const char *prefix)
char name2[512];
std::memset(name2, 0, 512);
if(is_percussion)
- std::snprintf(name2, 512, "%sP%u", prefix, gmno & 127);
+ snprintf(name2, 512, "%sP%u", prefix, gmno & 127);
else
- std::snprintf(name2, 512, "%sM%u", prefix, i);
+ snprintf(name2, 512, "%sM%u", prefix, i);
if(!real4op && !tmp2.pseudo4op)
{
diff --git a/utils/gen_adldata/gen_adldata.cc b/utils/gen_adldata/gen_adldata.cc
index 7c8af8b..bc5c231 100644
--- a/utils/gen_adldata/gen_adldata.cc
+++ b/utils/gen_adldata/gen_adldata.cc
@@ -312,7 +312,7 @@ int main(int argc, char**argv)
i->first.data[10],
i->first.finetune);
- #ifdef ADLDATA_WITH_COMMENTS
+#ifdef ADLDATA_WITH_COMMENTS
std::string names;
for(std::set<std::string>::const_iterator
j = i->second.second.begin();
@@ -326,9 +326,9 @@ int main(int argc, char**argv)
names += *j;
}
std::fprintf(outFile, " }, // %u: %s\n", (unsigned)c, names.c_str());
- #else
+#else
std::fprintf(outFile, " },\n");
- #endif
+#endif
}
}
std::fprintf(outFile, "};\n");
@@ -341,6 +341,7 @@ int main(int argc, char**argv)
" 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());
@@ -348,7 +349,7 @@ int main(int argc, char**argv)
MeasureThreaded measureCounter;
{
- std::printf("Beginning to generate measures data... (Hardware concurrency: %d)\n", std::thread::hardware_concurrency());
+ 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();
@@ -381,7 +382,7 @@ int main(int argc, char**argv)
//DurationInfo info = MeasureDurations(i->first);
MeasureThreaded::DurationInfoCache::iterator indo_i = measureCounter.m_durationInfo.find(i->first);
DurationInfo info = indo_i->second;
- #ifdef ADLDATA_WITH_COMMENTS
+#ifdef ADLDATA_WITH_COMMENTS
{
if(info.peak_amplitude_time == 0)
{
@@ -404,12 +405,14 @@ int main(int argc, char**argv)
info.keyoff_out_time / double(info.interval));
}
}
- #endif
+#endif
- unsigned flags = (i->first.pseudo4op ? 1 : 0) | (info.nosound ? 2 : 0);
+ unsigned flags = (i->first.pseudo4op ? ins::Flag_Pseudo4op : 0)|
+ (i->first.real4op ? ins::Flag_Real4op : 0) |
+ (info.nosound ? ins::Flag_NoSound : 0);
std::fprintf(outFile, " {");
- std::fprintf(outFile, "%4d,%4d,%3d, %d, %6" PRId64 ",%6" PRId64 ",%lf",
+ std::fprintf(outFile, "%4d,%4d,%3d, %d, %6" PRId64 ",%6" PRId64 ",%g",
(unsigned) i->first.insno1,
(unsigned) i->first.insno2,
(int)(i->first.notenum),
@@ -429,11 +432,11 @@ int main(int argc, char**argv)
else
names += *j;
}
- #ifdef ADLDATA_WITH_COMMENTS
+#ifdef ADLDATA_WITH_COMMENTS
std::fprintf(outFile, " }, // %u: %s\n\n", (unsigned)c, names.c_str());
- #else
+#else
std::fprintf(outFile, " },\n");
- #endif
+#endif
std::fflush(outFile);
adlins_flags.push_back(flags);
}
@@ -444,11 +447,11 @@ int main(int argc, char**argv)
std::fflush(stdout);
//fprintf(outFile, "static const unsigned short banks[][256] =\n");
- #ifdef HARD_BANKS
+#ifdef HARD_BANKS
const unsigned bankcount = sizeof(banknames) / sizeof(*banknames);
- #else
+#else
const size_t bankcount = banknames.size();
- #endif
+#endif
size_t nosound = InsertNoSoundIns();
@@ -486,25 +489,29 @@ int main(int argc, char**argv)
std::fprintf(outFile, "{\n");
for(unsigned bank = 0; bank < bankcount; ++bank)
{
- #ifdef ADLDATA_WITH_COMMENTS
+#ifdef ADLDATA_WITH_COMMENTS
std::fprintf(outFile, " { // bank %u, %s\n", bank, banknames[bank].c_str());
- #else
+#else
std::fprintf(outFile, " {\n");
#endif
+#ifdef ADLDATA_WITH_COMMENTS
bool redundant = true;
+#endif
for(unsigned p = 0; p < 256; ++p)
{
size_t v = bank_data[bank][p];
if(listed.find(v) == listed.end())
{
listed.insert(v);
+#ifdef ADLDATA_WITH_COMMENTS
redundant = false;
+#endif
}
std::fprintf(outFile, "%4d,", (unsigned int)v);
if(p % 16 == 15) fprintf(outFile, "\n");
}
std::fprintf(outFile, " },\n");
- #ifdef ADLDATA_WITH_COMMENTS
+#ifdef ADLDATA_WITH_COMMENTS
if(redundant)
{
std::fprintf(outFile, " // Bank %u defines nothing new.\n", bank);
@@ -523,7 +530,7 @@ int main(int argc, char**argv)
bank, refbank);
}
}
- #endif
+#endif
}
std::fprintf(outFile, "};\n\n");
diff --git a/utils/gen_adldata/ini/ini_processing.cpp b/utils/gen_adldata/ini/ini_processing.cpp
index 26da540..8a2807b 100644
--- a/utils/gen_adldata/ini/ini_processing.cpp
+++ b/utils/gen_adldata/ini/ini_processing.cpp
@@ -1,27 +1,26 @@
/*
-INI Processor - a small library which allows you parsing INI-files
-
-Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation the
-rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-sell copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-
-*/
+ * INI Processor - a small library which allows you parsing INI-files
+ *
+ * Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
//#define USE_FILE_MAPPER
diff --git a/utils/gen_adldata/ini/ini_processing.h b/utils/gen_adldata/ini/ini_processing.h
index 8da4b7e..64777a5 100644
--- a/utils/gen_adldata/ini/ini_processing.h
+++ b/utils/gen_adldata/ini/ini_processing.h
@@ -1,26 +1,26 @@
/*
-INI Processor - a small library which allows you parsing INI-files
-
-Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation the
-rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-sell copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-*/
+ * INI Processor - a small library which allows you parsing INI-files
+ *
+ * Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
#ifndef INIPROCESSING_H
#define INIPROCESSING_H
diff --git a/utils/gen_adldata/ini/ini_processing_variant.h b/utils/gen_adldata/ini/ini_processing_variant.h
index 41a96dd..d659aa9 100644
--- a/utils/gen_adldata/ini/ini_processing_variant.h
+++ b/utils/gen_adldata/ini/ini_processing_variant.h
@@ -1,31 +1,31 @@
/*
-INI Processor - a small library which allows you parsing INI-files
-
-Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation the
-rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-sell copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-*/
+ * INI Processor - a small library which allows you parsing INI-files
+ *
+ * Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
/*
-A QVariant-like thing created just like a proxy between
-INI Processor and target value (to be compatible with QSettings)
-*/
+ * A QVariant-like thing created just like a proxy between
+ * INI Processor and target value (to be compatible with QSettings)
+ */
#ifndef INI_PROCESSING_VARIANT_H
#define INI_PROCESSING_VARIANT_H
diff --git a/utils/gen_adldata/measurer.cpp b/utils/gen_adldata/measurer.cpp
index 7a81379..7caf883 100644
--- a/utils/gen_adldata/measurer.cpp
+++ b/utils/gen_adldata/measurer.cpp
@@ -1,7 +1,9 @@
#include "measurer.h"
#include <cmath>
-#include "../../src/chips/opl_chip_base.h"
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
// Nuked OPL3 emulator, Most accurate, but requires the powerful CPU
#ifndef ADLMIDI_DISABLE_NUKED_EMULATOR
@@ -14,208 +16,367 @@
# include "../../src/chips/dosbox_opl3.h"
#endif
-DurationInfo MeasureDurations(const ins &in)
+template <class T>
+class AudioHistory
{
- std::vector<int16_t> stereoSampleBuf;
-#ifdef ADLMIDI_USE_DOSBOX_OPL
- std::vector<int32_t> stereoSampleBuf_32;
-#endif
- insdata id[2];
- bool found[2] = {false, false};
- for(InstrumentDataTab::const_iterator j = insdatatab.begin();
- j != insdatatab.end();
- ++j)
+ std::unique_ptr<T[]> m_data;
+ size_t m_index = 0; // points to the next write slot
+ size_t m_length = 0;
+ size_t m_capacity = 0;
+
+public:
+ size_t size() const { return m_length; }
+ size_t capacity() const { return m_capacity; }
+ const T *data() const { return &m_data[m_index + m_capacity - m_length]; }
+
+ void reset(size_t capacity)
{
- if(j->second.first == in.insno1)
- {
- id[0] = j->first;
- found[0] = true;
- if(found[1]) break;
- }
- if(j->second.first == in.insno2)
- {
- id[1] = j->first;
- found[1] = true;
- if(found[0]) break;
- }
+ m_data.reset(new T[2 * capacity]());
+ m_index = 0;
+ m_length = 0;
+ m_capacity = capacity;
}
- const unsigned rate = 22010;
- const unsigned interval = 150;
- const unsigned samples_per_interval = rate / interval;
- const int notenum =
- in.notenum < 20 ? (44 + in.notenum)
- : in.notenum >= 128 ? (44 + 128 - in.notenum)
- : in.notenum;
- OPLChipBase *opl;
+ void clear()
+ {
+ m_length = 0;
+ }
- //DosBoxOPL3 db; opl = &db;
- //NukedOPL3 nuke; opl = &nuke;
- NukedOPL3v174 nuke74; opl = &nuke74;
+ void add(const T &item)
+ {
+ T *data = m_data.get();
+ const size_t capacity = m_capacity;
+ size_t index = m_index;
+ data[index] = item;
+ data[index + capacity] = item;
+ m_index = (index + 1 != capacity) ? (index + 1) : 0;
+ size_t length = m_length + 1;
+ m_length = (length < capacity) ? length : capacity;
+ }
+};
-#define WRITE_REG(key, value) opl->writeReg((uint16_t)(key), (uint8_t)(value))
+static void HannWindow(double *w, unsigned n)
+{
+ for (unsigned i = 0; i < n; ++i)
+ w[i] = 0.5 * (1.0 - std::cos(2 * M_PI * i / (n - 1)));
+}
- static const short initdata[(2 + 3 + 2 + 2) * 2] =
+static double MeasureRMS(const double *signal, const double *window, unsigned length)
+{
+ double mean = 0;
+#pragma omp simd reduction(+: mean)
+ for(unsigned i = 0; i < length; ++i)
+ mean += window[i] * signal[i];
+ mean /= length;
+
+ double rms = 0;
+#pragma omp simd reduction(+: rms)
+ for(unsigned i = 0; i < length; ++i)
{
- 0x004, 96, 0x004, 128, // Pulse timer
- 0x105, 0, 0x105, 1, 0x105, 0, // Pulse OPL3 enable, leave disabled
- 0x001, 32, 0x0BD, 0 // Enable wave & melodic
- };
- opl->setRate(rate);
+ double diff = window[i] * signal[i] - mean;
+ rms += diff * diff;
+ }
+ rms = std::sqrt(rms / (length - 1));
- for(unsigned a = 0; a < 18; a += 2) WRITE_REG(initdata[a], initdata[a + 1]);
+ return rms;
+}
- const unsigned n_notes = in.insno1 == in.insno2 ? 1 : 2;
- unsigned x[2];
+static const unsigned g_outputRate = 49716;
- if(n_notes == 2 && !in.pseudo4op)
+struct TinySynth
+{
+ OPLChipBase *m_chip;
+ unsigned m_notesNum;
+ int m_notenum;
+ int8_t m_fineTune;
+ int16_t m_noteOffsets[2];
+ unsigned m_x[2];
+
+ void resetChip()
{
- WRITE_REG(0x105, 1);
- WRITE_REG(0x104, 1);
- }
+ static const short initdata[(2 + 3 + 2 + 2) * 2] =
+ {
+ 0x004, 96, 0x004, 128, // Pulse timer
+ 0x105, 0, 0x105, 1, 0x105, 0, // Pulse OPL3 enable, leave disabled
+ 0x001, 32, 0x0BD, 0 // Enable wave & melodic
+ };
- for(unsigned n = 0; n < n_notes; ++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) WRITE_REG(patchdata[a] + n * 8, id[n].data[a]);
- WRITE_REG(patchdata[10] + n * 8, id[n].data[10] | 0x30);
+ 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(unsigned n = 0; n < n_notes; ++n)
+ void setInstrument(const ins &in)
{
- double hertz = 172.00093 * std::exp(0.057762265 * (notenum + id[n].finetune));
- if(hertz > 131071)
+ 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_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)
{
- std::fprintf(stderr, "MEASURER WARNING: Why does note %d + finetune %d produce hertz %g? \n",
- notenum, id[n].finetune, hertz);
- hertz = 131071;
+ m_chip->writeReg(0x105, 1);
+ m_chip->writeReg(0x104, 0xFF);
}
- x[n] = 0x2000;
- while(hertz >= 1023.5)
+
+ //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;
+
+ for(unsigned n = 0; n < m_notesNum; ++n)
{
- hertz /= 2.0; // Calculate octave
- x[n] += 0x400;
+ 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);
}
- x[n] += (unsigned int)(hertz + 0.5);
+ }
+
+ void noteOn()
+ {
+ std::memset(m_x, 0, sizeof(m_x));
+ for(unsigned n = 0; n < m_notesNum; ++n)
+ {
+ double hertz = 172.00093 * std::exp(0.057762265 * (m_notenum + 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);
+ std::fflush(stdout);
+ hertz = 131071;
+ }
+ m_x[n] = 0x2000;
+ while(hertz >= 1023.5)
+ {
+ hertz /= 2.0; // Calculate octave
+ m_x[n] += 0x400;
+ }
+ m_x[n] += (unsigned int)(hertz + 0.5);
- // Keyon the note
- WRITE_REG(0xA0 + n * 3, x[n] & 0xFF);
- WRITE_REG(0xB0 + n * 3, x[n] >> 8);
+ // Keyon the note
+ m_chip->writeReg(0xA0 + n * 3, m_x[n] & 0xFF);
+ m_chip->writeReg(0xB0 + n * 3, m_x[n] >> 8);
+ }
+ }
+
+ void noteOff()
+ {
+ // Keyoff the note
+ for(unsigned n = 0; n < m_notesNum; ++n)
+ m_chip->writeReg(0xB0 + n * 3, (m_x[n] >> 8) & 0xDF);
}
+ void generate(int16_t *output, size_t frames)
+ {
+ m_chip->generate(output, frames);
+ }
+};
+
+
+DurationInfo MeasureDurations(const ins &in, 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(in);
+ synth.noteOn();
+
+ /* 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.
- std::vector<double> amplitudecurve_on;
double highest_sofar = 0;
short sound_min = 0, sound_max = 0;
- for(unsigned period = 0; period < max_on * interval; ++period)
+
+ for(unsigned period = 0; period < max_period_on; ++period, ++windows_passed_on)
{
- stereoSampleBuf.clear();
- stereoSampleBuf.resize(samples_per_interval * 2);
- opl->generate(stereoSampleBuf.data(), samples_per_interval);
+ 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)
+ {
+ 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;
+ }
- double mean = 0.0;
- for(unsigned long c = 0; c < samples_per_interval; ++c)
+ if(winsize != audioHistory.size())
{
- short s = stereoSampleBuf[c * 2];
- mean += s;
- if(sound_min > s) sound_min = s;
- if(sound_max < s) sound_max = s;
+ winsize = audioHistory.size();
+ HannWindow(window.get(), winsize);
}
- mean /= samples_per_interval;
- double std_deviation = 0;
- for(unsigned long c = 0; c < samples_per_interval; ++c)
+
+ 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)
{
- double diff = (stereoSampleBuf[c * 2] - mean);
- std_deviation += diff * diff;
+ peak_amplitude_value = rms;
+ peak_amplitude_time = period;
+ // In next step, update the quater amplitude time
+ quarter_amplitude_time_found = false;
}
- std_deviation = std::sqrt(std_deviation / samples_per_interval);
- amplitudecurve_on.push_back(std_deviation);
- if(std_deviation > highest_sofar)
- highest_sofar = std_deviation;
+ 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) &&
- ((std_deviation < highest_sofar * 0.2)||
- (sound_min >= -1 && sound_max <= 1))
+ ( (rms < highest_sofar * min_coefficient_on) || (sound_min >= -1 && sound_max <= 1) )
)
break;
}
- // Keyoff the note
- for(unsigned n = 0; n < n_notes; ++n)
- WRITE_REG(0xB0 + n * 3, (x[n] >> 8) & 0xDF);
+ if(!quarter_amplitude_time_found)
+ quarter_amplitude_time = windows_passed_on;
- // Now, for up to 60 seconds, measure mean amplitude.
- std::vector<double> amplitudecurve_off;
- for(unsigned period = 0; period < max_off * interval; ++period)
+ if(windows_passed_on >= max_period_on)
{
- stereoSampleBuf.clear();
- stereoSampleBuf.resize(samples_per_interval * 2);
- opl->generate(stereoSampleBuf.data(), samples_per_interval);
-
- double mean = 0.0;
- for(unsigned long c = 0; c < samples_per_interval; ++c)
- {
- short s = stereoSampleBuf[c * 2];
- mean += s;
- if(sound_min > s) sound_min = s;
- if(sound_max < s) sound_max = s;
- }
- mean /= samples_per_interval;
- double std_deviation = 0;
- for(unsigned long c = 0; c < samples_per_interval; ++c)
+ // 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(in);
+ synth.noteOn();
+
+ audioHistory.reset(std::ceil(historyLength * g_outputRate));
+ for(unsigned period = 0;
+ (period < peak_amplitude_time) && (period < max_period_on);
+ ++period)
{
- double diff = (stereoSampleBuf[c * 2] - mean);
- std_deviation += diff * diff;
+ 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;
+ }
}
- std_deviation = std::sqrt(std_deviation / samples_per_interval);
- amplitudecurve_off.push_back(std_deviation);
-
- if(std_deviation < highest_sofar * 0.2)
- break;
-
- if((period > max_silent * interval) && (sound_min >= -1 && sound_max <= 1))
- break;
+ synth.noteOff();
}
- /* Analyze the results */
- double begin_amplitude = amplitudecurve_on[0];
- double peak_amplitude_value = begin_amplitude;
- size_t peak_amplitude_time = 0;
- size_t quarter_amplitude_time = amplitudecurve_on.size();
- size_t keyoff_out_time = 0;
-
- for(size_t a = 1; a < amplitudecurve_on.size(); ++a)
+ // Now, for up to 60 seconds, measure mean amplitude.
+ for(unsigned period = 0; period < max_period_off; ++period, ++windows_passed_off)
{
- if(amplitudecurve_on[a] > peak_amplitude_value)
+ for(unsigned i = 0; i < samples_per_interval;)
{
- peak_amplitude_value = amplitudecurve_on[a];
- peak_amplitude_time = a;
+ 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;
}
- }
- for(size_t a = peak_amplitude_time; a < amplitudecurve_on.size(); ++a)
- {
- if(amplitudecurve_on[a] <= peak_amplitude_value * 0.2)
+
+ if(winsize != audioHistory.size())
{
- quarter_amplitude_time = a;
- break;
+ winsize = audioHistory.size();
+ HannWindow(window.get(), winsize);
}
- }
- for(size_t a = 0; a < amplitudecurve_off.size(); ++a)
- {
- if(amplitudecurve_off[a] <= peak_amplitude_value * 0.2)
+
+ 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 = a;
- break;
+ keyoff_out_time = period;
+ keyoff_out_time_found = true;
}
- }
+ /* ======== Find Key Off time ==END=== */
+ if(rms < highest_sofar * min_coefficient_off)
+ break;
- if(keyoff_out_time == 0 && amplitudecurve_on.back() < peak_amplitude_value * 0.2)
- keyoff_out_time = quarter_amplitude_time;
+ if((period > max_silent * interval) && (sound_min >= -1 && sound_max <= 1))
+ break;
+ }
DurationInfo result;
result.peak_amplitude_time = peak_amplitude_time;
@@ -227,11 +388,10 @@ DurationInfo MeasureDurations(const ins &in)
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 >= -1) && (sound_max <= 1));
+
return result;
}
-static const char* spinner = "-\\|/";
-
void MeasureThreaded::LoadCache(const char *fileName)
{
FILE *in = std::fopen(fileName, "rb");
@@ -290,6 +450,8 @@ void MeasureThreaded::LoadCache(const char *fileName)
inst.insno2 = inval;
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)
@@ -418,6 +580,7 @@ void MeasureThreaded::SaveCache(const char *fileName)
outval = in.insno2;
fwrite(&outval, 1, sizeof(uint64_t), 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);
@@ -458,9 +621,13 @@ void MeasureThreaded::SaveCache(const char *fileName)
std::fclose(out);
}
+#ifdef ADL_GENDATA_PRINT_PROGRESS
+
+static const char* spinner = "-\\|/";
+
void MeasureThreaded::printProgress()
{
- std::printf("Calculating measures... [%c %3u%% (%4u/%4u) Threads %3u, Matches %u] \r",
+ std::printf("Calculating measures... [%c %3u%% {%4u/%4u} Threads %3u, Matches %u] \r",
spinner[m_done.load() % 4],
(unsigned int)(((double)m_done.load() / (double)(m_total)) * 100),
(unsigned int)m_done.load(),
@@ -470,6 +637,12 @@ void MeasureThreaded::printProgress()
);
std::fflush(stdout);
}
+#else
+void MeasureThreaded::printProgress()
+{
+ //Do nothing
+}
+#endif
void MeasureThreaded::printFinal()
{
@@ -501,14 +674,18 @@ void MeasureThreaded::run(InstrumentsData::const_iterator i)
dd->myself = this;
dd->start();
m_threads.push_back(dd);
+#ifdef ADL_GENDATA_PRINT_PROGRESS
printProgress();
+#endif
}
void MeasureThreaded::waitAll()
{
for(auto &th : m_threads)
{
+#ifdef ADL_GENDATA_PRINT_PROGRESS
printProgress();
+#endif
delete th;
}
m_threads.clear();
@@ -524,6 +701,7 @@ 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);
if(cachedEntry != s->myself->m_durationInfo.end())
@@ -532,7 +710,7 @@ void MeasureThreaded::destData::callback(void *myself)
goto endWork;
}
- info = MeasureDurations(s->i->first);
+ 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();
diff --git a/utils/gen_adldata/measurer.h b/utils/gen_adldata/measurer.h
index b9ae3c6..63475ca 100644
--- a/utils/gen_adldata/measurer.h
+++ b/utils/gen_adldata/measurer.h
@@ -100,6 +100,7 @@ struct MeasureThreaded
void waitAll();
};
-extern DurationInfo MeasureDurations(const ins &in);
+class OPLChipBase;
+extern DurationInfo MeasureDurations(const ins &in, OPLChipBase *chip);
#endif // MEASURER_H
diff --git a/utils/gen_adldata/progs_cache.cpp b/utils/gen_adldata/progs_cache.cpp
index a59e7b7..81bba4c 100644
--- a/utils/gen_adldata/progs_cache.cpp
+++ b/utils/gen_adldata/progs_cache.cpp
@@ -112,7 +112,7 @@ size_t InsertNoSoundIns()
{
// { 0x0F70700,0x0F70710, 0xFF,0xFF, 0x0,+0 },
insdata tmp1 = MakeNoSoundIns();
- struct ins tmp2 = { 0, 0, 0, false, 0.0 };
+ struct ins tmp2 = { 0, 0, 0, false, false, 0.0 };
return InsertIns(tmp1, tmp1, tmp2, "nosound", "");
}
diff --git a/utils/gen_adldata/progs_cache.h b/utils/gen_adldata/progs_cache.h
index 7b4cd39..5a916f5 100644
--- a/utils/gen_adldata/progs_cache.h
+++ b/utils/gen_adldata/progs_cache.h
@@ -49,9 +49,11 @@ inline bool equal_approx(double const a, double const b)
struct ins
{
+ enum { Flag_Pseudo4op = 0x01, Flag_NoSound = 0x02, Flag_Real4op = 0x04 };
size_t insno1, insno2;
unsigned char notenum;
bool pseudo4op;
+ bool real4op;
double voice2_fine_tune;
bool operator==(const ins &b) const
@@ -60,6 +62,7 @@ struct ins
&& insno1 == b.insno1
&& insno2 == b.insno2
&& pseudo4op == b.pseudo4op
+ && real4op == b.real4op
&& equal_approx(voice2_fine_tune, b.voice2_fine_tune);
}
bool operator< (const ins &b) const
@@ -68,6 +71,7 @@ struct ins
if(insno2 != b.insno2) return insno2 < b.insno2;
if(notenum != b.notenum) return notenum < b.notenum;
if(pseudo4op != b.pseudo4op) return pseudo4op < b.pseudo4op;
+ if(real4op != b.real4op) return real4op < b.real4op;
if(!equal_approx(voice2_fine_tune, b.voice2_fine_tune)) return voice2_fine_tune < b.voice2_fine_tune;
return 0;
}
diff --git a/utils/midiplay/adlmidiplay.cpp b/utils/midiplay/adlmidiplay.cpp
index a591626..8bffc50 100644
--- a/utils/midiplay/adlmidiplay.cpp
+++ b/utils/midiplay/adlmidiplay.cpp
@@ -320,6 +320,8 @@ int main(int argc, char **argv)
#endif
#ifndef HARDWARE_OPL3
int emulator = ADLMIDI_EMU_NUKED;
+ #endif
+ #if !defined(HARDWARE_OPL3) && !defined(OUTPUT_WAVE_ONLY)
g_audioFormat.type = ADLMIDI_SampleType_S16;
g_audioFormat.containerSize = sizeof(Sint16);
g_audioFormat.sampleOffset = sizeof(Sint16) * 2;
@@ -334,7 +336,7 @@ int main(int argc, char **argv)
else if(!std::strcmp("-v", argv[2]))
adl_setHVibrato(myDevice, 1);//Force turn on deep vibrato
- #ifndef OUTPUT_WAVE_ONLY
+ #if !defined(OUTPUT_WAVE_ONLY) && !defined(HARDWARE_OPL3)
else if(!std::strcmp("-w", argv[2]))
{
//Current Wave output implementation allows only SINT16 output
@@ -402,6 +404,7 @@ int main(int argc, char **argv)
adl_switchEmulator(myDevice, emulator);
#endif
+ std::fprintf(stdout, " - Library version %s\n", adl_linkedLibraryVersion());
#ifdef HARDWARE_OPL3
std::fprintf(stdout, " - Hardware OPL3 chip in use\n");
#else
diff --git a/utils/vlc_codec/libadlmidi.c b/utils/vlc_codec/libadlmidi.c
index 5f85a4d..aedd718 100644
--- a/utils/vlc_codec/libadlmidi.c
+++ b/utils/vlc_codec/libadlmidi.c
@@ -18,14 +18,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
-//#ifdef HAVE_CONFIG_H
-//# include "config.h"
-//#endif
-
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_codec.h>
#include <vlc_dialog.h>
+#include <libvlc_version.h>
#include <unistd.h>
@@ -43,18 +40,20 @@
#define SOUNDFONT_LONGTEXT N_( \
"Custom bank file to use for software synthesis." )
-//#define CHORUS_TEXT N_("Chorus")
+#if 0 /* Old code */
+#define CHORUS_TEXT N_("Chorus")
-//#define GAIN_TEXT N_("Synthesis gain")
-//#define GAIN_LONGTEXT N_("This gain is applied to synthesis output. " \
-// "High values may cause saturation when many notes are played at a time." )
+#define GAIN_TEXT N_("Synthesis gain")
+#define GAIN_LONGTEXT N_("This gain is applied to synthesis output. " \
+ "High values may cause saturation when many notes are played at a time." )
-//#define POLYPHONY_TEXT N_("Polyphony")
-//#define POLYPHONY_LONGTEXT N_( \
-// "The polyphony defines how many voices can be played at a time. " \
-// "Larger values require more processing power.")
+#define POLYPHONY_TEXT N_("Polyphony")
+#define POLYPHONY_LONGTEXT N_( \
+ "The polyphony defines how many voices can be played at a time. " \
+ "Larger values require more processing power.")
-//#define REVERB_TEXT N_("Reverb")
+#define REVERB_TEXT N_("Reverb")
+#endif
#define SAMPLE_RATE_TEXT N_("Sample rate")
@@ -67,7 +66,11 @@ static void Close (vlc_object_t *);
vlc_module_begin ()
set_description (N_("ADLMIDI OPL3 Synth MIDI synthesizer"))
+#if (LIBVLC_VERSION_MAJOR >= 3)
+ set_capability ("audio decoder", 150)
+#else
set_capability ("decoder", 150)
+#endif
set_shortname (N_("ADLMIDI"))
set_category (CAT_INPUT)
set_subcategory (SUBCAT_INPUT_ACODEC)
@@ -105,7 +108,11 @@ static const struct ADLMIDI_AudioFormat g_output_format =
};
//static int DecodeBlock (decoder_t *p_dec, block_t *p_block); //For different version
+#if (LIBVLC_VERSION_MAJOR >= 3)
+static int DecodeBlock (decoder_t *p_dec, block_t *p_block);
+#else
static block_t *DecodeBlock (decoder_t *p_dec, block_t **pp_block);
+#endif
static void Flush (decoder_t *);
static int Open (vlc_object_t *p_this)
@@ -149,10 +156,12 @@ static int Open (vlc_object_t *p_this)
date_Set (&p_sys->end_date, 0);
p_dec->p_sys = p_sys;
- //==For different version==
- //p_dec->pf_decode = DecodeBlock;
- //p_dec->pf_flush = Flush;
+#if (LIBVLC_VERSION_MAJOR >= 3)
+ p_dec->pf_decode = DecodeBlock;
+ p_dec->pf_flush = Flush;
+#else
p_dec->pf_decode_audio = DecodeBlock;
+#endif
return VLC_SUCCESS;//VLCDEC_SUCCESS
}
@@ -168,134 +177,61 @@ static void Close (vlc_object_t *p_this)
static void Flush (decoder_t *p_dec)
{
decoder_sys_t *p_sys = p_dec->p_sys;
-
+#if (LIBVLC_VERSION_MAJOR >= 3)
date_Set (&p_sys->end_date, VLC_TS_INVALID);
+#else
+ date_Set (&p_sys->end_date, 0);
+#endif
adl_panic(p_sys->synth);
}
+#if (LIBVLC_VERSION_MAJOR >= 3)
+static int DecodeBlock (decoder_t *p_dec, block_t *p_block)
+{
+ decoder_sys_t *p_sys = p_dec->p_sys;
+ block_t *p_out = NULL;
+#else
static block_t *DecodeBlock (decoder_t *p_dec, block_t **pp_block)
{
block_t *p_block;
decoder_sys_t *p_sys = p_dec->p_sys;
block_t *p_out = NULL;
-
if (pp_block == NULL)
return NULL;
p_block = *pp_block;
- if (p_block == NULL)
- return NULL;
- *pp_block = NULL;
-
- if (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED))
- {
- date_Set (&p_sys->end_date, 0);
- adl_panic(p_sys->synth);
- }
-
- if (p_block->i_pts > VLC_TS_INVALID && !date_Get (&p_sys->end_date))
- date_Set (&p_sys->end_date, p_block->i_pts);
- else
- if (p_block->i_pts < date_Get (&p_sys->end_date))
- {
- msg_Warn (p_dec, "MIDI message in the past?");
- goto drop;
- }
-
- if (p_block->i_buffer < 1)
- goto drop;
-
- uint8_t event = p_block->p_buffer[0];
- uint8_t channel = p_block->p_buffer[0] & 0xf;
- event &= 0xF0;
-
- if (event == 0xF0)
- switch (channel)
- {
- case 0:
- if (p_block->p_buffer[p_block->i_buffer - 1] != 0xF7)
- {
- case 7:
- msg_Warn (p_dec, "fragmented SysEx not implemented");
- goto drop;
- }
- //fluid_synth_sysex (p_sys->synth, (char *)p_block->p_buffer + 1,
- // p_block->i_buffer - 2, NULL, NULL, NULL, 0);
- break;
- case 0xF:
- adl_rt_resetState(p_sys->synth);
- break;
- }
-
- uint8_t p1 = (p_block->i_buffer > 1) ? (p_block->p_buffer[1] & 0x7f) : 0;
- uint8_t p2 = (p_block->i_buffer > 2) ? (p_block->p_buffer[2] & 0x7f) : 0;
+#endif
- switch (event & 0xF0)
+ if (p_block == NULL)
{
- case 0x80:
- adl_rt_noteOff(p_sys->synth, channel, p1);
- break;
- case 0x90:
- adl_rt_noteOn(p_sys->synth, channel, p1, p2);
- break;
- /*case 0xA0: note aftertouch not implemented */
- case 0xB0:
- adl_rt_controllerChange(p_sys->synth, channel, p1, p2);
- break;
- case 0xC0:
- adl_rt_patchChange(p_sys->synth, channel, p1);
- break;
- case 0xD0:
- adl_rt_channelAfterTouch(p_sys->synth, channel, p1);
- break;
- case 0xE0:
- adl_rt_pitchBendML(p_sys->synth, channel, p2, p1);
- break;
+#if (LIBVLC_VERSION_MAJOR >= 3)
+ return VLCDEC_SUCCESS;
+#else
+ return p_out;
+#endif
}
- unsigned samples =
- (p_block->i_pts - date_Get (&p_sys->end_date)) * 441 / 10000;
- if (samples == 0)
- goto drop;
-
- p_out = decoder_NewAudioBuffer (p_dec, samples);
- if (p_out == NULL)
- goto drop;
-
- p_out->i_pts = date_Get (&p_sys->end_date );
- samples = adl_generateFormat(p_sys->synth, (int)samples * 2,
- (ADL_UInt8*)p_out->p_buffer,
- (ADL_UInt8*)(p_out->p_buffer + g_output_format.containerSize),
- &g_output_format);
- samples /= 2;
- p_out->i_length = date_Increment (&p_sys->end_date, samples) - p_out->i_pts;
-
-drop:
- block_Release (p_block);
- return p_out;
-}
-
-#if 0
-static int DecodeBlock (decoder_t *p_dec, block_t *p_block)
-{
- decoder_sys_t *p_sys = p_dec->p_sys;
- block_t *p_out = NULL;
-
- if (p_block == NULL) /* No Drain */
- return VLC_SUCCESS;//VLCDEC_SUCCESS
+#if (LIBVLC_VERSION_MAJOR < 3)
+ *pp_block = NULL;
+#endif
if (p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED))
{
+#if (LIBVLC_VERSION_MAJOR >= 3)
Flush (p_dec);
if (p_block->i_flags & BLOCK_FLAG_CORRUPTED)
{
block_Release(p_block);
- return VLC_SUCCESS;//VLCDEC_SUCCESS
+ return VLCDEC_SUCCESS;
}
+#else
+ Flush (p_dec);
+#endif
}
- if (p_block->i_pts > VLC_TS_INVALID && !date_Get (&p_sys->end_date))
+ if (p_block->i_pts > VLC_TS_INVALID
+ && !date_Get (&p_sys->end_date))
date_Set (&p_sys->end_date, p_block->i_pts);
else
if (p_block->i_pts < date_Get (&p_sys->end_date))
@@ -360,21 +296,30 @@ static int DecodeBlock (decoder_t *p_dec, block_t *p_block)
if (samples == 0)
goto drop;
+#if (LIBVLC_VERSION_MAJOR >= 3)
if (decoder_UpdateAudioFormat (p_dec))
goto drop;
+#endif
+
p_out = decoder_NewAudioBuffer (p_dec, samples);
if (p_out == NULL)
goto drop;
p_out->i_pts = date_Get (&p_sys->end_date );
- p_out->i_length = date_Increment (&p_sys->end_date, samples)
- - p_out->i_pts;
- adl_generate(p_sys->synth, samples * 2, p_out->p_buffer);
+ samples = adl_generateFormat(p_sys->synth, (int)samples * 2,
+ (ADL_UInt8*)p_out->p_buffer,
+ (ADL_UInt8*)(p_out->p_buffer + g_output_format.containerSize),
+ &g_output_format);
+ samples /= 2;
+ p_out->i_length = date_Increment (&p_sys->end_date, samples) - p_out->i_pts;
+
drop:
block_Release (p_block);
+#if (LIBVLC_VERSION_MAJOR >= 3)
if (p_out != NULL)
decoder_QueueAudio (p_dec, p_out);
- return VLC_SUCCESS;//VLCDEC_SUCCESS
-}
-
+ return VLCDEC_SUCCESS;
+#else
+ return p_out;
#endif
+}