--- /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_mtm.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+ MTM module 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 MTMHEADER {\r
+ UBYTE id[3]; /* MTM file marker */\r
+ UBYTE version; /* upper major, lower nibble minor version number */\r
+ CHAR songname[20]; /* ASCIIZ songname */\r
+ UWORD numtracks; /* number of tracks saved */\r
+ UBYTE lastpattern; /* last pattern number saved */\r
+ UBYTE lastorder; /* last order number to play (songlength-1) */\r
+ UWORD commentsize; /* length of comment field */\r
+ UBYTE numsamples; /* number of samples saved */\r
+ UBYTE attribute; /* attribute byte (unused) */\r
+ UBYTE beatspertrack;\r
+ UBYTE numchannels; /* number of channels used */\r
+ UBYTE panpos[32]; /* voice pan positions */\r
+} MTMHEADER;\r
+\r
+typedef struct MTMSAMPLE {\r
+ CHAR samplename[22];\r
+ ULONG length;\r
+ ULONG reppos;\r
+ ULONG repend;\r
+ UBYTE finetune;\r
+ UBYTE volume;\r
+ UBYTE attribute;\r
+} MTMSAMPLE;\r
+\r
+typedef struct MTMNOTE {\r
+ UBYTE a,b,c;\r
+} MTMNOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+static MTMHEADER *mh = NULL;\r
+static MTMNOTE *mtmtrk = NULL;\r
+static UWORD pat[32];\r
+\r
+static CHAR MTM_Version[] = "MTM";\r
+\r
+/*========== Loader code */\r
+\r
+BOOL MTM_Test(void)\r
+{\r
+ UBYTE id[3];\r
+\r
+ if(!_mm_read_UBYTES(id,3,modreader)) return 0;\r
+ if(!memcmp(id,"MTM",3)) return 1;\r
+ return 0;\r
+}\r
+\r
+BOOL MTM_Init(void)\r
+{\r
+ if(!(mtmtrk=(MTMNOTE*)_mm_calloc(64,sizeof(MTMNOTE)))) return 0;\r
+ if(!(mh=(MTMHEADER*)_mm_malloc(sizeof(MTMHEADER)))) return 0;\r
+\r
+ return 1;\r
+}\r
+\r
+void MTM_Cleanup(void)\r
+{\r
+ _mm_free(mtmtrk);\r
+ _mm_free(mh);\r
+}\r
+\r
+static UBYTE* MTM_Convert(void)\r
+{\r
+ int t;\r
+ UBYTE a,b,inst,note,eff,dat;\r
+\r
+ UniReset();\r
+ for(t=0;t<64;t++) {\r
+ a=mtmtrk[t].a;\r
+ b=mtmtrk[t].b;\r
+ inst=((a&0x3)<<4)|(b>>4);\r
+ note=a>>2;\r
+ eff=b&0xf;\r
+ dat=mtmtrk[t].c;\r
+\r
+ if(inst) UniInstrument(inst-1);\r
+ if(note) UniNote(note+2*OCTAVE);\r
+\r
+ /* MTM bug workaround : when the effect is volslide, slide-up *always*\r
+ overrides slide-down. */\r
+ if(eff==0xa && (dat&0xf0)) dat&=0xf0;\r
+\r
+ /* Convert pattern jump from Dec to Hex */\r
+ if(eff==0xd)\r
+ dat=(((dat&0xf0)>>4)*10)+(dat&0xf);\r
+ UniPTEffect(eff,dat);\r
+ UniNewline();\r
+ }\r
+ return UniDup();\r
+}\r
+\r
+BOOL MTM_Load(BOOL curious)\r
+{\r
+ int t,u;\r
+ MTMSAMPLE s;\r
+ SAMPLE *q;\r
+ (void)curious;\r
+\r
+ /* try to read module header */\r
+ _mm_read_UBYTES(mh->id,3,modreader);\r
+ mh->version =_mm_read_UBYTE(modreader);\r
+ _mm_read_string(mh->songname,20,modreader);\r
+ mh->numtracks =_mm_read_I_UWORD(modreader);\r
+ mh->lastpattern =_mm_read_UBYTE(modreader);\r
+ mh->lastorder =_mm_read_UBYTE(modreader);\r
+ mh->commentsize =_mm_read_I_UWORD(modreader);\r
+ mh->numsamples =_mm_read_UBYTE(modreader);\r
+ mh->attribute =_mm_read_UBYTE(modreader);\r
+ mh->beatspertrack=_mm_read_UBYTE(modreader);\r
+ mh->numchannels =_mm_read_UBYTE(modreader);\r
+ _mm_read_UBYTES(mh->panpos,32,modreader);\r
+\r
+ if(_mm_eof(modreader)) {\r
+ _mm_errno = MMERR_LOADING_HEADER;\r
+ return 0;\r
+ }\r
+\r
+ /* set module variables */\r
+ of.initspeed = 6;\r
+ of.inittempo = 125;\r
+ of.modtype = strdup(MTM_Version);\r
+ of.numchn = mh->numchannels;\r
+ of.numtrk = mh->numtracks+1; /* get number of channels */\r
+ of.songname = DupStr(mh->songname,20,1); /* make a cstr of songname */\r
+ of.numpos = mh->lastorder+1; /* copy the songlength */\r
+ of.numpat = mh->lastpattern+1;\r
+ of.reppos = 0;\r
+ of.flags |= UF_PANNING;\r
+ for(t=0;t<32;t++) of.panning[t]=mh->panpos[t]<< 4;\r
+ of.numins=of.numsmp=mh->numsamples;\r
+\r
+ if(!AllocSamples()) return 0;\r
+ q=of.samples;\r
+ for(t=0;t<of.numins;t++) {\r
+ /* try to read sample info */\r
+ _mm_read_string(s.samplename,22,modreader);\r
+ s.length =_mm_read_I_ULONG(modreader);\r
+ s.reppos =_mm_read_I_ULONG(modreader);\r
+ s.repend =_mm_read_I_ULONG(modreader);\r
+ s.finetune =_mm_read_UBYTE(modreader);\r
+ s.volume =_mm_read_UBYTE(modreader);\r
+ s.attribute =_mm_read_UBYTE(modreader);\r
+\r
+ if(_mm_eof(modreader)) {\r
+ _mm_errno = MMERR_LOADING_SAMPLEINFO; \r
+ return 0;\r
+ }\r
+\r
+ q->samplename = DupStr(s.samplename,22,1);\r
+ q->seekpos = 0;\r
+ q->speed = finetune[s.finetune];\r
+ q->length = s.length;\r
+ q->loopstart = s.reppos;\r
+ q->loopend = s.repend;\r
+ q->volume = s.volume;\r
+ if((s.repend-s.reppos)>2) q->flags |= SF_LOOP;\r
+\r
+ if(s.attribute&1) {\r
+ /* If the sample is 16-bits, convert the length and replen\r
+ byte-values into sample-values */\r
+ q->flags|=SF_16BITS;\r
+ q->length>>=1;\r
+ q->loopstart>>=1;\r
+ q->loopend>>=1;\r
+ }\r
+ q++;\r
+ }\r
+\r
+ if(!AllocPositions(of.numpos)) return 0;\r
+ for(t=0;t<of.numpos;t++)\r
+ of.positions[t]=_mm_read_UBYTE(modreader);\r
+ for(;t<128;t++) _mm_read_UBYTE(modreader);\r
+ if(_mm_eof(modreader)) {\r
+ _mm_errno = MMERR_LOADING_HEADER;\r
+ return 0;\r
+ }\r
+\r
+ if(!AllocTracks()) return 0;\r
+ if(!AllocPatterns()) return 0;\r
+\r
+ of.tracks[0]=MTM_Convert(); /* track 0 is empty */\r
+ for(t=1;t<of.numtrk;t++) {\r
+ int s;\r
+\r
+ for(s=0;s<64;s++) {\r
+ mtmtrk[s].a=_mm_read_UBYTE(modreader);\r
+ mtmtrk[s].b=_mm_read_UBYTE(modreader);\r
+ mtmtrk[s].c=_mm_read_UBYTE(modreader);\r
+ }\r
+\r
+ if(_mm_eof(modreader)) {\r
+ _mm_errno = MMERR_LOADING_TRACK;\r
+ return 0;\r
+ }\r
+\r
+ if(!(of.tracks[t]=MTM_Convert())) return 0;\r
+ }\r
+\r
+ for(t=0;t<of.numpat;t++) {\r
+ _mm_read_I_UWORDS(pat,32,modreader);\r
+ for(u=0;u<of.numchn;u++)\r
+ of.patterns[((long)t*of.numchn)+u]=pat[u];\r
+ }\r
+\r
+ /* read comment field */\r
+ if(mh->commentsize)\r
+ if(!ReadLinedComment(mh->commentsize, 40)) return 0;\r
+\r
+ return 1;\r
+}\r
+\r
+CHAR *MTM_LoadTitle(void)\r
+{\r
+ CHAR s[20];\r
+\r
+ _mm_fseek(modreader,4,SEEK_SET);\r
+ if(!_mm_read_UBYTES(s,20,modreader)) return NULL;\r
+\r
+ return(DupStr(s,20,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_mtm={\r
+ NULL,\r
+ "MTM",\r
+ "MTM (MultiTracker Module editor)",\r
+ MTM_Init,\r
+ MTM_Test,\r
+ MTM_Load,\r
+ MTM_Cleanup,\r
+ MTM_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r