Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / loaders / load_far.c
diff --git a/apps/plugins/mikmod/loaders/load_far.c b/apps/plugins/mikmod/loaders/load_far.c
new file mode 100644 (file)
index 0000000..a66bf8f
--- /dev/null
@@ -0,0 +1,347 @@
+/*     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_far.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Farandole (FAR) 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 FARHEADER1 {\r
+       UBYTE id[4];                    /* file magic */\r
+       CHAR  songname[40];             /* songname */\r
+       CHAR  blah[3];                  /* 13,10,26 */\r
+       UWORD headerlen;                /* remaining length of header in bytes */\r
+       UBYTE version;\r
+       UBYTE onoff[16];\r
+       UBYTE edit1[9];\r
+       UBYTE speed;\r
+       UBYTE panning[16];\r
+       UBYTE edit2[4];\r
+       UWORD stlen;\r
+} FARHEADER1;\r
+\r
+typedef struct FARHEADER2 {\r
+       UBYTE orders[256];\r
+       UBYTE numpat;\r
+       UBYTE snglen;\r
+       UBYTE loopto;\r
+       UWORD patsiz[256];\r
+} FARHEADER2;\r
+\r
+typedef struct FARSAMPLE {\r
+       CHAR  samplename[32];\r
+       ULONG length;\r
+       UBYTE finetune;\r
+       UBYTE volume;\r
+       ULONG reppos;\r
+       ULONG repend;\r
+       UBYTE type;\r
+       UBYTE loop;\r
+} FARSAMPLE;\r
+\r
+typedef struct FARNOTE {\r
+       UBYTE note,ins,vol,eff;\r
+} FARNOTE;\r
+\r
+/*========== Loader variables */\r
+\r
+static CHAR FAR_Version[] = "Farandole";\r
+static FARHEADER1 *mh1 = NULL;\r
+static FARHEADER2 *mh2 = NULL;\r
+static FARNOTE *pat = NULL;\r
+\r
+static unsigned char FARSIG[4+3]={'F','A','R',0xfe,13,10,26};\r
+\r
+/*========== Loader code */\r
+\r
+BOOL FAR_Test(void)\r
+{\r
+       UBYTE id[47];\r
+\r
+       if(!_mm_read_UBYTES(id,47,modreader)) return 0;\r
+       if((memcmp(id,FARSIG,4))||(memcmp(id+44,FARSIG+4,3))) return 0;\r
+       return 1;\r
+}\r
+\r
+BOOL FAR_Init(void)\r
+{\r
+       if(!(mh1 = (FARHEADER1*)_mm_malloc(sizeof(FARHEADER1)))) return 0;\r
+       if(!(mh2 = (FARHEADER2*)_mm_malloc(sizeof(FARHEADER2)))) return 0;\r
+       if(!(pat = (FARNOTE*)_mm_malloc(256*16*4*sizeof(FARNOTE)))) return 0;\r
+\r
+       return 1;\r
+}\r
+\r
+void FAR_Cleanup(void)\r
+{\r
+       _mm_free(mh1);\r
+       _mm_free(mh2);\r
+       _mm_free(pat);\r
+}\r
+\r
+static UBYTE *FAR_ConvertTrack(FARNOTE* n,int rows)\r
+{\r
+       int t,vibdepth=1;\r
+\r
+       UniReset();\r
+       for(t=0;t<rows;t++) {\r
+               if(n->note) {\r
+                       UniInstrument(n->ins);\r
+                       UniNote(n->note+3*OCTAVE-1);\r
+               }\r
+               if (n->vol&0xf) UniPTEffect(0xc,(n->vol&0xf)<<2);\r
+               if (n->eff)\r
+                       switch(n->eff>>4) {\r
+                               case 0x3: /* porta to note */\r
+                                       UniPTEffect(0x3,(n->eff&0xf)<<4);\r
+                                       break;\r
+                               case 0x4: /* retrigger */\r
+                                       UniPTEffect(0x0e, 0x90 | (n->eff & 0x0f));\r
+                                       break;\r
+                               case 0x5: /* set vibrato depth */\r
+                                       vibdepth=n->eff&0xf;\r
+                                       break;\r
+                               case 0x6: /* vibrato */\r
+                                       UniPTEffect(0x4,((n->eff&0xf)<<4)|vibdepth);\r
+                                       break;\r
+                               case 0x7: /* volume slide up */\r
+                                       UniPTEffect(0xa,(n->eff&0xf)<<4);\r
+                                       break;\r
+                               case 0x8: /* volume slide down */\r
+                                       UniPTEffect(0xa,n->eff&0xf);\r
+                                       break;\r
+                               case 0xb: /* panning */\r
+                                       UniPTEffect(0xe,0x80|(n->eff&0xf));\r
+                                       break;\r
+                               case 0xf: /* set speed */\r
+                                       UniPTEffect(0xf,n->eff&0xf);\r
+                                       break;\r
+\r
+                               /* others not yet implemented */\r
+                               default:\r
+#ifdef MIKMOD_DEBUG\r
+                                       fprintf(stderr,"\rFAR: unsupported effect %02X\n",n->eff);\r
+#endif\r
+                                       break;\r
+                       }\r
+\r
+               UniNewline();\r
+               n+=16;\r
+       }\r
+       return UniDup();\r
+}\r
+\r
+BOOL FAR_Load(BOOL curious)\r
+{\r
+       int t,u,tracks=0;\r
+       SAMPLE *q;\r
+       FARSAMPLE s;\r
+       FARNOTE *crow;\r
+       UBYTE smap[8];\r
+       (void)curious;\r
+\r
+       /* try to read module header (first part) */\r
+       _mm_read_UBYTES(mh1->id,4,modreader);\r
+       _mm_read_SBYTES(mh1->songname,40,modreader);\r
+       _mm_read_SBYTES(mh1->blah,3,modreader);\r
+       mh1->headerlen = _mm_read_I_UWORD (modreader);\r
+       mh1->version   = _mm_read_UBYTE (modreader);\r
+       _mm_read_UBYTES(mh1->onoff,16,modreader);\r
+       _mm_read_UBYTES(mh1->edit1,9,modreader);\r
+       mh1->speed     = _mm_read_UBYTE(modreader);\r
+       _mm_read_UBYTES(mh1->panning,16,modreader);\r
+       _mm_read_UBYTES(mh1->edit2,4,modreader);\r
+       mh1->stlen     = _mm_read_I_UWORD (modreader);\r
+\r
+       /* init modfile data */\r
+       of.modtype   = strdup(FAR_Version);\r
+       of.songname  = DupStr(mh1->songname,40,1);\r
+       of.numchn    = 16;\r
+       of.initspeed = mh1->speed;\r
+       of.inittempo = 80;\r
+       of.reppos    = 0;\r
+       of.flags    |= UF_PANNING;\r
+       for(t=0;t<16;t++) of.panning[t]=mh1->panning[t]<<4;\r
+\r
+       /* read songtext into comment field */\r
+       if(mh1->stlen)\r
+               if (!ReadLinedComment(mh1->stlen, 66)) return 0;\r
+\r
+       /* try to read module header (second part) */\r
+       _mm_read_UBYTES(mh2->orders,256,modreader);\r
+       mh2->numpat        = _mm_read_UBYTE(modreader);\r
+       mh2->snglen        = _mm_read_UBYTE(modreader);\r
+       mh2->loopto        = _mm_read_UBYTE(modreader);\r
+       _mm_read_I_UWORDS(mh2->patsiz,256,modreader);\r
+\r
+       of.numpos = mh2->snglen;\r
+       if(!AllocPositions(of.numpos)) return 0;\r
+       for(t=0;t<of.numpos;t++) {\r
+               if(mh2->orders[t]==0xff) break;\r
+               of.positions[t] = mh2->orders[t];\r
+       }\r
+\r
+       /* count number of patterns stored in file */\r
+       of.numpat = 0;\r
+       for(t=0;t<256;t++)\r
+               if(mh2->patsiz[t])\r
+                       if((t+1)>of.numpat) of.numpat=t+1;\r
+       of.numtrk = of.numpat*of.numchn;\r
+\r
+       /* seek across eventual new data */\r
+       _mm_fseek(modreader,mh1->headerlen-(869+mh1->stlen),SEEK_CUR);\r
+\r
+       /* alloc track and pattern structures */\r
+       if(!AllocTracks()) return 0;\r
+       if(!AllocPatterns()) return 0;\r
+\r
+       for(t=0;t<of.numpat;t++) {\r
+               UBYTE rows=0,tempo;\r
+\r
+               memset(pat,0,256*16*4*sizeof(FARNOTE));\r
+               if(mh2->patsiz[t]) {\r
+                       rows  = _mm_read_UBYTE(modreader);\r
+                       tempo = _mm_read_UBYTE(modreader);\r
+\r
+                       crow = pat;\r
+                       /* file often allocates 64 rows even if there are less in pattern */\r
+                       if (mh2->patsiz[t]<2+(rows*16*4)) {\r
+                               _mm_errno = MMERR_LOADING_PATTERN;\r
+                               return 0;\r
+                       }\r
+                       for(u=(mh2->patsiz[t]-2)/4;u;u--,crow++) {\r
+                               crow->note = _mm_read_UBYTE(modreader);\r
+                               crow->ins  = _mm_read_UBYTE(modreader);\r
+                               crow->vol  = _mm_read_UBYTE(modreader);\r
+                               crow->eff  = _mm_read_UBYTE(modreader);\r
+                       }\r
+\r
+                       if(_mm_eof(modreader)) {\r
+                               _mm_errno = MMERR_LOADING_PATTERN;\r
+                               return 0;\r
+                       }\r
+\r
+                       crow=pat;\r
+                       of.pattrows[t] = rows;\r
+                       for(u=16;u;u--,crow++)\r
+                               if(!(of.tracks[tracks++]=FAR_ConvertTrack(crow,rows))) {\r
+                                       _mm_errno=MMERR_LOADING_PATTERN;\r
+                                       return 0;\r
+                               }\r
+               } else\r
+                       tracks+=16;\r
+       }\r
+\r
+       /* read sample map */\r
+       if(!_mm_read_UBYTES(smap,8,modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       /* count number of samples used */\r
+       of.numins = 0;\r
+       for(t=0;t<64;t++)\r
+               if(smap[t>>3]&(1<<(t&7))) of.numins=t+1;\r
+       of.numsmp = of.numins;             \r
+\r
+       /* alloc sample structs */\r
+       if(!AllocSamples()) return 0;\r
+\r
+       q = of.samples;\r
+       for(t=0;t<of.numsmp;t++) {\r
+               q->speed      = 8363;\r
+               q->flags      = SF_SIGNED;\r
+               if(smap[t>>3]&(1<<(t&7))) {\r
+                       _mm_read_SBYTES(s.samplename,32,modreader);\r
+                       s.length   = _mm_read_I_ULONG(modreader);\r
+                       s.finetune = _mm_read_UBYTE(modreader);\r
+                       s.volume   = _mm_read_UBYTE(modreader);\r
+                       s.reppos   = _mm_read_I_ULONG(modreader);\r
+                       s.repend   = _mm_read_I_ULONG(modreader);\r
+                       s.type     = _mm_read_UBYTE(modreader);\r
+                       s.loop     = _mm_read_UBYTE(modreader);\r
+\r
+                       q->samplename = DupStr(s.samplename,32,1);\r
+                       q->length     = s.length;\r
+                       q->loopstart  = s.reppos;\r
+                       q->loopend    = s.repend;\r
+                       q->volume     = s.volume<<2;\r
+\r
+                       if(s.type&1) q->flags|=SF_16BITS;\r
+                       if(s.loop&8) q->flags|=SF_LOOP;\r
+\r
+                       q->seekpos    = _mm_ftell(modreader);\r
+                       _mm_fseek(modreader,q->length,SEEK_CUR);\r
+               } else \r
+                       q->samplename = DupStr(NULL,0,0);\r
+               q++;\r
+       }\r
+       return 1;\r
+}\r
+\r
+CHAR *FAR_LoadTitle(void)\r
+{\r
+       CHAR s[40];\r
+\r
+       _mm_fseek(modreader,4,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,40,modreader)) return NULL;\r
+   \r
+       return(DupStr(s,40,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_far={\r
+       NULL,\r
+       "FAR",\r
+       "FAR (Farandole Composer)",\r
+       FAR_Init,\r
+       FAR_Test,\r
+       FAR_Load,\r
+       FAR_Cleanup,\r
+       FAR_LoadTitle\r
+};\r
+\r
+/* ex:set ts=4: */\r