1 /* MikMod sound library
\r
2 (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS
\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
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
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
21 /*==============================================================================
\r
23 $Id: mlutil.c,v 1.1.1.1 2004/01/21 01:36:35 raph Exp $
\r
25 Utility functions for the module loader
\r
27 ==============================================================================*/
\r
29 #ifdef HAVE_CONFIG_H
\r
33 #ifdef HAVE_MEMORY_H
\r
38 #include "mikmod_internals.h"
\r
41 extern int fprintf(FILE *, const char *, ...);
\r
44 /*========== Shared tracker identifiers */
\r
46 CHAR *STM_Signatures[STM_NTRACKERS] = {
\r
52 CHAR *STM_Version[STM_NTRACKERS] = {
\r
54 "Converted by MOD2STM (STM format)",
\r
55 "Wuzamod (STM format)"
\r
58 /*========== Shared loader variables */
\r
60 SBYTE remap[UF_MAXCHAN]; /* for removing empty channels */
\r
61 UBYTE* poslookup=NULL; /* lookup table for pattern jumps after blank
\r
64 UWORD* origpositions=NULL;
\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
71 /*========== Linear periods stuff */
\r
73 int* noteindex=NULL; /* remap value for linear period modules */
\r
74 static int noteindexcount=0;
\r
76 int *AllocLinear(void)
\r
78 if(of.numsmp>noteindexcount) {
\r
79 noteindexcount=of.numsmp;
\r
80 noteindex=realloc(noteindex,noteindexcount*sizeof(int));
\r
85 void FreeLinear(void)
\r
94 int speed_to_finetune(ULONG speed,int sample)
\r
96 int ctmp=0,tmp,note=1,finetune=0;
\r
99 while((tmp=getfrequency(of.flags,getlinearperiod(note<<1,0)))<speed) {
\r
105 if((tmp-speed)<(speed-ctmp))
\r
107 tmp=getfrequency(of.flags,getlinearperiod(note<<1,--finetune));
\r
111 ctmp=getfrequency(of.flags,getlinearperiod(note<<1,++finetune));
\r
115 noteindex[sample]=note-4*OCTAVE;
\r
119 /*========== Order stuff */
\r
121 /* handles S3M and IT orders */
\r
122 void S3MIT_CreateOrders(BOOL curious)
\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
136 /* end of song special order */
\r
137 if((order==LAST_PATTERN)&&(!(curious--))) break;
\r
141 /*========== Effect stuff */
\r
143 /* handles S3M and IT effects */
\r
144 void S3MIT_ProcessCmd(UBYTE cmd,UBYTE inf,unsigned int flags)
\r
151 /* process S3M / IT specific command structure */
\r
155 case 1: /* Axx set speed to xx */
\r
156 UniEffect(UNI_S3MEFFECTA,inf);
\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
165 if(!((SBYTE)poslookup[inf]<0))
\r
166 UniPTEffect(0xb,poslookup[inf]);
\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
173 UniPTEffect(0xd,inf);
\r
175 case 4: /* Dxy volumeslide */
\r
176 UniEffect(UNI_S3MEFFECTD,inf);
\r
178 case 5: /* Exy toneslide down */
\r
179 UniEffect(UNI_S3MEFFECTE,inf);
\r
181 case 6: /* Fxy toneslide up */
\r
182 UniEffect(UNI_S3MEFFECTF,inf);
\r
184 case 7: /* Gxx Tone portamento, speed xx */
\r
185 if (flags & S3MIT_OLDSTYLE)
\r
186 UniPTEffect(0x3,inf);
\r
188 UniEffect(UNI_ITEFFECTG,inf);
\r
190 case 8: /* Hxy vibrato */
\r
191 if (flags & S3MIT_OLDSTYLE)
\r
192 UniPTEffect(0x4,inf);
\r
194 UniEffect(UNI_ITEFFECTH,inf);
\r
196 case 9: /* Ixy tremor, ontime x, offtime y */
\r
197 if (flags & S3MIT_OLDSTYLE)
\r
198 UniEffect(UNI_S3MEFFECTI,inf);
\r
200 UniEffect(UNI_ITEFFECTI,inf);
\r
202 case 0xa: /* Jxy arpeggio */
\r
203 UniPTEffect(0x0,inf);
\r
205 case 0xb: /* Kxy Dual command H00 & Dxy */
\r
206 if (flags & S3MIT_OLDSTYLE)
\r
207 UniPTEffect(0x4,0);
\r
209 UniEffect(UNI_ITEFFECTH,0);
\r
210 UniEffect(UNI_S3MEFFECTD,inf);
\r
212 case 0xc: /* Lxy Dual command G00 & Dxy */
\r
213 if (flags & S3MIT_OLDSTYLE)
\r
214 UniPTEffect(0x3,0);
\r
216 UniEffect(UNI_ITEFFECTG,0);
\r
217 UniEffect(UNI_S3MEFFECTD,inf);
\r
219 case 0xd: /* Mxx Set Channel Volume */
\r
220 UniEffect(UNI_ITEFFECTM,inf);
\r
222 case 0xe: /* Nxy Slide Channel Volume */
\r
223 UniEffect(UNI_ITEFFECTN,inf);
\r
225 case 0xf: /* Oxx set sampleoffset xx00h */
\r
226 UniPTEffect(0x9,inf);
\r
228 case 0x10: /* Pxy Slide Panning Commands */
\r
229 UniEffect(UNI_ITEFFECTP,inf);
\r
231 case 0x11: /* Qxy Retrig (+volumeslide) */
\r
232 UniWriteByte(UNI_S3MEFFECTQ);
\r
233 if(inf && !lo && !(flags & S3MIT_OLDSTYLE))
\r
236 UniWriteByte(inf);
\r
238 case 0x12: /* Rxy tremolo speed x, depth y */
\r
239 UniEffect(UNI_S3MEFFECTR,inf);
\r
241 case 0x13: /* Sxx special commands */
\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
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
255 UniEffect(UNI_ITEFFECTS0,inf);
\r
258 case 0x14: /* Txx tempo */
\r
260 UniEffect(UNI_S3MEFFECTT,inf);
\r
262 if(!(flags & S3MIT_OLDSTYLE))
\r
263 /* IT Tempo slide */
\r
264 UniEffect(UNI_ITEFFECTT,inf);
\r
267 case 0x15: /* Uxy Fine Vibrato speed x, depth y */
\r
268 if(flags & S3MIT_OLDSTYLE)
\r
269 UniEffect(UNI_S3MEFFECTU,inf);
\r
271 UniEffect(UNI_ITEFFECTU,inf);
\r
273 case 0x16: /* Vxx Set Global Volume */
\r
274 UniEffect(UNI_XMEFFECTG,inf);
\r
276 case 0x17: /* Wxy Global Volume Slide */
\r
277 UniEffect(UNI_ITEFFECTW,inf);
\r
279 case 0x18: /* Xxx amiga command 8xx */
\r
280 if(flags & S3MIT_OLDSTYLE) {
\r
282 UniEffect(UNI_ITEFFECTS0,0x91); /* surround */
\r
284 UniPTEffect(0x8,(inf==128)?255:(inf<<1));
\r
286 UniPTEffect(0x8,inf);
\r
288 case 0x19: /* Yxy Panbrello speed x, depth y */
\r
289 UniEffect(UNI_ITEFFECTY,inf);
\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
302 /*========== Unitrk stuff */
\r
304 /* Generic effect writing routine */
\r
305 void UniEffect(UWORD eff,UWORD dat)
\r
307 if((!eff)||(eff>=UNI_LAST)) return;
\r
310 if(unioperands[eff]==2)
\r
316 /* Appends UNI_PTEFFECTX opcode to the unitrk stream. */
\r
317 void UniPTEffect(UBYTE eff, UBYTE dat)
\r
319 #ifdef MIKMOD_DEBUG
\r
321 fprintf(stderr,"UniPTEffect called with incorrect eff value %d\n",eff);
\r
324 if((eff)||(dat)||(of.flags&UF_ARPMEM)) UniEffect(UNI_PTEFFECT0+eff,dat);
\r
327 /* Appends UNI_VOLEFFECT + effect/dat to unistream. */
\r
328 void UniVolEffect(UWORD eff,UBYTE dat)
\r
330 if((eff)||(dat)) { /* don't write empty effect */
\r
331 UniWriteByte(UNI_VOLEFFECTS);
\r
332 UniWriteByte(eff);UniWriteByte(dat);
\r