Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / loaders / load_mtm.c
diff --git a/apps/plugins/mikmod/loaders/load_mtm.c b/apps/plugins/mikmod/loaders/load_mtm.c
new file mode 100644 (file)
index 0000000..3da7b28
--- /dev/null
@@ -0,0 +1,286 @@
+/*     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