]> 4ch.mooo.com Git - 16.git/blob - 16/adplug/adplug-2.2.1/src/adlibemu.c
Please enter the commit message for your changes. Lines starting
[16.git] / 16 / adplug / adplug-2.2.1 / src / adlibemu.c
1 /*
2  * ADLIBEMU.C
3  * Copyright (C) 1998-2001 Ken Silverman
4  * Ken Silverman's official web site: "http://www.advsys.net/ken"
5  * 
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  * 
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  * 
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 /*
22 This file is a digital Adlib emulator for OPL2 and possibly OPL3
23
24 Features that could be added in a future version:
25 - Amplitude and Frequency Vibrato Bits (not hard, but a big speed hit)
26 - Global Keyboard Split Number Bit (need to research this one some more)
27 - 2nd Adlib chip for OPL3 (simply need to make my cell array bigger)
28 - Advanced connection modes of OPL3 (Just need to add more "docell" cases)
29 - L/R Stereo bits of OPL3 (Need adlibgetsample to return stereo)
30
31 Features that aren't worth supporting:
32 - Anything related to adlib timers&interrupts (Sorry - I always used IRQ0)
33 - Composite sine wave mode (CSM) (Supported only on ancient cards)
34
35 I'm not sure about a few things in my code:
36 - Attack curve.  What function is this anyway?  I chose to use an order-3
37   polynomial to approximate but this doesn't seem right.
38 - Attack/Decay/Release constants - my constants may not be exact
39 - What should ADJUSTSPEED be?
40 - Haven't verified that Global Keyboard Split Number Bit works yet
41 - Some of the drums don't always sound right.  It's pretty hard to guess
42   the exact waveform of drums when you look at random data which is
43   slightly randomized due to digital ADC recording.
44 - Adlib seems to have a lot more treble than my emulator does.  I'm not
45   sure if this is simply unfixable due to the sound blaster's different
46   filtering on FM and digital playback or if it's a serious bug in my
47   code.
48 */
49
50 #include <math.h>
51 #include <string.h>
52
53 #if !defined(max) && !defined(__cplusplus)
54 #define max(a,b)  (((a) > (b)) ? (a) : (b))
55 #endif
56 #if !defined(min) && !defined(__cplusplus)
57 #define min(a,b)  (((a) < (b)) ? (a) : (b))
58 #endif
59
60 #define PI 3.141592653589793
61 #define MAXCELLS 18
62 #define WAVPREC 2048
63
64 static float AMPSCALE=(8192.0);
65 #define FRQSCALE (49716/512.0)
66
67 //Constants for Ken's Awe32, on a PII-266 (Ken says: Use these for KSM's!)
68 #define MODFACTOR 4.0      //How much of modulator cell goes into carrier
69 #define MFBFACTOR 1.0      //How much feedback goes back into modulator
70 #define ADJUSTSPEED 0.75   //0<=x<=1  Simulate finite rate of change of state
71
72 //Constants for Ken's Awe64G, on a P-133
73 //#define MODFACTOR 4.25   //How much of modulator cell goes into carrier
74 //#define MFBFACTOR 0.5    //How much feedback goes back into modulator
75 //#define ADJUSTSPEED 0.85 //0<=x<=1  Simulate finite rate of change of state
76
77 typedef struct
78 {
79     float val, t, tinc, vol, sustain, amp, mfb;
80     float a0, a1, a2, a3, decaymul, releasemul;
81     short *waveform;
82     long wavemask;
83     void (*cellfunc)(void *, float);
84     unsigned char flags, dum0, dum1, dum2;
85 } celltype;
86
87 static long numspeakers, bytespersample;
88 static float recipsamp;
89 static celltype cell[MAXCELLS];
90 static signed short wavtable[WAVPREC*3];
91 static float kslmul[4] = {0.0,0.5,0.25,1.0};
92 static float frqmul[16] = {.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15}, nfrqmul[16];
93 static unsigned char adlibreg[256], ksl[8][16];
94 static unsigned char modulatorbase[9] = {0,1,2,8,9,10,16,17,18};
95 static unsigned char odrumstat = 0;
96 static unsigned char base2cell[22] = {0,1,2,0,1,2,0,0,3,4,5,3,4,5,0,0,6,7,8,6,7,8};
97
98 float lvol[9] = {1,1,1,1,1,1,1,1,1};  //Volume multiplier on left speaker
99 float rvol[9] = {1,1,1,1,1,1,1,1,1};  //Volume multiplier on right speaker
100 long lplc[9] = {0,0,0,0,0,0,0,0,0};   //Samples to delay on left speaker
101 long rplc[9] = {0,0,0,0,0,0,0,0,0};   //Samples to delay on right speaker
102
103 long nlvol[9], nrvol[9];
104 long nlplc[9], nrplc[9];
105 long rend = 0;
106 #define FIFOSIZ 256
107 static float *rptr[9], *nrptr[9];
108 static float rbuf[9][FIFOSIZ*2];
109 static float snd[FIFOSIZ*2];
110
111 #ifndef USING_ASM
112 #define _inline
113 #endif
114
115 #ifdef USING_ASM
116 static _inline void ftol (float f, long *a)
117 {
118     _asm
119         {
120             mov eax, a
121                 fld f
122                 fistp dword ptr [eax]
123                 }
124 }
125 #else
126 static void ftol(float f, long *a) {
127     *a=f;
128 }
129 #endif
130
131 #define ctc ((celltype *)c)      //A rare attempt to make code easier to read!
132 void docell4 (void *c, float modulator) { }
133 void docell3 (void *c, float modulator)
134 {
135     long i;
136
137     ftol(ctc->t+modulator,&i);
138     ctc->t += ctc->tinc;
139     ctc->val += (ctc->amp*ctc->vol*((float)ctc->waveform[i&ctc->wavemask])-ctc->val)*ADJUSTSPEED;
140 }
141 void docell2 (void *c, float modulator)
142 {
143     long i;
144
145     ftol(ctc->t+modulator,&i);
146
147     if (*(long *)&ctc->amp <= 0x37800000)
148     {
149         ctc->amp = 0;
150         ctc->cellfunc = docell4;
151     }
152     ctc->amp *= ctc->releasemul;
153
154     ctc->t += ctc->tinc;
155     ctc->val += (ctc->amp*ctc->vol*((float)ctc->waveform[i&ctc->wavemask])-ctc->val)*ADJUSTSPEED;
156 }
157 void docell1 (void *c, float modulator)
158 {
159     long i;
160
161     ftol(ctc->t+modulator,&i);
162
163     if ((*(long *)&ctc->amp) <= (*(long *)&ctc->sustain))
164     {
165         if (ctc->flags&32)
166         {
167             ctc->amp = ctc->sustain;
168             ctc->cellfunc = docell3;
169         }
170         else
171             ctc->cellfunc = docell2;
172     }
173     else
174         ctc->amp *= ctc->decaymul;
175
176     ctc->t += ctc->tinc;
177     ctc->val += (ctc->amp*ctc->vol*((float)ctc->waveform[i&ctc->wavemask])-ctc->val)*ADJUSTSPEED;
178 }
179 void docell0 (void *c, float modulator)
180 {
181     long i;
182
183     ftol(ctc->t+modulator,&i);
184
185     ctc->amp = ((ctc->a3*ctc->amp + ctc->a2)*ctc->amp + ctc->a1)*ctc->amp + ctc->a0;
186     if ((*(long *)&ctc->amp) > 0x3f800000)
187     {
188         ctc->amp = 1;
189         ctc->cellfunc = docell1;
190     }
191
192     ctc->t += ctc->tinc;
193     ctc->val += (ctc->amp*ctc->vol*((float)ctc->waveform[i&ctc->wavemask])-ctc->val)*ADJUSTSPEED;
194 }
195
196
197 static long waveform[8] = {WAVPREC,WAVPREC>>1,WAVPREC,(WAVPREC*3)>>2,0,0,(WAVPREC*5)>>2,WAVPREC<<1};
198 static long wavemask[8] = {WAVPREC-1,WAVPREC-1,(WAVPREC>>1)-1,(WAVPREC>>1)-1,WAVPREC-1,((WAVPREC*3)>>2)-1,WAVPREC>>1,WAVPREC-1};
199 static long wavestart[8] = {0,WAVPREC>>1,0,WAVPREC>>2,0,0,0,WAVPREC>>3};
200 static float attackconst[4] = {1/2.82624,1/2.25280,1/1.88416,1/1.59744};
201 static float decrelconst[4] = {1/39.28064,1/31.41608,1/26.17344,1/22.44608};
202 void cellon (long i, long j, celltype *c, unsigned char iscarrier)
203 {
204     long frn, oct, toff;
205     float f;
206
207     frn = ((((long)adlibreg[i+0xb0])&3)<<8) + (long)adlibreg[i+0xa0];
208     oct = ((((long)adlibreg[i+0xb0])>>2)&7);
209     toff = (oct<<1) + ((frn>>9)&((frn>>8)|(((adlibreg[8]>>6)&1)^1)));
210     if (!(adlibreg[j+0x20]&16)) toff >>= 2;
211
212     f = pow(2.0,(adlibreg[j+0x60]>>4)+(toff>>2)-1)*attackconst[toff&3]*recipsamp;
213     c->a0 = .0377*f; c->a1 = 10.73*f+1; c->a2 = -17.57*f; c->a3 = 7.42*f;
214     f = -7.4493*decrelconst[toff&3]*recipsamp;
215     c->decaymul = pow(2.0,f*pow(2.0,(adlibreg[j+0x60]&15)+(toff>>2)));
216     c->releasemul = pow(2.0,f*pow(2.0,(adlibreg[j+0x80]&15)+(toff>>2)));
217     c->wavemask = wavemask[adlibreg[j+0xe0]&7];
218     c->waveform = &wavtable[waveform[adlibreg[j+0xe0]&7]];
219     if (!(adlibreg[1]&0x20)) c->waveform = &wavtable[WAVPREC];
220     c->t = wavestart[adlibreg[j+0xe0]&7];
221     c->flags = adlibreg[j+0x20];
222     c->cellfunc = docell0;
223     c->tinc = (float)(frn<<oct)*nfrqmul[adlibreg[j+0x20]&15];
224     c->vol = pow(2.0,((float)(adlibreg[j+0x40]&63) +
225                       (float)kslmul[adlibreg[j+0x40]>>6]*ksl[oct][frn>>6]) * -.125 - 14);
226     c->sustain = pow(2.0,(float)(adlibreg[j+0x80]>>4) * -.5);
227     if (!iscarrier) c->amp = 0;
228     c->mfb = pow(2.0,((adlibreg[i+0xc0]>>1)&7)+5)*(WAVPREC/2048.0)*MFBFACTOR;
229     if (!(adlibreg[i+0xc0]&14)) c->mfb = 0;
230     c->val = 0;
231 }
232
233 //This function (and bug fix) written by Chris Moeller
234 void cellfreq (signed long i, signed long j, celltype *c)
235 {
236     long frn, oct;
237
238     frn = ((((long)adlibreg[i+0xb0])&3)<<8) + (long)adlibreg[i+0xa0];
239     oct = ((((long)adlibreg[i+0xb0])>>2)&7);
240
241     c->tinc = (float)(frn<<oct)*nfrqmul[adlibreg[j+0x20]&15];
242     c->vol = pow(2.0,((float)(adlibreg[j+0x40]&63) +
243                       (float)kslmul[adlibreg[j+0x40]>>6]*ksl[oct][frn>>6]) * -.125 - 14);
244 }
245
246 static long initfirstime = 0;
247 void adlibinit (long dasamplerate, long danumspeakers, long dabytespersample)
248 {
249     long i, j, frn, oct;
250
251     memset((void *)adlibreg,0,sizeof(adlibreg));
252     memset((void *)cell,0,sizeof(celltype)*MAXCELLS);
253     memset((void *)rbuf,0,sizeof(rbuf));
254     rend = 0; odrumstat = 0;
255
256     for(i=0;i<MAXCELLS;i++)
257     {
258         cell[i].cellfunc = docell4;
259         cell[i].amp = 0;
260         cell[i].vol = 0;
261         cell[i].t = 0;
262         cell[i].tinc = 0;
263         cell[i].wavemask = 0;
264         cell[i].waveform = &wavtable[WAVPREC];
265     }
266
267     numspeakers = danumspeakers;
268     bytespersample = dabytespersample;
269
270     recipsamp = 1.0 / (float)dasamplerate;
271     for(i=15;i>=0;i--) nfrqmul[i] = frqmul[i]*recipsamp*FRQSCALE*(WAVPREC/2048.0);
272
273     if (!initfirstime)
274     {
275         initfirstime = 1;
276
277         for(i=0;i<(WAVPREC>>1);i++)
278         {
279             wavtable[i] =
280                 wavtable[(i<<1)  +WAVPREC] = (signed short)(16384*sin((float)((i<<1)  )*PI*2/WAVPREC));
281             wavtable[(i<<1)+1+WAVPREC] = (signed short)(16384*sin((float)((i<<1)+1)*PI*2/WAVPREC));
282         }
283         for(i=0;i<(WAVPREC>>3);i++)
284         {
285             wavtable[i+(WAVPREC<<1)] = wavtable[i+(WAVPREC>>3)]-16384;
286             wavtable[i+((WAVPREC*17)>>3)] = wavtable[i+(WAVPREC>>2)]+16384;
287         }
288
289         //[table in book]*8/3
290         ksl[7][0] = 0; ksl[7][1] = 24; ksl[7][2] = 32; ksl[7][3] = 37;
291         ksl[7][4] = 40; ksl[7][5] = 43; ksl[7][6] = 45; ksl[7][7] = 47;
292         ksl[7][8] = 48; for(i=9;i<16;i++) ksl[7][i] = i+41;
293         for(j=6;j>=0;j--)
294             for(i=0;i<16;i++)
295             {
296                 oct = (long)ksl[j+1][i]-8; if (oct < 0) oct = 0;
297                 ksl[j][i] = (unsigned char)oct;
298             }
299     }
300     else
301     {
302         for(i=0;i<9;i++)
303         {
304             frn = ((((long)adlibreg[i+0xb0])&3)<<8) + (long)adlibreg[i+0xa0];
305             oct = ((((long)adlibreg[i+0xb0])>>2)&7);
306             cell[i].tinc = (float)(frn<<oct)*nfrqmul[adlibreg[modulatorbase[i]+0x20]&15];
307         }
308     }
309 }
310
311 void adlib0 (long i, long v)
312 {
313     unsigned char tmp = adlibreg[i];
314     adlibreg[i] = v;
315
316     if (i == 0xbd)
317     {
318         if ((v&16) > (odrumstat&16)) //BassDrum
319         {
320             cellon(6,16,&cell[6],0);
321             cellon(6,19,&cell[15],1);
322             cell[15].vol *= 2;
323         }
324         if ((v&8) > (odrumstat&8)) //Snare
325         {
326             cellon(16,20,&cell[16],0);
327             cell[16].tinc *= 2*(nfrqmul[adlibreg[17+0x20]&15] / nfrqmul[adlibreg[20+0x20]&15]);
328             if (((adlibreg[20+0xe0]&7) >= 3) && ((adlibreg[20+0xe0]&7) <= 5)) cell[16].vol = 0;
329             cell[16].vol *= 2;
330         }
331         if ((v&4) > (odrumstat&4)) //TomTom
332         {
333             cellon(8,18,&cell[8],0);
334             cell[8].vol *= 2;
335         }
336         if ((v&2) > (odrumstat&2)) //Cymbal
337         {
338             cellon(17,21,&cell[17],0);
339
340             cell[17].wavemask = wavemask[5];
341             cell[17].waveform = &wavtable[waveform[5]];
342             cell[17].tinc *= 16; cell[17].vol *= 2;
343
344             //cell[17].waveform = &wavtable[WAVPREC]; cell[17].wavemask = 0;
345             //if (((adlibreg[21+0xe0]&7) == 0) || ((adlibreg[21+0xe0]&7) == 6))
346             //   cell[17].waveform = &wavtable[(WAVPREC*7)>>2];
347             //if (((adlibreg[21+0xe0]&7) == 2) || ((adlibreg[21+0xe0]&7) == 3))
348             //   cell[17].waveform = &wavtable[(WAVPREC*5)>>2];
349         }
350         if ((v&1) > (odrumstat&1)) //Hihat
351         {
352             cellon(7,17,&cell[7],0);
353             if (((adlibreg[17+0xe0]&7) == 1) || ((adlibreg[17+0xe0]&7) == 4) ||
354                 ((adlibreg[17+0xe0]&7) == 5) || ((adlibreg[17+0xe0]&7) == 7)) cell[7].vol = 0;
355             if ((adlibreg[17+0xe0]&7) == 6) { cell[7].wavemask = 0; cell[7].waveform = &wavtable[(WAVPREC*7)>>2]; }
356         }
357
358         odrumstat = v;
359     }
360     else if (((unsigned)(i-0x40) < (unsigned)22) && ((i&7) < 6))
361     {
362         if ((i&7) < 3) // Modulator
363             cellfreq(base2cell[i-0x40],i-0x40,&cell[base2cell[i-0x40]]);
364         else          // Carrier
365             cellfreq(base2cell[i-0x40],i-0x40,&cell[base2cell[i-0x40]+9]);
366     }
367     else if ((unsigned)(i-0xa0) < (unsigned)9)
368     {
369         cellfreq(i-0xa0,modulatorbase[i-0xa0],&cell[i-0xa0]);
370         cellfreq(i-0xa0,modulatorbase[i-0xa0]+3,&cell[i-0xa0+9]);
371     }
372     else if ((unsigned)(i-0xb0) < (unsigned)9)
373     {
374         if ((v&32) > (tmp&32))
375         {
376             cellon(i-0xb0,modulatorbase[i-0xb0],&cell[i-0xb0],0);
377             cellon(i-0xb0,modulatorbase[i-0xb0]+3,&cell[i-0xb0+9],1);
378         }
379         else if ((v&32) < (tmp&32))
380             cell[i-0xb0].cellfunc = cell[i-0xb0+9].cellfunc = docell2;
381         cellfreq(i-0xb0,modulatorbase[i-0xb0],&cell[i-0xb0]);
382         cellfreq(i-0xb0,modulatorbase[i-0xb0]+3,&cell[i-0xb0+9]);
383     }
384
385     //outdata(i,v);
386 }
387
388 #ifdef USING_ASM
389 static long fpuasm;
390 static float fakeadd = 8388608.0+128.0;
391 static _inline void clipit8 (float f, long a)
392 {
393     _asm
394         {
395             mov edi, a
396                 fld dword ptr f
397                 fadd dword ptr fakeadd
398                 fstp dword ptr fpuasm
399                 mov eax, fpuasm
400                 test eax, 0x007fff00
401                 jz short skipit
402                 shr eax, 16
403                 xor eax, -1
404                 skipit: mov byte ptr [edi], al
405                 }
406 }
407
408 static _inline void clipit16 (float f, long a)
409 {
410     _asm
411         {
412             mov eax, a
413                 fld dword ptr f
414                 fist word ptr [eax]
415                 cmp word ptr [eax], 0x8000
416                 jne short skipit2
417                 fst dword ptr [fpuasm]
418                 cmp fpuasm, 0x80000000
419                 sbb word ptr [eax], 0
420                 skipit2: fstp st
421                 }
422 }
423 #else
424 static void clipit8(float f,unsigned char *a) {
425     f/=256.0;
426     f+=128.0;
427     if (f>254.5) *a=255;
428     else if (f<0.5) *a=0;
429     else *a=f;
430 }
431
432 static void clipit16(float f,short *a) {
433     if (f>32766.5) *a=32767;
434     else if (f<-32767.5) *a=-32768;
435     else *a=f;
436 }
437 #endif
438
439 void adlibsetvolume(int i) {
440     AMPSCALE=i;
441 }
442
443 void adlibgetsample (unsigned char *sndptr, long numbytes)
444 {
445     long i, j, k=0, ns, endsamples, rptrs, numsamples;
446     celltype *cptr;
447     float f;
448     short *sndptr2=(short *)sndptr;
449
450     numsamples = (numbytes>>(numspeakers+bytespersample-2));
451
452     if (bytespersample == 1) f = AMPSCALE/256.0; else f = AMPSCALE;
453     if (numspeakers == 1)
454     {
455         nlvol[0] = lvol[0]*f;
456         for(i=0;i<9;i++) rptr[i] = &rbuf[0][0];
457         rptrs = 1;
458     }
459     else
460     {
461         rptrs = 0;
462         for(i=0;i<9;i++)
463         {
464             if ((!i) || (lvol[i] != lvol[i-1]) || (rvol[i] != rvol[i-1]) ||
465                 (lplc[i] != lplc[i-1]) || (rplc[i] != rplc[i-1]))
466             {
467                 nlvol[rptrs] = lvol[i]*f;
468                 nrvol[rptrs] = rvol[i]*f;
469                 nlplc[rptrs] = rend-min(max(lplc[i],0),FIFOSIZ);
470                 nrplc[rptrs] = rend-min(max(rplc[i],0),FIFOSIZ);
471                 rptrs++;
472             }
473             rptr[i] = &rbuf[rptrs-1][0];
474         }
475     }
476
477
478     //CPU time used to be somewhat less when emulator was only mono!
479     //   Because of no delay fifos!
480
481     for(ns=0;ns<numsamples;ns+=endsamples)
482     {
483         endsamples = min(FIFOSIZ*2-rend,FIFOSIZ);
484         endsamples = min(endsamples,numsamples-ns);
485
486         for(i=0;i<9;i++)
487             nrptr[i] = &rptr[i][rend];
488         for(i=0;i<rptrs;i++)
489             memset((void *)&rbuf[i][rend],0,endsamples*sizeof(float));
490
491         if (adlibreg[0xbd]&0x20)
492         {
493                                 //BassDrum (j=6)
494             if (cell[15].cellfunc != docell4)
495             {
496                 if (adlibreg[0xc6]&1)
497                 {
498                     for(i=0;i<endsamples;i++)
499                     {
500                         (cell[15].cellfunc)((void *)&cell[15],0.0);
501                         nrptr[6][i] += cell[15].val;
502                     }
503                 }
504                 else
505                 {
506                     for(i=0;i<endsamples;i++)
507                     {
508                         (cell[6].cellfunc)((void *)&cell[6],cell[6].val*cell[6].mfb);
509                         (cell[15].cellfunc)((void *)&cell[15],cell[6].val*WAVPREC*MODFACTOR);
510                         nrptr[6][i] += cell[15].val;
511                     }
512                 }
513             }
514
515                                 //Snare/Hihat (j=7), Cymbal/TomTom (j=8)
516             if ((cell[7].cellfunc != docell4) || (cell[8].cellfunc != docell4) || (cell[16].cellfunc != docell4) || (cell[17].cellfunc != docell4))
517             {
518                 for(i=0;i<endsamples;i++)
519                 {
520                     k = k*1664525+1013904223;
521                     (cell[16].cellfunc)((void *)&cell[16],k&((WAVPREC>>1)-1)); //Snare
522                     (cell[7].cellfunc)((void *)&cell[7],k&(WAVPREC-1));       //Hihat
523                     (cell[17].cellfunc)((void *)&cell[17],k&((WAVPREC>>3)-1)); //Cymbal
524                     (cell[8].cellfunc)((void *)&cell[8],0.0);                 //TomTom
525                     nrptr[7][i] += cell[7].val + cell[16].val;
526                     nrptr[8][i] += cell[8].val + cell[17].val;
527                 }
528             }
529         }
530         for(j=9-1;j>=0;j--)
531         {
532             if ((adlibreg[0xbd]&0x20) && (j >= 6) && (j < 9)) continue;
533
534             cptr = &cell[j]; k = j;
535             if (adlibreg[0xc0+k]&1)
536             {
537                 if ((cptr[9].cellfunc == docell4) && (cptr->cellfunc == docell4)) continue;
538                 for(i=0;i<endsamples;i++)
539                 {
540                     (cptr->cellfunc)((void *)cptr,cptr->val*cptr->mfb);
541                     (cptr->cellfunc)((void *)&cptr[9],0);
542                     nrptr[j][i] += cptr[9].val + cptr->val;
543                 }
544             }
545             else
546             {
547                 if (cptr[9].cellfunc == docell4) continue;
548                 for(i=0;i<endsamples;i++)
549                 {
550                     (cptr->cellfunc)((void *)cptr,cptr->val*cptr->mfb);
551                     (cptr[9].cellfunc)((void *)&cptr[9],cptr->val*WAVPREC*MODFACTOR);
552                     nrptr[j][i] += cptr[9].val;
553                 }
554             }
555         }
556
557         if (numspeakers == 1)
558         {
559             if (bytespersample == 1)
560             {
561                 for(i=endsamples-1;i>=0;i--)
562                     clipit8(nrptr[0][i]*nlvol[0],sndptr+1);
563             }
564             else
565             {
566                 for(i=endsamples-1;i>=0;i--)
567                     clipit16(nrptr[0][i]*nlvol[0],sndptr2+i);
568             }
569         }
570         else
571         {
572             memset((void *)snd,0,endsamples*sizeof(float)*2);
573             for(j=0;j<rptrs;j++)
574             {
575                 for(i=0;i<endsamples;i++)
576                 {
577                     snd[(i<<1)  ] += rbuf[j][(nlplc[j]+i)&(FIFOSIZ*2-1)]*nlvol[j];
578                     snd[(i<<1)+1] += rbuf[j][(nrplc[j]+i)&(FIFOSIZ*2-1)]*nrvol[j];
579                 }
580                 nlplc[j] += endsamples;
581                 nrplc[j] += endsamples;
582             }
583
584             if (bytespersample == 1)
585             {
586                 for(i=(endsamples<<1)-1;i>=0;i--)
587                     clipit8(snd[i],sndptr+i);
588             }
589             else
590             {
591                 for(i=(endsamples<<1)-1;i>=0;i--)
592                     clipit16(snd[i],sndptr2+i);
593             }
594         }
595
596         sndptr = sndptr+(numspeakers*endsamples);
597         sndptr2 = sndptr2+(numspeakers*endsamples);
598         rend = ((rend+endsamples)&(FIFOSIZ*2-1));
599     }
600 }