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