Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / loaders / load_ult.c
diff --git a/apps/plugins/mikmod/loaders/load_ult.c b/apps/plugins/mikmod/loaders/load_ult.c
new file mode 100644 (file)
index 0000000..5d8c76d
--- /dev/null
@@ -0,0 +1,336 @@
+/*     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_ult.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Ultratracker (ULT) 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 ULTHEADER {\r
+       CHAR  id[16];\r
+       CHAR  songtitle[32];\r
+       UBYTE reserved;\r
+} ULTHEADER;\r
+\r
+/* sample information */\r
+typedef struct ULTSAMPLE {\r
+       CHAR  samplename[32];\r
+       CHAR  dosname[12];\r
+       SLONG loopstart;\r
+       SLONG loopend;\r
+       SLONG sizestart;\r
+       SLONG sizeend;\r
+       UBYTE volume;\r
+       UBYTE flags;\r
+       UWORD speed;\r
+       SWORD finetune;\r
+} ULTSAMPLE;\r
+\r
+typedef struct ULTEVENT {\r
+       UBYTE note,sample,eff,dat1,dat2;\r
+} ULTEVENT;\r
+\r
+/*========== Loader variables */\r
+\r
+#define ULTS_16BITS     4\r
+#define ULTS_LOOP       8\r
+#define ULTS_REVERSE    16\r
+\r
+#define ULT_VERSION_LEN 18\r
+static CHAR ULT_Version[ULT_VERSION_LEN]="Ultra Tracker v1.x";\r
+\r
+static ULTEVENT ev;\r
+\r
+/*========== Loader code */\r
+\r
+BOOL ULT_Test(void)\r
+{\r
+       CHAR id[16];\r
+\r
+       if(!_mm_read_string(id,15,modreader)) return 0;\r
+       if(strncmp(id,"MAS_UTrack_V00",14)) return 0;\r
+       if((id[14]<'1')||(id[14]>'4')) return 0;\r
+       return 1;\r
+}\r
+\r
+BOOL ULT_Init(void)\r
+{\r
+       return 1;\r
+}\r
+\r
+void ULT_Cleanup(void)\r
+{\r
+}\r
+\r
+static UBYTE ReadUltEvent(ULTEVENT* event)\r
+{\r
+       UBYTE flag,rep=1;\r
+\r
+       flag = _mm_read_UBYTE(modreader);\r
+       if(flag==0xfc) {\r
+               rep = _mm_read_UBYTE(modreader);\r
+               event->note =_mm_read_UBYTE(modreader);\r
+       } else\r
+               event->note = flag;\r
+\r
+       event->sample   =_mm_read_UBYTE(modreader);\r
+       event->eff      =_mm_read_UBYTE(modreader);\r
+       event->dat1     =_mm_read_UBYTE(modreader);\r
+       event->dat2     =_mm_read_UBYTE(modreader);\r
+\r
+       return rep;\r
+}\r
+\r
+BOOL ULT_Load(BOOL curious)\r
+{\r
+       int t,u,tracks=0;\r
+       SAMPLE *q;\r
+       ULTSAMPLE s;\r
+       ULTHEADER mh;\r
+       UBYTE nos,noc,nopa;\r
+       (void)curious;\r
+\r
+       /* try to read module header */\r
+       _mm_read_string(mh.id,15,modreader);\r
+       _mm_read_string(mh.songtitle,32,modreader);\r
+       mh.reserved=_mm_read_UBYTE(modreader);\r
+\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       ULT_Version[ULT_VERSION_LEN-1]='3'+(mh.id[14]-'1');\r
+       of.modtype   = DupStr(ULT_Version,ULT_VERSION_LEN,1);\r
+       of.initspeed = 6;\r
+       of.inittempo = 125;\r
+       of.reppos    = 0;\r
+\r
+       /* read songtext */\r
+       if ((mh.id[14]>'1')&&(mh.reserved))\r
+               if(!ReadLinedComment(mh.reserved * 32, 32)) return 0;\r
+\r
+       nos=_mm_read_UBYTE(modreader);\r
+       if(_mm_eof(modreader)) {\r
+               _mm_errno = MMERR_LOADING_HEADER;\r
+               return 0;\r
+       }\r
+\r
+       of.songname=DupStr(mh.songtitle,32,1);\r
+       of.numins=of.numsmp=nos;\r
+\r
+       if(!AllocSamples()) return 0;\r
+       q = of.samples;\r
+       for(t=0;t<nos;t++) {\r
+               /* try to read sample info */\r
+               _mm_read_string(s.samplename,32,modreader);\r
+               _mm_read_string(s.dosname,12,modreader);\r
+               s.loopstart     =_mm_read_I_ULONG(modreader);\r
+               s.loopend       =_mm_read_I_ULONG(modreader);\r
+               s.sizestart     =_mm_read_I_ULONG(modreader);\r
+               s.sizeend       =_mm_read_I_ULONG(modreader);\r
+               s.volume        =_mm_read_UBYTE(modreader);\r
+               s.flags         =_mm_read_UBYTE(modreader);\r
+               s.speed         =(mh.id[14]>='4')?_mm_read_I_UWORD(modreader):8363;\r
+               s.finetune      =_mm_read_I_SWORD(modreader);\r
+\r
+               if(_mm_eof(modreader)) {\r
+                       _mm_errno = MMERR_LOADING_SAMPLEINFO;\r
+                       return 0;\r
+               }\r
+\r
+               q->samplename=DupStr(s.samplename,32,1);\r
+               /* The correct formula for the coefficient would be\r
+                  pow(2,(double)s.finetume/OCTAVE/32768), but to avoid floating point\r
+                  here, we'll use a first order approximation here.\r
+                  1/567290 == Ln(2)/OCTAVE/32768 */\r
+               q->speed=s.speed+s.speed*(((SLONG)s.speed*(SLONG)s.finetune)/567290);\r
+               q->length    = s.sizeend-s.sizestart;\r
+               q->volume    = s.volume>>2;\r
+               q->loopstart = s.loopstart;\r
+               q->loopend   = s.loopend;\r
+               q->flags = SF_SIGNED;\r
+               if(s.flags&ULTS_LOOP) q->flags|=SF_LOOP;\r
+               if(s.flags&ULTS_16BITS) {\r
+                       s.sizeend+=(s.sizeend-s.sizestart);\r
+                       s.sizestart<<=1;\r
+                       q->flags|=SF_16BITS;\r
+                       q->loopstart>>=1;\r
+                       q->loopend>>=1;\r
+               }\r
+               q++;\r
+       }\r
+\r
+       if(!AllocPositions(256)) return 0;\r
+       for(t=0;t<256;t++)\r
+               of.positions[t]=_mm_read_UBYTE(modreader);\r
+       for(t=0;t<256;t++)\r
+               if(of.positions[t]==255) {\r
+                       of.positions[t]=LAST_PATTERN;\r
+                       break;\r
+               }\r
+       of.numpos=t;\r
+\r
+       noc=_mm_read_UBYTE(modreader);\r
+       nopa=_mm_read_UBYTE(modreader);\r
+\r
+       of.numchn=++noc;\r
+       of.numpat=++nopa;\r
+       of.numtrk=of.numchn*of.numpat;\r
+       if(!AllocTracks()) return 0;\r
+       if(!AllocPatterns()) return 0;\r
+       for(u=0;u<of.numchn;u++)\r
+               for(t=0;t<of.numpat;t++)\r
+                       of.patterns[(t*of.numchn)+u]=tracks++;\r
+\r
+       /* read pan position table for v1.5 and higher */\r
+       if(mh.id[14]>='3') {\r
+               for(t=0;t<of.numchn;t++) of.panning[t]=_mm_read_UBYTE(modreader)<<4;\r
+               of.flags |= UF_PANNING;\r
+       }\r
+\r
+       for(t=0;t<of.numtrk;t++) {\r
+               int rep,row=0;\r
+\r
+               UniReset();\r
+               while(row<64) {\r
+                       rep=ReadUltEvent(&ev);\r
+\r
+                       if(_mm_eof(modreader)) {\r
+                               _mm_errno = MMERR_LOADING_TRACK;\r
+                               return 0;\r
+                       }\r
+\r
+                       while(rep--) {\r
+                               UBYTE eff;\r
+                               int offset;\r
+\r
+                               if(ev.sample) UniInstrument(ev.sample-1);\r
+                               if(ev.note)   UniNote(ev.note+2*OCTAVE-1);\r
+\r
+                               /* first effect - various fixes by Alexander Kerkhove and\r
+                                                 Thomas Neumann */\r
+                               eff = ev.eff>>4;\r
+                               switch(eff) {\r
+                                       case 0x3: /* tone portamento */\r
+                                               UniEffect(UNI_ITEFFECTG,ev.dat2);\r
+                                               break;\r
+                                       case 0x5:\r
+                                               break;\r
+                                       case 0x9: /* sample offset */\r
+                                               offset=(ev.dat2<<8)|((ev.eff&0xf)==9?ev.dat1:0);\r
+                                               UniEffect(UNI_ULTEFFECT9,offset);\r
+                                               break;\r
+                                       case 0xb: /* panning */\r
+                                               UniPTEffect(8,ev.dat2*0xf);\r
+                                               of.flags |= UF_PANNING;\r
+                                               break;\r
+                                       case 0xc: /* volume */\r
+                                               UniPTEffect(eff,ev.dat2>>2);\r
+                                               break;\r
+                                       default:\r
+                                               UniPTEffect(eff,ev.dat2);\r
+                                               break;\r
+                               }\r
+\r
+                               /* second effect */\r
+                               eff=ev.eff&0xf;\r
+                               switch(eff) {\r
+                                       case 0x3: /* tone portamento */\r
+                                               UniEffect(UNI_ITEFFECTG,ev.dat1);\r
+                                               break;\r
+                                       case 0x5:\r
+                                               break;\r
+                                       case 0x9: /* sample offset */\r
+                                               if((ev.eff>>4)!=9)\r
+                                                       UniEffect(UNI_ULTEFFECT9,((UWORD)ev.dat1)<<8);\r
+                                               break;\r
+                                       case 0xb: /* panning */\r
+                                               UniPTEffect(8,ev.dat1*0xf);\r
+                                               of.flags |= UF_PANNING;\r
+                                               break;\r
+                                       case 0xc: /* volume */\r
+                                               UniPTEffect(eff,ev.dat1>>2);\r
+                                               break;\r
+                                       default:\r
+                                               UniPTEffect(eff,ev.dat1);\r
+                                               break;\r
+                               }\r
+\r
+                               UniNewline();\r
+                               row++;\r
+                       }\r
+               }\r
+               if(!(of.tracks[t]=UniDup())) return 0;\r
+       }\r
+       return 1;\r
+}\r
+\r
+CHAR *ULT_LoadTitle(void)\r
+{\r
+       CHAR s[32];\r
+\r
+       _mm_fseek(modreader,15,SEEK_SET);\r
+       if(!_mm_read_UBYTES(s,32,modreader)) return NULL;\r
+\r
+       return(DupStr(s,32,1));\r
+}\r
+\r
+/*========== Loader information */\r
+\r
+MIKMODAPI MLOADER load_ult={\r
+       NULL,\r
+       "ULT",\r
+       "ULT (UltraTracker)",\r
+       ULT_Init,\r
+       ULT_Test,\r
+       ULT_Load,\r
+       ULT_Cleanup,\r
+       ULT_LoadTitle\r
+};\r
+\r
+\r
+/* ex:set ts=4: */\r