--- /dev/null
+/* MikMod sound library\r
+ (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file\r
+ AUTHORS for complete list.\r
+\r
+ This library is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU Library General Public License as\r
+ published by the Free Software Foundation; either version 2 of\r
+ the License, or (at your option) any later version.\r
+ \r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU Library General Public License for more details.\r
+ \r
+ You should have received a copy of the GNU Library General Public\r
+ License along with this library; if not, write to the Free Software\r
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+ 02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+ $Id: load_uni.c,v 1.2 2004/02/06 19:29:03 raph Exp $\r
+\r
+ UNIMOD (libmikmod's and APlayer's internal module format) loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\r
+#ifdef HAVE_UNISTD_H\r
+#include <unistd.h>\r
+#endif\r
+\r
+#include <stdio.h>\r
+#ifdef HAVE_MEMORY_H\r
+#include <memory.h>\r
+#endif\r
+#include <string.h>\r
+\r
+#include "mikmod_internals.h"\r
+\r
+#ifdef SUNOS\r
+extern int fprintf(FILE *, const char *, ...);\r
+#endif\r
+\r
+/*========== Module structure */\r
+\r
+typedef struct UNIHEADER {\r
+ CHAR id[4];\r
+ UBYTE numchn;\r
+ UWORD numpos;\r
+ UWORD reppos;\r
+ UWORD numpat;\r
+ UWORD numtrk;\r
+ UWORD numins;\r
+ UWORD numsmp;\r
+ UBYTE initspeed;\r
+ UBYTE inittempo;\r
+ UBYTE initvolume;\r
+ UWORD flags;\r
+ UBYTE numvoices;\r
+ UWORD bpmlimit;\r
+\r
+ UBYTE positions[256];\r
+ UBYTE panning[32];\r
+} UNIHEADER;\r
+\r
+typedef struct UNISMP05 {\r
+ UWORD c2spd;\r
+ UWORD transpose;\r
+ UBYTE volume;\r
+ UBYTE panning;\r
+ ULONG length;\r
+ ULONG loopstart;\r
+ ULONG loopend;\r
+ UWORD flags;\r
+ CHAR* samplename;\r
+ UBYTE vibtype;\r
+ UBYTE vibsweep;\r
+ UBYTE vibdepth;\r
+ UBYTE vibrate;\r
+} UNISMP05;\r
+\r
+/*========== Loader variables */\r
+\r
+static UWORD universion;\r
+static UNIHEADER mh;\r
+\r
+#define UNI_SMPINCR 64\r
+static UNISMP05 *wh=NULL,*s=NULL;\r
+\r
+/*========== Loader code */\r
+\r
+static char* readstring(void)\r
+{\r
+ char *s=NULL;\r
+ UWORD len;\r
+ \r
+ len=_mm_read_I_UWORD(modreader);\r
+ if(len) {\r
+ s=_mm_malloc(len+1);\r
+ _mm_read_UBYTES(s,len,modreader);\r
+ s[len]=0;\r
+ }\r
+ return s;\r
+}\r
+\r
+BOOL UNI_Test(void)\r
+{\r
+ char id[6];\r
+\r
+ if(!_mm_read_UBYTES(id,6,modreader)) return 0;\r
+\r
+ /* UNIMod created by MikCvt */\r
+ if(!(memcmp(id,"UN0",3))) {\r
+ if((id[3]>='4')&&(id[3]<='6')) return 1;\r
+ }\r
+ /* UNIMod created by APlayer */\r
+ if(!(memcmp(id,"APUN\01",5))) {\r
+ if((id[5]>=1)&&(id[5]<=6)) return 1;\r
+ }\r
+ return 0;\r
+}\r
+\r
+BOOL UNI_Init(void)\r
+{\r
+ return 1;\r
+}\r
+\r
+void UNI_Cleanup(void)\r
+{\r
+ _mm_free(wh);\r
+ s=NULL;\r
+}\r
+\r
+static UBYTE* readtrack(void)\r
+{\r
+ UBYTE *t;\r
+ UWORD len;\r
+ int cur=0,chunk;\r
+\r
+ if(universion>=6)\r
+ len=_mm_read_M_UWORD(modreader);\r
+ else\r
+ len=_mm_read_I_UWORD(modreader);\r
+\r
+ if(!len) return NULL;\r
+ if(!(t=_mm_malloc(len))) return NULL;\r
+ _mm_read_UBYTES(t,len,modreader);\r
+\r
+ /* Check if the track is correct */\r
+ while(1) {\r
+ chunk=t[cur++];\r
+ if(!chunk) break;\r
+ chunk=(chunk&0x1f)-1;\r
+ while(chunk>0) {\r
+ int opcode,oplen;\r
+\r
+ if(cur>=len) {\r
+ free(t);\r
+ return NULL;\r
+ }\r
+ opcode=t[cur];\r
+\r
+ /* Remap opcodes */\r
+ if (universion <= 5) {\r
+ if (opcode > 29) {\r
+ free(t);\r
+ return NULL;\r
+ }\r
+ switch (opcode) {\r
+ /* UNI_NOTE .. UNI_S3MEFFECTQ are the same */\r
+ case 25:\r
+ opcode = UNI_S3MEFFECTT;\r
+ break;\r
+ case 26:\r
+ opcode = UNI_XMEFFECTA;\r
+ break;\r
+ case 27:\r
+ opcode = UNI_XMEFFECTG;\r
+ break;\r
+ case 28:\r
+ opcode = UNI_XMEFFECTH;\r
+ break;\r
+ case 29:\r
+ opcode = UNI_XMEFFECTP;\r
+ break;\r
+ }\r
+ } else {\r
+ /* APlayer < 1.05 does not have XMEFFECT6 */\r
+ if (opcode >= UNI_XMEFFECT6 && universion < 0x105)\r
+ opcode++;\r
+ /* APlayer < 1.03 does not have ITEFFECTT */\r
+ if (opcode >= UNI_ITEFFECTT && universion < 0x103)\r
+ opcode++;\r
+ /* APlayer < 1.02 does not have ITEFFECTZ */\r
+ if (opcode >= UNI_ITEFFECTZ && universion < 0x102)\r
+ opcode++;\r
+ }\r
+\r
+ if((!opcode)||(opcode>=UNI_LAST)) {\r
+ free(t);\r
+ return NULL;\r
+ }\r
+ t[cur]=opcode;\r
+ oplen=unioperands[opcode]+1;\r
+ cur+=oplen;\r
+ chunk-=oplen;\r
+ }\r
+ if((chunk<0)||(cur>=len)) {\r
+ free(t);\r
+ return NULL;\r
+ }\r
+ }\r
+ return t;\r
+}\r
+\r
+static BOOL loadsmp6(void)\r
+{\r
+ int t;\r
+ SAMPLE *s;\r
+\r
+ s=of.samples;\r
+ for(t=0;t<of.numsmp;t++,s++) {\r
+ int flags;\r
+\r
+ flags = _mm_read_M_UWORD(modreader);\r
+ s->flags=0;\r
+ if(flags&0x0004) s->flags|=SF_STEREO;\r
+ if(flags&0x0002) s->flags|=SF_SIGNED;\r
+ if(flags&0x0001) s->flags|=SF_16BITS;\r
+ /* convert flags */\r
+ if(universion>=0x104) {\r
+ if(flags&0x2000) s->flags|=SF_UST_LOOP;\r
+ if(flags&0x1000) s->flags|=SF_OWNPAN;\r
+ if(flags&0x0800) s->flags|=SF_SUSTAIN;\r
+ if(flags&0x0400) s->flags|=SF_REVERSE;\r
+ if(flags&0x0200) s->flags|=SF_BIDI;\r
+ if(flags&0x0100) s->flags|=SF_LOOP;\r
+ if(flags&0x0020) s->flags|=SF_ITPACKED;\r
+ if(flags&0x0010) s->flags|=SF_DELTA;\r
+ if(flags&0x0008) s->flags|=SF_BIG_ENDIAN;\r
+ } else if(universion>=0x102) {\r
+ if(flags&0x0800) s->flags|=SF_UST_LOOP;\r
+ if(flags&0x0400) s->flags|=SF_OWNPAN;\r
+ if(flags&0x0200) s->flags|=SF_SUSTAIN;\r
+ if(flags&0x0100) s->flags|=SF_REVERSE;\r
+ if(flags&0x0080) s->flags|=SF_BIDI;\r
+ if(flags&0x0040) s->flags|=SF_LOOP;\r
+ if(flags&0x0020) s->flags|=SF_ITPACKED;\r
+ if(flags&0x0010) s->flags|=SF_DELTA;\r
+ if(flags&0x0008) s->flags|=SF_BIG_ENDIAN;\r
+ } else {\r
+ if(flags&0x400) s->flags|=SF_UST_LOOP;\r
+ if(flags&0x200) s->flags|=SF_OWNPAN;\r
+ if(flags&0x100) s->flags|=SF_REVERSE;\r
+ if(flags&0x080) s->flags|=SF_SUSTAIN;\r
+ if(flags&0x040) s->flags|=SF_BIDI;\r
+ if(flags&0x020) s->flags|=SF_LOOP;\r
+ if(flags&0x010) s->flags|=SF_BIG_ENDIAN;\r
+ if(flags&0x008) s->flags|=SF_DELTA;\r
+ }\r
+\r
+ s->speed = _mm_read_M_ULONG(modreader);\r
+ s->volume = _mm_read_UBYTE(modreader);\r
+ s->panning = _mm_read_M_UWORD(modreader);\r
+ s->length = _mm_read_M_ULONG(modreader);\r
+ s->loopstart = _mm_read_M_ULONG(modreader);\r
+ s->loopend = _mm_read_M_ULONG(modreader);\r
+ s->susbegin = _mm_read_M_ULONG(modreader);\r
+ s->susend = _mm_read_M_ULONG(modreader);\r
+ s->globvol = _mm_read_UBYTE(modreader);\r
+ s->vibflags = _mm_read_UBYTE(modreader);\r
+ s->vibtype = _mm_read_UBYTE(modreader);\r
+ s->vibsweep = _mm_read_UBYTE(modreader);\r
+ s->vibdepth = _mm_read_UBYTE(modreader);\r
+ s->vibrate = _mm_read_UBYTE(modreader);\r
+\r
+ s->samplename=readstring();\r
+\r
+ if(_mm_eof(modreader)) {\r
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+ return 0;\r
+ }\r
+ }\r
+ return 1;\r
+}\r
+\r
+static BOOL loadinstr6(void)\r
+{\r
+ int t,w;\r
+ INSTRUMENT *i;\r
+\r
+ i=of.instruments;\r
+ for(t=0;t<of.numins;t++,i++) {\r
+ i->flags = _mm_read_UBYTE(modreader);\r
+ i->nnatype = _mm_read_UBYTE(modreader);\r
+ i->dca = _mm_read_UBYTE(modreader);\r
+ i->dct = _mm_read_UBYTE(modreader);\r
+ i->globvol = _mm_read_UBYTE(modreader);\r
+ i->panning = _mm_read_M_UWORD(modreader);\r
+ i->pitpansep = _mm_read_UBYTE(modreader);\r
+ i->pitpancenter = _mm_read_UBYTE(modreader);\r
+ i->rvolvar = _mm_read_UBYTE(modreader);\r
+ i->rpanvar = _mm_read_UBYTE(modreader);\r
+ i->volfade = _mm_read_M_UWORD(modreader);\r
+\r
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
+#define UNI_LoadEnvelope6(name) \\r
+ i-> name##flg=_mm_read_UBYTE(modreader); \\r
+ i-> name##pts=_mm_read_UBYTE(modreader); \\r
+ i-> name##susbeg=_mm_read_UBYTE(modreader); \\r
+ i-> name##susend=_mm_read_UBYTE(modreader); \\r
+ i-> name##beg=_mm_read_UBYTE(modreader); \\r
+ i-> name##end=_mm_read_UBYTE(modreader); \\r
+ for(w=0;w<(universion>=0x100?32:i-> name##pts);w++) { \\r
+ i-> name##env[w].pos=_mm_read_M_SWORD(modreader); \\r
+ i-> name##env[w].val=_mm_read_M_SWORD(modreader); \\r
+ }\r
+#else\r
+#define UNI_LoadEnvelope6(name) \\r
+ i-> name/**/flg=_mm_read_UBYTE(modreader); \\r
+ i-> name/**/pts=_mm_read_UBYTE(modreader); \\r
+ i-> name/**/susbeg=_mm_read_UBYTE(modreader); \\r
+ i-> name/**/susend=_mm_read_UBYTE(modreader); \\r
+ i-> name/**/beg=_mm_read_UBYTE(modreader); \\r
+ i-> name/**/end=_mm_read_UBYTE(modreader); \\r
+ for (w=0;w<(universion>=0x100?32:i-> name/**/pts);w++) { \\r
+ i-> name/**/env[w].pos=_mm_read_M_SWORD(modreader); \\r
+ i-> name/**/env[w].val=_mm_read_M_SWORD(modreader); \\r
+ }\r
+#endif\r
+\r
+ UNI_LoadEnvelope6(vol);\r
+ UNI_LoadEnvelope6(pan);\r
+ UNI_LoadEnvelope6(pit);\r
+#undef UNI_LoadEnvelope6\r
+\r
+ if(universion>=0x103)\r
+ _mm_read_M_UWORDS(i->samplenumber,120,modreader);\r
+ else\r
+ for(w=0;w<120;w++)\r
+ i->samplenumber[w]=_mm_read_UBYTE(modreader);\r
+ _mm_read_UBYTES(i->samplenote,120,modreader);\r
+\r
+ i->insname=readstring();\r
+\r
+ if(_mm_eof(modreader)) {\r
+ _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+ return 0;\r
+ }\r
+ }\r
+ return 1;\r
+}\r
+\r
+static BOOL loadinstr5(void)\r
+{\r
+ INSTRUMENT *i;\r
+ int t;\r
+ UWORD wavcnt=0;\r
+ UBYTE vibtype,vibsweep,vibdepth,vibrate;\r
+\r
+ i=of.instruments;\r
+ for(of.numsmp=t=0;t<of.numins;t++,i++) {\r
+ int u,numsmp;\r
+\r
+ numsmp=_mm_read_UBYTE(modreader);\r
+\r
+ memset(i->samplenumber,0xff,INSTNOTES*sizeof(UWORD));\r
+ for(u=0;u<96;u++)\r
+ i->samplenumber[u]=of.numsmp+_mm_read_UBYTE(modreader);\r
+\r
+#if defined __STDC__ || defined _MSC_VER || defined MPW_C\r
+#define UNI_LoadEnvelope5(name) \\r
+ i-> name##flg=_mm_read_UBYTE(modreader); \\r
+ i-> name##pts=_mm_read_UBYTE(modreader); \\r
+ i-> name##susbeg=_mm_read_UBYTE(modreader); \\r
+ i-> name##susend=i-> name##susbeg; \\r
+ i-> name##beg=_mm_read_UBYTE(modreader); \\r
+ i-> name##end=_mm_read_UBYTE(modreader); \\r
+ for(u=0;u<12;u++) { \\r
+ i-> name##env[u].pos=_mm_read_I_SWORD(modreader); \\r
+ i-> name##env[u].val=_mm_read_I_SWORD(modreader); \\r
+ }\r
+#else\r
+#define UNI_LoadEnvelope5(name) \\r
+ i-> name/**/flg=_mm_read_UBYTE(modreader); \\r
+ i-> name/**/pts=_mm_read_UBYTE(modreader); \\r
+ i-> name/**/susbeg=_mm_read_UBYTE(modreader); \\r
+ i-> name/**/susend=i-> name/**/susbeg; \\r
+ i-> name/**/beg=_mm_read_UBYTE(modreader); \\r
+ i-> name/**/end=_mm_read_UBYTE(modreader); \\r
+ for(u=0;u<12;u++) { \\r
+ i-> name/**/env[u].pos=_mm_read_I_SWORD(modreader); \\r
+ i-> name/**/env[u].val=_mm_read_I_SWORD(modreader); \\r
+ }\r
+#endif\r
+\r
+ UNI_LoadEnvelope5(vol);\r
+ UNI_LoadEnvelope5(pan);\r
+#undef UNI_LoadEnvelope5\r
+\r
+ vibtype =_mm_read_UBYTE(modreader);\r
+ vibsweep =_mm_read_UBYTE(modreader);\r
+ vibdepth =_mm_read_UBYTE(modreader);\r
+ vibrate =_mm_read_UBYTE(modreader);\r
+\r
+ i->volfade=_mm_read_I_UWORD(modreader);\r
+ i->insname=readstring();\r
+\r
+ for(u=0;u<numsmp;u++,s++,of.numsmp++) {\r
+ /* Allocate more room for sample information if necessary */\r
+ if(of.numsmp+u==wavcnt) {\r
+ wavcnt+=UNI_SMPINCR;\r
+ if(!(wh=realloc(wh,wavcnt*sizeof(UNISMP05)))) {\r
+ _mm_errno=MMERR_OUT_OF_MEMORY;\r
+ return 0;\r
+ }\r
+ s=wh+(wavcnt-UNI_SMPINCR);\r
+ }\r
+\r
+ s->c2spd =_mm_read_I_UWORD(modreader);\r
+ s->transpose=_mm_read_SBYTE(modreader);\r
+ s->volume =_mm_read_UBYTE(modreader);\r
+ s->panning =_mm_read_UBYTE(modreader);\r
+ s->length =_mm_read_I_ULONG(modreader);\r
+ s->loopstart=_mm_read_I_ULONG(modreader);\r
+ s->loopend =_mm_read_I_ULONG(modreader);\r
+ s->flags =_mm_read_I_UWORD(modreader);\r
+ s->samplename=readstring();\r
+\r
+ s->vibtype =vibtype;\r
+ s->vibsweep=vibsweep;\r
+ s->vibdepth=vibdepth;\r
+ s->vibrate =vibrate;\r
+\r
+ if(_mm_eof(modreader)) {\r
+ free(wh);wh=NULL;\r
+ _mm_errno=MMERR_LOADING_SAMPLEINFO;\r
+ return 0;\r
+ }\r
+ }\r
+ }\r
+\r
+ /* sanity check */\r
+ if(!of.numsmp) {\r
+ if(wh) { free(wh);wh=NULL; }\r
+ _mm_errno=MMERR_LOADING_SAMPLEINFO;\r
+ return 0;\r
+ }\r
+ return 1;\r
+}\r
+\r
+static BOOL loadsmp5(void)\r
+{\r
+ int t,u;\r
+ SAMPLE *q;\r
+ INSTRUMENT *d;\r
+\r
+ q=of.samples;s=wh;\r
+ for(u=0;u<of.numsmp;u++,q++,s++) {\r
+ q->samplename=s->samplename;\r
+\r
+ q->length =s->length;\r
+ q->loopstart=s->loopstart;\r
+ q->loopend =s->loopend;\r
+ q->volume =s->volume;\r
+ q->speed =s->c2spd;\r
+ q->panning =s->panning;\r
+ q->vibtype =s->vibtype;\r
+ q->vibsweep =s->vibsweep;\r
+ q->vibdepth =s->vibdepth;\r
+ q->vibrate =s->vibrate;\r
+\r
+ /* convert flags */\r
+ q->flags=0;\r
+ if(s->flags&128) q->flags|=SF_REVERSE;\r
+ if(s->flags& 64) q->flags|=SF_SUSTAIN;\r
+ if(s->flags& 32) q->flags|=SF_BIDI;\r
+ if(s->flags& 16) q->flags|=SF_LOOP;\r
+ if(s->flags& 8) q->flags|=SF_BIG_ENDIAN;\r
+ if(s->flags& 4) q->flags|=SF_DELTA;\r
+ if(s->flags& 2) q->flags|=SF_SIGNED;\r
+ if(s->flags& 1) q->flags|=SF_16BITS;\r
+ }\r
+\r
+ d=of.instruments;s=wh;\r
+ for(u=0;u<of.numins;u++,d++)\r
+ for(t=0;t<INSTNOTES;t++)\r
+ d->samplenote[t]=(d->samplenumber[t]>=of.numsmp)?\r
+ 255:(t+s[d->samplenumber[t]].transpose);\r
+\r
+ free(wh);wh=NULL;\r
+\r
+ return 1;\r
+}\r
+\r
+BOOL UNI_Load(BOOL curious)\r
+{\r
+ int t;\r
+ char *modtype,*oldtype=NULL;\r
+ INSTRUMENT *d;\r
+ SAMPLE *q;\r
+ (void)curious;\r
+ \r
+ /* read module header */\r
+ _mm_read_UBYTES(mh.id,4,modreader);\r
+ if(mh.id[3]!='N')\r
+ universion=mh.id[3]-'0';\r
+ else\r
+ universion=0x100;\r
+\r
+ if(universion>=6) {\r
+ if (universion==6)\r
+ _mm_read_UBYTE(modreader);\r
+ else\r
+ universion=_mm_read_M_UWORD(modreader);\r
+\r
+ mh.flags =_mm_read_M_UWORD(modreader);\r
+ mh.numchn =_mm_read_UBYTE(modreader);\r
+ mh.numvoices =_mm_read_UBYTE(modreader);\r
+ mh.numpos =_mm_read_M_UWORD(modreader);\r
+ mh.numpat =_mm_read_M_UWORD(modreader);\r
+ mh.numtrk =_mm_read_M_UWORD(modreader);\r
+ mh.numins =_mm_read_M_UWORD(modreader);\r
+ mh.numsmp =_mm_read_M_UWORD(modreader);\r
+ mh.reppos =_mm_read_M_UWORD(modreader);\r
+ mh.initspeed =_mm_read_UBYTE(modreader);\r
+ mh.inittempo =_mm_read_UBYTE(modreader);\r
+ mh.initvolume=_mm_read_UBYTE(modreader);\r
+ /* I expect this to show up soon in APlayer 1.06 format */\r
+ if (universion >= 0x106)\r
+ mh.bpmlimit=_mm_read_M_UWORD(modreader);\r
+ else\r
+ mh.bpmlimit=32;\r
+\r
+ mh.flags &= UF_XMPERIODS | UF_LINEAR | UF_INST | UF_NNA;\r
+ mh.flags |= UF_PANNING;\r
+ } else {\r
+ mh.numchn =_mm_read_UBYTE(modreader);\r
+ mh.numpos =_mm_read_I_UWORD(modreader);\r
+ mh.reppos =(universion==5)?_mm_read_I_UWORD(modreader):0;\r
+ mh.numpat =_mm_read_I_UWORD(modreader);\r
+ mh.numtrk =_mm_read_I_UWORD(modreader);\r
+ mh.numins =_mm_read_I_UWORD(modreader);\r
+ mh.initspeed =_mm_read_UBYTE(modreader);\r
+ mh.inittempo =_mm_read_UBYTE(modreader);\r
+ _mm_read_UBYTES(mh.positions,256,modreader);\r
+ _mm_read_UBYTES(mh.panning,32,modreader);\r
+ mh.flags =_mm_read_UBYTE(modreader);\r
+ mh.bpmlimit =32;\r
+\r
+ mh.flags &= UF_XMPERIODS | UF_LINEAR;\r
+ mh.flags |= UF_INST | UF_NOWRAP | UF_PANNING;\r
+ }\r
+ \r
+ /* set module parameters */\r
+ of.flags =mh.flags;\r
+ of.numchn =mh.numchn;\r
+ of.numpos =mh.numpos;\r
+ of.numpat =mh.numpat;\r
+ of.numtrk =mh.numtrk;\r
+ of.numins =mh.numins;\r
+ of.reppos =mh.reppos;\r
+ of.initspeed =mh.initspeed;\r
+ of.inittempo =mh.inittempo;\r
+ if(mh.bpmlimit)\r
+ of.bpmlimit=mh.bpmlimit;\r
+ else\r
+ /* be bug-compatible with older releases */\r
+ of.bpmlimit=32;\r
+\r
+ of.songname=readstring();\r
+ if(universion<0x102)\r
+ oldtype=readstring();\r
+ if(oldtype) {\r
+ int len=strlen(oldtype)+20;\r
+ if(!(modtype=_mm_malloc(len))) return 0;\r
+#ifdef HAVE_SNPRINTF\r
+ snprintf(modtype,len,"%s (was %s)",(universion>=0x100)?"APlayer":"MikCvt2",oldtype);\r
+#else\r
+ sprintf(modtype,"%s (was %s)",(universion>=0x100)?"APlayer":"MikCvt2",oldtype);\r
+#endif\r
+ } else {\r
+ if(!(modtype=_mm_malloc(10))) return 0;\r
+#ifdef HAVE_SNPRINTF\r
+ snprintf(modtype,10,"%s",(universion>=0x100)?"APlayer":"MikCvt3");\r
+#else\r
+ sprintf(modtype,"%s",(universion>=0x100)?"APlayer":"MikCvt3");\r
+#endif\r
+ }\r
+ of.modtype=strdup(modtype);\r
+ free(modtype);free(oldtype);\r
+ of.comment=readstring();\r
+\r
+ if(universion>=6) {\r
+ of.numvoices=mh.numvoices;\r
+ of.initvolume=mh.initvolume;\r
+ }\r
+\r
+ if(_mm_eof(modreader)) {\r
+ _mm_errno=MMERR_LOADING_HEADER;\r
+ return 0;\r
+ }\r
+\r
+ /* positions */\r
+ if(!AllocPositions(of.numpos)) return 0;\r
+ if(universion>=6) {\r
+ if(universion>=0x100)\r
+ _mm_read_M_UWORDS(of.positions,of.numpos,modreader);\r
+ else\r
+ for(t=0;t<of.numpos;t++) of.positions[t]=_mm_read_UBYTE(modreader);\r
+ _mm_read_M_UWORDS(of.panning,of.numchn,modreader);\r
+ _mm_read_UBYTES(of.chanvol,of.numchn,modreader);\r
+ } else {\r
+ if((mh.numpos>256)||(mh.numchn>32)) {\r
+ _mm_errno=MMERR_LOADING_HEADER;\r
+ return 0;\r
+ }\r
+ for(t=0;t<of.numpos;t++) of.positions[t]=mh.positions[t];\r
+ for(t=0;t<of.numchn;t++) of.panning[t]=mh.panning[t];\r
+ }\r
+ /* convert the ``end of song'' pattern code if necessary */\r
+ if(universion<0x106)\r
+ for(t=0;t<of.numpos;t++)\r
+ if(of.positions[t]==255) of.positions[t]=LAST_PATTERN;\r
+\r
+ /* instruments and samples */\r
+ if(universion>=6) {\r
+ of.numsmp=mh.numsmp;\r
+ if(!AllocSamples()) return 0;\r
+ if(!loadsmp6()) return 0;\r
+\r
+ if(of.flags&UF_INST) {\r
+ if(!AllocInstruments()) return 0;\r
+ if(!loadinstr6()) return 0;\r
+ }\r
+ } else {\r
+ if(!AllocInstruments()) return 0;\r
+ if(!loadinstr5()) return 0;\r
+ if(!AllocSamples()) {\r
+ if(wh) { free(wh);wh=NULL; }\r
+ return 0;\r
+ }\r
+ if(!loadsmp5()) return 0;\r
+\r
+ /* check if the original file had no instruments */\r
+ if(of.numsmp==of.numins) {\r
+ for(t=0,d=of.instruments;t<of.numins;t++,d++) {\r
+ int u;\r
+\r
+ if((d->volpts)||(d->panpts)||(d->globvol!=64)) break;\r
+ for(u=0;u<96;u++)\r
+ if((d->samplenumber[u]!=t)||(d->samplenote[u]!=u)) break;\r
+ if(u!=96) break;\r
+ }\r
+ if(t==of.numins) {\r
+ of.flags&=~UF_INST;\r
+ of.flags&=~UF_NOWRAP;\r
+ for(t=0,d=of.instruments,q=of.samples;t<of.numins;t++,d++,q++) {\r
+ q->samplename=d->insname;\r
+ d->insname=NULL;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /* patterns */\r
+ if(!AllocPatterns()) return 0;\r
+ if(universion>=6) {\r
+ _mm_read_M_UWORDS(of.pattrows,of.numpat,modreader);\r
+ _mm_read_M_UWORDS(of.patterns,of.numpat*of.numchn,modreader);\r
+ } else {\r
+ _mm_read_I_UWORDS(of.pattrows,of.numpat,modreader);\r
+ _mm_read_I_UWORDS(of.patterns,of.numpat*of.numchn,modreader);\r
+ }\r
+\r
+ /* tracks */\r
+ if(!AllocTracks()) return 0;\r
+ for(t=0;t<of.numtrk;t++)\r
+ if(!(of.tracks[t]=readtrack())) {\r
+ _mm_errno=MMERR_LOADING_TRACK;\r
+ return 0;\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+CHAR *UNI_LoadTitle(void)\r
+{\r
+ UBYTE ver;\r
+ int posit[3]={304,306,26};\r
+\r
+ _mm_fseek(modreader,3,SEEK_SET);\r
+ ver=_mm_read_UBYTE(modreader);\r
+ if(ver=='N') ver='6';\r
+\r
+ _mm_fseek(modreader,posit[ver-'4'],SEEK_SET);\r
+ return readstring();\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_uni={\r
+ NULL,\r
+ "UNI",\r
+ "APUN (APlayer) and UNI (MikMod)",\r
+ UNI_Init,\r
+ UNI_Test,\r
+ UNI_Load,\r
+ UNI_Cleanup,\r
+ UNI_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r