Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / loaders / load_669.c
diff --git a/apps/plugins/mikmod/loaders/load_669.c b/apps/plugins/mikmod/loaders/load_669.c
new file mode 100644 (file)
index 0000000..1991e75
--- /dev/null
@@ -0,0 +1,369 @@
+/*     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_669.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Composer 669 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
+/* header */\r
+typedef struct S69HEADER {   \r
+       UBYTE   marker[2];\r
+       CHAR    message[108];\r
+       UBYTE   nos;\r
+       UBYTE   nopa;\r
+       UBYTE   looporder;\r
+       UBYTE   orders[0x80];\r
+       UBYTE   tempos[0x80];\r
+       UBYTE   breaks[0x80];\r
+} S69HEADER;\r
+\r
+/* sample information */\r
+typedef struct S69SAMPLE {\r
+       CHAR    filename[13];\r
+       SLONG   length;\r
+       SLONG   loopbeg;\r
+       SLONG   loopend;\r
+} S69SAMPLE;\r
+\r
+/* encoded note */\r
+typedef struct S69NOTE {\r
+       UBYTE   a,b,c;\r
+} S69NOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+/* current pattern */\r
+static S69NOTE* s69pat=NULL;\r
+/* Module header */\r
+static S69HEADER* mh=NULL;\r
+\r
+/* file type identification */\r
+static CHAR* S69_Version[]={\r
+       "Composer 669",\r
+       "Extended 669"\r
+};\r
+\r
+/*========== Loader code */\r
+\r
+BOOL S69_Test(void)\r
+{\r
+       UBYTE buf[0x80];\r
+\r
+       if(!_mm_read_UBYTES(buf,2,modreader))\r
+               return 0;\r
+       /* look for id */\r
+       if(!memcmp(buf,"if",2) || !memcmp(buf,"JN",2)) {\r
+               int i;\r
+\r
+               /* skip song message */\r
+               _mm_fseek(modreader,108,SEEK_CUR);\r
+               /* sanity checks */\r
+               if(_mm_read_UBYTE(modreader) > 64) return 0;\r
+               if(_mm_read_UBYTE(modreader) > 128) return 0;\r
+               if(_mm_read_UBYTE(modreader) > 127) return 0;\r
+               /* check order table */\r
+               if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;\r
+               for(i=0;i<0x80;i++)\r
+                       if((buf[i]>=0x80)&&(buf[i]!=0xff)) return 0;\r
+               /* check tempos table */\r
+               if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;\r
+               for(i=0;i<0x80;i++)\r
+                       if((!buf[i])||(buf[i]>32)) return 0;\r
+               /* check pattern length table */\r
+               if(!_mm_read_UBYTES(buf,0x80,modreader)) return 0;\r
+               for(i=0;i<0x80;i++)\r
+                       if(buf[i]>0x3f) return 0;\r
+       } else\r
+               return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+BOOL S69_Init(void)\r
+{\r
+       if(!(s69pat=(S69NOTE *)_mm_malloc(64*8*sizeof(S69NOTE)))) return 0;\r
+       if(!(mh=(S69HEADER *)_mm_malloc(sizeof(S69HEADER)))) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+void S69_Cleanup(void)\r
+{\r
+       _mm_free(s69pat);\r
+       _mm_free(mh);\r
+}\r
+\r
+static BOOL S69_LoadPatterns(void)\r
+{\r
+       int track,row,channel;\r
+       UBYTE note,inst,vol,effect,lastfx,lastval;\r
+       S69NOTE *cur;\r
+       int tracks=0;\r
+       \r
+       if(!AllocPatterns()) return 0;\r
+       if(!AllocTracks()) return 0;\r
+\r
+       for(track=0;track<of.numpat;track++) {\r
+               /* set pattern break locations */\r
+               of.pattrows[track]=mh->breaks[track]+1;\r
+\r
+               /* load the 669 pattern */\r
+               cur=s69pat;\r
+               for(row=0;row<64;row++) {\r
+                       for(channel=0;channel<8;channel++,cur++) {\r
+                               cur->a = _mm_read_UBYTE(modreader);\r
+                               cur->b = _mm_read_UBYTE(modreader);\r
+                               cur->c = _mm_read_UBYTE(modreader);\r
+                       }\r
+               }\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_PATTERN;\r
+                       return 0;\r
+               }\r
+\r
+               /* translate the pattern */\r
+               for(channel=0;channel<8;channel++) {\r
+                       UniReset();\r
+                       /* set pattern tempo */\r
+                       UniPTEffect(0xf,78);\r
+                       UniPTEffect(0xf,mh->tempos[track]);\r
+\r
+                       lastfx=0xff,lastval=0;\r
+\r
+                       for(row=0;row<=mh->breaks[track];row++) {\r
+                               int a,b,c;\r
+\r
+                               /* fetch the encoded note */\r
+                               a=s69pat[(row*8)+channel].a;\r
+                               b=s69pat[(row*8)+channel].b;\r
+                               c=s69pat[(row*8)+channel].c;\r
+\r
+                               /* decode it */\r
+                               note=a>>2;\r
+                               inst=((a&0x3)<<4)|((b&0xf0)>>4);\r
+                               vol=b&0xf;\r
+\r
+                               if (a<0xff) {\r
+                                       if (a<0xfe) {\r
+                                               UniInstrument(inst);\r
+                                               UniNote(note+2*OCTAVE);\r
+                                               lastfx=0xff; /* reset background effect memory */\r
+                                       }\r
+                                       UniPTEffect(0xc,vol<<2);\r
+                               }\r
+\r
+                               if ((c!=0xff)||(lastfx!=0xff)) {\r
+                                       if(c==0xff)\r
+                                               c=lastfx,effect=lastval;\r
+                                       else\r
+                                               effect=c&0xf;\r
+\r
+                                       switch(c>>4) {\r
+                                               case 0: /* porta up */\r
+                                                       UniPTEffect(0x1,effect);\r
+                                                       lastfx=c,lastval=effect;\r
+                                                       break;\r
+                                               case 1: /* porta down */\r
+                                                       UniPTEffect(0x2,effect);\r
+                                                       lastfx=c,lastval=effect;\r
+                                                       break;\r
+                                               case 2: /* porta to note */\r
+                                                       UniPTEffect(0x3,effect);\r
+                                                       lastfx=c,lastval=effect;\r
+                                                       break;\r
+                                               case 3: /* frequency adjust */\r
+                                                       /* DMP converts this effect to S3M FF1. Why not ? */\r
+                                                       UniEffect(UNI_S3MEFFECTF,0xf0|effect);\r
+                                                       break;\r
+                                               case 4: /* vibrato */\r
+                                                       UniPTEffect(0x4,effect);\r
+                                                       lastfx=c,lastval=effect;\r
+                                                       break;\r
+                                               case 5: /* set speed */\r
+                                                       if (effect)\r
+                                                               UniPTEffect(0xf,effect);\r
+                                                       else \r
+                                                         if(mh->marker[0]!=0x69) {\r
+#ifdef MIKMOD_DEBUG\r
+                                                               fprintf(stderr,"\r669: unsupported super fast tempo at pat=%d row=%d chan=%d\n",\r
+                                                                      track,row,channel);\r
+#endif\r
+                                                       }\r
+                                                       break;\r
+                                       }\r
+                               }\r
+                               UniNewline();\r
+                       }\r
+                       if(!(of.tracks[tracks++]=UniDup())) return 0;\r
+               }\r
+       }\r
+\r
+       return 1;\r
+}\r
+\r
+BOOL S69_Load(BOOL curious)\r
+{\r
+       int i;\r
+       SAMPLE *current;\r
+       S69SAMPLE sample;\r
+       (void)curious;\r
+\r
+       /* module header */\r
+       _mm_read_UBYTES(mh->marker,2,modreader);\r
+       _mm_read_UBYTES(mh->message,108,modreader);\r
+       mh->nos=_mm_read_UBYTE(modreader);\r
+       mh->nopa=_mm_read_UBYTE(modreader);\r
+       mh->looporder=_mm_read_UBYTE(modreader);\r
+       _mm_read_UBYTES(mh->orders,0x80,modreader);\r
+       for(i=0;i<0x80;i++)\r
+               if ((mh->orders[i]>=0x80)&&(mh->orders[i]!=0xff)) {\r
+                       _mm_errno=MMERR_NOT_A_MODULE;\r
+                       return 1;\r
+               }\r
+       _mm_read_UBYTES(mh->tempos,0x80,modreader);\r
+       for(i=0;i<0x80;i++)\r
+               if ((!mh->tempos[i])||(mh->tempos[i]>32)) {\r
+                       _mm_errno=MMERR_NOT_A_MODULE;\r
+                       return 1;\r
+               }\r
+       _mm_read_UBYTES(mh->breaks,0x80,modreader);\r
+       for(i=0;i<0x80;i++)\r
+               if (mh->breaks[i]>0x3f) {\r
+                       _mm_errno=MMERR_NOT_A_MODULE;\r
+                       return 1;\r
+               }\r
+\r
+       /* set module variables */\r
+       of.initspeed=4;\r
+       of.inittempo=78;\r
+       of.songname=DupStr(mh->message,36,1);\r
+       of.modtype=strdup(S69_Version[memcmp(mh->marker,"JN",2)==0]);\r
+       of.numchn=8;\r
+       of.numpat=mh->nopa;\r
+       of.numins=of.numsmp=mh->nos;\r
+       of.numtrk=of.numchn*of.numpat;\r
+       of.flags=UF_XMPERIODS|UF_LINEAR;\r
+\r
+       for(i=   35;(i>=   0)&&(mh->message[i]==' ');i--) mh->message[i]=0;\r
+       for(i=36+35;(i>=36+0)&&(mh->message[i]==' ');i--) mh->message[i]=0;\r
+       for(i=72+35;(i>=72+0)&&(mh->message[i]==' ');i--) mh->message[i]=0;\r
+       if((mh->message[0])||(mh->message[36])||(mh->message[72]))\r
+               if((of.comment=(CHAR*)_mm_malloc(3*(36+1)+1))) {\r
+                       strncpy(of.comment,mh->message,36);\r
+                       strcat(of.comment,"\r");\r
+                       if (mh->message[36]) strncat(of.comment,mh->message+36,36);\r
+                       strcat(of.comment,"\r");\r
+                       if (mh->message[72]) strncat(of.comment,mh->message+72,36);\r
+                       strcat(of.comment,"\r");\r
+                       of.comment[3*(36+1)]=0;\r
+               }\r
+\r
+       if(!AllocPositions(0x80)) return 0;\r
+       for(i=0;i<0x80;i++) {\r
+               if(mh->orders[i]>=mh->nopa) break;\r
+               of.positions[i]=mh->orders[i];\r
+       }\r
+       of.numpos=i;\r
+       of.reppos=mh->looporder<of.numpos?mh->looporder:0;\r
+\r
+       if(!AllocSamples()) return 0;\r
+       current=of.samples;\r
+\r
+       for(i=0;i<of.numins;i++) {\r
+               /* sample information */\r
+               _mm_read_UBYTES((UBYTE*)sample.filename,13,modreader);\r
+               sample.length=_mm_read_I_SLONG(modreader);\r
+               sample.loopbeg=_mm_read_I_SLONG(modreader);\r
+               sample.loopend=_mm_read_I_SLONG(modreader);\r
+               if (sample.loopend==0xfffff) sample.loopend=0;\r
+\r
+               if((sample.length<0)||(sample.loopbeg<-1)||(sample.loopend<-1)) {\r
+                       _mm_errno = MMERR_LOADING_HEADER;\r
+                       return 0;\r
+               }\r
+\r
+               current->samplename=DupStr(sample.filename,13,1);\r
+               current->seekpos=0;\r
+               current->speed=0;\r
+               current->length=sample.length;\r
+               current->loopstart=sample.loopbeg;\r
+               current->loopend=sample.loopend;\r
+               current->flags=(sample.loopbeg<sample.loopend)?SF_LOOP:0;\r
+               current->volume=64;\r
+\r
+               current++;\r
+       }\r
+\r
+       if(!S69_LoadPatterns()) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+CHAR *S69_LoadTitle(void)\r
+{\r
+       CHAR s[36];\r
+\r
+       _mm_fseek(modreader,2,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,36,modreader)) return NULL;\r
+\r
+       return(DupStr(s,36,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_669={\r
+       NULL,\r
+       "669",\r
+       "669 (Composer 669, Unis 669)",\r
+       S69_Init,\r
+       S69_Test,\r
+       S69_Load,\r
+       S69_Cleanup,\r
+       S69_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r