Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / loaders / load_dsm.c
diff --git a/apps/plugins/mikmod/loaders/load_dsm.c b/apps/plugins/mikmod/loaders/load_dsm.c
new file mode 100644 (file)
index 0000000..0eace5f
--- /dev/null
@@ -0,0 +1,365 @@
+/*     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_dsm.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  DSIK internal format (DSM) 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
+#define DSM_MAXCHAN (16)\r
+#define DSM_MAXORDERS (128)\r
+\r
+typedef struct DSMSONG {\r
+       CHAR    songname[28];\r
+       UWORD   version;\r
+       UWORD   flags;\r
+       ULONG   reserved2;\r
+       UWORD   numord;\r
+       UWORD   numsmp;\r
+       UWORD   numpat;\r
+       UWORD   numtrk;\r
+       UBYTE   globalvol;\r
+       UBYTE   mastervol;\r
+       UBYTE   speed;\r
+       UBYTE   bpm;\r
+       UBYTE   panpos[DSM_MAXCHAN];\r
+       UBYTE   orders[DSM_MAXORDERS];\r
+} DSMSONG;\r
+\r
+typedef struct DSMINST {\r
+       CHAR    filename[13];\r
+       UWORD   flags;\r
+       UBYTE   volume;\r
+       ULONG   length;\r
+       ULONG   loopstart;\r
+       ULONG   loopend;\r
+       ULONG   reserved1;\r
+       UWORD   c2spd;\r
+       UWORD   period;\r
+       CHAR    samplename[28];\r
+} DSMINST;\r
+\r
+typedef struct DSMNOTE {\r
+       UBYTE   note,ins,vol,cmd,inf;\r
+} DSMNOTE;\r
+\r
+#define DSM_SURROUND (0xa4)\r
+\r
+/*========== Loader variables */\r
+\r
+static CHAR* SONGID="SONG";\r
+static CHAR* INSTID="INST";\r
+static CHAR* PATTID="PATT";\r
+\r
+static UBYTE blockid[4];\r
+static ULONG blockln;\r
+static ULONG blocklp;\r
+static DSMSONG* mh=NULL;\r
+static DSMNOTE* dsmbuf=NULL;\r
+\r
+static CHAR DSM_Version[]="DSIK DSM-format";\r
+\r
+static unsigned char DSMSIG[4+4]={'R','I','F','F','D','S','M','F'};\r
+\r
+/*========== Loader code */\r
+\r
+BOOL DSM_Test(void)\r
+{\r
+       UBYTE id[12];\r
+\r
+       if(!_mm_read_UBYTES(id,12,modreader)) return 0;\r
+       if(!memcmp(id,DSMSIG,4) && !memcmp(id+8,DSMSIG+4,4)) return 1;\r
+\r
+       return 0;\r
+}\r
+\r
+BOOL DSM_Init(void)\r
+{\r
+       if(!(dsmbuf=(DSMNOTE *)_mm_malloc(DSM_MAXCHAN*64*sizeof(DSMNOTE)))) return 0;\r
+       if(!(mh=(DSMSONG *)_mm_calloc(1,sizeof(DSMSONG)))) return 0;\r
+       return 1;\r
+}\r
+\r
+void DSM_Cleanup(void)\r
+{\r
+       _mm_free(dsmbuf);\r
+       _mm_free(mh);\r
+}\r
+\r
+static BOOL GetBlockHeader(void)\r
+{\r
+       /* make sure we're at the right position for reading the\r
+          next riff block, no matter how many bytes read */\r
+       _mm_fseek(modreader, blocklp+blockln, SEEK_SET);\r
+   \r
+       while(1) {\r
+               _mm_read_UBYTES(blockid,4,modreader);\r
+               blockln=_mm_read_I_ULONG(modreader);\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_HEADER;\r
+                       return 0;\r
+               }\r
+\r
+               if(memcmp(blockid,SONGID,4) && memcmp(blockid,INSTID,4) &&\r
+                  memcmp(blockid,PATTID,4)) {\r
+#ifdef MIKMOD_DEBUG\r
+                               fprintf(stderr,"\rDSM: Skipping unknown block type %4.4s\n",blockid);\r
+#endif\r
+                               _mm_fseek(modreader, blockln, SEEK_CUR);\r
+               } else\r
+                       break;\r
+       }\r
+\r
+       blocklp = _mm_ftell(modreader);\r
+\r
+       return 1;\r
+}\r
+\r
+static BOOL DSM_ReadPattern(void)\r
+{\r
+       int flag,row=0;\r
+       SWORD length;\r
+       DSMNOTE *n;\r
+\r
+       /* clear pattern data */\r
+       memset(dsmbuf,255,DSM_MAXCHAN*64*sizeof(DSMNOTE));\r
+       length=_mm_read_I_SWORD(modreader);\r
+\r
+       while(row<64) {\r
+               flag=_mm_read_UBYTE(modreader);\r
+               if((_mm_eof(modreader))||(--length<0)) {\r
+                       _mm_errno = MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+\r
+               if(flag) {\r
+                       n=&dsmbuf[((flag&0xf)*64)+row];\r
+                       if(flag&0x80) n->note=_mm_read_UBYTE(modreader);\r
+                       if(flag&0x40) n->ins=_mm_read_UBYTE(modreader);\r
+                       if(flag&0x20) n->vol=_mm_read_UBYTE(modreader);\r
+                       if(flag&0x10) {\r
+                               n->cmd=_mm_read_UBYTE(modreader);\r
+                               n->inf=_mm_read_UBYTE(modreader);\r
+                       }\r
+               } else\r
+                       row++;\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+static UBYTE *DSM_ConvertTrack(DSMNOTE *tr)\r
+{\r
+       int t;\r
+       UBYTE note,ins,vol,cmd,inf;\r
+\r
+       UniReset();\r
+       for(t=0;t<64;t++) {\r
+               note=tr[t].note;\r
+               ins=tr[t].ins;\r
+               vol=tr[t].vol;\r
+               cmd=tr[t].cmd;\r
+               inf=tr[t].inf;\r
+\r
+               if(ins!=0 && ins!=255) UniInstrument(ins-1);\r
+               if(note!=255) UniNote(note-1); /* normal note */\r
+               if(vol<65) UniPTEffect(0xc,vol);\r
+\r
+               if(cmd!=255) {\r
+                       if(cmd==0x8) {\r
+                               if(inf==DSM_SURROUND)\r
+                                       UniEffect(UNI_ITEFFECTS0,0x91);\r
+                               else\r
+                                 if(inf<=0x80) {\r
+                                       inf=(inf<0x80)?inf<<1:255;\r
+                                       UniPTEffect(cmd,inf);\r
+                               }\r
+                       } else\r
+                         if(cmd==0xb) {\r
+                               if(inf<=0x7f) UniPTEffect(cmd,inf);\r
+                       } else {\r
+                               /* Convert pattern jump from Dec to Hex */\r
+                               if(cmd == 0xd)\r
+                                       inf = (((inf&0xf0)>>4)*10)+(inf&0xf);\r
+                               UniPTEffect(cmd,inf);\r
+                       }\r
+               }\r
+               UniNewline();\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+BOOL DSM_Load(BOOL curious)\r
+{\r
+       int t;\r
+       DSMINST s;\r
+       SAMPLE *q;\r
+       int cursmp=0,curpat=0,track=0;\r
+\r
+       blocklp=0;\r
+       blockln=12;\r
+       (void)curious;\r
+\r
+       if(!GetBlockHeader()) return 0;\r
+       if(memcmp(blockid,SONGID,4)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       _mm_read_UBYTES(mh->songname,28,modreader);\r
+       mh->version=_mm_read_I_UWORD(modreader);\r
+       mh->flags=_mm_read_I_UWORD(modreader);\r
+       mh->reserved2=_mm_read_I_ULONG(modreader);\r
+       mh->numord=_mm_read_I_UWORD(modreader);\r
+       mh->numsmp=_mm_read_I_UWORD(modreader);\r
+       mh->numpat=_mm_read_I_UWORD(modreader);\r
+       mh->numtrk=_mm_read_I_UWORD(modreader);\r
+       mh->globalvol=_mm_read_UBYTE(modreader);\r
+       mh->mastervol=_mm_read_UBYTE(modreader);\r
+       mh->speed=_mm_read_UBYTE(modreader);\r
+       mh->bpm=_mm_read_UBYTE(modreader);\r
+       _mm_read_UBYTES(mh->panpos,DSM_MAXCHAN,modreader);\r
+       _mm_read_UBYTES(mh->orders,DSM_MAXORDERS,modreader);\r
+\r
+       /* set module variables */\r
+       of.initspeed=mh->speed;\r
+       of.inittempo=mh->bpm;\r
+       of.modtype=strdup(DSM_Version);\r
+       of.numchn=mh->numtrk;\r
+       of.numpat=mh->numpat;\r
+       of.numtrk=of.numchn*of.numpat;\r
+       of.songname=DupStr(mh->songname,28,1); /* make a cstr of songname */\r
+       of.reppos=0;\r
+       of.flags |= UF_PANNING;\r
+       /* XXX whenever possible, we should try to determine the original format.\r
+          Here we assume it was S3M-style wrt bpmlimit... */\r
+       of.bpmlimit = 32;\r
+\r
+       for(t=0;t<DSM_MAXCHAN;t++)\r
+               of.panning[t]=mh->panpos[t]==DSM_SURROUND?PAN_SURROUND:\r
+                             mh->panpos[t]<0x80?(mh->panpos[t]<<1):255;\r
+\r
+       if(!AllocPositions(mh->numord)) return 0;\r
+       of.numpos=0;\r
+       for(t=0;t<mh->numord;t++) {\r
+               int order=mh->orders[t];\r
+               if(order==255) order=LAST_PATTERN;\r
+               of.positions[of.numpos]=order;\r
+               if(mh->orders[t]<254) of.numpos++;\r
+       }\r
+\r
+       of.numins=of.numsmp=mh->numsmp;\r
+\r
+       if(!AllocSamples()) return 0;\r
+       if(!AllocTracks()) return 0;\r
+       if(!AllocPatterns()) return 0;\r
+\r
+       while(cursmp<of.numins||curpat<of.numpat) {\r
+               if(!GetBlockHeader()) return 0;\r
+               if(!memcmp(blockid,INSTID,4) && cursmp<of.numins) {\r
+                       q=&of.samples[cursmp];\r
+\r
+                       /* try to read sample info */\r
+                       _mm_read_UBYTES(s.filename,13,modreader);\r
+                       s.flags=_mm_read_I_UWORD(modreader);\r
+                       s.volume=_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.reserved1=_mm_read_I_ULONG(modreader);\r
+                       s.c2spd=_mm_read_I_UWORD(modreader);\r
+                       s.period=_mm_read_I_UWORD(modreader);\r
+                       _mm_read_UBYTES(s.samplename,28,modreader);\r
+\r
+                       q->samplename=DupStr(s.samplename,28,1);\r
+                       q->seekpos=_mm_ftell(modreader);\r
+                       q->speed=s.c2spd;\r
+                       q->length=s.length;\r
+                       q->loopstart=s.loopstart;\r
+                       q->loopend=s.loopend;\r
+                       q->volume=s.volume;\r
+\r
+                       if(s.flags&1) q->flags|=SF_LOOP;\r
+                       if(s.flags&2) q->flags|=SF_SIGNED;\r
+                       /* (s.flags&4) means packed sample,\r
+                          but did they really exist in dsm ?*/\r
+                       cursmp++;\r
+               } else\r
+                 if(!memcmp(blockid,PATTID,4) && curpat<of.numpat) {\r
+                       DSM_ReadPattern();\r
+                       for(t=0;t<of.numchn;t++)\r
+                               if(!(of.tracks[track++]=DSM_ConvertTrack(&dsmbuf[t*64]))) return 0;\r
+                       curpat++;\r
+               }\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+CHAR *DSM_LoadTitle(void)\r
+{\r
+       CHAR s[28];\r
+\r
+       _mm_fseek(modreader,12,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,28,modreader)) return NULL;\r
+   \r
+       return(DupStr(s,28,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_dsm={\r
+       NULL,\r
+       "DSM",\r
+       "DSM (DSIK internal format)",\r
+       DSM_Init,\r
+       DSM_Test,\r
+       DSM_Load,\r
+       DSM_Cleanup,\r
+       DSM_LoadTitle\r
+};\r
+\r
+\r
+/* ex:set ts=4: */\r