IT import: comments, channel names and pat names

the latter two are MPT extensions

this may not work on songs with MIDI macro setup info
This commit is contained in:
tildearrow 2025-09-06 17:46:16 -05:00
parent 7709640aa0
commit d0c4fb0b42
3 changed files with 126 additions and 0 deletions

View file

@ -363,6 +363,103 @@ bool DivEngine::loadIT(unsigned char* file, size_t len) {
patPtr[i]=reader.readI();
}
// skip edit history if present
if (special&2) {
logD("skipping edit history...");
unsigned short editHistSize=reader.readS();
if (editHistSize>0) {
if (!reader.seek(editHistSize*8,SEEK_CUR)) {
logV("what? I wasn't expecting that from you.");
}
}
}
// read extension blocks, if any
logD("looking for extensions...");
bool hasExtensions=true;
while (hasExtensions) {
char extType[4];
unsigned int extSize=0;
memset(extType,0,4);
reader.read(extType,4);
extSize=reader.readI();
if (memcmp(extType,"PNAM",4)==0) {
logV("found MPT extension: pattern names");
// check whether this block is valid
if (extSize>patCount*32) {
logV("block may not be valid");
break;
}
// read pattern names
logV("reading pattern names...");
for (unsigned int i=0; i<(extSize>>5); i++) {
DivPattern* p=ds.subsong[0]->pat[0].getPattern(i,true);
p->name=reader.readStringLatin1(32);
}
} else if (memcmp(extType,"CNAM",4)==0) {
logV("found MPT extension: channel names");
// check whether this block is valid
if (extSize>DIV_MAX_CHANS*20) {
logV("block may not be valid");
break;
}
// read channel names
logV("reading channel names...");
for (unsigned int i=0; i<(extSize>>5); i++) {
String chanName=reader.readStringLatin1(20);
for (DivSubSong* j: ds.subsong) {
j->chanName[i]=chanName;
}
}
} else if (memcmp(extType,"CHFX",4)==0) {
logV("found MPT extension: channel effects");
// skip (stop if we cannot seek)
if (!reader.seek(extSize,SEEK_CUR)) {
break;
}
} else if (
extType[0]=='F' &&
(extType[1]=='X' || (extType[1]>='0' && extType[1]<='9')) &&
(extType[2]>='0' && extType[2]<='9') &&
(extType[3]>='0' && extType[3]<='9')
) { // effect slot
logV("found MPT extension: effect slot");
// skip (stop if we cannot seek)
if (!reader.seek(extSize,SEEK_CUR)) {
break;
}
} else {
logV("no further extensions found... %.2x%.2x%.2x%.2x",extType[0],extType[1],extType[2],extType[3]);
hasExtensions=false;
}
}
// read song comment
logD("reading song comment...");
if (reader.seek(commentPtr,SEEK_SET)) {
try {
String comment=reader.readStringLatin1Special(commentLen);
ds.notes="";
ds.notes.reserve(comment.size());
for (char& i: comment) {
if (i=='\r') {
ds.notes+='\n';
} else {
ds.notes+=i;
}
}
} catch (EndOfFileException& e) {
logW("couldn't read song comment due to premature end of file.");
}
} else {
logW("couldn't seek to comment!");
}
// read instruments
for (int i=0; i<ds.insLen; i++) {
DivInstrument* ins=new DivInstrument;

View file

@ -271,6 +271,15 @@ String SafeReader::readStringWithEncoding(DivStringEncoding encoding, size_t stl
ret.push_back(c);
}
}
} else if (encoding==DIV_ENCODING_LATIN1_SPECIAL) {
if (c&0x80) {
if (c>=0xa0) {
ret.push_back(0xc0|(c>>6));
ret.push_back(0x80|(c&63));
}
} else {
ret.push_back(c);
}
} else {
ret.push_back(c);
}
@ -297,6 +306,15 @@ String SafeReader::readStringWithEncoding(DivStringEncoding encoding) {
ret.push_back(c);
}
}
} else if (encoding==DIV_ENCODING_LATIN1_SPECIAL) {
if (c&0x80) {
if (c>=0xa0) {
ret.push_back(0xc0|(c>>6));
ret.push_back(0x80|(c&63));
}
} else {
ret.push_back(c);
}
} else {
ret.push_back(c);
}
@ -320,6 +338,14 @@ String SafeReader::readStringLatin1(size_t stlen) {
return readStringWithEncoding(DIV_ENCODING_LATIN1,stlen);
}
String SafeReader::readStringLatin1Special() {
return readStringWithEncoding(DIV_ENCODING_LATIN1_SPECIAL);
}
String SafeReader::readStringLatin1Special(size_t stlen) {
return readStringWithEncoding(DIV_ENCODING_LATIN1_SPECIAL,stlen);
}
String SafeReader::readStringLine() {
String ret;
unsigned char c;

View file

@ -33,6 +33,7 @@ enum DivStringEncoding {
DIV_ENCODING_NONE=0,
DIV_ENCODING_UTF8,
DIV_ENCODING_LATIN1,
DIV_ENCODING_LATIN1_SPECIAL,
DIV_ENCODING_SHIFT_JIS
};
@ -77,6 +78,8 @@ class SafeReader {
String readString(size_t len);
String readStringLatin1();
String readStringLatin1(size_t len);
String readStringLatin1Special();
String readStringLatin1Special(size_t len);
String readStringLine();
String readStringToken(unsigned char delim, bool stripContiguous);
String readStringToken();