audit .ftm import code

to-do: dkc_ending.ftm and fcm9.ftm no longer load... check out why
This commit is contained in:
tildearrow 2024-04-14 12:45:17 -05:00
parent 11d6cbc748
commit 6efef65b48

View file

@ -23,7 +23,6 @@
// portions apparently taken from FamiTracker source, which is under GPLv2+
// TODO:
// - audit for CVEs
// - format code?
#include "fileOpsCommon.h"
@ -258,6 +257,7 @@ const int eff_conversion_050[][2] = {
};
constexpr int ftEffectMapSize = sizeof(ftEffectMap) / sizeof(int);
constexpr int eftEffectMapSize = sizeof(eftEffectMap) / sizeof(int);
int convertMacros2A03[5] = {(int)DIV_MACRO_VOL, (int)DIV_MACRO_ARP, (int)DIV_MACRO_PITCH, -1, (int)DIV_MACRO_DUTY};
int convertMacrosVRC6[5] = {(int)DIV_MACRO_VOL, (int)DIV_MACRO_ARP, (int)DIV_MACRO_PITCH, -1, (int)DIV_MACRO_DUTY};
@ -434,7 +434,8 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
bool hasSequence[256][8];
unsigned char sequenceIndex[256][8];
unsigned char macro_types[256][8];
std::vector<std::vector<DivInstrumentMacro>> macros;
std::vector<DivInstrumentMacro> macros[256];
std::vector<String> encounteredBlocks;
unsigned char map_channels[DIV_MAX_CHANS];
unsigned int hilightA = 4;
unsigned int hilightB = 16;
@ -457,13 +458,9 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
memset(map_channels, 0xfe, DIV_MAX_CHANS * sizeof(unsigned char));
for (int i = 0; i < 256; i++) {
std::vector<DivInstrumentMacro> mac;
for (int j = 0; j < 8; j++) {
mac.push_back(DivInstrumentMacro(DIV_MACRO_VOL));
macros[i].push_back(DivInstrumentMacro(DIV_MACRO_VOL));
}
macros.push_back(mac);
}
if (!reader.seek((dnft && dnft_sig) ? 21 : 18, SEEK_SET)) {
@ -482,7 +479,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
return false;
}
for (DivSubSong* i : ds.subsong) {
for (DivSubSong* i: ds.subsong) {
i->clearData();
delete i;
}
@ -501,13 +498,30 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
// not the end
reader.seek(-3, SEEK_CUR);
if (!reader.seek(-3, SEEK_CUR)) {
logE("couldn't seek back by 3!");
lastError = "couldn't seek back by 3";
delete[] file;
return false;
}
blockName = reader.readString(16);
unsigned int blockVersion = (unsigned int)reader.readI();
unsigned int blockSize = (unsigned int)reader.readI();
size_t blockStart = reader.tell();
logD("reading block %s (version %d, %d bytes, position %x)", blockName, blockVersion, blockSize, reader.tell());
for (String& i: encounteredBlocks) {
if (blockName==i) {
logE("duplicate block %s!",blockName);
lastError = "duplicate block "+blockName;
ds.unload();
delete[] file;
return false;
}
}
encounteredBlocks.push_back(blockName);
if (blockName == "PARAMS") {
// versions 7-9 don't change anything?
CHECK_BLOCK_VERSION(9);
@ -529,6 +543,13 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
tchans = reader.readI();
if (tchans<0 || tchans>=DIV_MAX_CHANS) {
logE("invalid channel count! %d",tchans);
lastError = "invalid channel count";
delete[] file;
return false;
}
if (tchans == 5) {
expansions = 0; // This is strange. Sometimes expansion chip is set to 0xFF in files
}
@ -538,12 +559,15 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
if (blockVersion >= 7) {
// advanced Hz control
int controlType = reader.readI();
switch (controlType) {
int readHz=reader.readI();
if (readHz<=0) {
customHz=60.0;
} else switch (controlType) {
case 1:
customHz = 1000000.0 / (double)reader.readI();
customHz = 1000000.0 / (double)readHz;
break;
default:
reader.readI();
logW("unsupported tick rate control type %d",controlType);
break;
}
} else {
@ -553,6 +577,9 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
customHz = reader.readI();
}
if (customHz<1.0) customHz=1.0;
if (customHz>1000.0) customHz=1000.0;
unsigned int newVibrato = 0;
bool sweepReset = false;
unsigned int speedSplitPoint = 0;
@ -576,6 +603,12 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
if ((expansions & 16) && blockVersion >= 5) { // N163 channels
n163Chans = reader.readI();
if (n163Chans<1 || n163Chans>=9) {
logE("invalid Namco 163 channel count! %d",n163Chans);
lastError = "invalid Namco 163 channel count";
delete[] file;
return false;
}
}
if (blockVersion >= 6) {
speedSplitPoint = reader.readI();
@ -779,6 +812,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
}
if (calcChans != tchans) {
// TODO: would ignore trigger CVE? too bad if so!
if (!eft || (eft && (expansions & 8) == 0)) // ignore since I have no idea how to tell apart E-FT versions which do or do not have PCM chan. Yes, this may lead to all the righer channels to be shifted but at least you still get note data!
{
logE("channel counts do not match! %d != %d", tchans, calcChans);
@ -788,17 +822,20 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
}
if (tchans > DIV_MAX_CHANS) {
tchans = DIV_MAX_CHANS;
logW("too many channels!");
logE("too many channels!");
lastError = "too many channels";
delete[] file;
return false;
}
if (blockVersion == 9 && blockSize - (reader.tell() - blockStart) == 2) // weird
{
reader.seek(2, SEEK_CUR);
if (!reader.seek(2, SEEK_CUR)) {
logE("could not weird-seek by 2!");
lastError = "could not weird-seek by 2";
delete[] file;
return false;
}
}
if (eft) {
// reader.seek(8,SEEK_CUR);
}
} else if (blockName == "INFO") {
CHECK_BLOCK_VERSION(1);
ds.name = reader.readString(32);
@ -831,6 +868,13 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
for (int j = 0; j <= totalSongs; j++) {
unsigned char effectCols = reader.readC();
if (effectCols>7) {
logE("too many effect columns!");
lastError = "too many effect columns";
delete[] file;
return false;
}
if (map_channels[i] == 0xfe) {
ds.subsong[j]->pat[i].effectCols = 1;
logV("- song %d has %d effect columns", j, effectCols);
@ -850,8 +894,6 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
} else if (blockName == "INSTRUMENTS") {
CHECK_BLOCK_VERSION(9);
// reader.seek(blockSize,SEEK_CUR);
ds.insLen = reader.readI();
if (ds.insLen < 0 || ds.insLen > 256) {
logE("too many instruments/out of range!");
@ -870,10 +912,10 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
for (int i = 0; i < ds.insLen; i++) {
unsigned int insIndex = reader.readI();
if (insIndex >= ds.ins.size()) {
// logE("instrument index %d is out of range!",insIndex);
// lastError="instrument index out of range";
// delete[] file;
// return false;
logE("instrument index %d is out of range!",insIndex);
lastError="instrument index out of range";
delete[] file;
return false;
}
DivInstrument* ins = ds.ins[insIndex];
@ -937,6 +979,12 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
if (blockVersion >= 7) {
note = reader.readC();
}
if (note<0 || note>=120) {
logE("DPCM note %d out of range!",note);
lastError = "DPCM note out of range";
delete[] file;
return false;
}
ins->amiga.noteMap[note].map = (short)((unsigned char)reader.readC()) - 1;
unsigned char freq = reader.readC();
ins->amiga.noteMap[note].dpcmFreq = (freq & 15); // 0-15 = 0-15 unlooped, 128-143 = 0-15 looped
@ -981,8 +1029,9 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
case DIV_INS_OPLL: {
ins->fm.opllPreset = (unsigned int)reader.readI();
ins->fm.opllPreset&=15;
unsigned char custom_patch[8] = {0};
unsigned char custom_patch[8];
for (int i = 0; i < 8; i++) {
custom_patch[i] = reader.readC();
@ -1020,24 +1069,35 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
for (int j = 0; j < 64; j++) {
wave->data[j] = reader.readC();
}
ins->std.waveMacro.len = 1;
ins->std.waveMacro.val[0] = ds.wave.size();
for (int j = 0; j < 32; j++) {
ins->fds.modTable[j] = reader.readC() - 3;
}
ins->fds.modSpeed = reader.readI();
ins->fds.modDepth = reader.readI();
reader.readI(); // this is delay. currently ignored. TODO.
ds.wave.push_back(wave);
ds.waveLen++;
if (ds.wave.size()>=256) {
logW("too many waves! ignoring...");
delete wave;
} else {
ins->std.waveMacro.len = 1;
ins->std.waveMacro.val[0] = ds.wave.size();
ds.wave.push_back(wave);
ds.waveLen++;
}
unsigned int a = reader.readI();
unsigned int b = reader.readI();
reader.seek(-8, SEEK_CUR);
if (!reader.seek(-8, SEEK_CUR)) {
logE("couldn't seek back by 8 reading FDS ins");
lastError = "couldn't seek back by 8 reading FDS ins";
delete[] file;
return false;
}
if (a < 256 && (b & 0xFF) != 0x00) {
// don't look at me like this. I don't know why this should be like this either!
logW("a is less than 256 and b is not zero!");
} else {
ins->std.volMacro.len = reader.readC();
ins->std.volMacro.loop = reader.readI();
@ -1112,12 +1172,19 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
if (blockVersion >= 8) {
unsigned int autopos = reader.readI();
(void)autopos;
logV("autopos: %d",autopos);
}
unsigned int wave_count = reader.readI();
size_t waveOff = ds.wave.size();
if (wave_size>256) {
logE("wave size %d out of range",wave_size);
lastError = "wave size out of range";
delete[] file;
return false;
}
for (unsigned int ii = 0; ii < wave_count; ii++) {
DivWavetable* wave = new DivWavetable();
wave->len = wave_size;
@ -1131,6 +1198,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
if (ds.wave.size()<256) {
ds.wave.push_back(wave);
} else {
logW("too many waves...");
delete wave;
}
}
@ -1296,16 +1364,30 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
if (instVersion == 2) {
reader.seek(seek_amount, SEEK_CUR); // what the fuck
// I know right?
if (!reader.seek(seek_amount, SEEK_CUR)) {
logE("EFT seek fail");
lastError = "EFT seek fail";
delete[] file;
return false;
}
}
// this commented out block left here intentionally.
// total mess of code style... for with no space, UNDEFINED CHAR, escaping the unescapable, silly var names...
// ...whatever.
/*for(int tti = 0; tti < 20; tti++)
{
char aaaa = reader.readC();
logV("\'%c\'", aaaa);
}*/
} else {
reader.seek(-4, SEEK_CUR);
if (!reader.seek(-4, SEEK_CUR)) {
logE("EFT -4 seek fail");
lastError = "EFT -4 seek fail";
delete[] file;
return false;
}
}
break;
@ -1325,7 +1407,6 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
ds.insLen = 128;
} else if (blockName == "SEQUENCES") {
CHECK_BLOCK_VERSION(6);
@ -1342,6 +1423,14 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
unsigned int index = reader.readI();
unsigned int type = reader.readI();
unsigned char size = reader.readC();
if (index>=256 || type>=8) {
logE("%d: index/type out of range",i);
lastError = "sequence index/type out of range";
delete[] file;
return false;
}
macros[index][type].len = size;
for (int j = 0; j < size; j++) {
@ -1361,12 +1450,34 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
unsigned char* Indices = new unsigned char[128 * 5];
unsigned char* Types = new unsigned char[128 * 5];
memset(Indices,0,128*5);
memset(Types,0,128*5);
for (unsigned int i = 0; i < seq_count; i++) {
unsigned int index = reader.readI();
if (index>=128*5) {
logE("%d: index out of range",i);
lastError = "sequence index out of range";
delete[] file;
return false;
}
Indices[i] = index;
unsigned int type = reader.readI();
if (type>=128*5) {
logE("%d: type out of range",i);
lastError = "sequence type out of range";
delete[] file;
return false;
}
Types[i] = type;
if (index>=256 || type>=8) {
logE("%d: index/type out of range",i);
lastError = "sequence index/type out of range";
delete[] file;
return false;
}
unsigned char size = reader.readC();
unsigned int setting = 0;
@ -1393,7 +1504,6 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
DivInstrument* ins = ds.ins[k];
if (sequenceIndex[k][Types[i]] == Indices[i] && ins->type == DIV_INS_NES && hasSequence[k][Types[i]]) {
copyMacro(ins, &macros[index][type], Types[i], setting);
// memcpy(ins->std.get_macro(DIV_MACRO_VOL + (DivMacroType)Types[i], true), &macros[sequenceIndex[index][type]][type], sizeof(DivInstrumentMacro));
}
}
}
@ -1412,7 +1522,6 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
macro_types[k][j] = setting;
copyMacro(ins, &macros[sequenceIndex[k][j]][j], j, setting);
// memcpy(ins->std.get_macro(DIV_MACRO_VOL + (DivMacroType)j, true), &macros[sequenceIndex[k][j]][j], sizeof(DivInstrumentMacro));
}
}
}
@ -1425,9 +1534,6 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
unsigned int release = reader.readI();
unsigned int setting = reader.readI();
// macros[index][type].rel = release;
// macro_types[index][type] = setting;
for (int k = 0; k < (int)ds.ins.size(); k++) {
DivInstrument* ins = ds.ins[k];
if (sequenceIndex[k][Types[i]] == Indices[i] && ins->type == DIV_INS_NES && hasSequence[k][Types[i]]) {
@ -1435,7 +1541,6 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
macro_types[k][Types[i]] = setting;
copyMacro(ins, &macros[sequenceIndex[k][Types[i]]][Types[i]], Types[i], setting);
// memcpy(ins->std.get_macro(DIV_MACRO_VOL + (DivMacroType)Types[i], true), &macros[sequenceIndex[k][Types[i]]][Types[i]], sizeof(DivInstrumentMacro));
}
}
}
@ -1446,12 +1551,11 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
} else if (blockName == "GROOVES") {
CHECK_BLOCK_VERSION(6);
// reader.seek(blockSize,SEEK_CUR);
unsigned char num_grooves = reader.readC();
int max_groove = 0;
for (int i = 0; i < 0xff; i++) {
for (int i = 0; i < 256; i++) {
ds.grooves.push_back(DivGroovePattern());
}
@ -1459,15 +1563,18 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
unsigned char index = reader.readC();
unsigned char size = reader.readC();
if (index > max_groove)
if (index > max_groove) {
max_groove = index + 1;
}
DivGroovePattern gp;
gp.len = size;
for (int sz = 0; sz < size; sz++) {
unsigned char value = reader.readC();
gp.val[sz] = value;
if (sz<16) {
gp.val[sz] = value;
}
}
ds.grooves[index] = gp;
@ -1488,14 +1595,21 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
if ((reader.tell() - blockStart) != blockSize) {
logE("block %s size does not match! block size %d curr pos %d", blockName, blockSize, reader.tell() - blockStart);
}
} else if (blockName == "FRAMES") {
CHECK_BLOCK_VERSION(3);
for (size_t i = 0; i < ds.subsong.size(); i++) {
DivSubSong* s = ds.subsong[i];
s->ordersLen = reader.readI();
int framesLen=reader.readI();
if (framesLen<=1 || framesLen>=256) {
logE("frames out of range");
lastError = "frames out of range";
delete[] file;
return false;
}
s->ordersLen = framesLen;
if (blockVersion >= 3) {
s->speeds.val[0] = reader.readI();
}
@ -1510,18 +1624,31 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
s->virtualTempoN = tempo;
}
s->patLen = reader.readI();
int patLen=reader.readI();
if (patLen<1 || patLen>=256) {
logE("pattern length out of range");
lastError = "pattern length out of range";
delete[] file;
return false;
}
s->patLen = patLen;
}
int why = tchans;
if (blockVersion == 1) {
why = reader.readI();
if (why<0 || why>=DIV_MAX_CHANS) {
logE("why out of range!");
lastError = "why out of range";
delete[] file;
return false;
}
}
logV("reading %d and %d orders", tchans, s->ordersLen);
for (int j = 0; j < s->ordersLen; j++) {
for (int k = 0; k < why; k++) {
unsigned char o = reader.readC();
// logV("%.2x",o);
if (map_channels[k]>=DIV_MAX_CHANS) continue;
s->orders.ord[map_channels[k]][j] = o;
}
}
@ -1533,6 +1660,12 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
if (blockVersion == 1) {
int patLenOld = reader.readI();
if (patLenOld<1 || patLenOld>=256) {
logE("old pattern length out of range");
lastError = "old pattern length out of range";
delete[] file;
return false;
}
for (DivSubSong* i : ds.subsong) {
i->patLen = patLenOld;
}
@ -1553,6 +1686,37 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
logV("patNum: %d",patNum);
logV("rows: %d",numRows);
if (subs<0 || subs>=(int)ds.subsong.size()) {
logE("subsong out of range!");
lastError = "subsong out of range";
delete[] file;
return false;
}
if (ch<0 || ch>=DIV_MAX_CHANS) {
logE("channel out of range!");
lastError = "channel out of range";
delete[] file;
return false;
}
if (map_channels[ch]>=DIV_MAX_CHANS) {
logE("mapped channel out of range!");
lastError = "mapped channel out of range";
delete[] file;
return false;
}
if (patNum<0 || patNum>=256) {
logE("pattern number out of range!");
lastError = "pattern number out of range";
delete[] file;
return false;
}
if (numRows<0) {
logE("row count is negative!");
lastError = "row count is negative";
delete[] file;
return false;
}
DivPattern* pat = ds.subsong[subs]->pat[map_channels[ch]].getPattern(patNum, true);
for (int i = 0; i < numRows; i++) {
unsigned int row = 0;
@ -1562,6 +1726,13 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
row = reader.readI();
}
if (row>=256) {
logE("row index out of range");
lastError = "row index out of range";
delete[] file;
return false;
}
unsigned char nextNote = reader.readC();
unsigned char nextOctave = reader.readC();
@ -1592,6 +1763,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
unsigned char nextIns = reader.readC();
// TODO: you sure about 0xff?
if (map_channels[ch] != 0xff) {
if (nextIns < 0x40 && nextNote != 0x0d && nextNote != 0x0e) {
pat->data[row][2] = nextIns;
@ -1606,6 +1778,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
pat->data[row][3] = nextVol;
if (map_channels[ch] == vrc6_saw_chan) // scale volume
{
// TODO: shouldn't it be 32?
pat->data[row][3] = (pat->data[row][3] * 42) / 15;
}
@ -1625,13 +1798,9 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
effectCols = 1;
}
logV("effectCols: %d",effectCols);
unsigned char nextEffectVal = 0;
unsigned char nextEffect = 0;
//logV("row %d effects are read at %x",row,reader.tell());
for (int j = 0; j < effectCols; j++) {
nextEffect = reader.readC();
@ -1727,14 +1896,12 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
// logW("next effect %d val %d", nextEffect, nextEffectVal);
if (map_channels[ch] != 0xff) {
if (nextEffect == 0 && nextEffectVal == 0) {
pat->data[row][4 + (j * 2)] = -1;
pat->data[row][5 + (j * 2)] = -1;
} else {
if (nextEffect < ftEffectMapSize) {
if ((eft && nextEffect<eftEffectMapSize) || (!eft && nextEffect<ftEffectMapSize)) {
if (eft) {
pat->data[row][4 + (j * 2)] = eftEffectMap[nextEffect];
pat->data[row][5 + (j * 2)] = eftEffectMap[nextEffect] == -1 ? -1 : nextEffectVal;
@ -1782,7 +1949,6 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
} else if (blockName == "DPCM SAMPLES") {
CHECK_BLOCK_VERSION(1);
// reader.seek(blockSize,SEEK_CUR);
unsigned char num_samples = reader.readC();
for (int i = 0; i < 256; i++) {
@ -1808,14 +1974,16 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
unsigned int sample_len = reader.readI();
if (sample_len>=2097152) {
logE("%d: sample too large! %d",index,sample_len);
lastError = "sample too large";
delete[] file;
return false;
}
true_size = sample_len + ((1 - (int)sample_len) & 0x0f);
sample->lengthDPCM = true_size;
sample->samples = true_size * 8;
sample->dataDPCM = new unsigned char[true_size];
sample->init(true_size * 8);
memset(sample->dataDPCM, 0xAA, true_size);
reader.read(sample->dataDPCM, sample_len);
}
@ -1824,7 +1992,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
for (int i = 255; i > 0; i--) {
DivSample* s = ds.sample[i];
if (s->dataDPCM) {
if (s->samples>0) {
last_non_empty_sample = i;
break;
}
@ -1835,21 +2003,42 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
ds.sampleLen = ds.sample.size();
} else if (blockName == "SEQUENCES_VRC6") {
CHECK_BLOCK_VERSION(6);
unsigned char* Indices = new unsigned char[128 * 5];
unsigned char* Types = new unsigned char[128 * 5];
memset(Indices,0,128*5);
memset(Types,0,128*5);
unsigned int seq_count = reader.readI();
for (unsigned int i = 0; i < seq_count; i++) {
unsigned int index = reader.readI();
if (index>=128*5) {
logE("%d: index out of range",i);
lastError = "sequence index out of range";
delete[] file;
return false;
}
Indices[i] = index;
unsigned int type = reader.readI();
if (type>=128*5) {
logE("%d: type out of range",i);
lastError = "sequence type out of range";
delete[] file;
return false;
}
Types[i] = type;
if (index>=256 || type>=8) {
logE("%d: index/type out of range",i);
lastError = "sequence index/type out of range";
delete[] file;
return false;
}
unsigned char size = reader.readC();
unsigned int setting = 0;
@ -1914,9 +2103,6 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
unsigned int release = reader.readI();
unsigned int setting = reader.readI();
// macros[index][type].rel = release;
// macro_types[index][type] = setting;
for (int k = 0; k < (int)ds.ins.size(); k++) {
DivInstrument* ins = ds.ins[k];
if (sequenceIndex[k][Types[i]] == Indices[i] && ins->type == DIV_INS_VRC6 && hasSequence[k][Types[i]]) {
@ -1937,19 +2123,40 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
delete[] Types;
} else if (blockName == "SEQUENCES_N163" || blockName == "SEQUENCES_N106") {
CHECK_BLOCK_VERSION(1);
// reader.seek(blockSize,SEEK_CUR);
unsigned char* Indices = new unsigned char[128 * 5];
unsigned char* Types = new unsigned char[128 * 5];
memset(Indices,0,128*5);
memset(Types,0,128*5);
unsigned int seq_count = reader.readI();
for (unsigned int i = 0; i < seq_count; i++) {
unsigned int index = reader.readI();
if (index>=128*5) {
logE("%d: index out of range",i);
lastError = "sequence index out of range";
delete[] file;
return false;
}
Indices[i] = index;
unsigned int type = reader.readI();
if (type>=128*5) {
logE("%d: type out of range",i);
lastError = "sequence type out of range";
delete[] file;
return false;
}
Types[i] = type;
if (index>=256 || type>=8) {
logE("%d: index/type out of range",i);
lastError = "sequence index/type out of range";
delete[] file;
return false;
}
unsigned char size = reader.readC();
unsigned int setting = 0;
@ -1974,7 +2181,6 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
DivInstrument* ins = ds.ins[k];
if (sequenceIndex[k][Types[i]] == Indices[i] && ins->type == DIV_INS_N163 && hasSequence[k][Types[i]]) {
copyMacro(ins, &macros[index][type], type, setting);
// memcpy(ins->std.get_macro(DIV_MACRO_VOL + (DivMacroType)Types[i], true), &macros[sequenceIndex[index][type]][type], sizeof(DivInstrumentMacro));
}
}
}
@ -1984,19 +2190,40 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
} else if (blockName == "SEQUENCES_S5B") {
CHECK_BLOCK_VERSION(1);
// reader.seek(blockSize,SEEK_CUR);
unsigned char* Indices = new unsigned char[128 * 5];
unsigned char* Types = new unsigned char[128 * 5];
memset(Indices,0,128*5);
memset(Types,0,128*5);
unsigned int seq_count = reader.readI();
for (unsigned int i = 0; i < seq_count; i++) {
unsigned int index = reader.readI();
if (index>=128*5) {
logE("%d: index out of range",i);
lastError = "sequence index out of range";
delete[] file;
return false;
}
Indices[i] = index;
unsigned int type = reader.readI();
if (type>=128*5) {
logE("%d: type out of range",i);
lastError = "sequence type out of range";
delete[] file;
return false;
}
Types[i] = type;
if (index>=256 || type>=8) {
logE("%d: index/type out of range",i);
lastError = "sequence index/type out of range";
delete[] file;
return false;
}
unsigned char size = reader.readC();
unsigned int setting = 0;
@ -2021,7 +2248,6 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
DivInstrument* ins = ds.ins[k];
if (sequenceIndex[k][type] == Indices[i] && ins->type == DIV_INS_AY && hasSequence[k][type]) {
copyMacro(ins, &macros[index][type], type, setting);
// memcpy(ins->std.get_macro(DIV_MACRO_VOL + (DivMacroType)Types[i], true), &macros[sequenceIndex[index][type]][type], sizeof(DivInstrumentMacro));
}
}
}
@ -2034,14 +2260,36 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
unsigned char* Indices = new unsigned char[128 * 5];
unsigned char* Types = new unsigned char[128 * 5];
memset(Indices,0,128*5);
memset(Types,0,128*5);
unsigned int seq_count = reader.readI();
for (unsigned int i = 0; i < seq_count; i++) {
unsigned int index = reader.readI();
if (index>=128*5) {
logE("%d: index out of range",i);
lastError = "sequence index out of range";
delete[] file;
return false;
}
Indices[i] = index;
unsigned int type = reader.readI();
if (type>=128*5) {
logE("%d: type out of range",i);
lastError = "sequence type out of range";
delete[] file;
return false;
}
Types[i] = type;
if (index>=256 || type>=8) {
logE("%d: index/type out of range",i);
lastError = "sequence index/type out of range";
delete[] file;
return false;
}
unsigned char size = reader.readC();
unsigned int setting = 0;
@ -2066,7 +2314,6 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
DivInstrument* ins = ds.ins[k];
if (sequenceIndex[k][type] == Indices[i] && ins->type == DIV_INS_C64 && hasSequence[k][type]) {
copyMacro(ins, &macros[index][type], type, setting);
// memcpy(ins->std.get_macro(DIV_MACRO_VOL + (DivMacroType)Types[i], true), &macros[sequenceIndex[index][type]][type], sizeof(DivInstrumentMacro));
}
}
}
@ -2075,31 +2322,33 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
delete[] Types;
} else if (blockName == "JSON") {
CHECK_BLOCK_VERSION(1);
logW("block JSON not supported...");
reader.seek(blockSize, SEEK_CUR);
} else if (blockName == "PARAMS_EMU") {
CHECK_BLOCK_VERSION(1);
logW("block PARAMS_EMU not supported...");
reader.seek(blockSize, SEEK_CUR);
} else if (blockName == "DETUNETABLES") {
CHECK_BLOCK_VERSION(1);
logW("block DETUNETABLES not supported...");
reader.seek(blockSize, SEEK_CUR);
} else if (blockName == "COMMENTS") {
CHECK_BLOCK_VERSION(1);
// reader.seek(blockSize,SEEK_CUR);
unsigned int display_comment = reader.readI();
(void)display_comment;
char ch = 1;
logV("displayComment: %d",display_comment);
do {
char ch = 0;
// why not readString?
while (true) {
ch = reader.readC();
String sss = String() + ch;
ds.subsong[0]->notes += sss;
} while (ch != 0);
if (ch==0) break;
ds.subsong[0]->notes += ch;
}
// ds.subsong[0]->notes = reader.readS();
} else if (blockName == "PARAMS_EXTRA") {
CHECK_BLOCK_VERSION(3);
// reader.seek(blockSize,SEEK_CUR);
unsigned int linear_pitch = reader.readI();
ds.linearPitch = linear_pitch == 0 ? 0 : 2;
@ -2112,11 +2361,10 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
if (blockVersion >= 3) {
unsigned char flats = reader.readC();
(void)flats;
logV("flats: %d",(int)flats);
}
} else if (blockName == "TUNING") {
CHECK_BLOCK_VERSION(1);
// reader.seek(blockSize,SEEK_CUR);
if (blockVersion == 1) {
int fineTuneCents = reader.readC() * 100;
fineTuneCents += reader.readC();
@ -2125,6 +2373,7 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
}
} else if (blockName == "BOOKMARKS") {
CHECK_BLOCK_VERSION(1);
logW("block BOOKMARKS not supported...");
reader.seek(blockSize, SEEK_CUR);
} else {
logE("block %s is unknown!", blockName);
@ -2152,6 +2401,8 @@ bool DivEngine::loadFTM(unsigned char* file, size_t len, bool dnft, bool dnft_si
if (index < 0)
index = 0;
if (index>=(int)ds.ins.size()) continue;
DivInstrument* ins = ds.ins[index];
if (ins->type == DIV_INS_FM) {