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