aboutsummaryrefslogtreecommitdiff
path: root/utils/gen_adldata/measurer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/gen_adldata/measurer.cpp')
-rw-r--r--utils/gen_adldata/measurer.cpp568
1 files changed, 322 insertions, 246 deletions
diff --git a/utils/gen_adldata/measurer.cpp b/utils/gen_adldata/measurer.cpp
index 4f28671..af9e0da 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,116 @@ 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 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 +260,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,8 +278,7 @@ struct TinySynth
}
};
-
-DurationInfo MeasureDurations(const ins &in, OPLChipBase *chip)
+DurationInfo MeasureDurations(BanksDump &db, const BanksDump::InstrumentEntry &ins, OPLChipBase *chip)
{
AudioHistory<double> audioHistory;
@@ -219,9 +295,34 @@ DurationInfo MeasureDurations(const ins &in, OPLChipBase *chip)
TinySynth synth;
synth.m_chip = chip;
synth.resetChip();
- synth.setInstrument(in);
+ 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;
@@ -260,6 +361,11 @@ DurationInfo MeasureDurations(const ins &in, OPLChipBase *chip)
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];
@@ -318,7 +424,7 @@ DurationInfo MeasureDurations(const ins &in, OPLChipBase *chip)
{
// Reset the emulator and re-run the "ON" simulation until reaching the peak time
synth.resetChip();
- synth.setInstrument(in);
+ synth.setInstrument(db, ins);
synth.noteOn();
audioHistory.reset(std::ceil(historyLength * g_outputRate));
@@ -387,17 +493,66 @@ DurationInfo MeasureDurations(const ins &in, OPLChipBase *chip)
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));
+ 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();
+}
+
void MeasureThreaded::LoadCache(const char *fileName)
{
+ m_durationInfo.clear();
+
FILE *in = std::fopen(fileName, "rb");
if(!in)
{
- std::printf("Failed to load cache: file is not exists.\n"
+ std::printf("Failed to load CacheX: file is not exists.\n"
"Complete data will be generated from scratch.\n");
std::fflush(stdout);
return;
@@ -407,157 +562,75 @@ void MeasureThreaded::LoadCache(const char *fileName)
if(std::fread(magic, 1, 32, in) != 32)
{
std::fclose(in);
- std::printf("Failed to load cache: can't read magic.\n"
+ std::printf("Failed to load CacheX: can't read magic.\n"
"Complete data will be generated from scratch.\n");
std::fflush(stdout);
return;
}
- if(memcmp(magic, "ADLMIDI-DURATION-CACHE-FILE-V1.0", 32) != 0)
+ if(std::memcmp(magic, "ADLMIDI-DURATION-CACHE-FILE-V2.0", 32) != 0)
{
std::fclose(in);
- std::printf("Failed to load cache: magic missmatch.\n"
+ std::printf("Failed to load CacheX: magic missmatch.\n"
"Complete data will be generated from scratch.\n");
std::fflush(stdout);
return;
}
- while(!std::feof(in))
+ uint_fast32_t itemsCount;
+ uint8_t itemsCountA[4];
+ if(std::fread(itemsCountA, 1, 4, in) != 4)
{
- DurationInfo info;
- ins inst;
- //got by instrument
- insdata id[2];
- size_t insNo[2] = {0, 0};
- bool found[2] = {false, false};
- //got from file
- insdata id_f[2];
- bool found_f[2] = {false, false};
- bool isMatches = false;
-
- memset(id, 0, sizeof(insdata) * 2);
- memset(id_f, 0, sizeof(insdata) * 2);
- memset(&info, 0, sizeof(DurationInfo));
- memset(&inst, 0, sizeof(ins));
-
- //Instrument
- uint64_t inval;
- if(std::fread(&inval, 1, sizeof(uint64_t), in) != sizeof(uint64_t))
- break;
- inst.insno1 = inval;
- if(std::fread(&inval, 1, sizeof(uint64_t), in) != sizeof(uint64_t))
- break;
- 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)
- break;
+ 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;
+ }
- //Instrument data
- if(fread(found_f, 1, 2 * sizeof(bool), in) != sizeof(bool) * 2)
- break;
- for(size_t i = 0; i < 2; i++)
- {
- if(fread(id_f[i].data, 1, 11, in) != 11)
- break;
- if(fread(&id_f[i].finetune, 1, 1, in) != 1)
- break;
- if(fread(&id_f[i].diff, 1, sizeof(bool), in) != sizeof(bool))
- break;
- }
+ itemsCount = static_cast<uint_fast32_t>(toUint32LE(itemsCountA));
- if(found_f[0] || found_f[1])
- {
- for(InstrumentDataTab::const_iterator j = insdatatab.begin(); j != insdatatab.end(); ++j)
- {
- if(j->second.first == inst.insno1)
- {
- id[0] = j->first;
- found[0] = (id[0] == id_f[0]);
- insNo[0] = inst.insno1;
- if(found[1]) break;
- }
- if(j->second.first == inst.insno2)
- {
- id[1] = j->first;
- found[1] = (id[1] == id_f[1]);
- insNo[1] = inst.insno2;
- if(found[0]) break;
- }
- }
+ while(!std::feof(in) && itemsCount > 0)
+ {
+ OperatorsKey k;
+ DurationInfo v;
- //Find instrument entries are matching
- if((found[0] != found_f[0]) || (found[1] != found_f[1]))
- {
- for(InstrumentDataTab::const_iterator j = insdatatab.begin(); j != insdatatab.end(); ++j)
- {
- if(found_f[0] && (j->first == id_f[0]))
- {
- found[0] = true;
- insNo[0] = j->second.first;
- }
- if(found_f[1] && (j->first == id_f[1]))
- {
- found[1] = true;
- insNo[1] = j->second.first;
- }
- if(found[0] && !found_f[1])
- {
- isMatches = true;
- break;
- }
- if(found[0] && found[1])
- {
- isMatches = true;
- break;
- }
- }
- }
- else
- {
- isMatches = true;
- }
+ uint8_t data_k[5];
- //Then find instrument entry that uses found instruments
- if(isMatches)
+ for(auto &kv : k)
+ {
+ uint8_t data[4];
+ auto ret = std::fread(data, 1, 4, in);
+ if(ret != 4)
{
- inst.insno1 = insNo[0];
- inst.insno2 = insNo[1];
- InstrumentsData::iterator d = instab.find(inst);
- if(d == instab.end())
- isMatches = false;
+ 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));
}
- //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))
- break;
- if(std::fread(&info.nosound, 1, sizeof(bool), in) != sizeof(bool))
- break;
+ 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;
+ }
- if(isMatches)//Store only if cached entry matches actual raw instrument data
- m_durationInfo.insert({inst, info});
+ 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_durationInfo.insert({k, v});
+ itemsCount--;
}
- std::printf("Cache loaded!\n");
+ std::printf("CacheX loaded!\n");
std::fflush(stdout);
std::fclose(in);
@@ -566,57 +639,44 @@ void MeasureThreaded::LoadCache(const char *fileName)
void MeasureThreaded::SaveCache(const char *fileName)
{
FILE *out = std::fopen(fileName, "wb");
- fprintf(out, "ADLMIDI-DURATION-CACHE-FILE-V1.0");
- for(DurationInfoCache::iterator it = m_durationInfo.begin(); it != m_durationInfo.end(); it++)
+ std::fprintf(out, "ADLMIDI-DURATION-CACHE-FILE-V2.0");
+
+ uint_fast32_t itemsCount = static_cast<uint_fast32_t>(m_durationInfo.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_durationInfo.begin(); it != m_durationInfo.end(); it++)
{
- const ins &in = it->first;
- insdata id[2];
- bool found[2] = {false, false};
- memset(id, 0, sizeof(insdata) * 2);
-
- uint64_t outval;
- outval = in.insno1;
- fwrite(&outval, 1, sizeof(uint64_t), out);
- 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);
-
- for(InstrumentDataTab::const_iterator j = insdatatab.begin(); j != insdatatab.end(); ++j)
+ const OperatorsKey &k = it->first;
+ const DurationInfo &v = it->second;
+
+ uint8_t data_k[5] =
{
- 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;
- }
- }
+ 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)
+ };
- fwrite(found, 1, 2 * sizeof(bool), out);
- for(size_t i = 0; i < 2; i++)
+ for(auto &kv : k)
{
- fwrite(id[i].data, 1, 11, out);
- fwrite(&id[i].finetune, 1, 1, out);
- fwrite(&id[i].diff, 1, sizeof(bool), out);
+ 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);
}
-
- 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::fwrite(data_k, 1, 5, out);
}
std::fclose(out);
}
@@ -652,7 +712,7 @@ void MeasureThreaded::printFinal()
std::fflush(stdout);
}
-void MeasureThreaded::run(InstrumentsData::const_iterator i)
+void MeasureThreaded::run(BanksDump &bd, BanksDump::InstrumentEntry &e)
{
m_semaphore.wait();
if(m_threads.size() > 0)
@@ -670,7 +730,8 @@ void MeasureThreaded::run(InstrumentsData::const_iterator i)
}
destData *dd = new destData;
- dd->i = i;
+ dd->bd = &bd;
+ dd->bd_ins = &e;
dd->myself = this;
dd->start();
m_threads.push_back(dd);
@@ -701,18 +762,33 @@ 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);
+ DosBoxOPL3 chip;
+ // NukedOPL3 chip;
+
+ 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_durationInfo.find(ok);
+ bool atEnd = cachedEntry == s->myself->m_durationInfo.end();
+ s->myself->m_durationInfo_mx.unlock();
- if(cachedEntry != s->myself->m_durationInfo.end())
+ 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->i->first, &dosbox);
+ info = MeasureDurations(*s->bd, *s->bd_ins, &chip);
s->myself->m_durationInfo_mx.lock();
- s->myself->m_durationInfo.insert({s->i->first, info});
+ s->myself->m_durationInfo.insert({ok, info});
s->myself->m_durationInfo_mx.unlock();
endWork: