Address review comments

This commit is contained in:
James Alan Nguyen 2022-04-16 09:34:12 +10:00
parent 836fb57f14
commit a8201fa535
1 changed files with 117 additions and 125 deletions

View File

@ -35,6 +35,61 @@ enum DivInsFormats {
DIV_INSFORMAT_FF, DIV_INSFORMAT_FF,
}; };
// Patch data structures
// SBI and some other OPL containers
struct sbi_t {
uint8_t Mcharacteristics,
Ccharacteristics,
Mscaling_output,
Cscaling_output,
Meg_AD,
Ceg_AD,
Meg_SR,
Ceg_SR,
Mwave,
Cwave,
FeedConnect;
};
// Adlib Visual Composer BNK
struct bnkop_t {
uint8_t ksl,
multiple,
feedback, // op1 only
attack,
sustain,
eg,
decay,
releaseRate,
totalLevel,
am,
vib,
ksr,
con; // op1 only
};
struct bnktimbre_t {
uint8_t mode,
percVoice;
bnkop_t op[2];
uint8_t wave0,
wave1;
};
auto readSbiOpData = [](sbi_t& sbi, SafeReader& reader) {
sbi.Mcharacteristics = reader.readC();
sbi.Ccharacteristics = reader.readC();
sbi.Mscaling_output = reader.readC();
sbi.Cscaling_output = reader.readC();
sbi.Meg_AD = reader.readC();
sbi.Ceg_AD = reader.readC();
sbi.Meg_SR = reader.readC();
sbi.Ceg_SR = reader.readC();
sbi.Mwave = reader.readC();
sbi.Cwave = reader.readC();
sbi.FeedConnect = reader.readC();
};
void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath) { void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath) {
DivInstrument* ins=new DivInstrument; DivInstrument* ins=new DivInstrument;
// this is a ridiculous mess // this is a ridiculous mess
@ -46,7 +101,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
logD(".dmp version %d",version); logD(".dmp version %d",version);
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError="premature end of file"; lastError="premature end of file";
logE("premature end of file!"); logE(lastError.c_str());
delete ins; delete ins;
return; return;
} }
@ -105,7 +160,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
} }
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError="premature end of file"; lastError="premature end of file";
logE("premature end of file!"); logE(lastError.c_str());
delete ins; delete ins;
return; return;
} }
@ -297,7 +352,7 @@ void DivEngine::loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, St
} }
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError="premature end of file"; lastError="premature end of file";
logE("premature end of file!"); logE(lastError.c_str());
delete ins; delete ins;
return; return;
} }
@ -332,7 +387,7 @@ void DivEngine::loadTFI(SafeReader& reader, std::vector<DivInstrument*>& ret, St
} }
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError="premature end of file"; lastError="premature end of file";
logE("premature end of file!"); logE(lastError.c_str());
delete ins; delete ins;
return; return;
} }
@ -374,7 +429,7 @@ void DivEngine::loadVGI(SafeReader& reader, std::vector<DivInstrument*>& ret, St
} }
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError="premature end of file"; lastError="premature end of file";
logE("premature end of file!"); logE(lastError.c_str());
delete ins; delete ins;
return; return;
} }
@ -400,56 +455,48 @@ void DivEngine::loadS3I(SafeReader& reader, std::vector<DivInstrument*>& ret, St
// skip reserved bytes // skip reserved bytes
reader.seek(3, SEEK_CUR); reader.seek(3, SEEK_CUR);
// 12-byte opl value // 12-byte opl value - identical to SBI format
uint8_t s3i_Mcharacteristics = reader.readC(); sbi_t s3i;
uint8_t s3i_Ccharacteristics = reader.readC();
uint8_t s3i_Mscaling_output = reader.readC(); readSbiOpData(s3i, reader);
uint8_t s3i_Cscaling_output = reader.readC();
uint8_t s3i_Meg_AD = reader.readC();
uint8_t s3i_Ceg_AD = reader.readC();
uint8_t s3i_Meg_SR = reader.readC();
uint8_t s3i_Ceg_SR = reader.readC();
uint8_t s3i_Mwave = reader.readC();
uint8_t s3i_Cwave = reader.readC();
uint8_t s3i_FeedConnect = reader.readC();
DivInstrumentFM::Operator& opM = ins->fm.op[0]; DivInstrumentFM::Operator& opM = ins->fm.op[0];
DivInstrumentFM::Operator& opC = ins->fm.op[1]; DivInstrumentFM::Operator& opC = ins->fm.op[1];
ins->fm.ops = 2; ins->fm.ops = 2;
opM.mult = s3i_Mcharacteristics & 0xF; opM.mult = s3i.Mcharacteristics & 0xF;
opM.ksr = ((s3i_Mcharacteristics >> 4) & 0x1); opM.ksr = ((s3i.Mcharacteristics >> 4) & 0x1);
opM.sus = ((s3i_Mcharacteristics >> 5) & 0x1); opM.sus = ((s3i.Mcharacteristics >> 5) & 0x1);
opM.vib = ((s3i_Mcharacteristics >> 6) & 0x1); opM.vib = ((s3i.Mcharacteristics >> 6) & 0x1);
opM.am = ((s3i_Mcharacteristics >> 7) & 0x1); opM.am = ((s3i.Mcharacteristics >> 7) & 0x1);
opM.tl = s3i_Mscaling_output & 0x3F; opM.tl = s3i.Mscaling_output & 0x3F;
opM.ksl = ((s3i_Mscaling_output >> 6) & 0x3); opM.ksl = ((s3i.Mscaling_output >> 6) & 0x3);
opM.ar = ((s3i_Meg_AD >> 4) & 0xF); opM.ar = ((s3i.Meg_AD >> 4) & 0xF);
opM.dr = (s3i_Meg_AD & 0xF); opM.dr = (s3i.Meg_AD & 0xF);
opM.rr = (s3i_Meg_SR & 0xF); opM.rr = (s3i.Meg_SR & 0xF);
opM.sl = ((s3i_Meg_SR >> 4) & 0xF); opM.sl = ((s3i.Meg_SR >> 4) & 0xF);
opM.ws = s3i_Mwave; opM.ws = s3i.Mwave;
ins->fm.alg = (s3i_FeedConnect & 0x1); ins->fm.alg = (s3i.FeedConnect & 0x1);
ins->fm.fb = ((s3i_FeedConnect >> 1) & 0x7); ins->fm.fb = ((s3i.FeedConnect >> 1) & 0x7);
opC.mult = s3i_Ccharacteristics & 0xF; opC.mult = s3i.Ccharacteristics & 0xF;
opC.ksr = ((s3i_Ccharacteristics >> 4) & 0x1); opC.ksr = ((s3i.Ccharacteristics >> 4) & 0x1);
opC.sus = ((s3i_Ccharacteristics >> 5) & 0x1); opC.sus = ((s3i.Ccharacteristics >> 5) & 0x1);
opC.vib = ((s3i_Ccharacteristics >> 6) & 0x1); opC.vib = ((s3i.Ccharacteristics >> 6) & 0x1);
opC.am = ((s3i_Ccharacteristics >> 7) & 0x1); opC.am = ((s3i.Ccharacteristics >> 7) & 0x1);
opC.tl = s3i_Cscaling_output & 0x3F; opC.tl = s3i.Cscaling_output & 0x3F;
opC.ksl = ((s3i_Cscaling_output >> 6) & 0x3); opC.ksl = ((s3i.Cscaling_output >> 6) & 0x3);
opC.ar = ((s3i_Ceg_AD >> 4) & 0xF); opC.ar = ((s3i.Ceg_AD >> 4) & 0xF);
opC.dr = (s3i_Ceg_AD & 0xF); opC.dr = (s3i.Ceg_AD & 0xF);
opC.rr = (s3i_Ceg_SR & 0xF); opC.rr = (s3i.Ceg_SR & 0xF);
opC.sl = ((s3i_Ceg_SR >> 4) & 0xF); opC.sl = ((s3i.Ceg_SR >> 4) & 0xF);
opC.ws = s3i_Cwave; opC.ws = s3i.Cwave;
// Skip more stuff we don't need // Skip more stuff we don't need
reader.seek(21, SEEK_CUR); reader.seek(21, SEEK_CUR);
} else { } else {
lastError = "S3I PCM samples currently not supported."; lastError = "S3I PCM samples currently not supported.";
logE("S3I PCM samples currently not supported.\n"); logE(lastError.c_str());
} }
ins->name = reader.readString(28); ins->name = reader.readString(28);
ins->name = (ins->name.length() == 0) ? stripPath : ins->name; ins->name = (ins->name.length() == 0) ? stripPath : ins->name;
@ -457,12 +504,12 @@ void DivEngine::loadS3I(SafeReader& reader, std::vector<DivInstrument*>& ret, St
int s3i_signature = reader.readI(); int s3i_signature = reader.readI();
if (s3i_signature != 0x49524353) { if (s3i_signature != 0x49524353) {
lastError = "S3I signature invalid."; warnings = "S3I signature invalid.";
logW("S3I signature invalid.\n"); logW(lastError.c_str());
}; };
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError = "premature end of file"; lastError = "premature end of file";
logE("premature end of file!"); logE(lastError.c_str());
delete ins; delete ins;
return; return;
} }
@ -486,34 +533,6 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector<DivInstrument*>& ret, St
String patchName = reader.readString(32); String patchName = reader.readString(32);
patchName = (patchName.length() == 0) ? stripPath : patchName; patchName = (patchName.length() == 0) ? stripPath : patchName;
typedef struct {
uint8_t Mcharacteristics,
Ccharacteristics,
Mscaling_output,
Cscaling_output,
Meg_AD,
Ceg_AD,
Meg_SR,
Ceg_SR,
Mwave,
Cwave,
FeedConnect;
} sbi_t;
auto readSbiOpData = [](sbi_t& sbi, SafeReader& reader) {
sbi.Mcharacteristics = reader.readC();
sbi.Ccharacteristics = reader.readC();
sbi.Mscaling_output = reader.readC();
sbi.Cscaling_output = reader.readC();
sbi.Meg_AD = reader.readC();
sbi.Ceg_AD = reader.readC();
sbi.Meg_SR = reader.readC();
sbi.Ceg_SR = reader.readC();
sbi.Mwave = reader.readC();
sbi.Cwave = reader.readC();
sbi.FeedConnect = reader.readC();
};
auto writeOp = [](sbi_t& sbi, DivInstrumentFM::Operator& opM, DivInstrumentFM::Operator& opC) { auto writeOp = [](sbi_t& sbi, DivInstrumentFM::Operator& opM, DivInstrumentFM::Operator& opC) {
opM.mult = sbi.Mcharacteristics & 0xF; opM.mult = sbi.Mcharacteristics & 0xF;
opM.ksr = ((sbi.Mcharacteristics >> 4) & 0x1); opM.ksr = ((sbi.Mcharacteristics >> 4) & 0x1);
@ -611,49 +630,22 @@ void DivEngine::loadSBI(SafeReader& reader, std::vector<DivInstrument*>& ret, St
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError = "premature end of file"; lastError = "premature end of file";
logE("premature end of file!"); logE(lastError.c_str());
delete ins; delete ins;
} }
} }
void DivEngine::loadBNK(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath) { void DivEngine::loadBNK(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath) {
DivInstrument* insList[256]; std::vector<DivInstrument*> insList;
String instNames[256]; std::vector<String*> instNames;
memset(insList, 0, 256 * sizeof(void*));
reader.seek(0, SEEK_SET); reader.seek(0, SEEK_SET);
// First distinguish between GEMS BNK and Adlib BNK // First distinguish between GEMS BNK and Adlib BNK
uint64_t header = reader.readL(); uint64_t header = reader.readL();
bool is_adlib = ((header>>8) == 0x2d42494c444100L); bool is_adlib = ((header>>8) == 0x2d42494c444100L);
bool is_failed = false;
int readCount = 0; int readCount = 0;
if (is_adlib) { if (is_adlib) {
// Caveat: Technically Adlib BNK can hold up to 0xFFFF instruments,
// but Furnace only can handle up to 0xFF.
typedef struct {
uint8_t ksl,
multiple,
feedback, // op1 only
attack,
sustain,
eg,
decay,
releaseRate,
totalLevel,
am,
vib,
ksr,
con; // op1 only
} bnkop_t;
typedef struct {
uint8_t mode,
percVoice;
bnkop_t op[2];
uint8_t wave0,
wave1;
} bnktimbre_t;
try { try {
reader.seek(0x0c, SEEK_SET); reader.seek(0x0c, SEEK_SET);
uint32_t name_offset = reader.readI(); uint32_t name_offset = reader.readI();
@ -663,13 +655,8 @@ void DivEngine::loadBNK(SafeReader& reader, std::vector<DivInstrument*>& ret, St
// Seek to BNK patch names // Seek to BNK patch names
reader.seek(name_offset, SEEK_SET); reader.seek(name_offset, SEEK_SET);
while (reader.tell() < data_offset) { while (reader.tell() < data_offset) {
if (readCount >= 256) {
lastError = "BNK exceeds 256 presets. Only first 256 will be imported.";
logW("BNK exceeds 256 presets. Only first 256 will be imported.\n");
break;
}
reader.seek(3, SEEK_CUR); reader.seek(3, SEEK_CUR);
instNames[readCount] = reader.readString(9); instNames.push_back(new String(reader.readString(9)));
++readCount; ++readCount;
} }
@ -677,9 +664,9 @@ void DivEngine::loadBNK(SafeReader& reader, std::vector<DivInstrument*>& ret, St
reader.seek(data_offset, SEEK_SET); reader.seek(data_offset, SEEK_SET);
// Read until EOF // Read until EOF
for (int i = 0; i < readCount && i < 256; ++i) { for (int i = 0; i < readCount; ++i) {
bnktimbre_t timbre; bnktimbre_t timbre;
insList[i] = new DivInstrument; insList.push_back(new DivInstrument);
auto& ins = insList[i]; auto& ins = insList[i];
ins->type = DIV_INS_OPL; ins->type = DIV_INS_OPL;
@ -719,30 +706,35 @@ void DivEngine::loadBNK(SafeReader& reader, std::vector<DivInstrument*>& ret, St
ins->fm.op[0].ws = reader.readC(); ins->fm.op[0].ws = reader.readC();
ins->fm.op[1].ws = reader.readC(); ins->fm.op[1].ws = reader.readC();
ins->name = instNames[i].length() > 0 ? instNames[i] : fmt::format("{0}[{1}]", stripPath, i); ins->name = instNames[i]->length() > 0 ? (*instNames[i]) : fmt::format("{0}[{1}]", stripPath, i);
} }
reader.seek(0, SEEK_END); reader.seek(0, SEEK_END);
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError = "premature end of file"; lastError = "premature end of file";
logE("premature end of file!\n"); logE(lastError.c_str());
for (int i = readCount; i >= 0; --i) { for (int i = readCount; i >= 0; --i) {
delete insList[i]; delete insList[i];
} }
return; is_failed = true;
} }
} else { } else {
// assume GEMS BNK for now. // assume GEMS BNK for now.
lastError = "GEMS BNK currently not supported.\n"; lastError = "GEMS BNK currently not supported.";
logE("GEMS BNK currently not supported.\n"); logE(lastError.c_str());
} }
if (!is_failed) {
for (int i = 0; i < readCount; ++i) { for (int i = 0; i < readCount; ++i) {
ret.push_back(insList[i]); ret.push_back(insList[i]);
} }
} }
for (auto& name : instNames) {
delete name;
}
}
void DivEngine::loadFF(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath) { void DivEngine::loadFF(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath) {
DivInstrument* insList[256]; DivInstrument* insList[256];
@ -805,7 +797,7 @@ void DivEngine::loadFF(SafeReader& reader, std::vector<DivInstrument*>& ret, Str
} }
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError = "premature end of file"; lastError = "premature end of file";
logE("premature end of file!\n"); logE(lastError.c_str());
for (int i = readCount; i >= 0; --i) { for (int i = readCount; i >= 0; --i) {
delete insList[i]; delete insList[i];
} }
@ -826,7 +818,7 @@ void DivEngine::loadOPM(SafeReader& reader, std::vector<DivInstrument*>& ret, St
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError="premature end of file"; lastError="premature end of file";
logE("premature end of file!"); logE(lastError.c_str());
return; return;
} }
} }
@ -924,7 +916,7 @@ std::vector<DivInstrument*> DivEngine::instrumentFromFile(const char* path) {
} }
} catch (EndOfFileException& e) { } catch (EndOfFileException& e) {
lastError="premature end of file"; lastError="premature end of file";
logE("premature end of file!"); logE(lastError.c_str());
delete ins; delete ins;
delete[] buf; delete[] buf;
return ret; return ret;