1 /* OpenCP Module Player
2 * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3 *
4 * Wavetable Device: FPU HighQuality Software Mixer for Pentium/above CPUs
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * revision history: (please note changes here)
21 * -kb990208 Tammo Hinrichs <kb@vmo.nettrade.de>
22 * -first release
23 * -ryg990426 Fabian Giesen <fabian@jdcs.su.nw.schule.de>
24 * -slave strikes back and applies some of kebbys changes of which i
25 * obviously don't exactly know what they are (i'm not interested in it
26 * either). blame kb if you wanna have sum description :)
27 * -ryg990504 Fabian Giesen <fabian@jdcs.su.nw.schule.de>
28 * -added float postprocs. prepare for some really ruling effect filters
29 * in opencp soon...
30 *
31 * TODO:
32 * - some hack to re-enable the display mixer, which is of course
33 * NOT capable of handling float values... and I don't want to
34 * store both versions of the samples, as this would suck QUITE
35 * too much memory
36 *
37 *
38 * annotations:
39 * This mixer is and will always be only half of what I want it to be.
40 * The OpenCP 2.x.0 framework just does not contain the functionality
41 * i would need to unleash this mixing routine's full potential, such
42 * as almost infinite vol/pan resolution and perfect volume ramping.
43 * so wait for the GSL core which will hopefully be contained in OpenCP 3.x
44 * and will feature all this mixing routine can do. You've seen nothing yet.
45 */
46
47 #include "config.h"
48 #include <stdio.h>
49 #include <string.h>
50 #include <stdlib.h>
51 #include <math.h>
52 #include <unistd.h>
53 #include <sys/mman.h>
54 #include "types.h"
55 #include "boot/plinkman.h"
56 #include "dev/imsdev.h"
57 #include "dev/mcp.h"
58 #include "dev/mix.h"
59 #include "dev/player.h"
60 #include "stuff/imsrtns.h"
61 #include "devwmixf.h"
62 #include "stuff/poll.h"
63 #include "dwmixfa.h"
64 #ifdef I386_ASM
65 #include "stuff/pagesize.inc.c"
66 #endif
67
68 /* NB NB more includes further down in the file */
69
70 extern struct sounddevice mcpFMixer;
71
72 static int dopause;
73 static uint32_t playsamps;
74 static uint32_t pausesamps;
75
76 static struct sampleinfo *samples;
77 static int samplenum;
78
79 static volatile int clipbusy=0;
80 static float amplify;
81 static float transform[2][2];
82 static int volopt;
83 static uint32_t relpitch;
84 static int interpolation;
85 static void *plrbuf;
86
87 static int volramp;
88 static int declick;
89
90 static uint8_t stereo;
91 static uint8_t bit16;
92 static uint8_t signedout;
93 static uint8_t reversestereo;
94
95 static int channelnum;
96
97 struct channel
98 {
99 void *samp;
100
101 uint32_t length;
102 uint32_t loopstart;
103 uint32_t loopend;
104
105 int newsamp;
106
107 float dstvols[2];
108 int dontramp;
109
110 float vol[2];
111 float orgvol[2];
112
113 float orgvolx;
114 float orgpan;
115 float orgfrez;
116
117 float *sbpos;
118 float sbuf[8];
119
120 uint32_t orgrate;
121 uint32_t orgfrq;
122 uint32_t orgdiv;
123 int volopt;
124 uint32_t samptype;
125
126 uint32_t orgloopstart;
127 uint32_t orgloopend;
128 uint32_t orgsloopstart;
129 uint32_t orgsloopend;
130
131 long handle;
132 };
133 static struct channel *channels;
134
135 static unsigned int bufpos;
136 static uint32_t buflen;
137
138 static void (*playerproc)(void);
139
140 static uint32_t tickwidth;
141 static uint32_t tickplayed;
142 static uint32_t orgspeed;
143 static uint32_t relspeed;
144 static uint32_t newtickwidth;
145 static uint32_t cmdtimerpos;
146
147 static float mastervol;
148 static float masterbal;
149 static float masterpan;
150 static int mastersrnd;
151 static int masterrvb;
152 static int masterchr;
153
frchk(float a)154 static inline float frchk(float a)
155 {
156 switch (fpclassify(a))
157 {
158 default:
159 case FP_NAN:
160 case FP_INFINITE:
161 case FP_SUBNORMAL:
162
163 case FP_ZERO:
164 return 0.0f;
165
166 case FP_NORMAL:
167 if (fabs(a)<0.00000001)
168 return 0.0;
169 else
170 return a;
171 }
172 }
173
calcinterpoltab(void)174 static void calcinterpoltab(void)
175 {
176 int i;
177 for (i=0; i<256; i++)
178 {
179 float x1=i/256.0;
180 float x2=x1*x1;
181 float x3=x1*x1*x1;
182 dwmixfa_state.ct0[i]=-0.5*x3+x2-0.5*x1;
183 dwmixfa_state.ct1[i]=1.5*x3-2.5*x2+1;
184 dwmixfa_state.ct2[i]=-1.5*x3+2*x2+0.5*x1;
185 dwmixfa_state.ct3[i]=0.5*x3-0.5*x2;
186 };
187 }
188
189
calcstep(struct channel * c)190 static void calcstep(struct channel *c)
191 {
192 int n=c->handle;
193 uint32_t rstep;
194 if (!(dwmixfa_state.voiceflags[n]&MIXF_PLAYING))
195 return;
196 if (!c->orgdiv)
197 return;
198
199 rstep=imuldiv(imuldiv(c->orgfrq, c->orgrate, c->orgdiv)<<8, relpitch, dwmixfa_state.samprate);
200 dwmixfa_state.freqw[n]=rstep>>16;
201 dwmixfa_state.freqf[n]=rstep<<16;
202
203 dwmixfa_state.voiceflags[n]&=~(MIXF_INTERPOLATE|MIXF_INTERPOLATEQ);
204 dwmixfa_state.voiceflags[n]|=interpolation?((interpolation>1)?MIXF_INTERPOLATEQ:MIXF_INTERPOLATE):0;
205 }
206
calcsteps(void)207 static void calcsteps(void)
208 {
209 int i;
210 for (i=0; i<channelnum; i++)
211 calcstep(&channels[i]);
212 }
213
calcspeed(void)214 static void calcspeed(void)
215 {
216 if (channelnum)
217 newtickwidth=imuldiv(256*256*256, dwmixfa_state.samprate, orgspeed*relspeed);
218 }
219
transformvol(struct channel * ch)220 static void transformvol(struct channel *ch)
221 {
222 int n=ch->handle;
223
224 ch->vol[0]=transform[0][0]*ch->orgvol[0]+transform[0][1]*ch->orgvol[1];
225 ch->vol[1]=transform[1][0]*ch->orgvol[0]+transform[1][1]*ch->orgvol[1];
226 if (volopt^ch->volopt)
227 ch->vol[1]=-ch->vol[1];
228
229 if (dwmixfa_state.voiceflags[n]&MIXF_MUTE)
230 {
231 ch->dstvols[0]=ch->dstvols[1]=0;
232 } else if (!stereo)
233 {
234 ch->dstvols[0]=0.5*(fabs(ch->vol[0])+fabs(ch->vol[1]));
235 ch->dstvols[1]=0;
236 } else if (reversestereo)
237 {
238 ch->dstvols[0]=ch->vol[1];
239 ch->dstvols[1]=ch->vol[0];
240 } else {
241 ch->dstvols[0]=ch->vol[0];
242 ch->dstvols[1]=ch->vol[1];
243 }
244 }
245
calcvol(struct channel * chn)246 static void calcvol(struct channel *chn)
247 {
248 chn->orgvol[0]=chn->orgvolx*(0.5-chn->orgpan);
249 chn->orgvol[1]=chn->orgvolx*(0.5+chn->orgpan);
250 transformvol(chn);
251 }
252
calcvols(void)253 static void calcvols(void)
254 {
255 float vols[2][2];
256
257 float realamp=(1.0/65536.0)*amplify;
258 int i;
259
260 vols[0][0]=vols[1][1]=mastervol*(0.5+masterpan);
261 vols[0][1]=vols[1][0]=mastervol*(0.5-masterpan);
262
263 if (masterbal>0)
264 {
265 vols[0][0]=vols[0][0]*(0.5-masterbal);
266 vols[0][1]=vols[0][1]*(0.5-masterbal);
267 } else if (masterbal<0)
268 {
269 vols[1][0]=vols[1][0]*(0.5+masterbal);
270 vols[1][1]=vols[1][1]*(0.5+masterbal);
271 }
272
273 volopt=mastersrnd;
274 transform[0][0]=realamp*vols[0][0];
275 transform[0][1]=realamp*vols[0][1];
276 transform[1][0]=realamp*vols[1][0];
277 transform[1][1]=realamp*vols[1][1];
278
279 for (i=0; i<channelnum; i++)
280 transformvol(&channels[i]);
281 }
282
283
stopchan(struct channel * c)284 static void stopchan(struct channel *c)
285 {
286 int n=c->handle;
287 if (!(dwmixfa_state.voiceflags[n]&MIXF_PLAYING))
288 return;
289
290 /* cool end-of-sample-declicking */
291 if (!(dwmixfa_state.voiceflags[n] & MIXF_QUIET))
292 {
293 int offs = ( dwmixfa_state.voiceflags[n] & MIXF_INTERPOLATEQ ) ? 1 : 0;
294 float ff2 = dwmixfa_state.ffreq[n] * dwmixfa_state.ffreq[n];
295 dwmixfa_state.fadeleft += ff2*dwmixfa_state.volleft[n] * dwmixfa_state.smpposw[n][offs];
296 dwmixfa_state.faderight += ff2*dwmixfa_state.volright[n] * dwmixfa_state.smpposw[n][offs];
297 }
298
299 dwmixfa_state.voiceflags[n]&=~MIXF_PLAYING;
300 }
301
302
rstlbuf(struct channel * c)303 static void rstlbuf(struct channel *c)
304 {
305 if (c->sbpos)
306 {
307 int i;
308 for (i=0; i<8; i++)
309 c->sbpos[i]=c->sbuf[i];
310 c->sbpos=0;
311 }
312 }
313
314
setlbuf(struct channel * c)315 static void setlbuf(struct channel *c)
316 {
317 int n=c->handle;
318
319 if (c->sbpos)
320 rstlbuf(c);
321
322 if (dwmixfa_state.voiceflags[n]&MIXF_LOOPED)
323 {
324 float *dst=dwmixfa_state.loopend[n];
325 float *src=dst-dwmixfa_state.looplen[n];
326 int i;
327 for (i=0; i<8; i++)
328 {
329 c->sbuf[i]=dst[i];
330 dst[i]=src[i];
331 }
332 c->sbpos=dst;
333 }
334 }
335
336
337
mixmain()338 static void mixmain(/*int min*/)
339 {
340 int i;
341 int /*bufmin,*/
342 bufdeltatot;
343
344 if (!channelnum)
345 return;
346 if (clipbusy++)
347 {
348 clipbusy--;
349 return;
350 }
351
352
353 /*
354 bufmin=imulshr16(min, samprate);
355 if (bufmin<0)
356 bufmin=0;*/
357
358 bufdeltatot=((buflen+(plrGetBufPos()>>(stereo+bit16))-bufpos)%buflen);
359 /*
360 if (bufdeltatot<bufmin)
361 bufdeltatot=0;*/
362
363 if (dopause)
364 {
365 int pass2=((bufpos+bufdeltatot)>buflen)?(bufpos+bufdeltatot-buflen):0;
366
367 if (bit16)
368 {
369 memsetw((int16_t *)plrbuf+(bufpos<<stereo), signedout?0:0x8000, (bufdeltatot-pass2)<<stereo);
370 if (pass2)
371 memsetw((int16_t *)plrbuf, signedout?0:0x8000, pass2<<stereo);
372 } else {
373 memsetb((uint8_t *)plrbuf+(bufpos<<stereo), signedout?0:0x80, (bufdeltatot-pass2)<<stereo);
374 if (pass2)
375 memsetb((uint8_t *)plrbuf, signedout?0:0x80, pass2<<stereo);
376 }
377
378 bufpos+=bufdeltatot;
379 if (bufpos>=buflen)
380 bufpos-=buflen;
381
382 plrAdvanceTo(bufpos<<(stereo+bit16));
383 pausesamps+=bufdeltatot;
384 } else while (bufdeltatot>0)
385 {
386 unsigned int bufdelta=(bufdeltatot>MIXF_MIXBUFLEN)?MIXF_MIXBUFLEN:bufdeltatot;
387 uint32_t ticks2go;
388 /* float invt2g; */
389 if (bufdelta>(buflen-bufpos))
390 bufdelta=buflen-bufpos;
391
392 ticks2go=(tickwidth-tickplayed)>>8;
393
394 if (bufdelta>ticks2go)
395 bufdelta=ticks2go;
396
397 /* invt2g=1.0/(float)ticks2go; */
398
399 /* set-up mixing core variables */
400 for (i=0; i<channelnum; i++) if (dwmixfa_state.voiceflags[i]&MIXF_PLAYING)
401 {
402 struct channel *ch=&channels[i];
403
404 dwmixfa_state.volleft[i]=frchk(dwmixfa_state.volleft[i]);
405 dwmixfa_state.volright[i]=frchk(dwmixfa_state.volright[i]);
406
407 if (!dwmixfa_state.volleft[i] && !dwmixfa_state.volright[i] && !dwmixfa_state.rampleft[i] && !dwmixfa_state.rampright[i])
408 dwmixfa_state.voiceflags[i]|=MIXF_QUIET;
409 else
410 dwmixfa_state.voiceflags[i]&=~MIXF_QUIET;
411
412
413 if (dwmixfa_state.ffreq[i]!=1 || dwmixfa_state.freso[i]!=0)
414 dwmixfa_state.voiceflags[i]|=MIXF_FILTER;
415 else
416 dwmixfa_state.voiceflags[i]&=~MIXF_FILTER;
417
418 /* declick start of sample */
419 if (ch->newsamp)
420 {
421 if (!(dwmixfa_state.voiceflags[i] & MIXF_QUIET))
422 {
423 int offs = ( dwmixfa_state.voiceflags[i] & MIXF_INTERPOLATEQ ) ? 1 : 0;
424 float ff2 = dwmixfa_state.ffreq[i] * dwmixfa_state.ffreq[i];
425 dwmixfa_state.fadeleft -= ff2 * dwmixfa_state.volleft[i] * dwmixfa_state.smpposw[i][offs];
426 dwmixfa_state.faderight -= ff2 * dwmixfa_state.volright[i] * dwmixfa_state.smpposw[i][offs];
427 }
428 ch->newsamp=0;
429 }
430
431 /*voiceflags[i]|=isstereo; <- this was hard to track down*/
432 }
433 dwmixfa_state.nsamples=bufdelta;
434 dwmixfa_state.outbuf=((uint8_t *)(plrbuf))+(bufpos<<(stereo+bit16));
435
436 /* optionally turn off the declicking */
437 if (!declick)
438 dwmixfa_state.fadeleft=dwmixfa_state.faderight=0;
439 #ifdef MIXER_DEBUG
440 {
441 int i;
442 fprintf(stderr, "nsamples=%d\n", nsamples);
443 for (i=0;i<nvoices;i++)
444 if (voiceflags[i])
445 {
446 fprintf(stderr, "voice #%d\n", i);
447 fprintf(stderr, " samp: %p (%p)\n", channels[i].samp, channels[i].sbpos);
448 fprintf(stderr, " looplen: %08x\n", looplen[i]);
449 fprintf(stderr, " voiceflags: 0x%08x\n", voiceflags[i]);
450 fprintf(stderr, " freq: 0x%08x:0x%08x\n", freqw[i], freqf[i]);
451 fprintf(stderr, " vol %lf %lf\n", volleft[i], volright[i]);
452 }
453 fprintf(stderr, "\n");
454 }
455 #endif
456 mixer();
457
458 tickplayed+=bufdelta<<8;
459 if (!((tickwidth-tickplayed)>>8))
460 {
461 float invt2g;
462 tickplayed-=tickwidth;
463
464 playerproc();
465
466 cmdtimerpos+=tickwidth;
467 tickwidth=newtickwidth;
468 invt2g=256.0/tickwidth;
469
470 /* set up volume ramping */
471 for (i=0; i<channelnum; i++) if (dwmixfa_state.voiceflags[i]&MIXF_PLAYING)
472 {
473
474 struct channel *ch=&channels[i];
475 if (ch->dontramp)
476 {
477 dwmixfa_state.volleft[i]=frchk(ch->dstvols[0]);
478 dwmixfa_state.volright[i]=frchk(ch->dstvols[1]);
479 dwmixfa_state.rampleft[i]=dwmixfa_state.rampright[i]=0;
480 if (volramp)
481 ch->dontramp=0;
482 } else {
483 dwmixfa_state.rampleft[i]=frchk(invt2g*(ch->dstvols[0]-dwmixfa_state.volleft[i]));
484 if (dwmixfa_state.rampleft[i]==0)
485 dwmixfa_state.volleft[i]=ch->dstvols[0];
486 dwmixfa_state.rampright[i]=frchk(invt2g*(ch->dstvols[1]-dwmixfa_state.volright[i]));
487 if (dwmixfa_state.rampright[i]==0)
488 dwmixfa_state.volright[i]=ch->dstvols[1];
489 }
490 /* filter resonance */
491 dwmixfa_state.freso[i]=pow(ch->orgfrez,dwmixfa_state.ffreq[i]);
492 }
493 }
494 bufpos+=bufdelta;
495 if (bufpos>=buflen)
496 bufpos-=buflen;
497
498 plrAdvanceTo(bufpos<<(stereo+bit16));
499 bufdeltatot-=bufdelta;
500 playsamps+=bufdelta;
501 }
502
503 clipbusy--;
504 }
505
timerproc()506 static void timerproc()
507 {
508 #ifndef NO_BACKGROUND_MIXER
509 mixmain();
510 #endif
511 if (plrIdle)
512 plrIdle();
513 }
514
SET(int ch,int opt,int val)515 static void SET(int ch, int opt, int val)
516 {
517 struct channel *chn;
518 if (ch>=channelnum)
519 ch=channelnum-1;
520 if (ch<0)
521 ch=0;
522 chn=&channels[ch];
523 switch (opt)
524 {
525 case mcpCReset:
526 {
527 int reswasmute;
528 rstlbuf(chn);
529 stopchan(chn);
530 reswasmute=dwmixfa_state.voiceflags[ch]&MIXF_MUTE;
531 memset(chn, 0, sizeof(struct channel));
532 chn->handle=ch;
533 dwmixfa_state.voiceflags[ch]=reswasmute;
534 }
535 break;
536
537 case mcpCInstrument:
538 {
539 struct sampleinfo *samp;
540
541 rstlbuf(chn);
542 stopchan(chn);
543 if ((val<0)||(val>=samplenum))
544 break;
545 samp=&samples[val];
546 chn->samptype=samp->type;
547 chn->length=samp->length;
548 chn->orgrate=samp->samprate;
549 chn->samp=samp->ptr;
550 chn->orgloopstart=samp->loopstart;
551 chn->orgloopend=samp->loopend;
552 chn->orgsloopstart=samp->sloopstart;
553 chn->orgsloopend=samp->sloopend;
554 chn->dontramp=1;
555 chn->newsamp=1;
556
557 dwmixfa_state.voiceflags[ch]&=~(MIXF_PLAYING|MIXF_LOOPED);
558
559 dwmixfa_state.freqw[ch]=0;
560 dwmixfa_state.freqf[ch]=0;
561 dwmixfa_state.fl1[ch]=0;
562 dwmixfa_state.fb1[ch]=0;
563 dwmixfa_state.ffreq[ch]=1;
564 dwmixfa_state.freso[ch]=0;
565 dwmixfa_state.smpposf[ch]=0;
566 dwmixfa_state.smpposw[ch]=(float *)chn->samp;
567
568 if (chn->samptype&mcpSampSLoop)
569 {
570 dwmixfa_state.voiceflags[ch]|=MIXF_LOOPED;
571 chn->loopstart=chn->orgsloopstart;
572 chn->loopend=chn->orgsloopend;
573 } else if (chn->samptype&mcpSampLoop)
574 {
575 dwmixfa_state.voiceflags[ch]|=MIXF_LOOPED;
576 chn->loopstart=chn->orgloopstart;
577 chn->loopend=chn->orgloopend;
578 }
579
580 if (dwmixfa_state.voiceflags[ch]&MIXF_LOOPED)
581 {
582 dwmixfa_state.looplen[ch]=chn->loopend-chn->loopstart;
583 dwmixfa_state.loopend[ch]=(float *)chn->samp+chn->loopend;
584 } else {
585 dwmixfa_state.looplen[ch]=chn->length;
586 dwmixfa_state.loopend[ch]=(float *)chn->samp+chn->length-1;
587 }
588 setlbuf(chn);
589 }
590 break;
591 case mcpCStatus:
592 if (!val)
593 stopchan(chn);
594 else {
595 if (dwmixfa_state.smpposw[ch] >= (float *)(chn->samp)+chn->length)
596 break;
597 dwmixfa_state.voiceflags[ch]|=MIXF_PLAYING;
598 calcstep(chn);
599 }
600 break;
601 case mcpCMute:
602 if (val)
603 dwmixfa_state.voiceflags[ch]|=MIXF_MUTE;
604 else
605 dwmixfa_state.voiceflags[ch]&=~MIXF_MUTE;
606 calcvol(chn);
607 break;
608 case mcpCVolume:
609 val=(val>0x200)?0x200:(val<0)?0:val;
610 chn->orgvolx=(float)(val)/256.0;
611 calcvol(chn);
612 break;
613 case mcpCPanning:
614 val=(val>0x80)?0x80:(val<-0x80)?-0x80:val;
615 chn->orgpan=(float)(val)/256.0;
616 calcvol(chn);
617 break;
618 case mcpCSurround:
619 chn->volopt=val?1:0;
620 transformvol(chn);
621 break;
622 case mcpCLoop:
623 rstlbuf(chn);
624 dwmixfa_state.voiceflags[ch]&=~MIXF_LOOPED;
625
626 if ((val==1)&&!(chn->samptype&mcpSampSLoop))
627 val=2;
628 if ((val==2)&&!(chn->samptype&mcpSampLoop))
629 val=0;
630
631 if (val==1)
632 {
633 dwmixfa_state.voiceflags[ch]|=MIXF_LOOPED;
634 chn->loopstart=chn->orgsloopstart;
635 chn->loopend=chn->orgsloopend;
636 }
637 if (val==2)
638 {
639 dwmixfa_state.voiceflags[ch]|=MIXF_LOOPED;
640 chn->loopstart=chn->orgloopstart;
641 chn->loopend=chn->orgloopend;
642 }
643
644 if (dwmixfa_state.voiceflags[ch]&MIXF_LOOPED)
645 {
646 dwmixfa_state.looplen[ch]=chn->loopend-chn->loopstart;
647 dwmixfa_state.loopend[ch]=(float *)chn->samp+chn->loopend;
648 } else {
649 dwmixfa_state.looplen[ch]=chn->length;
650 dwmixfa_state.loopend[ch]=(float *)chn->samp+chn->length-1;
651 }
652 setlbuf(chn);
653
654 break;
655 case mcpCPosition:
656 {
657 int poswasplaying;
658 poswasplaying=dwmixfa_state.voiceflags[ch]&MIXF_PLAYING;
659 stopchan(chn);
660 chn->newsamp=1;
661 if (val<0)
662 val=0;
663 if ((unsigned)val>=chn->length)
664 val=chn->length-1;
665 dwmixfa_state.smpposw[ch]=(float *)(chn->samp)+val;
666 dwmixfa_state.smpposf[ch]=0;
667 dwmixfa_state.voiceflags[ch]|=poswasplaying;
668 }
669 break;
670 case mcpCPitch:
671 chn->orgfrq=8363;
672 chn->orgdiv=mcpGetFreq8363(-val);
673 calcstep(chn);
674 break;
675 case mcpCPitchFix:
676 chn->orgfrq=val;
677 chn->orgdiv=0x10000;
678 calcstep(chn);
679 break;
680 case mcpCPitch6848:
681 chn->orgfrq=6848;
682 chn->orgdiv=val;
683 calcstep(chn);
684 break;
685 case mcpCFilterFreq:
686 /*
687 cputs("ch");
688 cputs(utoa(ch,0,10));
689 cputs(": freq ");
690 cputs(utoa(val,0,16));
691 cputs("\r\n");
692 */
693 if (!(val&128))
694 {
695 dwmixfa_state.ffreq[ch]=1;
696 dwmixfa_state.freso[ch]=0;
697 break;
698 }
699 dwmixfa_state.ffreq[ch]=33075.0*pow(2,(val-255)/24.0)/dwmixfa_state.samprate;
700 if (dwmixfa_state.ffreq[ch]<0)
701 dwmixfa_state.ffreq[ch]=0;
702 if (dwmixfa_state.ffreq[ch]>1)
703 dwmixfa_state.ffreq[ch]=1;
704 break;
705 case mcpCFilterRez:
706 chn->orgfrez=val/300.0;
707 if (chn->orgfrez>1)
708 chn->orgfrez=1;
709 if (chn->orgfrez==0 && dwmixfa_state.ffreq[ch]==0)
710 dwmixfa_state.ffreq[ch]=1;
711 break;
712 case mcpGSpeed:
713 orgspeed=val;
714 calcspeed();
715 break;
716 case mcpMasterVolume:
717 if (val>=0 && val<=64)
718 mastervol=(float)(val)/64.0;
719 calcvols();
720 break;
721 case mcpMasterPanning:
722 if (val>=-64 && val<=64)
723 masterpan=(float)(val)/128.0;
724 calcvols();
725 break;
726 case mcpMasterBalance:
727 if (val>=-64 && val<=64)
728 masterbal=(float)(val)/128.0;
729 calcvols();
730 break;
731 case mcpMasterSurround:
732 mastersrnd=val?1:0;
733 calcvols();
734 break;
735 case mcpMasterReverb:
736 masterrvb=(val>=64)?63:(val<-64)?-64:val;
737 break;
738 case mcpMasterChorus:
739 masterchr=(val>=64)?63:(val<-64)?-64:val;
740 break;
741 case mcpMasterSpeed:
742 relspeed=(val<16)?16:val;
743 calcspeed();
744 break;
745 case mcpMasterPitch:
746 relpitch=val;
747 calcsteps();
748 break;
749 case mcpMasterFilter:
750 interpolation=val;
751 break;
752 case mcpMasterAmplify:
753 amplify=val;
754 if (channelnum)
755 mixSetAmplify(amplify);
756 calcvols();
757 break;
758 case mcpMasterPause:
759 dopause=val;
760 break;
761 }
762 }
763
GET(int ch,int opt)764 static int GET(int ch, int opt)
765 {
766 /*
767 struct channel *chn;*/
768 if (ch>=channelnum)
769 ch=channelnum-1;
770 if (ch<0)
771 ch=0;
772 /*
773 chn=&channels[ch];*/ /* No commands currently use the channel itself */
774 switch (opt)
775 {
776 case mcpCStatus:
777 return !!(dwmixfa_state.voiceflags[ch]&MIXF_PLAYING);
778 case mcpCMute:
779 return !!(dwmixfa_state.voiceflags[ch]&MIXF_MUTE);
780 case mcpGTimer:
781 if (dopause)
782 return imuldiv(playsamps, 65536, dwmixfa_state.samprate);
783 else
784 return plrGetTimer()-imuldiv(pausesamps, 65536, dwmixfa_state.samprate);
785 case mcpGCmdTimer:
786 return umuldiv(cmdtimerpos, 256, dwmixfa_state.samprate);
787 case mcpMasterReverb:
788 return masterrvb;
789 case mcpMasterChorus:
790 return masterchr;
791 }
792 return 0;
793 }
794
Idle(void)795 static void Idle(void)
796 {
797 mixmain();
798 if (plrIdle)
799 plrIdle();
800 }
801
802
803
804
805 /* Houston, we've got a problem there... the display mixer isn't
806 * able to handle floating point values at all. shit.
807 * (kebby, irgendwann mal: "ich will das nicht")
808
809 * bla, toller hack: es funktioniert. (fd)
810 */
811
GetMixChannel(unsigned int ch,struct mixchannel * chn,uint32_t rate)812 static void GetMixChannel(unsigned int ch, struct mixchannel *chn, uint32_t rate)
813 {
814 struct channel *c=&channels[ch];
815
816 chn->samp=c->samp;
817 chn->realsamp.fmt=c->samp;
818 chn->length=c->length;
819 chn->loopstart=c->loopstart;
820 chn->loopend=c->loopend;
821 chn->fpos=dwmixfa_state.smpposf[ch]>>16;
822 chn->pos=dwmixfa_state.smpposw[ch]-(float*)c->samp;
823 chn->vol.volfs[0]=fabs(c->vol[0]);
824 chn->vol.volfs[1]=fabs(c->vol[1]);
825 chn->step=imuldiv((dwmixfa_state.freqw[ch]<<16)|(dwmixfa_state.freqf[ch]>>16), dwmixfa_state.samprate, (signed)rate);
826 chn->status=MIX_PLAYFLOAT;
827 if (dwmixfa_state.voiceflags[ch]&MIXF_MUTE)
828 chn->status|=MIX_MUTE;
829 if (dwmixfa_state.voiceflags[ch]&MIXF_LOOPED)
830 chn->status|=MIX_LOOPED;
831 if (dwmixfa_state.voiceflags[ch]&MIXF_PLAYING)
832 chn->status|=MIX_PLAYING;
833 if (dwmixfa_state.voiceflags[ch]&MIXF_INTERPOLATE)
834 chn->status|=MIX_INTERPOLATE;
835 }
836
837
getrealvol(int ch,int * l,int * r)838 static void getrealvol(int ch, int *l, int *r)
839 {
840 getchanvol(ch, 256);
841 if (dwmixfa_state.voll<0)
842 dwmixfa_state.voll=-dwmixfa_state.voll;
843 *l=(dwmixfa_state.voll>16319)?255:(dwmixfa_state.voll/64.0);
844 if (dwmixfa_state.volr<0)
845 dwmixfa_state.volr=-dwmixfa_state.volr;
846 *r=(dwmixfa_state.volr>16319)?255:(dwmixfa_state.volr/64.0);
847 }
848
LoadSamples(struct sampleinfo * sil,int n)849 static int LoadSamples(struct sampleinfo *sil, int n)
850 {
851 if (!mcpReduceSamples(sil, n, 0x40000000, mcpRedToMono|mcpRedToFloat|mcpRedNoPingPong))
852 return 0;
853
854 #ifdef MIXER_DEBUG
855 {
856 int i;
857 for (i=0;i<n;i++)
858 fprintf(stderr, "sample #% 3d: %p - %p\n", i, sil[i].ptr, sil[i].ptr + sil[i].length*sizeof(float));
859 }
860 #endif
861
862 samples=sil;
863 samplenum=n;
864
865 return 1;
866 }
867
OpenPlayer(int chan,void (* proc)(void),struct ocpfilehandle_t * source_file)868 static int OpenPlayer(int chan, void (*proc)(void), struct ocpfilehandle_t *source_file)
869 {
870 uint32_t currentrate;
871 uint16_t mixfate;
872 int i;
873
874 playsamps=pausesamps=0;
875 if (chan>MIXF_MAXCHAN)
876 chan=MIXF_MAXCHAN;
877
878 if (!plrPlay)
879 return 0;
880
881 currentrate=mcpMixProcRate/chan;
882 mixfate=(currentrate>mcpMixMaxRate)?mcpMixMaxRate:currentrate;
883 plrSetOptions(mixfate, mcpMixOpt);
884
885 playerproc=proc;
886
887 if (!(dwmixfa_state.tempbuf=malloc(sizeof(float)*(MIXF_MIXBUFLEN<<1))))
888 return 0;
889 if (!(channels=calloc(sizeof(struct channel), chan)))
890 {
891 free(channels);
892 return 0;
893 }
894
895 mcpGetMasterSample=plrGetMasterSample;
896 mcpGetRealMasterVolume=plrGetRealMasterVolume;
897
898 if (!mixInit(GetMixChannel, 0, chan, amplify))
899 return 0;
900 mcpGetRealVolume=getrealvol;
901
902 calcvols();
903
904 for (i=0; i<chan; i++)
905 {
906 channels[i].handle=i;
907 dwmixfa_state.voiceflags[i]=0;
908 }
909
910
911 if (!plrOpenPlayer(&plrbuf, &buflen, mcpMixBufSize * plrRate / 1000, source_file))
912 {
913 mixClose();
914 return 0;
915 }
916
917 stereo=(plrOpt&PLR_STEREO)?1:0;
918 bit16=(plrOpt&PLR_16BIT)?1:0;
919 signedout=(plrOpt&PLR_SIGNEDOUT)?1:0;
920 reversestereo=!!(plrOpt&PLR_REVERSESTEREO);
921 dwmixfa_state.samprate=plrRate;
922 bufpos=0;
923 dopause=0;
924 orgspeed=12800;
925
926 channelnum=chan;
927 mcpNChan=chan;
928 mcpIdle=Idle;
929
930 dwmixfa_state.isstereo=stereo;
931 dwmixfa_state.outfmt=(bit16<<1)|(!signedout);
932 dwmixfa_state.nvoices=channelnum;
933 prepare_mixer();
934
935 calcspeed();
936 /*/ playerproc();*/ /* some timing is wrong here! */
937 tickwidth=newtickwidth;
938 tickplayed=0;
939 cmdtimerpos=0;
940
941 if (!pollInit(timerproc))
942 {
943 mcpNChan=0;
944 mcpIdle=0;
945 plrClosePlayer();
946 mixClose();
947 return 0;
948 }
949 {
950 struct mixfpostprocregstruct *mode;
951
952 for (mode=dwmixfa_state.postprocs; mode; mode=mode->next)
953 if (mode->Init) mode->Init(dwmixfa_state.samprate, stereo);
954 }
955 return 1;
956 }
957
ClosePlayer()958 static void ClosePlayer()
959 {
960 struct mixfpostprocregstruct *mode;
961
962 mcpNChan=0;
963 mcpIdle=0;
964
965 pollClose();
966
967 plrClosePlayer();
968
969 channelnum=0;
970
971 mixClose();
972
973 for (mode=dwmixfa_state.postprocs; mode; mode=mode->next)
974 if (mode->Close) mode->Close();
975
976 free(channels);
977 free(dwmixfa_state.tempbuf);
978 dwmixfa_state.tempbuf = 0;
979 }
980
Init(const struct deviceinfo * dev)981 static int Init(const struct deviceinfo *dev)
982 {
983 #ifdef I386_ASM
984 /* Self-modifying code needs access to modify it self */
985 {
986 int fd;
987 char *file=strdup("/tmp/ocpXXXXXX");
988 char *start1, *stop1;
989 int len1;
990 fd=mkstemp(file);
991
992 start1=(void *)start_dwmixfa;
993 stop1=(void *)stop_dwmixfa;
994 #ifdef MIXER_DEBUG
995 fprintf(stderr, "range1: %p - %p\n", start1, stop1);
996 #endif
997 start1=(char *)(((int)start1)&~(pagesize()-1));
998 len1=((stop1-start1)+pagesize()-1)& ~(pagesize()-1);
999 #ifdef MIXER_DEBUG
1000 fprintf(stderr, "mprot: %p + %08x\n", start1, len1);
1001 #endif
1002 if (write(fd, start1, len1)!=len1)
1003 {
1004 #ifdef MIXER_DEBUG
1005 fprintf(stderr, "write 1 failed\n");
1006 #endif
1007 return 0;
1008 }
1009 if (mmap(start1, len1, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, fd, 0)==MAP_FAILED)
1010 {
1011 perror("mmap()");
1012 return 0;
1013 }
1014
1015 /*
1016 if (mprotect((char *)(((int)remap_range1_start)&~(pagesize()-1)), (((char *)remap_range1_stop-(char *)remap_range1_start)+pagesize()-1)& ~(pagesize()-1), PROT_READ|PROT_WRITE|PROT_EXEC) )
1017 {
1018 perror("Couldn't mprotect");
1019 return 0;
1020 }*/
1021 #ifdef MIXER_DEBUG
1022 fprintf(stderr, "Done ?\n");
1023 #endif
1024 close(fd);
1025 unlink(file);
1026 free(file);
1027 }
1028 #endif
1029
1030 volramp=!!(dev->opt&MIXF_VOLRAMP);
1031 declick=!!(dev->opt&MIXF_DECLICK);
1032
1033 calcinterpoltab();
1034
1035 amplify=65535;
1036 relspeed=256;
1037 relpitch=256;
1038 interpolation=0;
1039 mastervol=64;
1040 masterbal=0;
1041 masterpan=0;
1042 mastersrnd=0;
1043 channelnum=0;
1044
1045 mcpLoadSamples=LoadSamples;
1046 mcpOpenPlayer=OpenPlayer;
1047 mcpClosePlayer=ClosePlayer;
1048 mcpGet=GET;
1049 mcpSet=SET;
1050
1051 return 1;
1052 }
1053
Close()1054 static void Close()
1055 {
1056 mcpOpenPlayer=0;
1057 }
1058
1059
Detect(struct deviceinfo * c)1060 static int Detect(struct deviceinfo *c)
1061 {
1062 c->devtype=&mcpFMixer;
1063 c->port=-1;
1064 c->port2=-1;
1065 /*
1066 c->irq=-1;
1067 c->irq2=-1;
1068 c->dma=-1;
1069 c->dma2=-1;
1070 */
1071 if (c->subtype==-1)
1072 c->subtype=0;
1073 c->chan=MIXF_MAXCHAN;
1074 c->mem=0;
1075 c->path[0]=0;
1076 return 1;
1077 }
1078
1079
1080
1081 #include "dev/devigen.h"
1082 #include "boot/psetting.h"
1083 #include "dev/deviplay.h"
1084 #include "boot/plinkman.h"
1085
1086 static struct mixfpostprocaddregstruct *postprocadds;
1087
mixfGetOpt(const char * sec)1088 static uint32_t mixfGetOpt(const char *sec)
1089 {
1090 uint32_t opt=0;
1091 if (cfGetProfileBool(sec, "volramp", 1, 1))
1092 opt|=MIXF_VOLRAMP;
1093 if (cfGetProfileBool(sec, "declick", 1, 1))
1094 opt|=MIXF_DECLICK;
1095 return opt;
1096 }
1097
mixfRegisterPostProc(struct mixfpostprocregstruct * mode)1098 void mixfRegisterPostProc(struct mixfpostprocregstruct *mode)
1099 {
1100 mode->next=dwmixfa_state.postprocs;
1101 dwmixfa_state.postprocs=mode;
1102 }
1103
mixfInit(const char * sec)1104 static void mixfInit(const char *sec)
1105 {
1106 char regname[50];
1107 const char *regs;
1108
1109 fprintf(stderr, "[devwmixf] INIT, ");
1110 #ifdef I386_ASM
1111 fprintf(stderr, "using dwmixfa.c x86-asm version\n");
1112 #else
1113 #ifdef I386_ASM_EMU
1114 fprintf(stderr, "using dwmixfa.c x86-emu-asm version\n");
1115 #else
1116 fprintf(stderr, "using dwmixfa.c C version\n");
1117 /*fprintf(stderr, "using dwmixa.c C version\n");*/
1118 #endif
1119 #endif
1120
1121 dwmixfa_state.postprocs=0;
1122 regs=cfGetProfileString(sec, "postprocs", "");
1123
1124 while (cfGetSpaceListEntry(regname, ®s, 49))
1125 {
1126 void *reg=_lnkGetSymbol(regname);
1127 if (reg)
1128 mixfRegisterPostProc((struct mixfpostprocregstruct*)reg);
1129 }
1130
1131 postprocadds=0;
1132 regs=cfGetProfileString(sec, "postprocadds", "");
1133 while (cfGetSpaceListEntry(regname, ®s, 49))
1134 {
1135 void *reg=_lnkGetSymbol(regname);
1136 if (reg)
1137 {
1138 ((struct mixfpostprocaddregstruct*)reg)->next=postprocadds;
1139 postprocadds=(struct mixfpostprocaddregstruct*)reg;
1140 }
1141 }
1142 }
1143
mixfProcKey(uint16_t key)1144 static int mixfProcKey(uint16_t key)
1145 {
1146 struct mixfpostprocaddregstruct *mode;
1147 for (mode=postprocadds; mode; mode=mode->next)
1148 {
1149 int r=mode->ProcessKey(key);
1150 if (r)
1151 return r;
1152 }
1153
1154 if (plrProcessKey)
1155 return plrProcessKey(key);
1156 return 0;
1157 }
1158
1159 struct devaddstruct mcpFMixAdd = {mixfGetOpt, mixfInit, 0, mixfProcKey};
1160 struct sounddevice mcpFMixer={SS_WAVETABLE|SS_NEEDPLAYER, 0, "FPU Mixer", Detect, Init, Close, &mcpFMixAdd};
1161 char *dllinfo="driver mcpFMixer";
1162
1163 struct linkinfostruct dllextinfo = {.name = "devwmixf", .desc = "OpenCP Wavetable Device: FPU HighQuality Mixer (c) 1999-10 Tammo Hinrichs, Fabian Giesen, Stian Skjelstad", .ver = DLLVERSION, .size = 0};
1164