separated the smoke-text effect to reuse it in multiple parts if
[dosdemo] / libs / mikmod / playercode / virtch_common.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   Common source parts between the two software mixers.
26   This file is probably the ugliest part of libmikmod...
27
28 ==============================================================================*/
29
30 #if defined(HAVE_CONFIG_H) && !defined(_IN_VIRTCH_) /* config.h isn't guarded */
31 #include "config.h"
32 #endif
33 #include "mikmod_internals.h"
34
35 #ifndef NO_HQMIXER
36 extern ULONG VC1_SilenceBytes(SBYTE*,ULONG);
37 extern ULONG VC2_SilenceBytes(SBYTE*,ULONG);
38 extern ULONG VC1_WriteBytes(SBYTE*,ULONG);
39 extern ULONG VC2_WriteBytes(SBYTE*,ULONG);
40 extern void  VC1_Exit(void);
41 extern void  VC2_Exit(void);
42 extern UWORD VC1_VoiceGetVolume(UBYTE);
43 extern UWORD VC2_VoiceGetVolume(UBYTE);
44 extern ULONG VC1_VoiceGetPanning(UBYTE);
45 extern ULONG VC2_VoiceGetPanning(UBYTE);
46 extern void  VC1_VoiceSetFrequency(UBYTE,ULONG);
47 extern void  VC2_VoiceSetFrequency(UBYTE,ULONG);
48 extern ULONG VC1_VoiceGetFrequency(UBYTE);
49 extern ULONG VC2_VoiceGetFrequency(UBYTE);
50 extern void  VC1_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
51 extern void  VC2_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
52 extern void  VC1_VoiceStop(UBYTE);
53 extern void  VC2_VoiceStop(UBYTE);
54 extern BOOL  VC1_VoiceStopped(UBYTE);
55 extern BOOL  VC2_VoiceStopped(UBYTE);
56 extern SLONG VC1_VoiceGetPosition(UBYTE);
57 extern SLONG VC2_VoiceGetPosition(UBYTE);
58 extern void  VC1_VoiceSetVolume(UBYTE,UWORD);
59 extern void  VC2_VoiceSetVolume(UBYTE,UWORD);
60 extern void  VC1_VoiceSetPanning(UBYTE,ULONG);
61 extern void  VC2_VoiceSetPanning(UBYTE,ULONG);
62 extern void  VC1_SampleUnload(SWORD);
63 extern void  VC2_SampleUnload(SWORD);
64 extern SWORD VC1_SampleLoad(struct SAMPLOAD*,int);
65 extern SWORD VC2_SampleLoad(struct SAMPLOAD*,int);
66 extern ULONG VC1_SampleSpace(int);
67 extern ULONG VC2_SampleSpace(int);
68 extern ULONG VC1_SampleLength(int,SAMPLE*);
69 extern ULONG VC2_SampleLength(int,SAMPLE*);
70 extern ULONG VC1_VoiceRealVolume(UBYTE);
71 extern ULONG VC2_VoiceRealVolume(UBYTE);
72 #endif
73
74
75 #ifndef _IN_VIRTCH_
76
77 #ifndef NO_HQMIXER
78 extern int   VC1_Init(void);
79 extern int   VC2_Init(void);
80 static int  (*VC_Init_ptr)(void)=VC1_Init;
81 static void (*VC_Exit_ptr)(void)=VC1_Exit;
82 extern int   VC1_SetNumVoices(void);
83 extern int   VC2_SetNumVoices(void);
84 static int  (*VC_SetNumVoices_ptr)(void);
85 static ULONG (*VC_SampleSpace_ptr)(int);
86 static ULONG (*VC_SampleLength_ptr)(int,SAMPLE*);
87
88 extern int   VC2_PlayStart(void);
89 static int  (*VC_PlayStart_ptr)(void);
90 extern void  VC2_PlayStop(void);
91 static void (*VC_PlayStop_ptr)(void);
92
93 static SWORD (*VC_SampleLoad_ptr)(struct SAMPLOAD*,int);
94 static void (*VC_SampleUnload_ptr)(SWORD);
95
96 static ULONG (*VC_WriteBytes_ptr)(SBYTE*,ULONG);
97 static ULONG (*VC_SilenceBytes_ptr)(SBYTE*,ULONG);
98
99 static void (*VC_VoiceSetVolume_ptr)(UBYTE,UWORD);
100 static UWORD (*VC_VoiceGetVolume_ptr)(UBYTE);
101 static void (*VC_VoiceSetFrequency_ptr)(UBYTE,ULONG);
102 static ULONG (*VC_VoiceGetFrequency_ptr)(UBYTE);
103 static void (*VC_VoiceSetPanning_ptr)(UBYTE,ULONG);
104 static ULONG (*VC_VoiceGetPanning_ptr)(UBYTE);
105 static void (*VC_VoicePlay_ptr)(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);
106
107 static void (*VC_VoiceStop_ptr)(UBYTE);
108 static BOOL (*VC_VoiceStopped_ptr)(UBYTE);
109 static SLONG (*VC_VoiceGetPosition_ptr)(UBYTE);
110 static ULONG (*VC_VoiceRealVolume_ptr)(UBYTE);
111
112 #if defined __STDC__ || defined _MSC_VER || defined MPW_C
113 #define VC_PROC0(suffix) \
114 MIKMODAPI void VC_##suffix (void) { VC_##suffix##_ptr(); }
115
116 #define VC_FUNC0(suffix,ret) \
117 MIKMODAPI ret VC_##suffix (void) { return VC_##suffix##_ptr(); }
118
119 #define VC_PROC1(suffix,typ1) \
120 MIKMODAPI void VC_##suffix (typ1 a) { VC_##suffix##_ptr(a); }
121
122 #define VC_FUNC1(suffix,ret,typ1) \
123 MIKMODAPI ret VC_##suffix (typ1 a) { return VC_##suffix##_ptr(a); }
124
125 #define VC_PROC2(suffix,typ1,typ2) \
126 MIKMODAPI void VC_##suffix (typ1 a,typ2 b) { VC_##suffix##_ptr(a,b); }
127
128 #define VC_FUNC2(suffix,ret,typ1,typ2) \
129 MIKMODAPI ret VC_##suffix (typ1 a,typ2 b) { return VC_##suffix##_ptr(a,b); }
130
131 #else
132
133 #define VC_PROC0(suffix) \
134 MIKMODAPI void VC_/**/suffix (void) { VC_/**/suffix/**/_ptr(); }
135
136 #define VC_FUNC0(suffix,ret) \
137 MIKMODAPI ret VC_/**/suffix (void) { return VC_/**/suffix/**/_ptr(); }
138
139 #define VC_PROC1(suffix,typ1) \
140 MIKMODAPI void VC_/**/suffix (typ1 a) { VC_/**/suffix/**/_ptr(a); }
141
142 #define VC_FUNC1(suffix,ret,typ1) \
143 MIKMODAPI ret VC_/**/suffix (typ1 a) { return VC_/**/suffix/**/_ptr(a); }
144
145 #define VC_PROC2(suffix,typ1,typ2) \
146 MIKMODAPI void VC_/**/suffix (typ1 a,typ2 b) { VC_/**/suffix/**/_ptr(a,b); }
147
148 #define VC_FUNC2(suffix,ret,typ1,typ2) \
149 MIKMODAPI ret VC_/**/suffix (typ1 a,typ2 b) { return VC_/**/suffix/**/_ptr(a,b); }
150 #endif
151
152 VC_FUNC0(Init,int)
153 VC_PROC0(Exit)
154 VC_FUNC0(SetNumVoices,int)
155 VC_FUNC1(SampleSpace,ULONG,int)
156 VC_FUNC2(SampleLength,ULONG,int,SAMPLE*)
157 VC_FUNC0(PlayStart,int)
158 VC_PROC0(PlayStop)
159 VC_FUNC2(SampleLoad,SWORD,struct SAMPLOAD*,int)
160 VC_PROC1(SampleUnload,SWORD)
161 VC_FUNC2(WriteBytes,ULONG,SBYTE*,ULONG)
162 VC_FUNC2(SilenceBytes,ULONG,SBYTE*,ULONG)
163 VC_PROC2(VoiceSetVolume,UBYTE,UWORD)
164 VC_FUNC1(VoiceGetVolume,UWORD,UBYTE)
165 VC_PROC2(VoiceSetFrequency,UBYTE,ULONG)
166 VC_FUNC1(VoiceGetFrequency,ULONG,UBYTE)
167 VC_PROC2(VoiceSetPanning,UBYTE,ULONG)
168 VC_FUNC1(VoiceGetPanning,ULONG,UBYTE)
169
170 void VC_VoicePlay(UBYTE a,SWORD b,ULONG c,ULONG d,ULONG e,ULONG f,UWORD g) {
171      VC_VoicePlay_ptr(a,b,c,d,e,f,g);
172 }
173
174 VC_PROC1(VoiceStop,UBYTE)
175 VC_FUNC1(VoiceStopped,BOOL,UBYTE)
176 VC_FUNC1(VoiceGetPosition,SLONG,UBYTE)
177 VC_FUNC1(VoiceRealVolume,ULONG,UBYTE)
178
179 void VC_SetupPointers(void)
180 {
181         if (md_mode&DMODE_HQMIXER) {
182                 VC_Init_ptr=VC2_Init;
183                 VC_Exit_ptr=VC2_Exit;
184                 VC_SetNumVoices_ptr=VC2_SetNumVoices;
185                 VC_SampleSpace_ptr=VC2_SampleSpace;
186                 VC_SampleLength_ptr=VC2_SampleLength;
187                 VC_PlayStart_ptr=VC2_PlayStart;
188                 VC_PlayStop_ptr=VC2_PlayStop;
189                 VC_SampleLoad_ptr=VC2_SampleLoad;
190                 VC_SampleUnload_ptr=VC2_SampleUnload;
191                 VC_WriteBytes_ptr=VC2_WriteBytes;
192                 VC_SilenceBytes_ptr=VC2_SilenceBytes;
193                 VC_VoiceSetVolume_ptr=VC2_VoiceSetVolume;
194                 VC_VoiceGetVolume_ptr=VC2_VoiceGetVolume;
195                 VC_VoiceSetFrequency_ptr=VC2_VoiceSetFrequency;
196                 VC_VoiceGetFrequency_ptr=VC2_VoiceGetFrequency;
197                 VC_VoiceSetPanning_ptr=VC2_VoiceSetPanning;
198                 VC_VoiceGetPanning_ptr=VC2_VoiceGetPanning;
199                 VC_VoicePlay_ptr=VC2_VoicePlay;
200                 VC_VoiceStop_ptr=VC2_VoiceStop;
201                 VC_VoiceStopped_ptr=VC2_VoiceStopped;
202                 VC_VoiceGetPosition_ptr=VC2_VoiceGetPosition;
203                 VC_VoiceRealVolume_ptr=VC2_VoiceRealVolume;
204         } else {
205                 VC_Init_ptr=VC1_Init;
206                 VC_Exit_ptr=VC1_Exit;
207                 VC_SetNumVoices_ptr=VC1_SetNumVoices;
208                 VC_SampleSpace_ptr=VC1_SampleSpace;
209                 VC_SampleLength_ptr=VC1_SampleLength;
210                 VC_PlayStart_ptr=VC1_PlayStart;
211                 VC_PlayStop_ptr=VC1_PlayStop;
212                 VC_SampleLoad_ptr=VC1_SampleLoad;
213                 VC_SampleUnload_ptr=VC1_SampleUnload;
214                 VC_WriteBytes_ptr=VC1_WriteBytes;
215                 VC_SilenceBytes_ptr=VC1_SilenceBytes;
216                 VC_VoiceSetVolume_ptr=VC1_VoiceSetVolume;
217                 VC_VoiceGetVolume_ptr=VC1_VoiceGetVolume;
218                 VC_VoiceSetFrequency_ptr=VC1_VoiceSetFrequency;
219                 VC_VoiceGetFrequency_ptr=VC1_VoiceGetFrequency;
220                 VC_VoiceSetPanning_ptr=VC1_VoiceSetPanning;
221                 VC_VoiceGetPanning_ptr=VC1_VoiceGetPanning;
222                 VC_VoicePlay_ptr=VC1_VoicePlay;
223                 VC_VoiceStop_ptr=VC1_VoiceStop;
224                 VC_VoiceStopped_ptr=VC1_VoiceStopped;
225                 VC_VoiceGetPosition_ptr=VC1_VoiceGetPosition;
226                 VC_VoiceRealVolume_ptr=VC1_VoiceRealVolume;
227         }
228 }
229 #endif/* !NO_HQMIXER */
230
231 #else /* _IN_VIRTCH_ */
232
233 #ifndef _VIRTCH_COMMON_
234 #define _VIRTCH_COMMON_
235
236 static ULONG samples2bytes(ULONG samples)
237 {
238         if(vc_mode & DMODE_FLOAT) samples <<= 2;
239         else if(vc_mode & DMODE_16BITS) samples <<= 1;
240         if(vc_mode & DMODE_STEREO) samples <<= 1;
241         return samples;
242 }
243
244 static ULONG bytes2samples(ULONG bytes)
245 {
246         if(vc_mode & DMODE_FLOAT) bytes >>= 2;
247         else if(vc_mode & DMODE_16BITS) bytes >>= 1;
248         if(vc_mode & DMODE_STEREO) bytes >>= 1;
249         return bytes;
250 }
251
252 /* Fill the buffer with 'todo' bytes of silence (it depends on the mixing mode
253    how the buffer is filled) */
254 ULONG VC1_SilenceBytes(SBYTE* buf,ULONG todo)
255 {
256         todo=samples2bytes(bytes2samples(todo));
257
258         /* clear the buffer to zero (16 bits signed) or 0x80 (8 bits unsigned) */
259         if(vc_mode &(DMODE_16BITS|DMODE_FLOAT))
260                 memset(buf,0,todo);
261         else
262                 memset(buf,0x80,todo);
263
264         return todo;
265 }
266
267 void VC1_WriteSamples(SBYTE*,ULONG);
268
269 /* Writes 'todo' mixed SBYTES (!!) to 'buf'. It returns the number of SBYTES
270    actually written to 'buf' (which is rounded to number of samples that fit
271    into 'todo' bytes). */
272 ULONG VC1_WriteBytes(SBYTE* buf,ULONG todo)
273 {
274         if(!vc_softchn)
275                 return VC1_SilenceBytes(buf,todo);
276
277         todo = bytes2samples(todo);
278         VC1_WriteSamples(buf,todo);
279
280         return samples2bytes(todo);
281 }
282
283 void VC1_Exit(void)
284 {
285         MikMod_free(vinf);
286         MikMod_afree(vc_tickbuf);
287         MikMod_afree(Samples);
288
289         vc_tickbuf = NULL;
290         vinf = NULL;
291         Samples = NULL;
292
293         VC_SetupPointers();
294 }
295
296 UWORD VC1_VoiceGetVolume(UBYTE voice)
297 {
298         return vinf[voice].vol;
299 }
300
301 ULONG VC1_VoiceGetPanning(UBYTE voice)
302 {
303         return vinf[voice].pan;
304 }
305
306 void VC1_VoiceSetFrequency(UBYTE voice,ULONG frq)
307 {
308         vinf[voice].frq=frq;
309 }
310
311 ULONG VC1_VoiceGetFrequency(UBYTE voice)
312 {
313         return vinf[voice].frq;
314 }
315
316 void VC1_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags)
317 {
318         vinf[voice].flags  = flags;
319         vinf[voice].handle = handle;
320         vinf[voice].start  = start;
321         vinf[voice].size   = size;
322         vinf[voice].reppos = reppos;
323         vinf[voice].repend = repend;
324         vinf[voice].kick   = 1;
325 }
326
327 void VC1_VoiceStop(UBYTE voice)
328 {
329         vinf[voice].active = 0;
330 }
331
332 BOOL VC1_VoiceStopped(UBYTE voice)
333 {
334         return(vinf[voice].active==0);
335 }
336
337 SLONG VC1_VoiceGetPosition(UBYTE voice)
338 {
339         return (SLONG)(vinf[voice].current>>FRACBITS);
340 }
341
342 void VC1_VoiceSetVolume(UBYTE voice,UWORD vol)
343 {
344         /* protect against clicks if volume variation is too high */
345         if(abs((int)vinf[voice].vol-(int)vol)>32)
346                 vinf[voice].rampvol=CLICK_BUFFER;
347         vinf[voice].vol=vol;
348 }
349
350 void VC1_VoiceSetPanning(UBYTE voice,ULONG pan)
351 {
352         /* protect against clicks if panning variation is too high */
353         if(abs((int)vinf[voice].pan-(int)pan)>48)
354                 vinf[voice].rampvol=CLICK_BUFFER;
355         vinf[voice].pan=pan;
356 }
357
358 /*========== External mixer interface */
359
360 void VC1_SampleUnload(SWORD handle)
361 {
362         if (Samples && (handle < MAXSAMPLEHANDLES)) {
363                 MikMod_afree(Samples[handle]);
364                 Samples[handle]=NULL;
365         }
366 }
367
368 SWORD VC1_SampleLoad(struct SAMPLOAD* sload,int type)
369 {
370         SAMPLE *s = sload->sample;
371         int handle;
372         ULONG t, length,loopstart,loopend,looplen;
373
374         if(type==MD_HARDWARE) return -1;
375
376         /* Find empty slot to put sample address in */
377         for(handle=0;handle<MAXSAMPLEHANDLES;handle++)
378                 if(!Samples[handle]) break;
379
380         if(handle==MAXSAMPLEHANDLES) {
381                 _mm_errno = MMERR_OUT_OF_HANDLES;
382                 return -1;
383         }
384
385         /* Reality check for loop settings */
386         if (s->loopend > s->length)
387                 s->loopend = s->length;
388         if (s->loopstart >= s->loopend)
389                 s->flags &= ~SF_LOOP;
390
391         length    = s->length;
392         loopstart = s->loopstart;
393         loopend   = s->loopend;
394
395         SL_SampleSigned(sload);
396         SL_Sample8to16(sload);
397
398         if(!(Samples[handle]=(SWORD*)MikMod_amalloc((length+20)<<1))) {
399                 _mm_errno = MMERR_SAMPLE_TOO_BIG;
400                 return -1;
401         }
402
403         /* read sample into buffer */
404         if (SL_Load(Samples[handle],sload,length))
405                 return -1;
406
407         /* Unclick sample */
408         if(s->flags & SF_LOOP) {
409                 looplen = loopend - loopstart;/* handle short samples */
410                 if(s->flags & SF_BIDI)
411                         for(t=0;t<16 && t<looplen;t++)
412                                 Samples[handle][loopend+t]=Samples[handle][(loopend-t)-1];
413                 else
414                         for(t=0;t<16 && t<looplen;t++)
415                                 Samples[handle][loopend+t]=Samples[handle][t+loopstart];
416         } else
417                 for(t=0;t<16;t++)
418                         Samples[handle][t+length]=0;
419
420         return handle;
421 }
422
423 ULONG VC1_SampleSpace(int type)
424 {
425         return vc_memory;
426 }
427
428 ULONG VC1_SampleLength(int type,SAMPLE* s)
429 {
430         if (!s) return 0;
431
432         return (s->length*((s->flags&SF_16BITS)?2:1))+16;
433 }
434
435 ULONG VC1_VoiceRealVolume(UBYTE voice)
436 {
437         ULONG i,s,size;
438         int k,j;
439         SWORD *smp;
440         SLONG t;
441
442         t = (SLONG)(vinf[voice].current>>FRACBITS);
443         if(!vinf[voice].active) return 0;
444
445         s = vinf[voice].handle;
446         size = vinf[voice].size;
447
448         i=64; t-=64; k=0; j=0;
449         if(i>size) i = size;
450         if(t<0) t = 0;
451         if(t+i > size) t = size-i;
452
453         i &= ~1;  /* make sure it's EVEN. */
454
455         smp = &Samples[s][t];
456         for(;i;i--,smp++) {
457                 if(k<*smp) k = *smp;
458                 if(j>*smp) j = *smp;
459         }
460         return abs(k-j);
461 }
462
463 #endif /* _VIRTCH_COMMON_ */
464
465 #endif /* _IN_VIRTCH_ */
466
467 /* ex:set ts=4: */