1
0
Fork 0
forked from len0rd/rockbox

FS#13539: Resync mikmod plugin with upstream

Brings it up to libmikmod 3.3.12, relased 2024-12-31

Also fix a segfault that only happened on simulators when using
non-default samplerates.

Change-Id: I2ade2d72a00edab5395328fe76a88a88516aac72
This commit is contained in:
Solomon Peachy 2025-01-03 08:34:47 -05:00
parent 08c32cee7c
commit af7ed73f31
29 changed files with 1860 additions and 706 deletions

View file

@ -94,7 +94,7 @@ static int AMF_Test(void)
if(memcmp(id,"AMF",3)) return 0;
ver=_mm_read_UBYTE(modreader);
if((ver>=10)&&(ver<=14)) return 1;
if((ver>=8)&&(ver<=14)) return 1;
return 0;
}
@ -114,7 +114,48 @@ static void AMF_Cleanup(void)
track=NULL;
}
static int AMF_UnpackTrack(MREADER* r)
/* Some older version 1.0 AMFs contain an anomaly where the sample length is
* a DWORD, the loop start is a WORD, and the loop end is missing. Later AMF
* 1.0 modules and up contain all three as DWORDs, and earlier versions have
* all three as WORDs. This function tries to detect this edge case in the
* instruments table. This should only be called on 1.0 AMFs.
*/
static int AMF_ScanV10Instruments(MREADER *r, unsigned int numins)
{
SLONG resetpos;
int res = 0;
char str[32];
ULONG idx, len, start, end;
UBYTE type, vol;
UWORD c2spd;
unsigned int i;
resetpos = _mm_ftell(r);
if(resetpos < 0) return 0;
for(i = 0; i < numins; i++) {
type = _mm_read_UBYTE(r); /* type: should be 0 or 1 */
_mm_read_string(str, 32, r); /* name */
_mm_read_string(str, 13, r); /* filename */
idx = _mm_read_I_ULONG(r); /* index (should be <= numins) */
len = _mm_read_I_ULONG(r);
c2spd = _mm_read_I_UWORD(r); /* should be > 0 */
vol = _mm_read_UBYTE(r); /* should be [0,0x40] */
start = _mm_read_I_ULONG(r); /* should be <= len */
end = _mm_read_I_ULONG(r); /* should be <= len */
if((type != 0 && type != 1) || (idx > numins) || (c2spd == 0) ||
(vol > 0x40) || (start > len) || (end > len)) {
res = 1;
break;
}
}
_mm_fseek(r, resetpos, SEEK_SET);
return res;
}
static int AMF_UnpackTrack(MREADER *r)
{
ULONG tracksize;
UBYTE row,cmd;
@ -126,7 +167,12 @@ static int AMF_UnpackTrack(MREADER* r)
/* read packed track */
if (r) {
tracksize=_mm_read_I_UWORD(r);
tracksize+=((ULONG)_mm_read_UBYTE(r))<<16;
/* The original code in DSMI library read the byte,
but it is not used, so we won't either */
// tracksize+=((ULONG)_mm_read_UBYTE(r))<<16;
(void)_mm_read_UBYTE(r);
if (tracksize)
while(tracksize--) {
row=_mm_read_UBYTE(r);
@ -144,18 +190,23 @@ static int AMF_UnpackTrack(MREADER* r)
}
/* invalid row (probably unexpected end of row) */
if (row>=64)
return 0;
if (row>=64) {
_mm_fseek(modreader, tracksize * 3, SEEK_CUR);
return 1;
}
if (cmd<0x7f) {
/* note, vol */
/* Note that 0xff values mean this note was not originally
accomanied by a volume event. The +1 here causes it to
overflow to 0, which will then (correctly) be ignored later. */
track[row].note=cmd;
track[row].volume=(UBYTE)arg+1;
} else
if (cmd==0x7f) {
/* duplicate row */
if ((arg<0)&&(row+arg>=0)) {
memcpy(track+row,track+(row+arg),sizeof(AMFNOTE));
}
/* AMF.TXT claims this should duplicate the previous row, but
this is a lie. This note value is used to communicate to
DSMI that the current playing note should be updated when
an instrument is used with no note. This can be ignored. */
} else
if (cmd==0x80) {
/* instr */
@ -173,8 +224,11 @@ static int AMF_UnpackTrack(MREADER* r)
} else
if(track[row].fxcnt<3) {
/* effect, param */
if(cmd>0x97)
return 0;
if(cmd>0x97) {
/* Instead of failing, we just ignore unknown effects.
This will load the "escape from dulce base" module */
continue;
}
track[row].effect[track[row].fxcnt]=cmd&0x7f;
track[row].parameter[track[row].fxcnt]=arg;
track[row].fxcnt++;
@ -185,7 +239,7 @@ static int AMF_UnpackTrack(MREADER* r)
return 1;
}
static UBYTE* AMF_ConvertTrack(void)
static UBYTE *AMF_ConvertTrack(void)
{
int row,fx4memory=0;
@ -315,6 +369,7 @@ static UBYTE* AMF_ConvertTrack(void)
UniEffect(fx4memory,0);
break;
case 0x17: /* Panning */
/* S3M pan, except offset by -64. */
if (inf>64)
UniEffect(UNI_ITEFFECTS0,0x91); /* surround */
else
@ -338,17 +393,29 @@ static int AMF_Load(int curious)
SAMPLE *q;
UWORD *track_remap;
ULONG samplepos, fileend;
int channel_remap[16];
UBYTE channel_remap[16];
int no_loopend;
(void)curious;
/* try to read module header */
_mm_read_UBYTES(mh->id,3,modreader);
mh->version =_mm_read_UBYTE(modreader);
/* For version 8, the song name is only 20 characters long and then come
// some data, which I do not know what is. The original code by Otto Chrons
// load the song name as 20 characters long and then it is overwritten again
// it another function, where it loads 32 characters, no matter which version
// it is. So we do the same here */
_mm_read_string(mh->songname,32,modreader);
mh->numsamples =_mm_read_UBYTE(modreader);
mh->numorders =_mm_read_UBYTE(modreader);
mh->numtracks =_mm_read_I_UWORD(modreader);
mh->numchannels =_mm_read_UBYTE(modreader);
if(mh->version>=9)
mh->numchannels=_mm_read_UBYTE(modreader);
else
mh->numchannels=4;
if((!mh->numchannels)||(mh->numchannels>(mh->version>=12?32:16))) {
_mm_errno=MMERR_NOT_A_MODULE;
return 0;
@ -357,7 +424,7 @@ static int AMF_Load(int curious)
if(mh->version>=11) {
memset(mh->panpos,0,32);
_mm_read_SBYTES(mh->panpos,(mh->version>=13)?32:16,modreader);
} else
} else if(mh->version>=9)
_mm_read_UBYTES(channel_remap,16,modreader);
if (mh->version>=13) {
@ -408,16 +475,22 @@ static int AMF_Load(int curious)
* UF_PANNING, to use our preferred panning table for this case.
*/
defaultpanning = 1;
for (t = 0; t < 32; t++) {
if (mh->panpos[t] > 64) {
of.panning[t] = PAN_SURROUND;
defaultpanning = 0;
} else
if (mh->panpos[t] == 64)
of.panning[t] = PAN_RIGHT;
else
of.panning[t] = (mh->panpos[t] + 64) << 1;
if(mh->version>=11) {
for (t = 0; t < 32; t++) {
if (mh->panpos[t] > 64) {
of.panning[t] = PAN_SURROUND;
defaultpanning = 0;
} else
if (mh->panpos[t] == 64)
of.panning[t] = PAN_RIGHT;
else
of.panning[t] = (mh->panpos[t] + 64) << 1;
}
}
else
defaultpanning = 0;
if (defaultpanning) {
for (t = 0; t < of.numchn; t++)
if (of.panning[t] == (((t + 1) & 2) ? PAN_RIGHT : PAN_LEFT)) {
@ -442,11 +515,13 @@ static int AMF_Load(int curious)
if (mh->version>=14)
/* track size */
of.pattrows[t]=_mm_read_I_UWORD(modreader);
if (mh->version>=10)
_mm_read_I_UWORDS(of.patterns+(t*of.numchn),of.numchn,modreader);
if ((mh->version==9) || (mh->version==10)) {
/* Only version 9 and 10 uses channel remap */
for (u = 0; u < of.numchn; u++)
of.patterns[t * of.numchn + channel_remap[u]] = _mm_read_I_UWORD(modreader);
}
else
for(u=0;u<of.numchn;u++)
of.patterns[t*of.numchn+channel_remap[u]]=_mm_read_I_UWORD(modreader);
_mm_read_I_UWORDS(of.patterns + (t * of.numchn), of.numchn, modreader);
}
if(_mm_eof(modreader)) {
_mm_errno = MMERR_LOADING_HEADER;
@ -455,6 +530,12 @@ static int AMF_Load(int curious)
/* read sample information */
if(!AllocSamples()) return 0;
no_loopend = 0;
if(mh->version == 10) {
no_loopend = AMF_ScanV10Instruments(modreader, of.numins);
}
q=of.samples;
for(t=0;t<of.numins;t++) {
/* try to read sample info */
@ -462,19 +543,38 @@ static int AMF_Load(int curious)
_mm_read_string(s.samplename,32,modreader);
_mm_read_string(s.filename,13,modreader);
s.offset =_mm_read_I_ULONG(modreader);
s.length =_mm_read_I_ULONG(modreader);
if(mh->version>=10)
s.length =_mm_read_I_ULONG(modreader);
else
s.length = _mm_read_I_UWORD(modreader);
s.c2spd =_mm_read_I_UWORD(modreader);
if(s.c2spd==8368) s.c2spd=8363;
s.volume =_mm_read_UBYTE(modreader);
/* "the tribal zone.amf" and "the way its gonna b.amf" by Maelcum
* are the only version 10 files I can find, and they have 32 bit
* reppos and repend, not 16. */
if(mh->version>=10) {/* was 11 */
if(mh->version>=10 && no_loopend==0) {/* was 11 */
s.reppos =_mm_read_I_ULONG(modreader);
s.repend =_mm_read_I_ULONG(modreader);
} else {
} else if(mh->version==10) {
/* Early AMF 1.0 modules have the upper two bytes of
* the loop start and the entire loop end truncated.
* libxmp cites "sweetdrm.amf" and "facing_n.amf", but
* these are currently missing. M2AMF 1.3 (from DMP 2.32)
* has been confirmed to output these, however. */
s.reppos =_mm_read_I_UWORD(modreader);
s.repend =s.length;
/* There's not really a correct way to handle the loop
* end, but this makes unlooped samples work at least. */
if(s.reppos==0)
s.repend=0;
} else {
s.reppos =_mm_read_I_UWORD(modreader);
s.repend =_mm_read_I_UWORD(modreader);
if (s.repend==0xffff)
s.repend=0;
}
if(_mm_eof(modreader)) {