OPM parser tidyup, GYBv1/2/3 foundation support done, BNK parser cleanup
This commit is contained in:
parent
e289ba652d
commit
1c88e20fa7
|
@ -97,7 +97,7 @@ static void readSbiOpData(sbi_t& sbi, SafeReader& reader) {
|
||||||
// detune needs extra translation from register to furnace format
|
// detune needs extra translation from register to furnace format
|
||||||
static inline uint8_t fmDtRegisterToFurnace(uint8_t&& dtNative) {
|
static inline uint8_t fmDtRegisterToFurnace(uint8_t&& dtNative) {
|
||||||
return (dtNative>=4) ? (7-dtNative) : (dtNative+3);
|
return (dtNative>=4) ? (7-dtNative) : (dtNative+3);
|
||||||
};
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
@ -886,44 +886,40 @@ void DivEngine::loadBNK(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
||||||
|
|
||||||
// Read until EOF
|
// Read until EOF
|
||||||
for (int i = 0; i < insCount; ++i) {
|
for (int i = 0; i < insCount; ++i) {
|
||||||
bnktimbre_t timbre;
|
|
||||||
DivInstrument *ins = new DivInstrument;
|
DivInstrument *ins = new DivInstrument;
|
||||||
|
|
||||||
ins->type = DIV_INS_OPL;
|
ins->type = DIV_INS_OPL;
|
||||||
ins->fm.ops = 2;
|
ins->fm.ops = 2;
|
||||||
|
|
||||||
timbre.mode = reader.readC();
|
uint8_t timbreMode = reader.readC();
|
||||||
timbre.percVoice = reader.readC();
|
uint8_t timbrePercVoice = reader.readC();
|
||||||
if (timbre.mode == 1) {
|
if (timbreMode == 1) {
|
||||||
ins->fm.opllPreset = (uint8_t)(1<<4);
|
ins->fm.opllPreset = (uint8_t)(1<<4);
|
||||||
}
|
}
|
||||||
ins->fm.op[0].ksl = reader.readC();
|
|
||||||
ins->fm.op[0].mult = reader.readC();
|
|
||||||
ins->fm.fb = reader.readC();
|
|
||||||
ins->fm.op[0].ar = reader.readC();
|
|
||||||
ins->fm.op[0].sl = reader.readC();
|
|
||||||
ins->fm.op[0].sus = (reader.readC() != 0) ? 1 : 0;
|
|
||||||
ins->fm.op[0].dr = reader.readC();
|
|
||||||
ins->fm.op[0].rr = reader.readC();
|
|
||||||
ins->fm.op[0].tl = reader.readC();
|
|
||||||
ins->fm.op[0].am = reader.readC();
|
|
||||||
ins->fm.op[0].vib = reader.readC();
|
|
||||||
ins->fm.op[0].ksr = reader.readC();
|
|
||||||
ins->fm.alg = (reader.readC() == 0) ? 1 : 0;
|
|
||||||
|
|
||||||
ins->fm.op[1].ksl = reader.readC();
|
for (int i = 0; i < 2; ++i) {
|
||||||
ins->fm.op[1].mult = reader.readC();
|
ins->fm.op[i].ksl = reader.readC();
|
||||||
|
ins->fm.op[i].mult = reader.readC();
|
||||||
|
if (i==0) {
|
||||||
|
ins->fm.fb = reader.readC();
|
||||||
|
} else {
|
||||||
reader.readC(); // skip
|
reader.readC(); // skip
|
||||||
ins->fm.op[1].ar = reader.readC();
|
}
|
||||||
ins->fm.op[1].sl = reader.readC();
|
ins->fm.op[i].ar = reader.readC();
|
||||||
ins->fm.op[1].sus = (reader.readC() != 0) ? 1 : 0;
|
ins->fm.op[i].sl = reader.readC();
|
||||||
ins->fm.op[1].dr = reader.readC();
|
ins->fm.op[i].sus = (reader.readC() != 0) ? 1 : 0;
|
||||||
ins->fm.op[1].rr = reader.readC();
|
ins->fm.op[i].dr = reader.readC();
|
||||||
ins->fm.op[1].tl = reader.readC();
|
ins->fm.op[i].rr = reader.readC();
|
||||||
ins->fm.op[1].am = reader.readC();
|
ins->fm.op[i].tl = reader.readC();
|
||||||
ins->fm.op[1].vib = reader.readC();
|
ins->fm.op[i].am = reader.readC();
|
||||||
ins->fm.op[1].ksr = reader.readC();
|
ins->fm.op[i].vib = reader.readC();
|
||||||
|
ins->fm.op[i].ksr = reader.readC();
|
||||||
|
if (i==0) {
|
||||||
|
ins->fm.alg = (reader.readC() == 0) ? 1 : 0;
|
||||||
|
} else {
|
||||||
reader.readC(); // skip
|
reader.readC(); // skip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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();
|
||||||
|
@ -1033,9 +1029,9 @@ void DivEngine::loadFF(SafeReader& reader, std::vector<DivInstrument*>& ret, Str
|
||||||
|
|
||||||
void DivEngine::loadGYB(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath) {
|
void DivEngine::loadGYB(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath) {
|
||||||
std::vector<DivInstrument*> insList;
|
std::vector<DivInstrument*> insList;
|
||||||
|
|
||||||
int readCount = 0;
|
int readCount = 0;
|
||||||
bool is_failed = false;
|
bool is_failed = false;
|
||||||
|
|
||||||
auto readInstrument = [](SafeReader& reader, bool readRegB4) -> DivInstrument* {
|
auto readInstrument = [](SafeReader& reader, bool readRegB4) -> DivInstrument* {
|
||||||
const int opOrder[] = { 0,1,2,3 };
|
const int opOrder[] = { 0,1,2,3 };
|
||||||
DivInstrument* ins = new DivInstrument;
|
DivInstrument* ins = new DivInstrument;
|
||||||
|
@ -1127,12 +1123,13 @@ void DivEngine::loadGYB(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
||||||
for (int i = 0; i < (insMelodyCount+insDrumCount); ++i) {
|
for (int i = 0; i < (insMelodyCount+insDrumCount); ++i) {
|
||||||
bool isDrum = (i >= insMelodyCount);
|
bool isDrum = (i >= insMelodyCount);
|
||||||
DivInstrument* newIns = readInstrument(reader, (version == 2));
|
DivInstrument* newIns = readInstrument(reader, (version == 2));
|
||||||
|
insList.push_back(newIns);
|
||||||
|
++readCount;
|
||||||
|
|
||||||
reader.readC(); // skip transpose
|
reader.readC(); // skip transpose
|
||||||
if (version == 2) {
|
if (version == 2) {
|
||||||
reader.readC(); // skip padding
|
reader.readC(); // skip padding
|
||||||
}
|
}
|
||||||
insList.push_back(newIns);
|
|
||||||
++readCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instrument name
|
// Instrument name
|
||||||
|
@ -1154,7 +1151,6 @@ void DivEngine::loadGYB(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
||||||
if (reader.size() != fileSize || bankOffset > fileSize || mapOffset > fileSize) {
|
if (reader.size() != fileSize || bankOffset > fileSize || mapOffset > fileSize) {
|
||||||
lastError = "GYBv3 file appears to have invalid data offsets.";
|
lastError = "GYBv3 file appears to have invalid data offsets.";
|
||||||
logE("GYBv3 file appears to have invalid data offsets.");
|
logE("GYBv3 file appears to have invalid data offsets.");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!reader.seek(bankOffset, SEEK_SET)) {
|
if (!reader.seek(bankOffset, SEEK_SET)) {
|
||||||
|
@ -1163,7 +1159,13 @@ void DivEngine::loadGYB(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
||||||
uint16_t insCount = reader.readS();
|
uint16_t insCount = reader.readS();
|
||||||
|
|
||||||
for (int i = 0; i < insCount; ++i) {
|
for (int i = 0; i < insCount; ++i) {
|
||||||
|
uint16_t patchPos = reader.tell();
|
||||||
|
uint16_t patchSize = reader.readS();
|
||||||
|
|
||||||
DivInstrument* newIns = readInstrument(reader, true);
|
DivInstrument* newIns = readInstrument(reader, true);
|
||||||
|
insList.push_back(newIns);
|
||||||
|
++readCount;
|
||||||
|
|
||||||
reader.readC(); // skip transpose
|
reader.readC(); // skip transpose
|
||||||
uint8_t additionalDataFlags = reader.readC() & 0x1; // skip additional data bitfield
|
uint8_t additionalDataFlags = reader.readC() & 0x1; // skip additional data bitfield
|
||||||
// TODO if chord notes attached, skip this
|
// TODO if chord notes attached, skip this
|
||||||
|
@ -1173,13 +1175,9 @@ void DivEngine::loadGYB(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
||||||
reader.readC();
|
reader.readC();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reader.readC(); // padding
|
|
||||||
reader.readC(); // padding
|
|
||||||
uint8_t nameLen = reader.readC();
|
uint8_t nameLen = reader.readC();
|
||||||
String insName = (nameLen > 0) ? reader.readString(nameLen) : fmt::sprintf("%s [%d]", stripPath, readCount++);
|
String insName = (nameLen > 0) ? reader.readString(nameLen) : fmt::sprintf("%s [%d]", stripPath, readCount++);
|
||||||
newIns->name = insName;
|
newIns->name = insName;
|
||||||
insList.push_back(newIns);
|
|
||||||
++readCount;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reader.seek(0, SEEK_END);
|
reader.seek(0, SEEK_END);
|
||||||
|
@ -1252,10 +1250,18 @@ void DivEngine::loadOPM(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
||||||
op.dt2 = readIntStrWithinRange(reader.readStringToken(), 0, 3);
|
op.dt2 = readIntStrWithinRange(reader.readStringToken(), 0, 3);
|
||||||
op.am = readIntStrWithinRange(reader.readStringToken(), 0, 1);
|
op.am = readIntStrWithinRange(reader.readStringToken(), 0, 1);
|
||||||
};
|
};
|
||||||
|
auto seekGroupValStart = [](SafeReader& reader, int pos) {
|
||||||
|
// Seek to position then move to next ':' character
|
||||||
|
if (!reader.seek(pos, SEEK_SET)) {
|
||||||
|
throw EndOfFileException(&reader, pos);
|
||||||
|
}
|
||||||
|
reader.readStringToken(':', false);
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
reader.seek(0, SEEK_SET);
|
reader.seek(0, SEEK_SET);
|
||||||
while (!reader.isEOF()) {
|
while (!reader.isEOF()) {
|
||||||
|
size_t linePos = reader.tell();
|
||||||
String token = reader.readStringToken();
|
String token = reader.readStringToken();
|
||||||
if (token.size() == 0) {
|
if (token.size() == 0) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1276,58 +1282,63 @@ void DivEngine::loadOPM(SafeReader& reader, std::vector<DivInstrument*>& ret, St
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read each line for their respective params. They may not be written in the same LINE order but they
|
// Read each line for their respective params. They may not be written in the same LINE order but they
|
||||||
// must absolutely be properly grouped per patch! Line prefixes MUST be separated by a space!
|
// must absolutely be properly grouped per patch! See inline comments indicating line structure examples.
|
||||||
// (see inline comments indicating line structure examples)
|
|
||||||
|
|
||||||
if (token.size() >= 2) {
|
if (token.size() >= 2) {
|
||||||
|
// Checking line prefixes since they sometimes may not have a space after the ':'
|
||||||
if (token[0] == '@') {
|
if (token[0] == '@') {
|
||||||
// @:123 Name of patch
|
// @:123 Name of patch
|
||||||
// Note: Fallback to bank filename and current patch number in _file_ order (not @n order)
|
seekGroupValStart(reader, linePos);
|
||||||
|
// Note: Fallback to bank filename and current patch number specified by @n
|
||||||
|
String opmPatchNum = reader.readStringToken();
|
||||||
newPatch->name = reader.readStringLine();
|
newPatch->name = reader.readStringLine();
|
||||||
newPatch->name = newPatch->name.size() > 0 ? newPatch->name : fmt::sprintf("%s[%d]", stripPath, readCount);
|
newPatch->name = newPatch->name.size() > 0 ? newPatch->name : fmt::sprintf("%s @%s", stripPath, opmPatchNum);
|
||||||
patchNameRead = true;
|
patchNameRead = true;
|
||||||
|
|
||||||
} else if (token == "CH:") {
|
} else if (token.compare(0,3,"CH:") == 0) {
|
||||||
// CH: PAN FL CON AMS PMS SLOT NE
|
// CH: PAN FL CON AMS PMS SLOT NE
|
||||||
|
seekGroupValStart(reader, linePos);
|
||||||
reader.readStringToken(); // skip PAN
|
reader.readStringToken(); // skip PAN
|
||||||
newPatch->fm.fb = readIntStrWithinRange(reader.readStringToken(), 0, 7);
|
newPatch->fm.fb = readIntStrWithinRange(reader.readStringToken(), 0, 7);
|
||||||
newPatch->fm.alg = readIntStrWithinRange(reader.readStringToken(), 0, 7);
|
newPatch->fm.alg = readIntStrWithinRange(reader.readStringToken(), 0, 7);
|
||||||
newPatch->fm.ams = readIntStrWithinRange(reader.readStringToken(), 0, 4);
|
newPatch->fm.ams = readIntStrWithinRange(reader.readStringToken(), 0, 4);
|
||||||
newPatch->fm.fms = readIntStrWithinRange(reader.readStringToken(), 0, 7);
|
newPatch->fm.fms = readIntStrWithinRange(reader.readStringToken(), 0, 7);
|
||||||
reader.readStringToken(); // skip SLOT
|
reader.readStringToken(); // skip SLOT (no furnace equivalent...yet?)
|
||||||
reader.readStringToken(); // skip NE
|
reader.readStringToken(); // skip NE (^^^)
|
||||||
characteristicRead = true;
|
characteristicRead = true;
|
||||||
|
|
||||||
} else if (token == "C1:") {
|
} else if (token.compare(0,3,"C1:") == 0) {
|
||||||
// C1: AR D1R D2R RR D1L TL KS MUL DT1 DT2 AMS-EN
|
// C1: AR D1R D2R RR D1L TL KS MUL DT1 DT2 AMS-EN
|
||||||
|
seekGroupValStart(reader, linePos);
|
||||||
readOpmOperator(reader, newPatch->fm.op[2]);
|
readOpmOperator(reader, newPatch->fm.op[2]);
|
||||||
c1Read = true;
|
c1Read = true;
|
||||||
|
|
||||||
} else if (token == "C2:") {
|
} else if (token.compare(0,3,"C2:") == 0) {
|
||||||
// C2: AR D1R D2R RR D1L TL KS MUL DT1 DT2 AMS-EN
|
// C2: AR D1R D2R RR D1L TL KS MUL DT1 DT2 AMS-EN
|
||||||
|
seekGroupValStart(reader, linePos);
|
||||||
readOpmOperator(reader, newPatch->fm.op[3]);
|
readOpmOperator(reader, newPatch->fm.op[3]);
|
||||||
c2Read = true;
|
c2Read = true;
|
||||||
|
|
||||||
} else if (token == "M1:") {
|
} else if (token.compare(0,3,"M1:") == 0) {
|
||||||
// M1: AR D1R D2R RR D1L TL KS MUL DT1 DT2 AMS-EN
|
// M1: AR D1R D2R RR D1L TL KS MUL DT1 DT2 AMS-EN
|
||||||
|
seekGroupValStart(reader, linePos);
|
||||||
readOpmOperator(reader, newPatch->fm.op[0]);
|
readOpmOperator(reader, newPatch->fm.op[0]);
|
||||||
m1Read = true;
|
m1Read = true;
|
||||||
|
|
||||||
} else if (token == "M2:") {
|
} else if (token.compare(0,3,"M2:") == 0) {
|
||||||
// M2: AR D1R D2R RR D1L TL KS MUL DT1 DT2 AMS-EN
|
// M2: AR D1R D2R RR D1L TL KS MUL DT1 DT2 AMS-EN
|
||||||
|
seekGroupValStart(reader, linePos);
|
||||||
readOpmOperator(reader, newPatch->fm.op[1]);
|
readOpmOperator(reader, newPatch->fm.op[1]);
|
||||||
m2Read = true;
|
m2Read = true;
|
||||||
|
|
||||||
} else if (token.compare(0,4,"LFO:") == 0) {
|
} else if (token.compare(0,4,"LFO:") == 0) {
|
||||||
// LFO:LFRQ AMD PMD WF NFRQ
|
// LFO:LFRQ AMD PMD WF NFRQ
|
||||||
|
seekGroupValStart(reader, linePos);
|
||||||
// Furnace patches do not store these as they are chip-global.
|
// Furnace patches do not store these as they are chip-global.
|
||||||
reader.readStringLine();
|
reader.readStringLine();
|
||||||
lfoRead = true;
|
lfoRead = true;
|
||||||
|
|
||||||
} else {
|
|
||||||
// other unsupported lines ignored.
|
|
||||||
reader.readStringLine();
|
|
||||||
}
|
}
|
||||||
|
// other unsupported lines ignored.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (completePatchRead()) {
|
if (completePatchRead()) {
|
||||||
|
|
|
@ -200,5 +200,6 @@ String SafeReader::readStringToken(unsigned char delim, bool stripContiguous) {
|
||||||
}
|
}
|
||||||
|
|
||||||
String SafeReader::readStringToken() {
|
String SafeReader::readStringToken() {
|
||||||
|
// This will strip LHS whitespace and only return contents after it.
|
||||||
return readStringToken(' ', true);
|
return readStringToken(' ', true);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue