--- /dev/null
+/* 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