audit .ftm import code
to-do: dkc_ending.ftm and fcm9.ftm no longer load... check out why
This commit is contained in:
parent
11d6cbc748
commit
6efef65b48
|
@ -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, ¯os[index][type], Types[i], setting);
|
||||
// memcpy(ins->std.get_macro(DIV_MACRO_VOL + (DivMacroType)Types[i], true), ¯os[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, ¯os[sequenceIndex[k][j]][j], j, setting);
|
||||
// memcpy(ins->std.get_macro(DIV_MACRO_VOL + (DivMacroType)j, true), ¯os[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, ¯os[sequenceIndex[k][Types[i]]][Types[i]], Types[i], setting);
|
||||
// memcpy(ins->std.get_macro(DIV_MACRO_VOL + (DivMacroType)Types[i], true), ¯os[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, ¯os[index][type], type, setting);
|
||||
// memcpy(ins->std.get_macro(DIV_MACRO_VOL + (DivMacroType)Types[i], true), ¯os[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, ¯os[index][type], type, setting);
|
||||
// memcpy(ins->std.get_macro(DIV_MACRO_VOL + (DivMacroType)Types[i], true), ¯os[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, ¯os[index][type], type, setting);
|
||||
// memcpy(ins->std.get_macro(DIV_MACRO_VOL + (DivMacroType)Types[i], true), ¯os[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) {
|
||||
|
|
Loading…
Reference in a new issue