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:
parent
08c32cee7c
commit
af7ed73f31
29 changed files with 1860 additions and 706 deletions
|
@ -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)) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue