Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / playercode / mlutil.c
1 /*      MikMod sound library\r
2         (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS\r
3         for complete list.\r
4 \r
5         This library is free software; you can redistribute it and/or modify\r
6         it under the terms of the GNU Library General Public License as\r
7         published by the Free Software Foundation; either version 2 of\r
8         the License, or (at your option) any later version.\r
9  \r
10         This program is distributed in the hope that it will be useful,\r
11         but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13         GNU Library General Public License for more details.\r
14  \r
15         You should have received a copy of the GNU Library General Public\r
16         License along with this library; if not, write to the Free Software\r
17         Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
18         02111-1307, USA.\r
19 */\r
20 \r
21 /*==============================================================================\r
22 \r
23   $Id: mlutil.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $\r
24 \r
25   Utility functions for the module loader\r
26 \r
27 ==============================================================================*/\r
28 \r
29 #ifdef HAVE_CONFIG_H\r
30 #include "config.h"\r
31 #endif\r
32 \r
33 #ifdef HAVE_MEMORY_H\r
34 #include <memory.h>\r
35 #endif\r
36 #include <string.h>\r
37 \r
38 #include "mikmod_internals.h"\r
39 \r
40 #ifdef SUNOS\r
41 extern int fprintf(FILE *, const char *, ...);\r
42 #endif\r
43 \r
44 /*========== Shared tracker identifiers */\r
45 \r
46 CHAR *STM_Signatures[STM_NTRACKERS] = {\r
47         "!Scream!",\r
48         "BMOD2STM",\r
49         "WUZAMOD!"\r
50 };\r
51 \r
52 CHAR *STM_Version[STM_NTRACKERS] = {\r
53         "Screamtracker 2",\r
54         "Converted by MOD2STM (STM format)",\r
55         "Wuzamod (STM format)"\r
56 };\r
57 \r
58 /*========== Shared loader variables */\r
59 \r
60 SBYTE  remap[UF_MAXCHAN];   /* for removing empty channels */\r
61 UBYTE* poslookup=NULL;      /* lookup table for pattern jumps after blank\r
62                                pattern removal */\r
63 UBYTE  poslookupcnt;\r
64 UWORD* origpositions=NULL;\r
65 \r
66 BOOL   filters;             /* resonant filters in use */\r
67 UBYTE  activemacro;         /* active midi macro number for Sxx,xx<80h */\r
68 UBYTE  filtermacros[UF_MAXMACRO];    /* midi macro settings */\r
69 FILTER filtersettings[UF_MAXFILTER]; /* computed filter settings */\r
70 \r
71 /*========== Linear periods stuff */\r
72 \r
73 int*   noteindex=NULL;      /* remap value for linear period modules */\r
74 static int noteindexcount=0;\r
75 \r
76 int *AllocLinear(void)\r
77 {\r
78         if(of.numsmp>noteindexcount) {\r
79                 noteindexcount=of.numsmp;\r
80                 noteindex=realloc(noteindex,noteindexcount*sizeof(int));\r
81         }\r
82         return noteindex;\r
83 }\r
84 \r
85 void FreeLinear(void)\r
86 {\r
87         if(noteindex) {\r
88                 free(noteindex);\r
89                 noteindex=NULL;\r
90         }\r
91         noteindexcount=0;\r
92 }\r
93 \r
94 int speed_to_finetune(ULONG speed,int sample)\r
95 {\r
96     int ctmp=0,tmp,note=1,finetune=0;\r
97 \r
98     speed>>=1;\r
99     while((tmp=getfrequency(of.flags,getlinearperiod(note<<1,0)))<speed) {\r
100         ctmp=tmp;\r
101         note++;\r
102     }\r
103 \r
104     if(tmp!=speed) {\r
105         if((tmp-speed)<(speed-ctmp))\r
106             while(tmp>speed)\r
107                 tmp=getfrequency(of.flags,getlinearperiod(note<<1,--finetune));\r
108         else {\r
109             note--;\r
110             while(ctmp<speed)\r
111                 ctmp=getfrequency(of.flags,getlinearperiod(note<<1,++finetune));\r
112         }\r
113     }\r
114 \r
115     noteindex[sample]=note-4*OCTAVE;\r
116     return finetune;\r
117 }\r
118 \r
119 /*========== Order stuff */\r
120 \r
121 /* handles S3M and IT orders */\r
122 void S3MIT_CreateOrders(BOOL curious)\r
123 {\r
124         int t;\r
125 \r
126         of.numpos = 0;\r
127         memset(of.positions,0,poslookupcnt*sizeof(UWORD));\r
128         memset(poslookup,-1,256);\r
129         for(t=0;t<poslookupcnt;t++) {\r
130                 int order=origpositions[t];\r
131                 if(order==255) order=LAST_PATTERN;\r
132                 of.positions[of.numpos]=order;\r
133                 poslookup[t]=of.numpos; /* bug fix for freaky S3Ms / ITs */\r
134                 if(origpositions[t]<254) of.numpos++;\r
135                 else\r
136                         /* end of song special order */\r
137                         if((order==LAST_PATTERN)&&(!(curious--))) break;\r
138         }\r
139 }\r
140 \r
141 /*========== Effect stuff */\r
142 \r
143 /* handles S3M and IT effects */\r
144 void S3MIT_ProcessCmd(UBYTE cmd,UBYTE inf,unsigned int flags)\r
145 {\r
146         UBYTE hi,lo;\r
147 \r
148         lo=inf&0xf;\r
149         hi=inf>>4;\r
150 \r
151         /* process S3M / IT specific command structure */\r
152 \r
153         if(cmd!=255) {\r
154                 switch(cmd) {\r
155                         case 1: /* Axx set speed to xx */\r
156                                 UniEffect(UNI_S3MEFFECTA,inf);\r
157                                 break;\r
158                         case 2: /* Bxx position jump */\r
159                                 if (inf<poslookupcnt) {\r
160                                         /* switch to curious mode if necessary, for example\r
161                                            sympex.it, deep joy.it */\r
162                                         if(((SBYTE)poslookup[inf]<0)&&(origpositions[inf]!=255))\r
163                                                 S3MIT_CreateOrders(1);\r
164 \r
165                                         if(!((SBYTE)poslookup[inf]<0))\r
166                                                 UniPTEffect(0xb,poslookup[inf]);\r
167                                 }\r
168                                 break;\r
169                         case 3: /* Cxx patternbreak to row xx */\r
170                                 if ((flags & S3MIT_OLDSTYLE) && !(flags & S3MIT_IT))\r
171                                         UniPTEffect(0xd,(inf>>4)*10+(inf&0xf));\r
172                                 else\r
173                                         UniPTEffect(0xd,inf);\r
174                                 break;\r
175                         case 4: /* Dxy volumeslide */\r
176                                 UniEffect(UNI_S3MEFFECTD,inf);\r
177                                 break;\r
178                         case 5: /* Exy toneslide down */\r
179                                 UniEffect(UNI_S3MEFFECTE,inf);\r
180                                 break;\r
181                         case 6: /* Fxy toneslide up */\r
182                                 UniEffect(UNI_S3MEFFECTF,inf);\r
183                                 break;\r
184                         case 7: /* Gxx Tone portamento, speed xx */\r
185                                 if (flags & S3MIT_OLDSTYLE)\r
186                                         UniPTEffect(0x3,inf);\r
187                                 else\r
188                                         UniEffect(UNI_ITEFFECTG,inf);\r
189                                 break;\r
190                         case 8: /* Hxy vibrato */\r
191                                 if (flags & S3MIT_OLDSTYLE)\r
192                                         UniPTEffect(0x4,inf);\r
193                                 else\r
194                                         UniEffect(UNI_ITEFFECTH,inf);\r
195                                 break;\r
196                         case 9: /* Ixy tremor, ontime x, offtime y */\r
197                                 if (flags & S3MIT_OLDSTYLE)\r
198                                         UniEffect(UNI_S3MEFFECTI,inf);\r
199                                 else                     \r
200                                         UniEffect(UNI_ITEFFECTI,inf);\r
201                                 break;\r
202                         case 0xa: /* Jxy arpeggio */\r
203                                 UniPTEffect(0x0,inf);\r
204                                 break;\r
205                         case 0xb: /* Kxy Dual command H00 & Dxy */\r
206                                 if (flags & S3MIT_OLDSTYLE)\r
207                                         UniPTEffect(0x4,0);    \r
208                                 else\r
209                                         UniEffect(UNI_ITEFFECTH,0);\r
210                                 UniEffect(UNI_S3MEFFECTD,inf);\r
211                                 break;\r
212                         case 0xc: /* Lxy Dual command G00 & Dxy */\r
213                                 if (flags & S3MIT_OLDSTYLE)\r
214                                         UniPTEffect(0x3,0);\r
215                                 else\r
216                                         UniEffect(UNI_ITEFFECTG,0);\r
217                                 UniEffect(UNI_S3MEFFECTD,inf);\r
218                                 break;\r
219                         case 0xd: /* Mxx Set Channel Volume */\r
220                                 UniEffect(UNI_ITEFFECTM,inf);\r
221                                 break;       \r
222                         case 0xe: /* Nxy Slide Channel Volume */\r
223                                 UniEffect(UNI_ITEFFECTN,inf);\r
224                                 break;\r
225                         case 0xf: /* Oxx set sampleoffset xx00h */\r
226                                 UniPTEffect(0x9,inf);\r
227                                 break;\r
228                         case 0x10: /* Pxy Slide Panning Commands */\r
229                                 UniEffect(UNI_ITEFFECTP,inf);\r
230                                 break;\r
231                         case 0x11: /* Qxy Retrig (+volumeslide) */\r
232                                 UniWriteByte(UNI_S3MEFFECTQ);\r
233                                 if(inf && !lo && !(flags & S3MIT_OLDSTYLE))\r
234                                         UniWriteByte(1);\r
235                                 else\r
236                                         UniWriteByte(inf); \r
237                                 break;\r
238                         case 0x12: /* Rxy tremolo speed x, depth y */\r
239                                 UniEffect(UNI_S3MEFFECTR,inf);\r
240                                 break;\r
241                         case 0x13: /* Sxx special commands */\r
242                                 if (inf>=0xf0) {\r
243                                         /* change resonant filter settings if necessary */\r
244                                         if((filters)&&((inf&0xf)!=activemacro)) {\r
245                                                 activemacro=inf&0xf;\r
246                                                 for(inf=0;inf<0x80;inf++)\r
247                                                         filtersettings[inf].filter=filtermacros[activemacro];\r
248                                         }\r
249                                 } else {\r
250                                         /* Scream Tracker does not have samples larger than\r
251                                            64 Kb, thus doesn't need the SAx effect */\r
252                                         if ((flags & S3MIT_SCREAM) && ((inf & 0xf0) == 0xa0))\r
253                                                 break;\r
254 \r
255                                         UniEffect(UNI_ITEFFECTS0,inf);\r
256                                 }\r
257                                 break;\r
258                         case 0x14: /* Txx tempo */\r
259                                 if(inf>=0x20)\r
260                                         UniEffect(UNI_S3MEFFECTT,inf);\r
261                                 else {\r
262                                         if(!(flags & S3MIT_OLDSTYLE))\r
263                                                 /* IT Tempo slide */\r
264                                                 UniEffect(UNI_ITEFFECTT,inf);\r
265                                 }\r
266                                 break;\r
267                         case 0x15: /* Uxy Fine Vibrato speed x, depth y */\r
268                                 if(flags & S3MIT_OLDSTYLE)\r
269                                         UniEffect(UNI_S3MEFFECTU,inf);\r
270                                 else\r
271                                         UniEffect(UNI_ITEFFECTU,inf);\r
272                                 break;\r
273                         case 0x16: /* Vxx Set Global Volume */\r
274                                 UniEffect(UNI_XMEFFECTG,inf);\r
275                                 break;\r
276                         case 0x17: /* Wxy Global Volume Slide */\r
277                                 UniEffect(UNI_ITEFFECTW,inf);\r
278                                 break;\r
279                         case 0x18: /* Xxx amiga command 8xx */\r
280                                 if(flags & S3MIT_OLDSTYLE) {\r
281                                         if(inf>128)\r
282                                                 UniEffect(UNI_ITEFFECTS0,0x91); /* surround */\r
283                                         else\r
284                                                 UniPTEffect(0x8,(inf==128)?255:(inf<<1));\r
285                                 } else\r
286                                         UniPTEffect(0x8,inf);\r
287                                 break;\r
288                         case 0x19: /* Yxy Panbrello  speed x, depth y */\r
289                                 UniEffect(UNI_ITEFFECTY,inf);\r
290                                 break;\r
291                         case 0x1a: /* Zxx midi/resonant filters */\r
292                                 if(filtersettings[inf].filter) {\r
293                                         UniWriteByte(UNI_ITEFFECTZ);\r
294                                         UniWriteByte(filtersettings[inf].filter);\r
295                                         UniWriteByte(filtersettings[inf].inf);\r
296                                 }\r
297                                 break;\r
298                 }\r
299         }\r
300 }\r
301 \r
302 /*========== Unitrk stuff */\r
303 \r
304 /* Generic effect writing routine */\r
305 void UniEffect(UWORD eff,UWORD dat)\r
306 {\r
307         if((!eff)||(eff>=UNI_LAST)) return;\r
308 \r
309         UniWriteByte(eff);\r
310         if(unioperands[eff]==2)\r
311                 UniWriteWord(dat);\r
312         else\r
313                 UniWriteByte(dat);\r
314 }\r
315 \r
316 /*  Appends UNI_PTEFFECTX opcode to the unitrk stream. */\r
317 void UniPTEffect(UBYTE eff, UBYTE dat)\r
318 {\r
319 #ifdef MIKMOD_DEBUG\r
320         if (eff>=0x10)\r
321                 fprintf(stderr,"UniPTEffect called with incorrect eff value %d\n",eff);\r
322         else\r
323 #endif\r
324         if((eff)||(dat)||(of.flags&UF_ARPMEM)) UniEffect(UNI_PTEFFECT0+eff,dat);\r
325 }\r
326 \r
327 /* Appends UNI_VOLEFFECT + effect/dat to unistream. */\r
328 void UniVolEffect(UWORD eff,UBYTE dat)\r
329 {\r
330         if((eff)||(dat)) { /* don't write empty effect */\r
331                 UniWriteByte(UNI_VOLEFFECTS);\r
332                 UniWriteByte(eff);UniWriteByte(dat);\r
333         }\r
334 }\r
335 \r
336 /* ex:set ts=4: */\r