Add "MikMod for Rockbox 0.1" from 2007-06-29
[mikmod-rockbox.git] / apps / plugins / mikmod / playercode / virtch2.c
1 /*      MikMod sound library\r
2         (c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for\r
3         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: virtch2.c,v 1.2 2004/02/13 13:31:54 raph Exp $\r
24 \r
25   High-quality sample mixing routines, using a 32 bits mixing buffer,\r
26   interpolation, and sample smoothing to improve sound quality and remove\r
27   clicks.\r
28 \r
29 ==============================================================================*/\r
30 \r
31 /*\r
32 \r
33   Future Additions:\r
34         Low-Pass filter to remove annoying staticy buzz.\r
35 \r
36 */\r
37 \r
38 #ifdef HAVE_CONFIG_H\r
39 #include "config.h"\r
40 #endif\r
41 \r
42 #ifdef HAVE_MEMORY_H\r
43 #include <memory.h>\r
44 #endif\r
45 #include <string.h>\r
46 \r
47 #include "mikmod_internals.h"\r
48   \r
49 /*\r
50    Constant Definitions\r
51    ====================\r
52 \r
53         MAXVOL_FACTOR (was BITSHIFT in virtch.c)\r
54                 Controls the maximum volume of the output data. All mixed data is\r
55                 divided by this number after mixing, so larger numbers result in\r
56                 quieter mixing.  Smaller numbers will increase the likeliness of\r
57                 distortion on loud modules.\r
58 \r
59         REVERBERATION\r
60                 Larger numbers result in shorter reverb duration. Longer reverb\r
61                 durations can cause unwanted static and make the reverb sound more\r
62                 like a crappy echo.\r
63 \r
64         SAMPLING_SHIFT\r
65                 Specified the shift multiplier which controls by how much the mixing\r
66                 rate is multiplied while mixing.  Higher values can improve quality by\r
67                 smoothing the sound and reducing pops and clicks. Note, this is a shift\r
68                 value, so a value of 2 becomes a mixing-rate multiplier of 4, and a\r
69                 value of 3 = 8, etc.\r
70 \r
71         FRACBITS\r
72                 The number of bits per integer devoted to the fractional part of the\r
73                 number. Generally, this number should not be changed for any reason.\r
74 \r
75         !!! IMPORTANT !!! All values below MUST ALWAYS be greater than 0\r
76 \r
77 */\r
78 \r
79 #define MAXVOL_FACTOR (1<<9)\r
80 #define REVERBERATION 11000L\r
81 \r
82 #define SAMPLING_SHIFT 2\r
83 #define SAMPLING_FACTOR (1UL<<SAMPLING_SHIFT)\r
84 \r
85 #define FRACBITS 28\r
86 #define FRACMASK ((1UL<<FRACBITS)-1UL)\r
87 \r
88 #define TICKLSIZE 8192\r
89 #define TICKWSIZE (TICKLSIZE * 2)\r
90 #define TICKBSIZE (TICKWSIZE * 2)\r
91 \r
92 #define CLICK_SHIFT_BASE 6\r
93 #define CLICK_SHIFT (CLICK_SHIFT_BASE + SAMPLING_SHIFT)\r
94 #define CLICK_BUFFER (1L << CLICK_SHIFT)\r
95 \r
96 #ifndef MIN\r
97 #define MIN(a,b) (((a)<(b)) ? (a) : (b))\r
98 #endif\r
99 \r
100 typedef struct VINFO {\r
101         UBYTE     kick;              /* =1 -> sample has to be restarted */\r
102         UBYTE     active;            /* =1 -> sample is playing */\r
103         UWORD     flags;             /* 16/8 bits looping/one-shot */\r
104         SWORD     handle;            /* identifies the sample */\r
105         ULONG     start;             /* start index */\r
106         ULONG     size;              /* samplesize */\r
107         ULONG     reppos;            /* loop start */\r
108         ULONG     repend;            /* loop end */\r
109         ULONG     frq;               /* current frequency */\r
110         int       vol;               /* current volume */\r
111         int       pan;               /* current panning position */\r
112 \r
113         int       click;\r
114         int       rampvol;\r
115         SLONG     lastvalL,lastvalR;\r
116         int       lvolsel,rvolsel;   /* Volume factor in range 0-255 */\r
117         int       oldlvol,oldrvol;\r
118 \r
119         SLONGLONG current;           /* current index in the sample */\r
120         SLONGLONG increment;         /* increment value */\r
121 } VINFO;\r
122 \r
123 static  SWORD **Samples;\r
124 static  VINFO *vinf=NULL,*vnf;\r
125 static  long tickleft,samplesthatfit,vc_memory=0;\r
126 static  int vc_softchn;\r
127 static  SLONGLONG idxsize,idxlpos,idxlend;\r
128 static  SLONG *vc_tickbuf=NULL;\r
129 static  UWORD vc_mode;\r
130 \r
131 /* Reverb control variables */\r
132 \r
133 static  int RVc1, RVc2, RVc3, RVc4, RVc5, RVc6, RVc7, RVc8;\r
134 static  ULONG RVRindex;\r
135 \r
136 /* For Mono or Left Channel */\r
137 static  SLONG *RVbufL1=NULL,*RVbufL2=NULL,*RVbufL3=NULL,*RVbufL4=NULL,\r
138                       *RVbufL5=NULL,*RVbufL6=NULL,*RVbufL7=NULL,*RVbufL8=NULL;\r
139 \r
140 /* For Stereo only (Right Channel) */\r
141 static  SLONG *RVbufR1=NULL,*RVbufR2=NULL,*RVbufR3=NULL,*RVbufR4=NULL,\r
142                       *RVbufR5=NULL,*RVbufR6=NULL,*RVbufR7=NULL,*RVbufR8=NULL;\r
143 \r
144 #ifdef NATIVE_64BIT_INT\r
145 #define NATIVE SLONGLONG\r
146 #else\r
147 #define NATIVE SLONG\r
148 #endif\r
149 \r
150 /*========== 32 bit sample mixers - only for 32 bit platforms */\r
151 #ifndef NATIVE_64BIT_INT\r
152 \r
153 static SLONG Mix32MonoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)\r
154 {\r
155         SWORD sample=0;\r
156         SLONG i,f;\r
157 \r
158         while(todo--) {\r
159                 i=index>>FRACBITS,f=index&FRACMASK;\r
160                 sample=(((SLONG)(srce[i]*(FRACMASK+1L-f)) +\r
161                         ((SLONG)srce[i+1]*f)) >> FRACBITS);\r
162                 index+=increment;\r
163 \r
164                 if(vnf->rampvol) {\r
165                         *dest++ += (long)(\r
166                           ( ( (SLONG)(vnf->oldlvol*vnf->rampvol) +\r
167                               (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *\r
168                             (SLONG)sample ) >> CLICK_SHIFT );\r
169                         vnf->rampvol--;\r
170                 } else\r
171                   if(vnf->click) {\r
172                         *dest++ += (long)(\r
173                           ( ( ((SLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *\r
174                               (SLONG)sample ) +\r
175                             (vnf->lastvalL*vnf->click) ) >> CLICK_SHIFT );\r
176                         vnf->click--;\r
177                 } else\r
178                         *dest++ +=vnf->lvolsel*sample;\r
179         }\r
180         vnf->lastvalL=vnf->lvolsel * sample;\r
181 \r
182         return index;\r
183 }\r
184 \r
185 static SLONG Mix32StereoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,ULONG todo)\r
186 {\r
187         SWORD sample=0;\r
188         SLONG i,f;\r
189 \r
190         while(todo--) {\r
191                 i=index>>FRACBITS,f=index&FRACMASK;\r
192                 sample=((((SLONG)srce[i]*(FRACMASK+1L-f)) +\r
193                         ((SLONG)srce[i+1] * f)) >> FRACBITS);\r
194                 index += increment;\r
195 \r
196                 if(vnf->rampvol) {\r
197                         *dest++ += (long)(\r
198                           ( ( ((SLONG)vnf->oldlvol*vnf->rampvol) +\r
199                               (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol))\r
200                             ) * (SLONG)sample ) >> CLICK_SHIFT );\r
201                         *dest++ += (long)(\r
202                           ( ( ((SLONG)vnf->oldrvol*vnf->rampvol) +\r
203                               (vnf->rvolsel*(CLICK_BUFFER-vnf->rampvol))\r
204                             ) * (SLONG)sample ) >> CLICK_SHIFT );\r
205                         vnf->rampvol--;\r
206                 } else\r
207                   if(vnf->click) {\r
208                         *dest++ += (long)(\r
209                           ( ( (SLONG)(vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *\r
210                               (SLONG)sample ) + (vnf->lastvalL * vnf->click) )\r
211                             >> CLICK_SHIFT );\r
212                         *dest++ += (long)(\r
213                           ( ( ((SLONG)vnf->rvolsel*(CLICK_BUFFER-vnf->click)) *\r
214                               (SLONG)sample ) + (vnf->lastvalR * vnf->click) )\r
215                             >> CLICK_SHIFT );\r
216                         vnf->click--;\r
217                 } else {\r
218                         *dest++ +=vnf->lvolsel*sample;\r
219                         *dest++ +=vnf->rvolsel*sample;\r
220                 }\r
221         }\r
222         vnf->lastvalL=vnf->lvolsel*sample;\r
223         vnf->lastvalR=vnf->rvolsel*sample;\r
224 \r
225         return index;\r
226 }\r
227 \r
228 static SLONG Mix32StereoSurround(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,ULONG todo)\r
229 {\r
230         SWORD sample=0;\r
231         long whoop;\r
232         SLONG i, f;\r
233 \r
234         while(todo--) {\r
235                 i=index>>FRACBITS,f=index&FRACMASK;\r
236                 sample=((((SLONG)srce[i]*(FRACMASK+1L-f)) +\r
237                         ((SLONG)srce[i+1]*f)) >> FRACBITS);\r
238                 index+=increment;\r
239 \r
240                 if(vnf->rampvol) {\r
241                         whoop=(long)(\r
242                           ( ( (SLONG)(vnf->oldlvol*vnf->rampvol) +\r
243                               (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *\r
244                             (SLONG)sample) >> CLICK_SHIFT );\r
245                         *dest++ +=whoop;\r
246                         *dest++ -=whoop;\r
247                         vnf->rampvol--;\r
248                 } else\r
249                   if(vnf->click) {\r
250                         whoop = (long)(\r
251                           ( ( ((SLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *\r
252                               (SLONG)sample) +\r
253                             (vnf->lastvalL * vnf->click) ) >> CLICK_SHIFT );\r
254                         *dest++ +=whoop;\r
255                         *dest++ -=whoop;\r
256                         vnf->click--;\r
257                 } else {\r
258                         *dest++ +=vnf->lvolsel*sample;\r
259                         *dest++ -=vnf->lvolsel*sample;\r
260                 }\r
261         }\r
262         vnf->lastvalL=vnf->lvolsel*sample;\r
263         vnf->lastvalR=vnf->lvolsel*sample;\r
264 \r
265         return index;\r
266 }\r
267 #endif\r
268 \r
269 /*========== 64 bit mixers */\r
270 \r
271 static SLONGLONG MixMonoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)\r
272 {\r
273         SWORD sample=0;\r
274         SLONGLONG i,f;\r
275 \r
276         while(todo--) {\r
277                 i=index>>FRACBITS,f=index&FRACMASK;\r
278                 sample=(((SLONGLONG)(srce[i]*(FRACMASK+1L-f)) +\r
279                         ((SLONGLONG)srce[i+1]*f)) >> FRACBITS);\r
280                 index+=increment;\r
281 \r
282                 if(vnf->rampvol) {\r
283                         *dest++ += (long)(\r
284                           ( ( (SLONGLONG)(vnf->oldlvol*vnf->rampvol) +\r
285                               (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *\r
286                             (SLONGLONG)sample ) >> CLICK_SHIFT );\r
287                         vnf->rampvol--;\r
288                 } else\r
289                   if(vnf->click) {\r
290                         *dest++ += (long)(\r
291                           ( ( ((SLONGLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *\r
292                               (SLONGLONG)sample ) +\r
293                             (vnf->lastvalL*vnf->click) ) >> CLICK_SHIFT );\r
294                         vnf->click--;\r
295                 } else\r
296                         *dest++ +=vnf->lvolsel*sample;\r
297         }\r
298         vnf->lastvalL=vnf->lvolsel * sample;\r
299 \r
300         return index;\r
301 }\r
302 \r
303 static SLONGLONG MixStereoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,ULONG todo)\r
304 {\r
305         SWORD sample=0;\r
306         SLONGLONG i,f;\r
307 \r
308         while(todo--) {\r
309                 i=index>>FRACBITS,f=index&FRACMASK;\r
310                 sample=((((SLONGLONG)srce[i]*(FRACMASK+1L-f)) +\r
311                         ((SLONGLONG)srce[i+1] * f)) >> FRACBITS);\r
312                 index += increment;\r
313 \r
314                 if(vnf->rampvol) {\r
315                         *dest++ += (long)(\r
316                           ( ( ((SLONGLONG)vnf->oldlvol*vnf->rampvol) +\r
317                               (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol))\r
318                             ) * (SLONGLONG)sample ) >> CLICK_SHIFT );\r
319                         *dest++ += (long)(\r
320                           ( ( ((SLONGLONG)vnf->oldrvol*vnf->rampvol) +\r
321                               (vnf->rvolsel*(CLICK_BUFFER-vnf->rampvol))\r
322                             ) * (SLONGLONG)sample ) >> CLICK_SHIFT );\r
323                         vnf->rampvol--;\r
324                 } else\r
325                   if(vnf->click) {\r
326                         *dest++ += (long)(\r
327                           ( ( (SLONGLONG)(vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *\r
328                               (SLONGLONG)sample ) + (vnf->lastvalL * vnf->click) )\r
329                             >> CLICK_SHIFT );\r
330                         *dest++ += (long)(\r
331                           ( ( ((SLONGLONG)vnf->rvolsel*(CLICK_BUFFER-vnf->click)) *\r
332                               (SLONGLONG)sample ) + (vnf->lastvalR * vnf->click) )\r
333                             >> CLICK_SHIFT );\r
334                         vnf->click--;\r
335                 } else {\r
336                         *dest++ +=vnf->lvolsel*sample;\r
337                         *dest++ +=vnf->rvolsel*sample;\r
338                 }\r
339         }\r
340         vnf->lastvalL=vnf->lvolsel*sample;\r
341         vnf->lastvalR=vnf->rvolsel*sample;\r
342 \r
343         return index;\r
344 }\r
345 \r
346 static SLONGLONG MixStereoSurround(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,ULONG todo)\r
347 {\r
348         SWORD sample=0;\r
349         long whoop;\r
350         SLONGLONG i, f;\r
351 \r
352         while(todo--) {\r
353                 i=index>>FRACBITS,f=index&FRACMASK;\r
354                 sample=((((SLONGLONG)srce[i]*(FRACMASK+1L-f)) +\r
355                         ((SLONGLONG)srce[i+1]*f)) >> FRACBITS);\r
356                 index+=increment;\r
357 \r
358                 if(vnf->rampvol) {\r
359                         whoop=(long)(\r
360                           ( ( (SLONGLONG)(vnf->oldlvol*vnf->rampvol) +\r
361                               (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *\r
362                             (SLONGLONG)sample) >> CLICK_SHIFT );\r
363                         *dest++ +=whoop;\r
364                         *dest++ -=whoop;\r
365                         vnf->rampvol--;\r
366                 } else\r
367                   if(vnf->click) {\r
368                         whoop = (long)(\r
369                           ( ( ((SLONGLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *\r
370                               (SLONGLONG)sample) +\r
371                             (vnf->lastvalL * vnf->click) ) >> CLICK_SHIFT );\r
372                         *dest++ +=whoop;\r
373                         *dest++ -=whoop;\r
374                         vnf->click--;\r
375                 } else {\r
376                         *dest++ +=vnf->lvolsel*sample;\r
377                         *dest++ -=vnf->lvolsel*sample;\r
378                 }\r
379         }\r
380         vnf->lastvalL=vnf->lvolsel*sample;\r
381         vnf->lastvalR=vnf->lvolsel*sample;\r
382 \r
383         return index;\r
384 }\r
385 \r
386 static  void(*Mix32toFP)(float* dste,SLONG* srce,NATIVE count);\r
387 static  void(*Mix32to16)(SWORD* dste,SLONG* srce,NATIVE count);\r
388 static  void(*Mix32to8)(SBYTE* dste,SLONG* srce,NATIVE count);\r
389 static  void(*MixReverb)(SLONG* srce,NATIVE count);\r
390 \r
391 /* Reverb macros */\r
392 #define COMPUTE_LOC(n) loc##n = RVRindex % RVc##n\r
393 #define COMPUTE_LECHO(n) RVbufL##n [loc##n ]=speedup+((ReverbPct*RVbufL##n [loc##n ])>>7)\r
394 #define COMPUTE_RECHO(n) RVbufR##n [loc##n ]=speedup+((ReverbPct*RVbufR##n [loc##n ])>>7)\r
395 \r
396 static void MixReverb_Normal(SLONG* srce,NATIVE count)\r
397 {\r
398         NATIVE speedup;\r
399         int ReverbPct;\r
400         unsigned int loc1,loc2,loc3,loc4,loc5,loc6,loc7,loc8;\r
401 \r
402         ReverbPct=58+(md_reverb*4);\r
403 \r
404         COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);\r
405         COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);\r
406 \r
407         while(count--) {\r
408                 /* Compute the left channel echo buffers */\r
409                 speedup = *srce >> 3;\r
410 \r
411                 COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4);\r
412                 COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8);\r
413 \r
414                 /* Prepare to compute actual finalized data */\r
415                 RVRindex++;\r
416 \r
417                 COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);\r
418                 COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);\r
419 \r
420                 /* left channel */\r
421                 *srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+\r
422                           RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];\r
423         }\r
424 }\r
425 \r
426 static void MixReverb_Stereo(SLONG *srce,NATIVE count)\r
427 {\r
428         NATIVE speedup;\r
429         int ReverbPct;\r
430         unsigned int loc1,loc2,loc3,loc4,loc5,loc6,loc7,loc8;\r
431 \r
432         ReverbPct=58+(md_reverb*4);\r
433 \r
434         COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);\r
435         COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);\r
436 \r
437         while(count--) {\r
438                 /* Compute the left channel echo buffers */\r
439                 speedup = *srce >> 3;\r
440 \r
441                 COMPUTE_LECHO(1); COMPUTE_LECHO(2); COMPUTE_LECHO(3); COMPUTE_LECHO(4);\r
442                 COMPUTE_LECHO(5); COMPUTE_LECHO(6); COMPUTE_LECHO(7); COMPUTE_LECHO(8);\r
443 \r
444                 /* Compute the right channel echo buffers */\r
445                 speedup = srce[1] >> 3;\r
446 \r
447                 COMPUTE_RECHO(1); COMPUTE_RECHO(2); COMPUTE_RECHO(3); COMPUTE_RECHO(4);\r
448                 COMPUTE_RECHO(5); COMPUTE_RECHO(6); COMPUTE_RECHO(7); COMPUTE_RECHO(8);\r
449 \r
450                 /* Prepare to compute actual finalized data */\r
451                 RVRindex++;\r
452 \r
453                 COMPUTE_LOC(1); COMPUTE_LOC(2); COMPUTE_LOC(3); COMPUTE_LOC(4);\r
454                 COMPUTE_LOC(5); COMPUTE_LOC(6); COMPUTE_LOC(7); COMPUTE_LOC(8);\r
455 \r
456                 /* left channel */\r
457                 *srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+ \r
458                           RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];\r
459 \r
460                 /* right channel */\r
461                 *srce++ +=RVbufR1[loc1]-RVbufR2[loc2]+RVbufR3[loc3]-RVbufR4[loc4]+\r
462                           RVbufR5[loc5]-RVbufR6[loc6]+RVbufR7[loc7]-RVbufR8[loc8];\r
463         }\r
464 }\r
465 \r
466 /* Mixing macros */\r
467 #define EXTRACT_SAMPLE_FP(var,attenuation) var=*srce++*((1.0f / 32768.0f) / (MAXVOL_FACTOR*attenuation))\r
468 #define CHECK_SAMPLE_FP(var,bound) var=(var>bound)?bound:(var<-bound)?-bound:var\r
469 \r
470 static void Mix32ToFP_Normal(float* dste,SLONG* srce,NATIVE count)\r
471 {\r
472         float x1,x2,tmpx;\r
473         int i;\r
474 \r
475         for(count/=SAMPLING_FACTOR;count;count--) {\r
476                 tmpx=0.0f;\r
477 \r
478                 for(i=SAMPLING_FACTOR/2;i;i--) {\r
479                         EXTRACT_SAMPLE_FP(x1,1.0f); EXTRACT_SAMPLE_FP(x2,1.0f);\r
480 \r
481                         CHECK_SAMPLE_FP(x1,1.0f); CHECK_SAMPLE_FP(x2,1.0f);\r
482 \r
483                         tmpx+=x1+x2;\r
484                 }\r
485                 *dste++ =tmpx*(1.0f/SAMPLING_FACTOR);\r
486         }\r
487 }\r
488 \r
489 static void Mix32ToFP_Stereo(float* dste,SLONG* srce,NATIVE count)\r
490 {\r
491         float x1,x2,x3,x4,tmpx,tmpy;\r
492         int i;\r
493 \r
494         for(count/=SAMPLING_FACTOR;count;count--) {\r
495                 tmpx=tmpy=0.0f;\r
496 \r
497                 for(i=SAMPLING_FACTOR/2;i;i--) {\r
498                         EXTRACT_SAMPLE_FP(x1,1.0f); EXTRACT_SAMPLE_FP(x2,1.0f);\r
499                         EXTRACT_SAMPLE_FP(x3,1.0f); EXTRACT_SAMPLE_FP(x4,1.0f);\r
500 \r
501                         CHECK_SAMPLE_FP(x1,1.0f); CHECK_SAMPLE_FP(x2,1.0f);\r
502                         CHECK_SAMPLE_FP(x3,1.0f); CHECK_SAMPLE_FP(x4,1.0f);\r
503 \r
504                         tmpx+=x1+x3;\r
505                         tmpy+=x2+x4;\r
506                 }\r
507                 *dste++ =tmpx*(1.0f/SAMPLING_FACTOR);\r
508                 *dste++ =tmpy*(1.0f/SAMPLING_FACTOR);\r
509         }\r
510 }\r
511 \r
512 /* Mixing macros */\r
513 #define EXTRACT_SAMPLE(var,attenuation) var=*srce++/(MAXVOL_FACTOR*attenuation)\r
514 #define CHECK_SAMPLE(var,bound) var=(var>=bound)?bound-1:(var<-bound)?-bound:var\r
515 \r
516 static void Mix32To16_Normal(SWORD* dste,SLONG* srce,NATIVE count)\r
517 {\r
518         NATIVE x1,x2,tmpx;\r
519         int i;\r
520 \r
521         for(count/=SAMPLING_FACTOR;count;count--) {\r
522                 tmpx=0;\r
523 \r
524                 for(i=SAMPLING_FACTOR/2;i;i--) {\r
525                         EXTRACT_SAMPLE(x1,1); EXTRACT_SAMPLE(x2,1);\r
526 \r
527                         CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768);\r
528 \r
529                         tmpx+=x1+x2;\r
530                 }\r
531                 *dste++ =tmpx/SAMPLING_FACTOR;\r
532         }\r
533 }\r
534 \r
535 static void Mix32To16_Stereo(SWORD* dste,SLONG* srce,NATIVE count)\r
536 {\r
537         NATIVE x1,x2,x3,x4,tmpx,tmpy;\r
538         int i;\r
539 \r
540         for(count/=SAMPLING_FACTOR;count;count--) {\r
541                 tmpx=tmpy=0;\r
542 \r
543                 for(i=SAMPLING_FACTOR/2;i;i--) {\r
544                         EXTRACT_SAMPLE(x1,1); EXTRACT_SAMPLE(x2,1);\r
545                         EXTRACT_SAMPLE(x3,1); EXTRACT_SAMPLE(x4,1);\r
546 \r
547                         CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768);\r
548                         CHECK_SAMPLE(x3,32768); CHECK_SAMPLE(x4,32768);\r
549 \r
550                         tmpx+=x1+x3;\r
551                         tmpy+=x2+x4;\r
552                 }\r
553                 *dste++ =tmpx/SAMPLING_FACTOR;\r
554                 *dste++ =tmpy/SAMPLING_FACTOR;\r
555         }\r
556 }\r
557 \r
558 static void Mix32To8_Normal(SBYTE* dste,SLONG* srce,NATIVE count)\r
559 {\r
560         NATIVE x1,x2,tmpx;\r
561         int i;\r
562 \r
563         for(count/=SAMPLING_FACTOR;count;count--) {\r
564                 tmpx = 0;\r
565 \r
566                 for(i=SAMPLING_FACTOR/2;i;i--) {\r
567                         EXTRACT_SAMPLE(x1,256); EXTRACT_SAMPLE(x2,256);\r
568 \r
569                         CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128);\r
570 \r
571                         tmpx+=x1+x2;\r
572                 }\r
573                 *dste++ =(tmpx/SAMPLING_FACTOR)+128;\r
574         }\r
575 }\r
576 \r
577 static void Mix32To8_Stereo(SBYTE* dste,SLONG* srce,NATIVE count)\r
578 {\r
579         NATIVE x1,x2,x3,x4,tmpx,tmpy;\r
580         int i;\r
581 \r
582         for(count/=SAMPLING_FACTOR;count;count--) {\r
583                 tmpx=tmpy=0;\r
584 \r
585                 for(i=SAMPLING_FACTOR/2;i;i--) {\r
586                         EXTRACT_SAMPLE(x1,256); EXTRACT_SAMPLE(x2,256);\r
587                         EXTRACT_SAMPLE(x3,256); EXTRACT_SAMPLE(x4,256);\r
588 \r
589                         CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128);\r
590                         CHECK_SAMPLE(x3,128); CHECK_SAMPLE(x4,128);\r
591 \r
592                         tmpx+=x1+x3;\r
593                         tmpy+=x2+x4;\r
594                 }\r
595                 *dste++ =(tmpx/SAMPLING_FACTOR)+128;        \r
596                 *dste++ =(tmpy/SAMPLING_FACTOR)+128;        \r
597         }\r
598 }\r
599 \r
600 static void AddChannel(SLONG* ptr,NATIVE todo)\r
601 {\r
602         SLONGLONG end,done;\r
603         SWORD *s;\r
604 \r
605         if(!(s=Samples[vnf->handle])) {\r
606                 vnf->current = vnf->active  = 0;\r
607                 vnf->lastvalL = vnf->lastvalR = 0;\r
608                 return;\r
609         }\r
610 \r
611         /* update the 'current' index so the sample loops, or stops playing if it\r
612            reached the end of the sample */\r
613         while(todo>0) {\r
614                 SLONGLONG endpos;\r
615 \r
616                 if(vnf->flags & SF_REVERSE) {\r
617                         /* The sample is playing in reverse */\r
618                         if((vnf->flags&SF_LOOP)&&(vnf->current<idxlpos)) {\r
619                                 /* the sample is looping and has reached the loopstart index */\r
620                                 if(vnf->flags & SF_BIDI) {\r
621                                         /* sample is doing bidirectional loops, so 'bounce' the\r
622                                            current index against the idxlpos */\r
623                                         vnf->current = idxlpos+(idxlpos-vnf->current);\r
624                                         vnf->flags &= ~SF_REVERSE;\r
625                                         vnf->increment = -vnf->increment;\r
626                                 } else\r
627                                         /* normal backwards looping, so set the current position to\r
628                                            loopend index */\r
629                                         vnf->current=idxlend-(idxlpos-vnf->current);\r
630                         } else {\r
631                                 /* the sample is not looping, so check if it reached index 0 */\r
632                                 if(vnf->current < 0) {\r
633                                         /* playing index reached 0, so stop playing this sample */\r
634                                         vnf->current = vnf->active  = 0;\r
635                                         break;\r
636                                 }\r
637                         }\r
638                 } else {\r
639                         /* The sample is playing forward */\r
640                         if((vnf->flags & SF_LOOP) &&\r
641                            (vnf->current >= idxlend)) {\r
642                                 /* the sample is looping, check the loopend index */\r
643                                 if(vnf->flags & SF_BIDI) {\r
644                                         /* sample is doing bidirectional loops, so 'bounce' the\r
645                                            current index against the idxlend */\r
646                                         vnf->flags |= SF_REVERSE;\r
647                                         vnf->increment = -vnf->increment;\r
648                                         vnf->current = idxlend-(vnf->current-idxlend);\r
649                                 } else\r
650                                         /* normal backwards looping, so set the current position\r
651                                            to loopend index */\r
652                                         vnf->current=idxlpos+(vnf->current-idxlend);\r
653                         } else {\r
654                                 /* sample is not looping, so check if it reached the last\r
655                                    position */\r
656                                 if(vnf->current >= idxsize) {\r
657                                         /* yes, so stop playing this sample */\r
658                                         vnf->current = vnf->active  = 0;\r
659                                         break;\r
660                                 }\r
661                         }\r
662                 }\r
663 \r
664                 end=(vnf->flags&SF_REVERSE)?(vnf->flags&SF_LOOP)?idxlpos:0:\r
665                      (vnf->flags&SF_LOOP)?idxlend:idxsize;\r
666 \r
667                 /* if the sample is not blocked... */\r
668                 if((end==vnf->current)||(!vnf->increment))\r
669                         done=0;\r
670                 else {\r
671                         done=MIN((end-vnf->current)/vnf->increment+1,todo);\r
672                         if(done<0) done=0;\r
673                 }\r
674 \r
675                 if(!done) {\r
676                         vnf->active = 0;\r
677                         break;\r
678                 }\r
679 \r
680                 endpos=vnf->current+done*vnf->increment;\r
681 \r
682                 if(vnf->vol || vnf->rampvol) {\r
683 #ifndef NATIVE_64BIT_INT\r
684                         /* use the 32 bit mixers as often as we can (they're much faster) */\r
685                         if((vnf->current<0x7fffffff)&&(endpos<0x7fffffff)) {\r
686                                 if(vc_mode & DMODE_STEREO) {\r
687                                         if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND))\r
688                                                 vnf->current=Mix32StereoSurround\r
689                                                                (s,ptr,vnf->current,vnf->increment,done);\r
690                                         else\r
691                                                 vnf->current=Mix32StereoNormal\r
692                                                                (s,ptr,vnf->current,vnf->increment,done);\r
693                                 } else\r
694                                         vnf->current=Mix32MonoNormal\r
695                                                            (s,ptr,vnf->current,vnf->increment,done);\r
696                         } else\r
697 #endif\r
698                                {\r
699                                 if(vc_mode & DMODE_STEREO) {\r
700                                         if((vnf->pan==PAN_SURROUND)&&(vc_mode&DMODE_SURROUND))\r
701                                                 vnf->current=MixStereoSurround\r
702                                                                (s,ptr,vnf->current,vnf->increment,done);\r
703                                         else\r
704                                                 vnf->current=MixStereoNormal\r
705                                                                (s,ptr,vnf->current,vnf->increment,done);\r
706                                 } else\r
707                                         vnf->current=MixMonoNormal\r
708                                                            (s,ptr,vnf->current,vnf->increment,done);\r
709                         }\r
710                 } else  {\r
711                         vnf->lastvalL = vnf->lastvalR = 0;\r
712                         /* update sample position */\r
713                         vnf->current=endpos;\r
714                 }\r
715 \r
716                 todo -= done;\r
717                 ptr +=(vc_mode & DMODE_STEREO)?(done<<1):done;\r
718         }\r
719 }\r
720 \r
721 #define _IN_VIRTCH_\r
722 \r
723 #define VC1_SilenceBytes      VC2_SilenceBytes\r
724 #define VC1_WriteSamples      VC2_WriteSamples\r
725 #define VC1_WriteBytes        VC2_WriteBytes\r
726 #define VC1_Exit              VC2_Exit\r
727 #define VC1_VoiceSetVolume    VC2_VoiceSetVolume\r
728 #define VC1_VoiceGetVolume    VC2_VoiceGetVolume\r
729 #define VC1_VoiceSetPanning   VC2_VoiceSetPanning\r
730 #define VC1_VoiceGetPanning   VC2_VoiceGetPanning\r
731 #define VC1_VoiceSetFrequency VC2_VoiceSetFrequency\r
732 #define VC1_VoiceGetFrequency VC2_VoiceGetFrequency\r
733 #define VC1_VoicePlay         VC2_VoicePlay\r
734 #define VC1_VoiceStop         VC2_VoiceStop\r
735 #define VC1_VoiceStopped      VC2_VoiceStopped\r
736 #define VC1_VoiceGetPosition  VC2_VoiceGetPosition\r
737 #define VC1_SampleUnload      VC2_SampleUnload\r
738 #define VC1_SampleLoad        VC2_SampleLoad\r
739 #define VC1_SampleSpace       VC2_SampleSpace\r
740 #define VC1_SampleLength      VC2_SampleLength\r
741 #define VC1_VoiceRealVolume   VC2_VoiceRealVolume\r
742 \r
743 #include "virtch_common.c"\r
744 #undef _IN_VIRTCH_\r
745 \r
746 void VC2_WriteSamples(SBYTE* buf,ULONG todo)\r
747 {\r
748         int left,portion=0;\r
749         SBYTE *buffer;\r
750         int t,pan,vol;\r
751 \r
752         todo*=SAMPLING_FACTOR;\r
753 \r
754         while(todo) {\r
755                 if(!tickleft) {\r
756                         if(vc_mode & DMODE_SOFT_MUSIC) md_player();\r
757                         tickleft=(md_mixfreq*125L*SAMPLING_FACTOR)/(md_bpm*50L);\r
758                         tickleft&=~(SAMPLING_FACTOR-1);\r
759                 }\r
760                 left = MIN(tickleft, todo);\r
761                 buffer    = buf;\r
762                 tickleft -= left;\r
763                 todo     -= left;\r
764                 buf += samples2bytes(left)/SAMPLING_FACTOR;\r
765 \r
766                 while(left) {\r
767                         portion = MIN(left, samplesthatfit);\r
768                         memset(vc_tickbuf,0,portion<<((vc_mode&DMODE_STEREO)?3:2));\r
769                         for(t=0;t<vc_softchn;t++) {\r
770                                 vnf = &vinf[t];\r
771 \r
772                                 if(vnf->kick) {\r
773                                         vnf->current=((SLONGLONG)(vnf->start))<<FRACBITS;\r
774                                         vnf->kick    = 0;\r
775                                         vnf->active  = 1;\r
776                                         vnf->click   = CLICK_BUFFER;\r
777                                         vnf->rampvol = 0;\r
778                                 }\r
779 \r
780                                 if(!vnf->frq) vnf->active = 0;\r
781 \r
782                                 if(vnf->active) {\r
783                                         vnf->increment=((SLONGLONG)(vnf->frq)<<(FRACBITS-SAMPLING_SHIFT))\r
784                                                        /md_mixfreq;\r
785                                         if(vnf->flags&SF_REVERSE) vnf->increment=-vnf->increment;\r
786                                         vol = vnf->vol;  pan = vnf->pan;\r
787 \r
788                                         vnf->oldlvol=vnf->lvolsel;vnf->oldrvol=vnf->rvolsel;\r
789                                         if(vc_mode & DMODE_STEREO) {\r
790                                                 if(pan!=PAN_SURROUND) {\r
791                                                         vnf->lvolsel=(vol*(PAN_RIGHT-pan))>>8;\r
792                                                         vnf->rvolsel=(vol*pan)>>8;\r
793                                                 } else {\r
794                                                         vnf->lvolsel=vnf->rvolsel=(vol * 256L) / 480;\r
795                                                 }\r
796                                         } else\r
797                                                 vnf->lvolsel=vol;\r
798 \r
799                                         idxsize=(vnf->size)?((SLONGLONG)(vnf->size)<<FRACBITS)-1:0;\r
800                                         idxlend=(vnf->repend)?((SLONGLONG)(vnf->repend)<<FRACBITS)-1:0;\r
801                                         idxlpos=(SLONGLONG)(vnf->reppos)<<FRACBITS;\r
802                                         AddChannel(vc_tickbuf,portion);\r
803                                 }\r
804                         }\r
805 \r
806                         if(md_reverb) {\r
807                                 if(md_reverb>15) md_reverb=15;\r
808                                 MixReverb(vc_tickbuf,portion);\r
809                         }\r
810 \r
811                         if(vc_mode & DMODE_FLOAT)\r
812                                 Mix32toFP((float*)buffer,vc_tickbuf,portion);\r
813                         else if(vc_mode & DMODE_16BITS)\r
814                                 Mix32to16((SWORD*)buffer,vc_tickbuf,portion);\r
815                         else\r
816                                 Mix32to8((SBYTE*)buffer,vc_tickbuf,portion);\r
817 \r
818                         buffer += samples2bytes(portion) / SAMPLING_FACTOR;\r
819                         left   -= portion;\r
820                 }\r
821         }\r
822 }\r
823 \r
824 BOOL VC2_Init(void)\r
825 {\r
826         VC_SetupPointers();\r
827         \r
828         if (!(md_mode&DMODE_HQMIXER))\r
829                 return VC1_Init();\r
830         \r
831         if(!(Samples=(SWORD**)_mm_calloc(MAXSAMPLEHANDLES,sizeof(SWORD*)))) {\r
832                 _mm_errno = MMERR_INITIALIZING_MIXER;\r
833                 return 1;\r
834         }\r
835         if(!vc_tickbuf)\r
836                 if(!(vc_tickbuf=(SLONG*)_mm_malloc((TICKLSIZE+32)*sizeof(SLONG)))) {\r
837                         _mm_errno = MMERR_INITIALIZING_MIXER;\r
838                         return 1;\r
839                 }\r
840 \r
841         if(md_mode & DMODE_STEREO) {\r
842                 Mix32toFP  = Mix32ToFP_Stereo;\r
843                 Mix32to16  = Mix32To16_Stereo;\r
844                 Mix32to8   = Mix32To8_Stereo;\r
845                 MixReverb  = MixReverb_Stereo;\r
846         } else {\r
847                 Mix32toFP  = Mix32ToFP_Normal;\r
848                 Mix32to16  = Mix32To16_Normal;\r
849                 Mix32to8   = Mix32To8_Normal;\r
850                 MixReverb  = MixReverb_Normal;\r
851         }\r
852         md_mode |= DMODE_INTERP;\r
853         vc_mode = md_mode;\r
854         return 0;\r
855 }\r
856 \r
857 BOOL VC2_PlayStart(void)\r
858 {\r
859         md_mode|=DMODE_INTERP;\r
860 \r
861         samplesthatfit = TICKLSIZE;\r
862         if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1;\r
863         tickleft = 0;\r
864 \r
865         RVc1 = (5000L * md_mixfreq) / (REVERBERATION * 10);\r
866         RVc2 = (5078L * md_mixfreq) / (REVERBERATION * 10);\r
867         RVc3 = (5313L * md_mixfreq) / (REVERBERATION * 10);\r
868         RVc4 = (5703L * md_mixfreq) / (REVERBERATION * 10);\r
869         RVc5 = (6250L * md_mixfreq) / (REVERBERATION * 10);\r
870         RVc6 = (6953L * md_mixfreq) / (REVERBERATION * 10);\r
871         RVc7 = (7813L * md_mixfreq) / (REVERBERATION * 10);\r
872         RVc8 = (8828L * md_mixfreq) / (REVERBERATION * 10);\r
873 \r
874         if(!(RVbufL1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1;\r
875         if(!(RVbufL2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1;\r
876         if(!(RVbufL3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1;\r
877         if(!(RVbufL4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1;\r
878         if(!(RVbufL5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1;\r
879         if(!(RVbufL6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1;\r
880         if(!(RVbufL7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1;\r
881         if(!(RVbufL8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1;\r
882 \r
883         if(!(RVbufR1=(SLONG*)_mm_calloc((RVc1+1),sizeof(SLONG)))) return 1;\r
884         if(!(RVbufR2=(SLONG*)_mm_calloc((RVc2+1),sizeof(SLONG)))) return 1;\r
885         if(!(RVbufR3=(SLONG*)_mm_calloc((RVc3+1),sizeof(SLONG)))) return 1;\r
886         if(!(RVbufR4=(SLONG*)_mm_calloc((RVc4+1),sizeof(SLONG)))) return 1;\r
887         if(!(RVbufR5=(SLONG*)_mm_calloc((RVc5+1),sizeof(SLONG)))) return 1;\r
888         if(!(RVbufR6=(SLONG*)_mm_calloc((RVc6+1),sizeof(SLONG)))) return 1;\r
889         if(!(RVbufR7=(SLONG*)_mm_calloc((RVc7+1),sizeof(SLONG)))) return 1;\r
890         if(!(RVbufR8=(SLONG*)_mm_calloc((RVc8+1),sizeof(SLONG)))) return 1;\r
891 \r
892         RVRindex = 0;\r
893         return 0;\r
894 }\r
895 \r
896 void VC2_PlayStop(void)\r
897 {\r
898         if(RVbufL1) free(RVbufL1);\r
899         if(RVbufL2) free(RVbufL2);\r
900         if(RVbufL3) free(RVbufL3);\r
901         if(RVbufL4) free(RVbufL4);\r
902         if(RVbufL5) free(RVbufL5);\r
903         if(RVbufL6) free(RVbufL6);\r
904         if(RVbufL7) free(RVbufL7);\r
905         if(RVbufL8) free(RVbufL8);\r
906         if(RVbufR1) free(RVbufR1);\r
907         if(RVbufR2) free(RVbufR2);\r
908         if(RVbufR3) free(RVbufR3);\r
909         if(RVbufR4) free(RVbufR4);\r
910         if(RVbufR5) free(RVbufR5);\r
911         if(RVbufR6) free(RVbufR6);\r
912         if(RVbufR7) free(RVbufR7);\r
913         if(RVbufR8) free(RVbufR8);\r
914 \r
915         RVbufL1=RVbufL2=RVbufL3=RVbufL4=RVbufL5=RVbufL6=RVbufL7=RVbufL8=NULL;\r
916         RVbufR1=RVbufR2=RVbufR3=RVbufR4=RVbufR5=RVbufR6=RVbufR7=RVbufR8=NULL;\r
917 }\r
918 \r
919 BOOL VC2_SetNumVoices(void)\r
920 {\r
921         int t;\r
922 \r
923         md_mode|=DMODE_INTERP;\r
924 \r
925         if(!(vc_softchn=md_softchn)) return 0;\r
926 \r
927         if(vinf) free(vinf);\r
928         if(!(vinf=_mm_calloc(sizeof(VINFO),vc_softchn))) return 1;\r
929 \r
930         for(t=0;t<vc_softchn;t++) {\r
931                 vinf[t].frq=10000;\r
932                 vinf[t].pan=(t&1)?PAN_LEFT:PAN_RIGHT;\r
933         }\r
934 \r
935         return 0;\r
936 }\r
937 \r
938 /* ex:set ts=4: */\r