1 /* MikMod sound library
\r
2 (c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
\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: virtch2.c,v 1.2 2004/02/13 13:31:54 raph Exp $
\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
29 ==============================================================================*/
\r
34 Low-Pass filter to remove annoying staticy buzz.
\r
38 #ifdef HAVE_CONFIG_H
\r
42 #ifdef HAVE_MEMORY_H
\r
47 #include "mikmod_internals.h"
\r
50 Constant Definitions
\r
51 ====================
\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
60 Larger numbers result in shorter reverb duration. Longer reverb
\r
61 durations can cause unwanted static and make the reverb sound more
\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
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
75 !!! IMPORTANT !!! All values below MUST ALWAYS be greater than 0
\r
79 #define MAXVOL_FACTOR (1<<9)
\r
80 #define REVERBERATION 11000L
\r
82 #define SAMPLING_SHIFT 2
\r
83 #define SAMPLING_FACTOR (1UL<<SAMPLING_SHIFT)
\r
86 #define FRACMASK ((1UL<<FRACBITS)-1UL)
\r
88 #define TICKLSIZE 8192
\r
89 #define TICKWSIZE (TICKLSIZE * 2)
\r
90 #define TICKBSIZE (TICKWSIZE * 2)
\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
97 #define MIN(a,b) (((a)<(b)) ? (a) : (b))
\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
115 SLONG lastvalL,lastvalR;
\r
116 int lvolsel,rvolsel; /* Volume factor in range 0-255 */
\r
117 int oldlvol,oldrvol;
\r
119 SLONGLONG current; /* current index in the sample */
\r
120 SLONGLONG increment; /* increment value */
\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
131 /* Reverb control variables */
\r
133 static int RVc1, RVc2, RVc3, RVc4, RVc5, RVc6, RVc7, RVc8;
\r
134 static ULONG RVRindex;
\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
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
144 #ifdef NATIVE_64BIT_INT
\r
145 #define NATIVE SLONGLONG
\r
147 #define NATIVE SLONG
\r
150 /*========== 32 bit sample mixers - only for 32 bit platforms */
\r
151 #ifndef NATIVE_64BIT_INT
\r
153 static SLONG Mix32MonoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,SLONG 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
166 ( ( (SLONG)(vnf->oldlvol*vnf->rampvol) +
\r
167 (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *
\r
168 (SLONG)sample ) >> CLICK_SHIFT );
\r
173 ( ( ((SLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
\r
175 (vnf->lastvalL*vnf->click) ) >> CLICK_SHIFT );
\r
178 *dest++ +=vnf->lvolsel*sample;
\r
180 vnf->lastvalL=vnf->lvolsel * sample;
\r
185 static SLONG Mix32StereoNormal(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,ULONG 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
198 ( ( ((SLONG)vnf->oldlvol*vnf->rampvol) +
\r
199 (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol))
\r
200 ) * (SLONG)sample ) >> CLICK_SHIFT );
\r
202 ( ( ((SLONG)vnf->oldrvol*vnf->rampvol) +
\r
203 (vnf->rvolsel*(CLICK_BUFFER-vnf->rampvol))
\r
204 ) * (SLONG)sample ) >> CLICK_SHIFT );
\r
209 ( ( (SLONG)(vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
\r
210 (SLONG)sample ) + (vnf->lastvalL * vnf->click) )
\r
213 ( ( ((SLONG)vnf->rvolsel*(CLICK_BUFFER-vnf->click)) *
\r
214 (SLONG)sample ) + (vnf->lastvalR * vnf->click) )
\r
218 *dest++ +=vnf->lvolsel*sample;
\r
219 *dest++ +=vnf->rvolsel*sample;
\r
222 vnf->lastvalL=vnf->lvolsel*sample;
\r
223 vnf->lastvalR=vnf->rvolsel*sample;
\r
228 static SLONG Mix32StereoSurround(SWORD* srce,SLONG* dest,SLONG index,SLONG increment,ULONG 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
242 ( ( (SLONG)(vnf->oldlvol*vnf->rampvol) +
\r
243 (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *
\r
244 (SLONG)sample) >> CLICK_SHIFT );
\r
251 ( ( ((SLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
\r
253 (vnf->lastvalL * vnf->click) ) >> CLICK_SHIFT );
\r
258 *dest++ +=vnf->lvolsel*sample;
\r
259 *dest++ -=vnf->lvolsel*sample;
\r
262 vnf->lastvalL=vnf->lvolsel*sample;
\r
263 vnf->lastvalR=vnf->lvolsel*sample;
\r
269 /*========== 64 bit mixers */
\r
271 static SLONGLONG MixMonoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,SLONG 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
284 ( ( (SLONGLONG)(vnf->oldlvol*vnf->rampvol) +
\r
285 (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *
\r
286 (SLONGLONG)sample ) >> CLICK_SHIFT );
\r
291 ( ( ((SLONGLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
\r
292 (SLONGLONG)sample ) +
\r
293 (vnf->lastvalL*vnf->click) ) >> CLICK_SHIFT );
\r
296 *dest++ +=vnf->lvolsel*sample;
\r
298 vnf->lastvalL=vnf->lvolsel * sample;
\r
303 static SLONGLONG MixStereoNormal(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,ULONG 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
316 ( ( ((SLONGLONG)vnf->oldlvol*vnf->rampvol) +
\r
317 (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol))
\r
318 ) * (SLONGLONG)sample ) >> CLICK_SHIFT );
\r
320 ( ( ((SLONGLONG)vnf->oldrvol*vnf->rampvol) +
\r
321 (vnf->rvolsel*(CLICK_BUFFER-vnf->rampvol))
\r
322 ) * (SLONGLONG)sample ) >> CLICK_SHIFT );
\r
327 ( ( (SLONGLONG)(vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
\r
328 (SLONGLONG)sample ) + (vnf->lastvalL * vnf->click) )
\r
331 ( ( ((SLONGLONG)vnf->rvolsel*(CLICK_BUFFER-vnf->click)) *
\r
332 (SLONGLONG)sample ) + (vnf->lastvalR * vnf->click) )
\r
336 *dest++ +=vnf->lvolsel*sample;
\r
337 *dest++ +=vnf->rvolsel*sample;
\r
340 vnf->lastvalL=vnf->lvolsel*sample;
\r
341 vnf->lastvalR=vnf->rvolsel*sample;
\r
346 static SLONGLONG MixStereoSurround(SWORD* srce,SLONG* dest,SLONGLONG index,SLONGLONG increment,ULONG 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
360 ( ( (SLONGLONG)(vnf->oldlvol*vnf->rampvol) +
\r
361 (vnf->lvolsel*(CLICK_BUFFER-vnf->rampvol)) ) *
\r
362 (SLONGLONG)sample) >> CLICK_SHIFT );
\r
369 ( ( ((SLONGLONG)vnf->lvolsel*(CLICK_BUFFER-vnf->click)) *
\r
370 (SLONGLONG)sample) +
\r
371 (vnf->lastvalL * vnf->click) ) >> CLICK_SHIFT );
\r
376 *dest++ +=vnf->lvolsel*sample;
\r
377 *dest++ -=vnf->lvolsel*sample;
\r
380 vnf->lastvalL=vnf->lvolsel*sample;
\r
381 vnf->lastvalR=vnf->lvolsel*sample;
\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
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
396 static void MixReverb_Normal(SLONG* srce,NATIVE count)
\r
400 unsigned int loc1,loc2,loc3,loc4,loc5,loc6,loc7,loc8;
\r
402 ReverbPct=58+(md_reverb*4);
\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
408 /* Compute the left channel echo buffers */
\r
409 speedup = *srce >> 3;
\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
414 /* Prepare to compute actual finalized data */
\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
421 *srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+
\r
422 RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];
\r
426 static void MixReverb_Stereo(SLONG *srce,NATIVE count)
\r
430 unsigned int loc1,loc2,loc3,loc4,loc5,loc6,loc7,loc8;
\r
432 ReverbPct=58+(md_reverb*4);
\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
438 /* Compute the left channel echo buffers */
\r
439 speedup = *srce >> 3;
\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
444 /* Compute the right channel echo buffers */
\r
445 speedup = srce[1] >> 3;
\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
450 /* Prepare to compute actual finalized data */
\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
457 *srce++ +=RVbufL1[loc1]-RVbufL2[loc2]+RVbufL3[loc3]-RVbufL4[loc4]+
\r
458 RVbufL5[loc5]-RVbufL6[loc6]+RVbufL7[loc7]-RVbufL8[loc8];
\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
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
470 static void Mix32ToFP_Normal(float* dste,SLONG* srce,NATIVE count)
\r
475 for(count/=SAMPLING_FACTOR;count;count--) {
\r
478 for(i=SAMPLING_FACTOR/2;i;i--) {
\r
479 EXTRACT_SAMPLE_FP(x1,1.0f); EXTRACT_SAMPLE_FP(x2,1.0f);
\r
481 CHECK_SAMPLE_FP(x1,1.0f); CHECK_SAMPLE_FP(x2,1.0f);
\r
485 *dste++ =tmpx*(1.0f/SAMPLING_FACTOR);
\r
489 static void Mix32ToFP_Stereo(float* dste,SLONG* srce,NATIVE count)
\r
491 float x1,x2,x3,x4,tmpx,tmpy;
\r
494 for(count/=SAMPLING_FACTOR;count;count--) {
\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
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
507 *dste++ =tmpx*(1.0f/SAMPLING_FACTOR);
\r
508 *dste++ =tmpy*(1.0f/SAMPLING_FACTOR);
\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
516 static void Mix32To16_Normal(SWORD* dste,SLONG* srce,NATIVE count)
\r
521 for(count/=SAMPLING_FACTOR;count;count--) {
\r
524 for(i=SAMPLING_FACTOR/2;i;i--) {
\r
525 EXTRACT_SAMPLE(x1,1); EXTRACT_SAMPLE(x2,1);
\r
527 CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768);
\r
531 *dste++ =tmpx/SAMPLING_FACTOR;
\r
535 static void Mix32To16_Stereo(SWORD* dste,SLONG* srce,NATIVE count)
\r
537 NATIVE x1,x2,x3,x4,tmpx,tmpy;
\r
540 for(count/=SAMPLING_FACTOR;count;count--) {
\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
547 CHECK_SAMPLE(x1,32768); CHECK_SAMPLE(x2,32768);
\r
548 CHECK_SAMPLE(x3,32768); CHECK_SAMPLE(x4,32768);
\r
553 *dste++ =tmpx/SAMPLING_FACTOR;
\r
554 *dste++ =tmpy/SAMPLING_FACTOR;
\r
558 static void Mix32To8_Normal(SBYTE* dste,SLONG* srce,NATIVE count)
\r
563 for(count/=SAMPLING_FACTOR;count;count--) {
\r
566 for(i=SAMPLING_FACTOR/2;i;i--) {
\r
567 EXTRACT_SAMPLE(x1,256); EXTRACT_SAMPLE(x2,256);
\r
569 CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128);
\r
573 *dste++ =(tmpx/SAMPLING_FACTOR)+128;
\r
577 static void Mix32To8_Stereo(SBYTE* dste,SLONG* srce,NATIVE count)
\r
579 NATIVE x1,x2,x3,x4,tmpx,tmpy;
\r
582 for(count/=SAMPLING_FACTOR;count;count--) {
\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
589 CHECK_SAMPLE(x1,128); CHECK_SAMPLE(x2,128);
\r
590 CHECK_SAMPLE(x3,128); CHECK_SAMPLE(x4,128);
\r
595 *dste++ =(tmpx/SAMPLING_FACTOR)+128;
\r
596 *dste++ =(tmpy/SAMPLING_FACTOR)+128;
\r
600 static void AddChannel(SLONG* ptr,NATIVE todo)
\r
602 SLONGLONG end,done;
\r
605 if(!(s=Samples[vnf->handle])) {
\r
606 vnf->current = vnf->active = 0;
\r
607 vnf->lastvalL = vnf->lastvalR = 0;
\r
611 /* update the 'current' index so the sample loops, or stops playing if it
\r
612 reached the end of the sample */
\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
627 /* normal backwards looping, so set the current position to
\r
629 vnf->current=idxlend-(idxlpos-vnf->current);
\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
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
650 /* normal backwards looping, so set the current position
\r
651 to loopend index */
\r
652 vnf->current=idxlpos+(vnf->current-idxlend);
\r
654 /* sample is not looping, so check if it reached the last
\r
656 if(vnf->current >= idxsize) {
\r
657 /* yes, so stop playing this sample */
\r
658 vnf->current = vnf->active = 0;
\r
664 end=(vnf->flags&SF_REVERSE)?(vnf->flags&SF_LOOP)?idxlpos:0:
\r
665 (vnf->flags&SF_LOOP)?idxlend:idxsize;
\r
667 /* if the sample is not blocked... */
\r
668 if((end==vnf->current)||(!vnf->increment))
\r
671 done=MIN((end-vnf->current)/vnf->increment+1,todo);
\r
680 endpos=vnf->current+done*vnf->increment;
\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
691 vnf->current=Mix32StereoNormal
\r
692 (s,ptr,vnf->current,vnf->increment,done);
\r
694 vnf->current=Mix32MonoNormal
\r
695 (s,ptr,vnf->current,vnf->increment,done);
\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
704 vnf->current=MixStereoNormal
\r
705 (s,ptr,vnf->current,vnf->increment,done);
\r
707 vnf->current=MixMonoNormal
\r
708 (s,ptr,vnf->current,vnf->increment,done);
\r
711 vnf->lastvalL = vnf->lastvalR = 0;
\r
712 /* update sample position */
\r
713 vnf->current=endpos;
\r
717 ptr +=(vc_mode & DMODE_STEREO)?(done<<1):done;
\r
721 #define _IN_VIRTCH_
\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
743 #include "virtch_common.c"
\r
746 void VC2_WriteSamples(SBYTE* buf,ULONG todo)
\r
748 int left,portion=0;
\r
752 todo*=SAMPLING_FACTOR;
\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
760 left = MIN(tickleft, todo);
\r
764 buf += samples2bytes(left)/SAMPLING_FACTOR;
\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
773 vnf->current=((SLONGLONG)(vnf->start))<<FRACBITS;
\r
776 vnf->click = CLICK_BUFFER;
\r
780 if(!vnf->frq) vnf->active = 0;
\r
783 vnf->increment=((SLONGLONG)(vnf->frq)<<(FRACBITS-SAMPLING_SHIFT))
\r
785 if(vnf->flags&SF_REVERSE) vnf->increment=-vnf->increment;
\r
786 vol = vnf->vol; pan = vnf->pan;
\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
794 vnf->lvolsel=vnf->rvolsel=(vol * 256L) / 480;
\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
807 if(md_reverb>15) md_reverb=15;
\r
808 MixReverb(vc_tickbuf,portion);
\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
816 Mix32to8((SBYTE*)buffer,vc_tickbuf,portion);
\r
818 buffer += samples2bytes(portion) / SAMPLING_FACTOR;
\r
824 BOOL VC2_Init(void)
\r
826 VC_SetupPointers();
\r
828 if (!(md_mode&DMODE_HQMIXER))
\r
831 if(!(Samples=(SWORD**)_mm_calloc(MAXSAMPLEHANDLES,sizeof(SWORD*)))) {
\r
832 _mm_errno = MMERR_INITIALIZING_MIXER;
\r
836 if(!(vc_tickbuf=(SLONG*)_mm_malloc((TICKLSIZE+32)*sizeof(SLONG)))) {
\r
837 _mm_errno = MMERR_INITIALIZING_MIXER;
\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
847 Mix32toFP = Mix32ToFP_Normal;
\r
848 Mix32to16 = Mix32To16_Normal;
\r
849 Mix32to8 = Mix32To8_Normal;
\r
850 MixReverb = MixReverb_Normal;
\r
852 md_mode |= DMODE_INTERP;
\r
857 BOOL VC2_PlayStart(void)
\r
859 md_mode|=DMODE_INTERP;
\r
861 samplesthatfit = TICKLSIZE;
\r
862 if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1;
\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
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
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
896 void VC2_PlayStop(void)
\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
915 RVbufL1=RVbufL2=RVbufL3=RVbufL4=RVbufL5=RVbufL6=RVbufL7=RVbufL8=NULL;
\r
916 RVbufR1=RVbufR2=RVbufR3=RVbufR4=RVbufR5=RVbufR6=RVbufR7=RVbufR8=NULL;
\r
919 BOOL VC2_SetNumVoices(void)
\r
923 md_mode|=DMODE_INTERP;
\r
925 if(!(vc_softchn=md_softchn)) return 0;
\r
927 if(vinf) free(vinf);
\r
928 if(!(vinf=_mm_calloc(sizeof(VINFO),vc_softchn))) return 1;
\r
930 for(t=0;t<vc_softchn;t++) {
\r
932 vinf[t].pan=(t&1)?PAN_LEFT:PAN_RIGHT;
\r