diff options
author | Vitaly Novichkov <Wohlstand@users.noreply.github.com> | 2020-08-30 14:00:15 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-30 14:00:15 +0200 |
commit | 82fa5cb3e0859942fc6b353a3138aae8c10520a3 (patch) | |
tree | 28e99c08b430742c719f6b9bda236d29b650ffd8 /utils/gen_adldata/measurer.cpp | |
parent | 678be9ff7eb835087a426684a24f0e0172c9178d (diff) | |
parent | 6223286c01b83748f5c92cd21612e9eecc3d7525 (diff) | |
download | libADLMIDI-82fa5cb3e0859942fc6b353a3138aae8c10520a3.tar.gz libADLMIDI-82fa5cb3e0859942fc6b353a3138aae8c10520a3.tar.bz2 libADLMIDI-82fa5cb3e0859942fc6b353a3138aae8c10520a3.zip |
Merge pull request #232 from Wohlstand/wip-new-embedded-banks
Brand new embedded banks database format
Diffstat (limited to 'utils/gen_adldata/measurer.cpp')
-rw-r--r-- | utils/gen_adldata/measurer.cpp | 568 |
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: |