Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / playercode / mlutil.c
diff --git a/apps/plugins/mikmod/playercode/mlutil.c b/apps/plugins/mikmod/playercode/mlutil.c
new file mode 100644 (file)
index 0000000..0746a13
--- /dev/null
@@ -0,0 +1,336 @@
+/*     MikMod sound library\r
+       (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS\r
+       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: mlutil.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
+\r
+  Utility functions for the module loader\r
+\r
+==============================================================================*/\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include "config.h"\r
+#endif\r
+\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
+/*========== Shared tracker identifiers */\r
+\r
+CHAR *STM_Signatures[STM_NTRACKERS] = {\r
+       "!Scream!",\r
+       "BMOD2STM",\r
+       "WUZAMOD!"\r
+};\r
+\r
+CHAR *STM_Version[STM_NTRACKERS] = {\r
+       "Screamtracker 2",\r
+       "Converted by MOD2STM (STM format)",\r
+       "Wuzamod (STM format)"\r
+};\r
+\r
+/*========== Shared loader variables */\r
+\r
+SBYTE  remap[UF_MAXCHAN];   /* for removing empty channels */\r
+UBYTE* poslookup=NULL;      /* lookup table for pattern jumps after blank\r
+                               pattern removal */\r
+UBYTE  poslookupcnt;\r
+UWORD* origpositions=NULL;\r
+\r
+BOOL   filters;             /* resonant filters in use */\r
+UBYTE  activemacro;         /* active midi macro number for Sxx,xx<80h */\r
+UBYTE  filtermacros[UF_MAXMACRO];    /* midi macro settings */\r
+FILTER filtersettings[UF_MAXFILTER]; /* computed filter settings */\r
+\r
+/*========== Linear periods stuff */\r
+\r
+int*   noteindex=NULL;      /* remap value for linear period modules */\r
+static int noteindexcount=0;\r
+\r
+int *AllocLinear(void)\r
+{\r
+       if(of.numsmp>noteindexcount) {\r
+               noteindexcount=of.numsmp;\r
+               noteindex=realloc(noteindex,noteindexcount*sizeof(int));\r
+       }\r
+       return noteindex;\r
+}\r
+\r
+void FreeLinear(void)\r
+{\r
+       if(noteindex) {\r
+               free(noteindex);\r
+               noteindex=NULL;\r
+       }\r
+       noteindexcount=0;\r
+}\r
+\r
+int speed_to_finetune(ULONG speed,int sample)\r
+{\r
+    int ctmp=0,tmp,note=1,finetune=0;\r
+\r
+    speed>>=1;\r
+    while((tmp=getfrequency(of.flags,getlinearperiod(note<<1,0)))<speed) {\r
+        ctmp=tmp;\r
+        note++;\r
+    }\r
+\r
+    if(tmp!=speed) {\r
+        if((tmp-speed)<(speed-ctmp))\r
+            while(tmp>speed)\r
+                tmp=getfrequency(of.flags,getlinearperiod(note<<1,--finetune));\r
+        else {\r
+            note--;\r
+            while(ctmp<speed)\r
+                ctmp=getfrequency(of.flags,getlinearperiod(note<<1,++finetune));\r
+        }\r
+    }\r
+\r
+    noteindex[sample]=note-4*OCTAVE;\r
+    return finetune;\r
+}\r
+\r
+/*========== Order stuff */\r
+\r
+/* handles S3M and IT orders */\r
+void S3MIT_CreateOrders(BOOL curious)\r
+{\r
+       int t;\r
+\r
+       of.numpos = 0;\r
+       memset(of.positions,0,poslookupcnt*sizeof(UWORD));\r
+       memset(poslookup,-1,256);\r
+       for(t=0;t<poslookupcnt;t++) {\r
+               int order=origpositions[t];\r
+               if(order==255) order=LAST_PATTERN;\r
+               of.positions[of.numpos]=order;\r
+               poslookup[t]=of.numpos; /* bug fix for freaky S3Ms / ITs */\r
+               if(origpositions[t]<254) of.numpos++;\r
+               else\r
+                       /* end of song special order */\r
+                       if((order==LAST_PATTERN)&&(!(curious--))) break;\r
+       }\r
+}\r
+\r
+/*========== Effect stuff */\r
+\r
+/* handles S3M and IT effects */\r
+void S3MIT_ProcessCmd(UBYTE cmd,UBYTE inf,unsigned int flags)\r
+{\r
+       UBYTE hi,lo;\r
+\r
+       lo=inf&0xf;\r
+       hi=inf>>4;\r
+\r
+       /* process S3M / IT specific command structure */\r
+\r
+       if(cmd!=255) {\r
+               switch(cmd) {\r
+                       case 1: /* Axx set speed to xx */\r
+                               UniEffect(UNI_S3MEFFECTA,inf);\r
+                               break;\r
+                       case 2: /* Bxx position jump */\r
+                               if (inf<poslookupcnt) {\r
+                                       /* switch to curious mode if necessary, for example\r
+                                          sympex.it, deep joy.it */\r
+                                       if(((SBYTE)poslookup[inf]<0)&&(origpositions[inf]!=255))\r
+                                               S3MIT_CreateOrders(1);\r
+\r
+                                       if(!((SBYTE)poslookup[inf]<0))\r
+                                               UniPTEffect(0xb,poslookup[inf]);\r
+                               }\r
+                               break;\r
+                       case 3: /* Cxx patternbreak to row xx */\r
+                               if ((flags & S3MIT_OLDSTYLE) && !(flags & S3MIT_IT))\r
+                                       UniPTEffect(0xd,(inf>>4)*10+(inf&0xf));\r
+                               else\r
+                                       UniPTEffect(0xd,inf);\r
+                               break;\r
+                       case 4: /* Dxy volumeslide */\r
+                               UniEffect(UNI_S3MEFFECTD,inf);\r
+                               break;\r
+                       case 5: /* Exy toneslide down */\r
+                               UniEffect(UNI_S3MEFFECTE,inf);\r
+                               break;\r
+                       case 6: /* Fxy toneslide up */\r
+                               UniEffect(UNI_S3MEFFECTF,inf);\r
+                               break;\r
+                       case 7: /* Gxx Tone portamento, speed xx */\r
+                               if (flags & S3MIT_OLDSTYLE)\r
+                                       UniPTEffect(0x3,inf);\r
+                               else\r
+                                       UniEffect(UNI_ITEFFECTG,inf);\r
+                               break;\r
+                       case 8: /* Hxy vibrato */\r
+                               if (flags & S3MIT_OLDSTYLE)\r
+                                       UniPTEffect(0x4,inf);\r
+                               else\r
+                                       UniEffect(UNI_ITEFFECTH,inf);\r
+                               break;\r
+                       case 9: /* Ixy tremor, ontime x, offtime y */\r
+                               if (flags & S3MIT_OLDSTYLE)\r
+                                       UniEffect(UNI_S3MEFFECTI,inf);\r
+                               else                     \r
+                                       UniEffect(UNI_ITEFFECTI,inf);\r
+                               break;\r
+                       case 0xa: /* Jxy arpeggio */\r
+                               UniPTEffect(0x0,inf);\r
+                               break;\r
+                       case 0xb: /* Kxy Dual command H00 & Dxy */\r
+                               if (flags & S3MIT_OLDSTYLE)\r
+                                       UniPTEffect(0x4,0);    \r
+                               else\r
+                                       UniEffect(UNI_ITEFFECTH,0);\r
+                               UniEffect(UNI_S3MEFFECTD,inf);\r
+                               break;\r
+                       case 0xc: /* Lxy Dual command G00 & Dxy */\r
+                               if (flags & S3MIT_OLDSTYLE)\r
+                                       UniPTEffect(0x3,0);\r
+                               else\r
+                                       UniEffect(UNI_ITEFFECTG,0);\r
+                               UniEffect(UNI_S3MEFFECTD,inf);\r
+                               break;\r
+                       case 0xd: /* Mxx Set Channel Volume */\r
+                               UniEffect(UNI_ITEFFECTM,inf);\r
+                               break;       \r
+                       case 0xe: /* Nxy Slide Channel Volume */\r
+                               UniEffect(UNI_ITEFFECTN,inf);\r
+                               break;\r
+                       case 0xf: /* Oxx set sampleoffset xx00h */\r
+                               UniPTEffect(0x9,inf);\r
+                               break;\r
+                       case 0x10: /* Pxy Slide Panning Commands */\r
+                               UniEffect(UNI_ITEFFECTP,inf);\r
+                               break;\r
+                       case 0x11: /* Qxy Retrig (+volumeslide) */\r
+                               UniWriteByte(UNI_S3MEFFECTQ);\r
+                               if(inf && !lo && !(flags & S3MIT_OLDSTYLE))\r
+                                       UniWriteByte(1);\r
+                               else\r
+                                       UniWriteByte(inf); \r
+                               break;\r
+                       case 0x12: /* Rxy tremolo speed x, depth y */\r
+                               UniEffect(UNI_S3MEFFECTR,inf);\r
+                               break;\r
+                       case 0x13: /* Sxx special commands */\r
+                               if (inf>=0xf0) {\r
+                                       /* change resonant filter settings if necessary */\r
+                                       if((filters)&&((inf&0xf)!=activemacro)) {\r
+                                               activemacro=inf&0xf;\r
+                                               for(inf=0;inf<0x80;inf++)\r
+                                                       filtersettings[inf].filter=filtermacros[activemacro];\r
+                                       }\r
+                               } else {\r
+                                       /* Scream Tracker does not have samples larger than\r
+                                          64 Kb, thus doesn't need the SAx effect */\r
+                                       if ((flags & S3MIT_SCREAM) && ((inf & 0xf0) == 0xa0))\r
+                                               break;\r
+\r
+                                       UniEffect(UNI_ITEFFECTS0,inf);\r
+                               }\r
+                               break;\r
+                       case 0x14: /* Txx tempo */\r
+                               if(inf>=0x20)\r
+                                       UniEffect(UNI_S3MEFFECTT,inf);\r
+                               else {\r
+                                       if(!(flags & S3MIT_OLDSTYLE))\r
+                                               /* IT Tempo slide */\r
+                                               UniEffect(UNI_ITEFFECTT,inf);\r
+                               }\r
+                               break;\r
+                       case 0x15: /* Uxy Fine Vibrato speed x, depth y */\r
+                               if(flags & S3MIT_OLDSTYLE)\r
+                                       UniEffect(UNI_S3MEFFECTU,inf);\r
+                               else\r
+                                       UniEffect(UNI_ITEFFECTU,inf);\r
+                               break;\r
+                       case 0x16: /* Vxx Set Global Volume */\r
+                               UniEffect(UNI_XMEFFECTG,inf);\r
+                               break;\r
+                       case 0x17: /* Wxy Global Volume Slide */\r
+                               UniEffect(UNI_ITEFFECTW,inf);\r
+                               break;\r
+                       case 0x18: /* Xxx amiga command 8xx */\r
+                               if(flags & S3MIT_OLDSTYLE) {\r
+                                       if(inf>128)\r
+                                               UniEffect(UNI_ITEFFECTS0,0x91); /* surround */\r
+                                       else\r
+                                               UniPTEffect(0x8,(inf==128)?255:(inf<<1));\r
+                               } else\r
+                                       UniPTEffect(0x8,inf);\r
+                               break;\r
+                       case 0x19: /* Yxy Panbrello  speed x, depth y */\r
+                               UniEffect(UNI_ITEFFECTY,inf);\r
+                               break;\r
+                       case 0x1a: /* Zxx midi/resonant filters */\r
+                               if(filtersettings[inf].filter) {\r
+                                       UniWriteByte(UNI_ITEFFECTZ);\r
+                                       UniWriteByte(filtersettings[inf].filter);\r
+                                       UniWriteByte(filtersettings[inf].inf);\r
+                               }\r
+                               break;\r
+               }\r
+       }\r
+}\r
+\r
+/*========== Unitrk stuff */\r
+\r
+/* Generic effect writing routine */\r
+void UniEffect(UWORD eff,UWORD dat)\r
+{\r
+       if((!eff)||(eff>=UNI_LAST)) return;\r
+\r
+       UniWriteByte(eff);\r
+       if(unioperands[eff]==2)\r
+               UniWriteWord(dat);\r
+       else\r
+               UniWriteByte(dat);\r
+}\r
+\r
+/*  Appends UNI_PTEFFECTX opcode to the unitrk stream. */\r
+void UniPTEffect(UBYTE eff, UBYTE dat)\r
+{\r
+#ifdef MIKMOD_DEBUG\r
+       if (eff>=0x10)\r
+               fprintf(stderr,"UniPTEffect called with incorrect eff value %d\n",eff);\r
+       else\r
+#endif\r
+       if((eff)||(dat)||(of.flags&UF_ARPMEM)) UniEffect(UNI_PTEFFECT0+eff,dat);\r
+}\r
+\r
+/* Appends UNI_VOLEFFECT + effect/dat to unistream. */\r
+void UniVolEffect(UWORD eff,UBYTE dat)\r
+{\r
+       if((eff)||(dat)) { /* don't write empty effect */\r
+               UniWriteByte(UNI_VOLEFFECTS);\r
+               UniWriteByte(eff);UniWriteByte(dat);\r
+       }\r
+}\r
+\r
+/* ex:set ts=4: */\r