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
5 This library is free software; you can redistribute it and/or modify
\r
6 it under the terms of the GNU Library General Public License as
\r
7 published by the Free Software Foundation; either version 2 of
\r
8 the License, or (at your option) any later version.
\r
10 This program is distributed in the hope that it will be useful,
\r
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 GNU Library General Public License for more details.
\r
15 You should have received a copy of the GNU Library General Public
\r
16 License along with this library; if not, write to the Free Software
\r
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
\r
21 /*==============================================================================
\r
23 $Id: virtch.c,v 1.2 2004/02/13 13:31:54 raph Exp $
\r
25 Sample mixing routines, using a 32 bits mixing buffer.
\r
27 ==============================================================================*/
\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
37 #ifdef HAVE_CONFIG_H
\r
42 #ifdef HAVE_MEMORY_H
\r
47 #include "mikmod_internals.h"
\r
50 Constant definitions
\r
51 ====================
\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
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
66 #define REVERBERATION 110000L
\r
69 #define FRACMASK ((1L<<FRACBITS)-1L)
\r
71 #define TICKLSIZE 8192
\r
72 #define TICKWSIZE (TICKLSIZE<<1)
\r
73 #define TICKBSIZE (TICKWSIZE<<1)
\r
75 #define CLICK_SHIFT 6
\r
76 #define CLICK_BUFFER (1L<<CLICK_SHIFT)
\r
79 #define MIN(a,b) (((a)<(b)) ? (a) : (b))
\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
96 int lvolsel,rvolsel; /* Volume factor in range 0-255 */
\r
97 int oldlvol,oldrvol;
\r
99 SLONGLONG current; /* current index in the sample */
\r
100 SLONGLONG increment; /* increment value */
\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
111 /* Reverb control variables */
\r
113 static int RVc1, RVc2, RVc3, RVc4, RVc5, RVc6, RVc7, RVc8;
\r
114 static ULONG RVRindex;
\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
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
124 #ifdef NATIVE_64BIT_INT
\r
125 #define NATIVE SLONGLONG
\r
127 #define NATIVE SLONG
\r
130 /*========== 32 bit sample mixers - only for 32 bit platforms */
\r
131 #ifndef NATIVE_64BIT_INT
\r
133 static SLONG Mix32MonoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
\r
136 SLONG lvolsel = vnf->lvolsel;
\r
139 sample = srce[index >> FRACBITS];
\r
140 index += increment;
\r
142 *dest++ += lvolsel * sample;
\r
147 static SLONG Mix32StereoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
\r
150 SLONG lvolsel = vnf->lvolsel;
\r
151 SLONG rvolsel = vnf->rvolsel;
\r
154 sample=srce[index >> FRACBITS];
\r
155 index += increment;
\r
157 *dest++ += lvolsel * sample;
\r
158 *dest++ += rvolsel * sample;
\r
163 static SLONG Mix32SurroundNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
\r
166 SLONG lvolsel = vnf->lvolsel;
\r
167 SLONG rvolsel = vnf->rvolsel;
\r
169 if (lvolsel>=rvolsel) {
\r
171 sample = srce[index >> FRACBITS];
\r
172 index += increment;
\r
174 *dest++ += lvolsel*sample;
\r
175 *dest++ -= lvolsel*sample;
\r
179 sample = srce[index >> FRACBITS];
\r
180 index += increment;
\r
182 *dest++ -= rvolsel*sample;
\r
183 *dest++ += rvolsel*sample;
\r
189 static SLONG Mix32MonoInterp(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
\r
192 SLONG lvolsel = vnf->lvolsel;
\r
193 SLONG rampvol = vnf->rampvol;
\r
196 SLONG oldlvol = vnf->oldlvol - lvolsel;
\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
203 *dest++ += ((lvolsel << CLICK_SHIFT) + oldlvol * rampvol)
\r
204 * sample >> CLICK_SHIFT;
\r
208 vnf->rampvol = rampvol;
\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
219 *dest++ += lvolsel * sample;
\r
224 static SLONG Mix32StereoInterp(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
\r
227 SLONG lvolsel = vnf->lvolsel;
\r
228 SLONG rvolsel = vnf->rvolsel;
\r
229 SLONG rampvol = vnf->rampvol;
\r
232 SLONG oldlvol = vnf->oldlvol - lvolsel;
\r
233 SLONG oldrvol = vnf->oldrvol - rvolsel;
\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
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
247 vnf->rampvol = rampvol;
\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
258 *dest++ += lvolsel * sample;
\r
259 *dest++ += rvolsel * sample;
\r
264 static SLONG Mix32SurroundInterp(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG todo)
\r
267 SLONG lvolsel = vnf->lvolsel;
\r
268 SLONG rvolsel = vnf->rvolsel;
\r
269 SLONG rampvol = vnf->rampvol;
\r
272 if (lvolsel >= rvolsel) {
\r
274 oldvol = vnf->oldlvol;
\r
277 oldvol = vnf->oldrvol;
\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
288 sample=((vol << CLICK_SHIFT) + oldvol * rampvol)
\r
289 * sample >> CLICK_SHIFT;
\r
296 vnf->rampvol = rampvol;
\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
307 *dest++ += vol*sample;
\r
308 *dest++ -= vol*sample;
\r
314 /*========== 64 bit sample mixers - all platforms */
\r
316 static SLONGLONG MixMonoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
\r
319 SLONG lvolsel = vnf->lvolsel;
\r
322 sample = srce[index >> FRACBITS];
\r
323 index += increment;
\r
325 *dest++ += lvolsel * sample;
\r
330 static SLONGLONG MixStereoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
\r
333 SLONG lvolsel = vnf->lvolsel;
\r
334 SLONG rvolsel = vnf->rvolsel;
\r
337 sample=srce[index >> FRACBITS];
\r
338 index += increment;
\r
340 *dest++ += lvolsel * sample;
\r
341 *dest++ += rvolsel * sample;
\r
346 static SLONGLONG MixSurroundNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
\r
349 SLONG lvolsel = vnf->lvolsel;
\r
350 SLONG rvolsel = vnf->rvolsel;
\r
352 if(vnf->lvolsel>=vnf->rvolsel) {
\r
354 sample = srce[index >> FRACBITS];
\r
355 index += increment;
\r
357 *dest++ += lvolsel*sample;
\r
358 *dest++ -= lvolsel*sample;
\r
362 sample = srce[index >> FRACBITS];
\r
363 index += increment;
\r
365 *dest++ -= rvolsel*sample;
\r
366 *dest++ += rvolsel*sample;
\r
372 static SLONGLONG MixMonoInterp(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
\r
375 SLONG lvolsel = vnf->lvolsel;
\r
376 SLONG rampvol = vnf->rampvol;
\r
379 SLONG oldlvol = vnf->oldlvol - lvolsel;
\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
386 *dest++ += ((lvolsel << CLICK_SHIFT) + oldlvol * rampvol)
\r
387 * sample >> CLICK_SHIFT;
\r
391 vnf->rampvol = rampvol;
\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
402 *dest++ += lvolsel * sample;
\r
407 static SLONGLONG MixStereoInterp(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
\r
410 SLONG lvolsel = vnf->lvolsel;
\r
411 SLONG rvolsel = vnf->rvolsel;
\r
412 SLONG rampvol = vnf->rampvol;
\r
415 SLONG oldlvol = vnf->oldlvol - lvolsel;
\r
416 SLONG oldrvol = vnf->oldrvol - rvolsel;
\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
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
430 vnf->rampvol = rampvol;
\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
441 *dest++ += lvolsel * sample;
\r
442 *dest++ += rvolsel * sample;
\r
447 static SLONGLONG MixSurroundInterp(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG todo)
\r
450 SLONG lvolsel = vnf->lvolsel;
\r
451 SLONG rvolsel = vnf->rvolsel;
\r
452 SLONG rampvol = vnf->rampvol;
\r
455 if (lvolsel >= rvolsel) {
\r
457 oldvol = vnf->oldlvol;
\r
460 oldvol = vnf->oldrvol;
\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
471 sample=((vol << CLICK_SHIFT) + oldvol * rampvol)
\r
472 * sample >> CLICK_SHIFT;
\r
478 vnf->rampvol = rampvol;
\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
489 *dest++ += vol*sample;
\r
490 *dest++ -= vol*sample;
\r
495 static void (*MixReverb)(SLONG* srce,NATIVE count);
\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
502 static void MixReverb_Normal(SLONG* srce,NATIVE count)
\r
504 unsigned int speedup;
\r
506 unsigned int loc1,loc2,loc3,loc4;
\r
507 unsigned int loc5,loc6,loc7,loc8;
\r
509 ReverbPct=58+(md_reverb<<2);
\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
515 /* Compute the left channel echo buffers */
\r
516 speedup = *srce >> 3;
\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
521 /* Prepare to compute actual finalized data */
\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
528 *srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+
\r
529 RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];
\r
533 static void MixReverb_Stereo(SLONG* srce,NATIVE count)
\r
535 unsigned int speedup;
\r
537 unsigned int loc1, loc2, loc3, loc4;
\r
538 unsigned int loc5, loc6, loc7, loc8;
\r
540 ReverbPct = 92+(md_reverb<<1);
\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
546 /* Compute the left channel echo buffers */
\r
547 speedup = *srce >> 3;
\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
552 /* Compute the right channel echo buffers */
\r
553 speedup = srce[1] >> 3;
\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
558 /* Prepare to compute actual finalized data */
\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
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
568 *srce++ +=RVbufR1[loc1]-RVbufR2[loc2]+RVbufR3[loc3]-RVbufR4[loc4]+
\r
569 RVbufR5[loc5]-RVbufR6[loc6]+RVbufR7[loc7]-RVbufR8[loc8];
\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
578 static void Mix32ToFP(float* dste,SLONG* srce,NATIVE count)
\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
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
593 PUT_SAMPLE_FP(x1); PUT_SAMPLE_FP(x2);
\r
594 PUT_SAMPLE_FP(x3); PUT_SAMPLE_FP(x4);
\r
597 EXTRACT_SAMPLE_FP(x1,FP_SHIFT);
\r
598 CHECK_SAMPLE_FP(x1,1.0f);
\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
609 static void Mix32To16(SWORD* dste,SLONG* srce,NATIVE count)
\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
619 CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768);
\r
620 CHECK_SAMPLE(x3,32768); CHECK_SAMPLE(x4,32768);
\r
622 PUT_SAMPLE(x1); PUT_SAMPLE(x2); PUT_SAMPLE(x3); PUT_SAMPLE(x4);
\r
625 EXTRACT_SAMPLE(x1,16);
\r
626 CHECK_SAMPLE(x1,32768);
\r
631 static void Mix32To8(SBYTE* dste,SLONG* srce,NATIVE count)
\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
641 CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128);
\r
642 CHECK_SAMPLE(x3,128); CHECK_SAMPLE(x4,128);
\r
644 PUT_SAMPLE(x1+128); PUT_SAMPLE(x2+128);
\r
645 PUT_SAMPLE(x3+128); PUT_SAMPLE(x4+128);
\r
648 EXTRACT_SAMPLE(x1,8);
\r
649 CHECK_SAMPLE(x1,128);
\r
650 PUT_SAMPLE(x1+128);
\r
654 static void AddChannel(SLONG* ptr,NATIVE todo)
\r
656 SLONGLONG end,done;
\r
659 if(!(s=Samples[vnf->handle])) {
\r
660 vnf->current = vnf->active = 0;
\r
664 /* update the 'current' index so the sample loops, or stops playing if it
\r
665 reached the end of the sample */
\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
680 /* normal backwards looping, so set the current position to
\r
682 vnf->current=idxlend-(idxlpos-vnf->current);
\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
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
703 /* normal backwards looping, so set the current position
\r
704 to loopend index */
\r
705 vnf->current=idxlpos+(vnf->current-idxlend);
\r
707 /* sample is not looping, so check if it reached the last
\r
709 if(vnf->current >= idxsize) {
\r
710 /* yes, so stop playing this sample */
\r
711 vnf->current = vnf->active = 0;
\r
717 end=(vnf->flags&SF_REVERSE)?(vnf->flags&SF_LOOP)?idxlpos:0:
\r
718 (vnf->flags&SF_LOOP)?idxlend:idxsize;
\r
720 /* if the sample is not blocked... */
\r
721 if((end==vnf->current)||(!vnf->increment))
\r
724 done=MIN((end-vnf->current)/vnf->increment+1,todo);
\r
733 endpos=vnf->current+done*vnf->increment;
\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
745 vnf->current=Mix32StereoInterp
\r
746 (s,ptr,vnf->current,vnf->increment,done);
\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
755 vnf->current=Mix32StereoNormal
\r
756 (s,ptr,vnf->current,vnf->increment,done);
\r
758 vnf->current=Mix32MonoNormal
\r
759 (s,ptr,vnf->current,vnf->increment,done);
\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
769 vnf->current=MixStereoInterp
\r
770 (s,ptr,vnf->current,vnf->increment,done);
\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
779 vnf->current=MixStereoNormal
\r
780 (s,ptr,vnf->current,vnf->increment,done);
\r
782 vnf->current=MixMonoNormal
\r
783 (s,ptr,vnf->current,vnf->increment,done);
\r
786 /* update sample position */
\r
787 vnf->current=endpos;
\r
790 ptr +=(vc_mode & DMODE_STEREO)?(done<<1):done;
\r
794 #define _IN_VIRTCH_
\r
795 #include "virtch_common.c"
\r
798 void VC1_WriteSamples(SBYTE* buf,ULONG todo)
\r
800 int left,portion=0,count;
\r
806 if(vc_mode & DMODE_SOFT_MUSIC) md_player();
\r
807 tickleft=(md_mixfreq*125L)/(md_bpm*50L);
\r
809 left = MIN(tickleft, todo);
\r
813 buf += samples2bytes(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
823 vnf->current=((SLONGLONG)vnf->start)<<FRACBITS;
\r
828 if(!vnf->frq) vnf->active = 0;
\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
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
841 vnf->lvolsel=vnf->rvolsel=vol/2;
\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
853 if(md_reverb>15) md_reverb=15;
\r
854 MixReverb(vc_tickbuf, portion);
\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
862 Mix32To8((SBYTE*) buffer, vc_tickbuf, count);
\r
864 buffer += samples2bytes(portion);
\r
870 BOOL VC1_Init(void)
\r
872 VC_SetupPointers();
\r
874 if (md_mode&DMODE_HQMIXER)
\r
877 if(!(Samples=(SWORD**)_mm_calloc(MAXSAMPLEHANDLES,sizeof(SWORD*)))) {
\r
878 _mm_errno = MMERR_INITIALIZING_MIXER;
\r
882 if(!(vc_tickbuf=(SLONG*)_mm_malloc((TICKLSIZE+32)*sizeof(SLONG)))) {
\r
883 _mm_errno = MMERR_INITIALIZING_MIXER;
\r
887 MixReverb=(md_mode&DMODE_STEREO)?MixReverb_Stereo:MixReverb_Normal;
\r
892 BOOL VC1_PlayStart(void)
\r
894 samplesthatfit=TICKLSIZE;
\r
895 if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1;
\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
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
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
929 void VC1_PlayStop(void)
\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
951 BOOL VC1_SetNumVoices(void)
\r
955 if(!(vc_softchn=md_softchn)) return 0;
\r
957 if(vinf) free(vinf);
\r
958 if(!(vinf= _mm_calloc(sizeof(VINFO),vc_softchn))) return 1;
\r
960 for(t=0;t<vc_softchn;t++) {
\r
962 vinf[t].pan=(t&1)?PAN_LEFT:PAN_RIGHT;
\r