1 /* OpenCP Module Player
2 * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3 *
4 * Wavetable Device: Software Mixer for sample stream output via devp
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 * -nb980510 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
22 * -first release
23 * -kb980525 Tammo Hinrichs <kb@nwn.de>
24 * - restructured volume calculations to avoid those nasty
25 * rounding errors
26 * - changed behaviour on loop change a bit (may cause problems with
27 * some .ULTs but fixes many .ITs instead ;)
28 * - extended volume table to 256 values, thus consuming more memory,
29 * but definitely increasing the output quality ;)
30 * - added _dllinfo record
31 * -ryg990504 Fabian Giesen <fabian@jdcs.su.nw.schule.de>
32 * -fixed sum really stupid memory leak
33 */
34
35 #include "config.h"
36 #include <string.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39
40 #include <unistd.h>
41
42 #include <sys/mman.h>
43
44 #include "types.h"
45 #include "boot/plinkman.h"
46 #include "dev/imsdev.h"
47 #include "dev/mcp.h"
48 #include "stuff/poll.h"
49 #include "dev/mix.h"
50 #include "dev/player.h"
51 #include "devwmix.h"
52 #include "stuff/imsrtns.h"
53 #include "dwmix.h"
54 #include "dwmixa.h"
55 #include "dwmixqa.h"
56
57 #if defined(__PIC__) && defined(I386_ASM)
58 #warning I386_ASM is disabled in non FPU mixers when compiled PIC
59 #undef I386_ASM
60 #endif
61
62
63 #ifdef I386_ASM
64 #include "stuff/pagesize.inc.c"
65 #endif
66
67 #define MIXBUFLEN 4096
68 #define MAXCHAN 255
69
70 extern struct sounddevice mcpMixer;
71
72 static struct mixqpostprocregstruct *postprocs;
73
74 static int quality;
75 static int resample;
76
77 static int _pause;
78 static long playsamps;
79 static long pausesamps;
80
81 static struct sampleinfo *samples;
82 static int samplenum;
83
84 static int16_t (*amptab)[256]; /* signedness is not fixed here */
85 static unsigned long clipmax;
86 static volatile int clipbusy;
87 #define BARRIER __asm__ __volatile__ ("":);
88
89 static unsigned long amplify;
90 static unsigned short transform[2][2];
91 static int volopt;
92 static unsigned long relpitch;
93 static int interpolation;
94 static int restricted;
95
96 static unsigned char stereo;
97 static unsigned char bit16;
98 static unsigned char signedout;
99 static unsigned long samprate;
100 static unsigned char reversestereo;
101
102 static int channelnum;
103 static struct channel *channels;
104 static int32_t fadedown[2];
105
106 static int32_t (*voltabsr)[256];
107 static int16_t (*voltabsq)[2][256];
108
109 static uint8_t (*interpoltabr)[256][2];
110 static int16_t (*interpoltabq)[32][256][2];
111 static int16_t (*interpoltabq2)[16][256][4];
112
113 static int16_t *scalebuf=0;
114 static int32_t *buf32;
115 static uint32_t bufpos;
116 static uint32_t buflen;
117 static void *plrbuf;
118
119 static void (*playerproc)(void);
120 static unsigned long tickwidth;
121 static unsigned long tickplayed;
122 static unsigned long orgspeed;
123 static unsigned short relspeed;
124 static unsigned long newtickwidth;
125 static unsigned long cmdtimerpos;
126
127 static int mastervol;
128 static int masterbal;
129 static int masterpan;
130 static int mastersrnd;
131 static int masterrvb;
132
calcinterpoltabr(void)133 static void calcinterpoltabr(void)
134 /* used by OpenPlayer */
135 {
136 int i,j;
137 for (i=0; i<16; i++)
138 for (j=0; j<256; j++)
139 {
140 interpoltabr[i][j][1]=(i*(signed char)j)>>4;
141 interpoltabr[i][j][0]=(signed char)j-interpoltabr[i][j][1];
142 }
143 }
144
calcinterpoltabq(void)145 static void calcinterpoltabq(void)
146 /* used by OpenPlayer */
147 {
148 int i,j;
149 for (i=0; i<32; i++)
150 for (j=0; j<256; j++)
151 {
152 interpoltabq[0][i][j][1]=(i*(signed char)j)<<3;
153 interpoltabq[0][i][j][0]=(((signed char)j)<<8)-interpoltabq[0][i][j][1];
154 interpoltabq[1][i][j][1]=(i*j)>>5;
155 interpoltabq[1][i][j][0]=j-interpoltabq[1][i][j][1];
156 }
157 for (i=0; i<16; i++)
158 for (j=0; j<256; j++)
159 {
160 interpoltabq2[0][i][j][0]=((16-i)*(16-i)*(signed char)j)>>1;
161 interpoltabq2[0][i][j][2]=(i*i*(signed char)j)>>1;
162 interpoltabq2[0][i][j][1]=(((signed char)j)<<8)-interpoltabq2[0][i][j][0]-interpoltabq2[0][i][j][2];
163 interpoltabq2[1][i][j][0]=((16-i)*(16-i)*j)>>9;
164 interpoltabq2[1][i][j][2]=(i*i*j)>>9;
165 interpoltabq2[1][i][j][1]=j-interpoltabq2[1][i][j][0]-interpoltabq2[1][i][j][2];
166 }
167 }
168
calcvoltabsr(void)169 static void calcvoltabsr(void)
170 /* used by OpenPlayer */
171 {
172 int i,j;
173 for (i=0; i<=512; i++)
174 for (j=0; j<256; j++)
175 voltabsr[i][j]=(i-256)*(signed char)j;
176 }
177
calcvoltabsq(void)178 static void calcvoltabsq(void)
179 /* used by OpenPlayer */
180 {
181 int i,j;
182 for (j=0; j<=512; j++)
183 {
184 long amp=j-256;
185 for (i=0; i<256; i++)
186 {
187 int v=amp*(signed char)i;
188 voltabsq[j][0][i]=(v==0x8000)?0x7FFF:v;
189 voltabsq[j][1][i]=(amp*i)>>8;
190 }
191 }
192 }
193
calcamptab(signed long amp)194 static void calcamptab(signed long amp)
195 /* Used by SET
196 * OpenPlayer
197 */
198 {
199 int i;
200
201 clipbusy++;
202
203 BARRIER
204
205 amp=3*amp/16;
206
207 for (i=0; i<256; i++)
208 {
209 amptab[0][i]=(amp*i)>>12;
210 amptab[1][i]=(amp*i)>>4;
211 amptab[2][i]=(amp*(signed char)i)<<4;
212 }
213
214 if(amp)
215 clipmax=0x07FFF000/amp;
216 else
217 clipmax=0x07FFF000;
218
219 if (!signedout)
220 for (i=0; i<256; i++)
221 amptab[0][i]^=0x8000;
222
223 BARRIER
224
225 clipbusy--;
226 }
227
calcstep(struct channel * c)228 static void calcstep(struct channel *c)
229 /* Used by calcsteps
230 * SET
231 */
232 {
233 if (!(c->status&MIXRQ_PLAYING))
234 return;
235 if (c->orgdiv)
236 c->step=imuldiv(imuldiv((c->step>=0)?c->orgfrq:-c->orgfrq, c->orgrate, c->orgdiv)<<8, relpitch, samprate);
237 else
238 c->step=0;
239 c->status&=~MIXRQ_INTERPOLATE;
240 if (!quality)
241 {
242 if (interpolation>1)
243 c->status|=MIXRQ_INTERPOLATE;
244 if (interpolation==1)
245 if (abs(c->step)<=(3<<15))
246 c->status|=MIXRQ_INTERPOLATE;
247 } else {
248 if (interpolation>1)
249 c->status|=MIXRQ_INTERPOLATEMAX|MIXRQ_INTERPOLATE;
250 if (interpolation==1)
251 {
252 c->status|=MIXRQ_INTERPOLATE;
253 c->status&=~MIXRQ_INTERPOLATEMAX;
254 }
255 }
256 }
257
calcsteps(void)258 static void calcsteps(void)
259 /* Used by SET */
260 {
261 int i;
262 for (i=0; i<channelnum; i++)
263 calcstep(&channels[i]);
264 }
265
calcspeed(void)266 static void calcspeed(void)
267 {
268 /* Used by SET
269 * OpenPlayer
270 */
271 if (channelnum)
272 newtickwidth=imuldiv(256*256*256, samprate, orgspeed*relspeed);
273 }
274
transformvol(struct channel * ch)275 static void transformvol(struct channel *ch)
276 /* Used by calcvol
277 * calcvols
278 * SET
279 */
280 {
281 int32_t v;
282
283 v=transform[0][0]*ch->orgvol[0]+transform[0][1]*ch->orgvol[1];
284 ch->vol[0]=(v>0x10000)?256:(v<-0x10000)?-256:((v+192)>>8);
285
286 v=transform[1][0]*ch->orgvol[0]+transform[1][1]*ch->orgvol[1];
287 if (volopt^ch->volopt)
288 v=-v;
289 ch->vol[1]=(v>0x10000)?256:(v<-0x10000)?-256:((v+192)>>8);
290
291 if (ch->status&MIXRQ_MUTE)
292 {
293 ch->dstvols[0]=ch->dstvols[1]=0;
294 return;
295 }
296 if (!stereo)
297 {
298 ch->dstvols[0]=(abs(ch->vol[0])+abs(ch->vol[1])+1)>>1;
299 ch->dstvols[1]=0;
300 } else if (reversestereo)
301 {
302 ch->dstvols[0]=ch->vol[1];
303 ch->dstvols[1]=ch->vol[0];
304 } else {
305 ch->dstvols[0]=ch->vol[0];
306 ch->dstvols[1]=ch->vol[1];
307 }
308 }
309
calcvol(struct channel * chn)310 static void calcvol(struct channel *chn)
311 /* Used by calcvols
312 * SET
313 */
314 {
315 chn->orgvol[1]=((int32_t)chn->orgvolx*(0x80L+chn->orgpan))>>8;
316 chn->orgvol[0]=((int32_t)chn->orgvolx*(0x80L-chn->orgpan))>>8;
317 /* werte: 0-0x100; */
318 transformvol(chn);
319 }
320
321
calcvols(void)322 static void calcvols(void)
323 /* Used by SET
324 * OpenPlayer
325 */
326 {
327 int16_t vols[2][2];
328 int i;
329
330 vols[0][0]=vols[1][1]=(mastervol*(0x40+masterpan))>>6;
331 vols[0][1]=vols[1][0]=(mastervol*(0x40-masterpan))>>6;
332 /* werte: 0-0x100 */
333
334 if (masterbal>0)
335 {
336 vols[0][0]=(vols[0][0]*(0x40-masterbal))>>6;
337 vols[0][1]=(vols[0][1]*(0x40-masterbal))>>6;
338 } else if (masterbal<0)
339 {
340 vols[1][0]=(vols[1][0]*(0x40+masterbal))>>6;
341 vols[1][1]=(vols[1][1]*(0x40+masterbal))>>6;
342 }
343
344 volopt=mastersrnd;
345 transform[0][0]=vols[0][0];
346 transform[0][1]=vols[0][1];
347 transform[1][0]=vols[1][0];
348 transform[1][1]=vols[1][1];
349 for (i=0; i<channelnum; i++)
350 transformvol(&channels[i]);
351 }
352
fadechanq(int * fade,struct channel * c)353 static void fadechanq(int *fade, struct channel *c)
354 /* Used by stopchan
355 * playchannelq
356 */
357 {
358 int s;
359 if (c->status&MIXRQ_PLAY16BIT)
360 s=((short*)((unsigned long)c->samp*2))[c->pos];
361 else
362 s=(((signed char*)c->samp)[c->pos])<<8;
363 fade[0]+=(c->curvols[0]*s)>>8;
364 fade[1]+=(c->curvols[1]*s)>>8;
365 c->curvols[0]=c->curvols[1]=0;
366 }
367
stopchan(struct channel * c)368 static void stopchan(struct channel *c)
369 {
370 /* Used by SET
371 */
372 if (!(c->status&MIXRQ_PLAYING))
373 return;
374 if (!quality)
375 mixrFadeChannel(fadedown, c);
376 else
377 fadechanq(fadedown, c);
378 c->status&=~MIXRQ_PLAYING;
379 }
380
amplifyfadeq(uint32_t pos,uint32_t cl,int32_t * curvol,int32_t dstvol)381 static void amplifyfadeq(uint32_t pos, uint32_t cl, int32_t *curvol, int32_t dstvol)
382 /* Used by playchannelq
383 */
384 {
385 uint32_t l=abs(dstvol-*curvol);
386
387 if (l>cl)
388 l=cl;
389 if (dstvol<*curvol)
390 {
391 mixqAmplifyChannelDown(buf32+pos, scalebuf, l, *curvol, 4<<stereo);
392 *curvol-=l;
393 } else if (dstvol>*curvol)
394 {
395 mixqAmplifyChannelUp(buf32+pos, scalebuf, l, *curvol, 4<<stereo);
396 *curvol+=l;
397 }
398 cl-=l;
399 if (*curvol&&cl)
400 mixqAmplifyChannel(buf32+pos+(l<<stereo), scalebuf+l, cl, *curvol, 4<<stereo);
401 }
402
playchannelq(int ch,uint32_t len)403 static void playchannelq(int ch, uint32_t len)
404 {
405 /* Used by mixer
406 */
407 struct channel *c=&channels[ch];
408 if (c->status&MIXRQ_PLAYING)
409 {
410 int quiet=!c->curvols[0]&&!c->curvols[1]&&!c->dstvols[0]&&!c->dstvols[1];
411 mixqPlayChannel(scalebuf, len, c, quiet);
412 if (quiet)
413 return;
414
415 if (stereo)
416 {
417 amplifyfadeq(0, len, &c->curvols[0], c->dstvols[0]);
418 amplifyfadeq(1, len, &c->curvols[1], c->dstvols[1]);
419 } else
420 amplifyfadeq(0, len, &c->curvols[0], c->dstvols[0]);
421
422 if (!(c->status&MIXRQ_PLAYING))
423 fadechanq(fadedown, c);
424 }
425 }
426
427
428
mixer(void)429 static void mixer(void)
430 {
431 /* mixer used by timerproc
432 * Idle
433 */
434 int i;
435 int bufdeltatot;
436 struct mixqpostprocregstruct *mode;
437
438 if (!channelnum)
439 return;
440
441 BARRIER
442
443 if (clipbusy++)
444 {
445 clipbusy--;
446 return;
447 }
448
449 BARRIER
450
451 bufdeltatot=((buflen+(plrGetBufPos()>>(stereo+bit16))-bufpos)%buflen);
452 if (_pause)
453 {
454 uint32_t pass2=((bufpos+bufdeltatot)>buflen)?(bufpos+bufdeltatot-buflen):0;
455
456 if (bit16)
457 {
458 memsetw((short*)plrbuf+(bufpos<<stereo), signedout?0:0x8000, (bufdeltatot-pass2)<<stereo);
459 if (pass2)
460 memsetw((short*)plrbuf, signedout?0:0x8000, pass2<<stereo);
461 } else {
462 memsetb((char*)plrbuf+(bufpos<<stereo), signedout?0:0x80, (bufdeltatot-pass2)<<stereo);
463 if (pass2)
464 memsetb((char*)plrbuf, signedout?0:0x80, pass2<<stereo);
465 }
466
467 bufpos+=bufdeltatot;
468 if (bufpos>=buflen)
469 bufpos-=buflen;
470
471 plrAdvanceTo(bufpos<<(stereo+bit16));
472 pausesamps+=bufdeltatot;
473 } else while (bufdeltatot>0)
474 {
475 uint32_t bufdelta=(bufdeltatot>MIXBUFLEN)?MIXBUFLEN:bufdeltatot;
476
477 if (bufdelta>(buflen-bufpos))
478 bufdelta=buflen-bufpos;
479 if (bufdelta>((tickwidth-tickplayed)>>8))
480 bufdelta=(tickwidth-tickplayed)>>8;
481
482 mixrFade(buf32, fadedown, bufdelta, stereo);
483 if (!quality)
484 {
485 for (i=0; i<channelnum; i++)
486 mixrPlayChannel(buf32, fadedown, bufdelta, &channels[i], stereo);
487 } else {
488 for (i=0; i<channelnum; i++)
489 playchannelq(i, bufdelta);
490 }
491
492 for (mode=postprocs; mode; mode=mode->next)
493 mode->Process(buf32, bufdelta, samprate, stereo);
494
495 mixrClip((char*)plrbuf+(bufpos<<(stereo+bit16)), buf32, bufdelta<<stereo, amptab, clipmax, bit16);
496
497 tickplayed+=bufdelta<<8;
498 if (!((tickwidth-tickplayed)>>8))
499 {
500 tickplayed-=tickwidth;
501 playerproc();
502 cmdtimerpos+=tickwidth;
503 tickwidth=newtickwidth;
504 }
505 bufpos+=bufdelta;
506 if (bufpos>=buflen)
507 bufpos-=buflen;
508
509 plrAdvanceTo(bufpos<<(stereo+bit16));
510 bufdeltatot-=bufdelta;
511 playsamps+=bufdelta;
512 }
513
514 BARRIER
515
516 clipbusy--;
517 }
518
timerproc(void)519 static void timerproc(void)
520 {
521 /* Referred by OpenPlayer
522 */
523 #ifndef NO_BACKGROUND_MIXER
524 mixer();
525 #endif
526 if (plrIdle)
527 plrIdle();
528 }
529
530
531
532
533
534
535
536
537
538 #ifdef __STRANGE_BUG__
539 void *GetReturnAddress12();
540 #pragma aux GetReturnAddress12="mov eax, [esp+12]" value [eax];
541
sbDumpRetAddr(void * ptr)542 void sbDumpRetAddr(void *ptr)
543 {
544 linkaddressinfostruct a;
545 lnkGetAddressInfo(a, ptr);
546 printf("--> called from %s.%s+0x%x, %s.%d+0x%x\n", a.module, a.sym,
547 a.symoff, a.source, a.line, a.lineoff);
548 fflush(stdout);
549 }
550 #endif
551
552
SET(int ch,int opt,int val)553 static void SET(int ch, int opt, int val)
554 {
555 /* Refered by OpenPlayer
556 */
557 struct channel *chn;
558
559 #ifdef __STRANGE_BUG__
560 if ((opt==mcpMasterBalance)&&(val<-64 || val>64)) /* got that damn bug. */
561 {
562 sbDumpRetAddr(GetReturnAddress12());
563 printf("mcpSet(%d, %d, %d);\n", ch, opt, val);
564 }
565 #endif
566
567 if (ch>=channelnum)
568 ch=channelnum-1;
569 if (ch<0)
570 ch=0;
571 chn=&channels[ch];
572 switch (opt)
573 {
574 case mcpCReset:
575 {
576 int reswasmute;
577 stopchan(chn);
578 reswasmute=chn->status&MIXRQ_MUTE;
579 memset(chn, 0, sizeof(struct channel));
580 chn->status=reswasmute;
581 break;
582 }
583 case mcpCInstrument:
584 stopchan(chn);
585 if ((val<0)||(val>=samplenum))
586 break;
587 {
588 struct sampleinfo *samp=&samples[val];
589 chn->samptype=samp->type;
590 chn->length=samp->length;
591 chn->orgrate=samp->samprate;
592 chn->samp=samp->ptr;
593 chn->realsamp.bit8=chn->samp;
594 chn->orgloopstart=samp->loopstart;
595 chn->orgloopend=samp->loopend;
596 chn->orgsloopstart=samp->sloopstart;
597 chn->orgsloopend=samp->sloopend;
598
599 chn->status&=~(MIXRQ_PLAYING|MIXRQ_LOOPED|MIXRQ_PINGPONGLOOP|MIXRQ_PLAY16BIT|MIXRQ_PLAYSTEREO);
600 }
601 if (chn->samptype&mcpSamp16Bit)
602 {
603 chn->status|=MIXRQ_PLAY16BIT;
604 chn->samp=(void*)((unsigned long)chn->samp>>1);
605 }
606 if (chn->samptype&mcpSampStereo)
607 {
608 chn->status|=MIXRQ_PLAYSTEREO;
609 chn->samp=(void*)((unsigned long)chn->samp>>1);
610 }
611 if (chn->samptype&mcpSampSLoop)
612 {
613 chn->status|=MIXRQ_LOOPED;
614 chn->loopstart=chn->orgsloopstart;
615 chn->loopend=chn->orgsloopend;
616 if (chn->samptype&mcpSampSBiDi)
617 chn->status|=MIXRQ_PINGPONGLOOP;
618 } else if (chn->samptype&mcpSampLoop)
619 {
620 chn->status|=MIXRQ_LOOPED;
621 chn->loopstart=chn->orgloopstart;
622 chn->loopend=chn->orgloopend;
623 if (chn->samptype&mcpSampBiDi)
624 chn->status|=MIXRQ_PINGPONGLOOP;
625 }
626 chn->replen=(chn->status&MIXRQ_LOOPED)?(chn->loopend-chn->loopstart):0;
627 chn->step=0;
628 chn->pos=0;
629 chn->fpos=0;
630 break;
631 case mcpCStatus:
632 if (!val)
633 stopchan(chn);
634 else {
635 if (chn->pos>=chn->length)
636 break;
637 chn->status|=MIXRQ_PLAYING;
638 calcstep(chn);
639 }
640 break;
641 case mcpCMute:
642 if (val)
643 chn->status|=MIXRQ_MUTE;
644 else
645 chn->status&=~MIXRQ_MUTE;
646 transformvol(chn);
647 break;
648 case mcpCVolume:
649 chn->orgvolx=(val>0x100)?0x100:(val<0)?0:val;
650 calcvol(chn);
651 break;
652 case mcpCPanning:
653 chn->orgpan=(val>0x80)?0x80:(val<-0x80)?-0x80:val;
654 calcvol(chn);
655 break;
656 case mcpCSurround:
657 chn->volopt=val?1:0;
658 transformvol(chn);
659 break;
660 case mcpCDirect:
661 if (val==0)
662 chn->step=abs(chn->step);
663 else
664 if (val==1)
665 chn->step=-abs(chn->step);
666 else
667 chn->step=-chn->step;
668 break;
669 case mcpCLoop:
670 chn->status&=~(MIXRQ_LOOPED|MIXRQ_PINGPONGLOOP);
671 if ((val==1)&&!(chn->samptype&mcpSampSLoop))
672 val=2;
673 if ((val==2)&&!(chn->samptype&mcpSampLoop))
674 val=0;
675 if (val==1)
676 {
677 chn->status|=MIXRQ_LOOPED;
678 chn->loopstart=chn->orgsloopstart;
679 chn->loopend=chn->orgsloopend;
680 if (chn->samptype&mcpSampSBiDi)
681 chn->status|=MIXRQ_PINGPONGLOOP;
682 }
683 if (val==2)
684 {
685 chn->status|=MIXRQ_LOOPED;
686 chn->loopstart=chn->orgloopstart;
687 chn->loopend=chn->orgloopend;
688 if (chn->samptype&mcpSampBiDi)
689 chn->status|=MIXRQ_PINGPONGLOOP;
690 }
691 chn->replen=(chn->status&MIXRQ_LOOPED)?(chn->loopend-chn->loopstart):0;
692 if (chn->replen)
693 {
694 if (((chn->pos<chn->loopstart)&&(chn->step<0))||((chn->pos>=chn->loopend)&&(chn->step>0)))
695 chn->step=-chn->step;
696 } else if (chn->step<0)
697 chn->step=-chn->step;
698 break;
699
700 case mcpCPosition:
701 {
702 int poswasplaying;
703 poswasplaying=chn->status&MIXRQ_PLAYING;
704 stopchan(chn);
705 if (val<0)
706 val=0;
707 if ((unsigned)val>=chn->length)
708 val=chn->length-1;
709 chn->pos=val;
710 chn->fpos=0;
711 chn->status|=poswasplaying;
712 break;
713 }
714 case mcpCPitch:
715 chn->orgfrq=8363;
716 chn->orgdiv=mcpGetFreq8363(-val);
717 calcstep(chn);
718 break;
719 case mcpCPitchFix:
720 chn->orgfrq=val;
721 chn->orgdiv=0x10000;
722 calcstep(chn);
723 break;
724 case mcpCPitch6848:
725 chn->orgfrq=6848;
726 chn->orgdiv=val;
727 calcstep(chn);
728 break;
729
730 case mcpGSpeed:
731 orgspeed=val;
732 calcspeed();
733 break;
734
735 case mcpMasterVolume:
736 if (val>=0 && val<=64)
737 mastervol=(val<0)?0:(val>63)?63:val;
738 calcvols();
739 break;
740
741 case mcpMasterPanning:
742 #ifndef __STRANGE_BUG__
743 if (val>=-64 && val<=64)
744 #endif
745 masterpan=(val<-64)?-64:(val>64)?64:val;
746 calcvols();
747 break;
748 case mcpMasterBalance:
749 if (val>=-64 && val<=64)
750 masterbal=(val<-64)?-64:(val>64)?64:val;
751 calcvols();
752 break;
753 case mcpMasterSurround:
754 mastersrnd=val?1:0;
755 calcvols();
756 break;
757 case mcpMasterReverb:
758 masterrvb=(val>=64)?63:(val<-64)?-64:val;
759 break;
760 case mcpMasterSpeed:
761 relspeed=(val<16)?16:val;
762 calcspeed();
763 break;
764 case mcpMasterPitch:
765 relpitch=val;
766 calcsteps();
767 break;
768 case mcpMasterFilter:
769 interpolation=val;
770 break;
771 case mcpMasterAmplify:
772 amplify=val;
773 if (channelnum)
774 {
775 calcamptab(amplify);
776 mixSetAmplify(amplify);
777 }
778 break;
779 case mcpMasterPause:
780 _pause=val;
781 break;
782 case mcpGRestrict:
783 restricted=val;
784 break;
785 }
786 }
787
GET(int ch,int opt)788 static int GET(int ch, int opt)
789 {
790 /* Refered by OpenPlayer
791 */
792 struct channel *chn;
793
794 if (ch>=channelnum)
795 ch=channelnum-1;
796 if (ch<0)
797 ch=0;
798 chn=&channels[ch];
799 switch (opt)
800 {
801 case mcpCStatus:
802 return !!(chn->status&MIXRQ_PLAYING);
803 case mcpCMute:
804 return !!(chn->status&MIXRQ_MUTE);
805 case mcpGTimer:
806 if (_pause)
807 return imuldiv(playsamps, 65536, samprate);
808 else
809 return plrGetTimer()-imuldiv(pausesamps, 65536, samprate);
810 case mcpGCmdTimer:
811 return umuldiv(cmdtimerpos, 256, samprate);
812 case mcpMasterReverb:
813 return masterrvb;
814 }
815 return 0;
816 }
817
Idle(void)818 static void Idle(void)
819 {
820 mixer();
821 if (plrIdle)
822 plrIdle();
823 }
824
825
826
GetMixChannel(unsigned int ch,struct mixchannel * chn,uint32_t rate)827 static void GetMixChannel(unsigned int ch, struct mixchannel *chn, uint32_t rate)
828 /* Refered to by OpenPlayer to mixInit */
829 {
830 struct channel *c=&channels[ch];
831
832 if (c->status&MIXRQ_PLAY16BIT)
833 chn->samp=(void*)((unsigned long)c->samp<<1);
834 else
835 chn->samp=c->samp;
836 chn->realsamp.fmt=chn->samp; /* at this point, they match */
837 chn->length=c->length;
838 chn->loopstart=c->loopstart;
839 chn->loopend=c->loopend;
840 chn->fpos=c->fpos;
841 chn->pos=c->pos;
842 chn->vol.vols[0]=abs(c->vol[0]);
843 chn->vol.vols[1]=abs(c->vol[1]);
844 chn->step=imuldiv(c->step, samprate, (signed)rate);
845 chn->status=0;
846 if (c->status&MIXRQ_MUTE)
847 chn->status|=MIX_MUTE;
848 if (c->status&MIXRQ_PLAY16BIT)
849 chn->status|=MIX_PLAY16BIT;
850 if (c->status&MIXRQ_LOOPED)
851 chn->status|=MIX_LOOPED;
852 if (c->status&MIXRQ_PINGPONGLOOP)
853 chn->status|=MIX_PINGPONGLOOP;
854 if (c->status&MIXRQ_PLAYING)
855 chn->status|=MIX_PLAYING;
856 if (c->status&MIXRQ_INTERPOLATE)
857 chn->status|=MIX_INTERPOLATE;
858 }
859
LoadSamples(struct sampleinfo * sil,int n)860 static int LoadSamples(struct sampleinfo *sil, int n)
861 {
862 #if 0
863 int i;
864 if (!mcpReduceSamples(sil, n, 0x40000000, mcpRedToMono))
865 return 0;
866
867 samples=malloc(sizeof(*sil)*n);
868 memcpy(samples, sil, sizeof(*sil)*n);
869
870 for (i=0;i<n;i++)
871 {
872 samples[i].ptr=malloc(samples[i].length+pagesize()*10);
873 samples[i].ptr= (char *)(((int) samples[i].ptr + pagesize()*4) & ~(pagesize()-1) );
874 memcpy(samples[i].ptr, sil[i].ptr, samples[i].length);
875 mprotect((void *)((int)(samples[i].ptr) & ~(pagesize()-1)), samples[i].length, PROT_READ);
876 }
877 samplenum=n;
878
879 #else
880 if (!mcpReduceSamples(sil, n, 0x40000000, mcpRedToMono))
881 return 0;
882
883 samples=sil;
884 samplenum=n;
885 #endif
886 return 1;
887 }
888
OpenPlayer(int chan,void (* proc)(),struct ocpfilehandle_t * source_file)889 static int OpenPlayer(int chan, void (*proc)(), struct ocpfilehandle_t *source_file)
890 {
891 uint32_t currentrate;
892 uint16_t mixrate;
893 struct mixqpostprocregstruct *mode;
894
895 fadedown[0]=fadedown[1]=0;
896 playsamps=pausesamps=0;
897 if (chan>MAXCHAN)
898 chan=MAXCHAN;
899
900 if (!plrPlay)
901 return 0;
902
903 currentrate=mcpMixProcRate/chan;
904 mixrate=(currentrate>mcpMixMaxRate)?mcpMixMaxRate:currentrate;
905 plrSetOptions(mixrate, mcpMixOpt|(restricted?PLR_RESTRICTED:0));
906
907 playerproc=proc;
908
909 if (!quality)
910 {
911 scalebuf=0;
912 voltabsq=0;
913 interpoltabq=0;
914 interpoltabq2=0;
915 if (!(voltabsr=malloc(sizeof(uint32_t)*513*256))) /*new long [513][256];*/
916 return 0;
917 if (!(interpoltabr=malloc(sizeof(uint8_t)*16*256*2))) /*new unsigned char [16][256][2];*/
918 {
919 free(voltabsr);
920 return 0;
921 }
922 } else {
923 voltabsr=0;
924 interpoltabr=0;
925 if (!(scalebuf=malloc(sizeof(int16_t)*MIXBUFLEN))) /* new short [MIXBUFLEN];*/
926 return 0;
927
928 if (!(voltabsq=malloc(sizeof(uint16_t)*513*2*256))) /*new short [513][2][256];*/
929 {
930 free(scalebuf);
931 scalebuf=0;
932 return 0;
933 }
934 if (!(interpoltabq=malloc(sizeof(uint16_t)*2*32*256*2))) /*new unsigned short [2][32][256][2];*/
935 {
936 free(scalebuf);
937 free(voltabsq);
938 scalebuf=0;
939 return 0;
940 }
941 if (!(interpoltabq2=malloc(sizeof(uint16_t)*2*16*256*4))) /*new unsigned short [2][16][256][4];*/
942 {
943 free(scalebuf);
944 free(voltabsq);
945 free(interpoltabq);
946 scalebuf=0;
947 return 0;
948 }
949 }
950 if (!(buf32=malloc(sizeof(uint32_t)*(MIXBUFLEN<<1)))) /*new long [MIXBUFLEN<<1];*/
951 {
952 if (voltabsr) free(voltabsr);
953 if (interpoltabr) free(interpoltabr);
954 if (scalebuf) free(scalebuf);
955 if (voltabsq) free(voltabsq);
956 if (interpoltabq) free(interpoltabq);
957 if (interpoltabq2) free(interpoltabq2);
958 scalebuf=0;
959 return 0;
960 }
961 if (!(amptab=malloc(sizeof(int16_t)*3*256+sizeof(int32_t)))) /* PADDING since assembler indexes some bytes beyond tab and ignores upper bits */ /*new short [3][256];*/
962 {
963 if (voltabsr) free(voltabsr);
964 if (interpoltabr) free(interpoltabr);
965 if (scalebuf) free(scalebuf);
966 if (voltabsq) free(voltabsq);
967 if (interpoltabq) free(interpoltabq);
968 if (interpoltabq2) free(interpoltabq2);
969 free(buf32);
970 scalebuf=0;
971 return 0;
972 }
973
974 if (!(channels=malloc(sizeof(struct channel)*chan))) /*new channel[chan];*/
975 {
976 if (voltabsr) free(voltabsr);
977 if (interpoltabr) free(interpoltabr);
978 if (scalebuf) free(scalebuf);
979 if (voltabsq) free(voltabsq);
980 if (interpoltabq) free(interpoltabq);
981 if (interpoltabq2) free(interpoltabq2);
982 free(buf32);
983 free(channels);
984 scalebuf=0;
985 return 0;
986 }
987
988 mcpGetMasterSample=plrGetMasterSample;
989 mcpGetRealMasterVolume=plrGetRealMasterVolume;
990 if (!mixInit(GetMixChannel, resample, chan, amplify))
991 return 0;
992
993 memset(channels, 0, sizeof(struct channel)*chan);
994 calcvols();
995
996 if (!quality)
997 {
998 mixrSetupAddresses(&voltabsr[256], interpoltabr);
999 calcinterpoltabr();
1000 calcvoltabsr();
1001 } else {
1002 mixqSetupAddresses(&voltabsq[256], interpoltabq, interpoltabq2);
1003 calcinterpoltabq();
1004 calcvoltabsq();
1005 }
1006
1007 if (!plrOpenPlayer(&plrbuf, &buflen, mcpMixBufSize * plrRate / 1000, source_file))
1008 {
1009 mixClose();
1010 return 0;
1011 }
1012
1013 stereo=(plrOpt&PLR_STEREO)?1:0;
1014 bit16=(plrOpt&PLR_16BIT)?1:0;
1015 signedout=!!(plrOpt&PLR_SIGNEDOUT);
1016 reversestereo=!!(plrOpt&PLR_REVERSESTEREO);
1017
1018 samprate=plrRate;
1019 bufpos=0;
1020 _pause=0;
1021 orgspeed=12800;
1022
1023 channelnum=chan;
1024 mcpNChan=chan;
1025 mcpIdle=Idle;
1026
1027 calcamptab(amplify);
1028 calcspeed();
1029 /* playerproc();*/ /* some timing is wrong here!*/
1030 tickwidth=newtickwidth;
1031 tickplayed=0;
1032 cmdtimerpos=0;
1033 if (!pollInit(timerproc))
1034 {
1035 mcpNChan=0;
1036 mcpIdle=0;
1037 plrClosePlayer();
1038 mixClose();
1039 return 0;
1040 }
1041
1042 for (mode=postprocs; mode; mode=mode->next)
1043 if (mode->Init)
1044 mode->Init(samprate, stereo);
1045
1046 return 1;
1047 }
1048
ClosePlayer()1049 static void ClosePlayer()
1050 {
1051 struct mixqpostprocregstruct *mode;
1052
1053 mcpNChan=0;
1054 mcpIdle=0;
1055
1056 pollClose();
1057
1058 plrClosePlayer();
1059
1060 channelnum=0;
1061 restricted=0;
1062
1063 mixClose();
1064
1065 for (mode=postprocs; mode; mode=mode->next)
1066 if (mode->Close)
1067 mode->Close();
1068
1069 if (voltabsr) free(voltabsr);
1070 if (interpoltabr) free(interpoltabr);
1071 if (scalebuf) free(scalebuf);
1072 if (voltabsq) free(voltabsq);
1073 if (interpoltabq) free(interpoltabq);
1074 if (interpoltabq2) free(interpoltabq2);
1075
1076 free(channels);
1077 free(amptab);
1078 free(buf32);
1079 scalebuf=0;
1080
1081 voltabsr=NULL;
1082 interpoltabr=NULL;
1083 scalebuf=NULL;
1084 voltabsq=NULL;
1085 interpoltabq=NULL;
1086 interpoltabq2=NULL;
1087 }
1088
wmixInit(const struct deviceinfo * dev)1089 static int wmixInit(const struct deviceinfo *dev)
1090 {
1091 resample=!!(dev->opt&MIXRQ_RESAMPLE);
1092 quality=!!dev->subtype;
1093
1094 restricted=0;
1095 amplify=65535;
1096 relspeed=256;
1097 relpitch=256;
1098 interpolation=0;
1099 mastervol=64;
1100 masterbal=0;
1101 masterpan=0;
1102 mastersrnd=0;
1103 channelnum=0;
1104
1105 mcpLoadSamples=LoadSamples;
1106 mcpOpenPlayer=OpenPlayer;
1107 mcpClosePlayer=ClosePlayer;
1108 mcpGet=GET;
1109 mcpSet=SET;
1110
1111 #ifdef I386_ASM
1112
1113 /* Self-modifying code needs access to modify it self */
1114 {
1115 int fd;
1116 char *file=strdup("/tmp/ocpXXXXXX");
1117 char *start1, *stop1, *start2, *stop2;
1118 int len1, len2;
1119 fd=mkstemp(file);
1120
1121 start1=(void *)remap_range1_start;
1122 stop1=(void *)remap_range1_stop;
1123 start2=(void *)remap_range2_start;
1124 stop2=(void *)remap_range2_stop;
1125 #ifdef MIXER_DEBUG
1126 fprintf(stderr, "range1: %p - %p\n", start1, stop1);
1127 fprintf(stderr, "range2: %p - %p\n", start2, stop2);
1128 #endif
1129
1130 start1=(char *)(((int)start1)&~(pagesize()-1));
1131 start2=(char *)(((int)start2)&~(pagesize()-1));
1132 len1=((stop1-start1)+pagesize()-1)& ~(pagesize()-1);
1133 len2=((stop2-start2)+pagesize()-1)& ~(pagesize()-1);
1134 #ifdef MIXER_DEBUG
1135 fprintf(stderr, "mprot: %p + %08x\n", start1, len1);
1136 fprintf(stderr, "mprot: %p + %08x\n", start2, len2);
1137 #endif
1138 if (write(fd, start1, len1)!=len1)
1139 {
1140 #ifdef MIXER_DEBUG
1141 fprintf(stderr, "write 1 failed\n");
1142 #endif
1143 return 0;
1144 }
1145 if (write(fd, start2, len2)!=len2)
1146 {
1147 #ifdef MIXER_DEBUG
1148 fprintf(stderr, "write 2 failed\n");
1149 #endif
1150 return 0;
1151 }
1152
1153 if (mmap(start1, len1, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, fd, 0)==MAP_FAILED)
1154 {
1155 perror("mmap()");
1156 return 0;
1157 }
1158
1159 if (mmap(start2, len2, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, fd, len1)==MAP_FAILED)
1160 {
1161 perror("mmap()");
1162 return 0;
1163 }
1164
1165 /*
1166 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) ||
1167 mprotect((char *)(((int)remap_range2_start)&~(pagesize()-1)), (((char *)remap_range2_stop-(char *)remap_range2_start)+pagesize()-1)& ~(pagesize()-1), PROT_READ|PROT_WRITE|PROT_EXEC) )
1168 {
1169 perror("Couldn't mprotect");
1170 return 0;
1171 }*/
1172 #ifdef MIXER_DEBUG
1173 fprintf(stderr, "Done ?\n");
1174 #endif
1175 close(fd);
1176 unlink(file);
1177 free(file);
1178 }
1179 #endif
1180
1181 return 1;
1182 }
1183
wmixClose(void)1184 static void wmixClose(void)
1185 {
1186 mcpOpenPlayer=0;
1187 }
1188
1189
wmixDetect(struct deviceinfo * c)1190 static int wmixDetect(struct deviceinfo *c)
1191 {
1192 c->devtype=&mcpMixer;
1193 c->port=-1;
1194 c->port2=-1;
1195 /*
1196 c->irq=-1;
1197 c->irq2=-1;
1198 c->dma=-1;
1199 c->dma2=-1;
1200 */
1201 if (c->subtype==-1)
1202 c->subtype=0;
1203 c->chan=/*(MAXCHAN>99)?99:MAXCHAN;*/MAXCHAN;
1204 c->mem=0;
1205 return 1;
1206 }
1207
mixrRegisterPostProc(struct mixqpostprocregstruct * mode)1208 void mixrRegisterPostProc(struct mixqpostprocregstruct *mode)
1209 {
1210 mode->next=postprocs;
1211 postprocs=mode;
1212 }
1213
1214 #include "dev/devigen.h"
1215 #include "boot/psetting.h"
1216 #include "dev/deviplay.h"
1217 #include "boot/plinkman.h"
1218
1219 static struct mixqpostprocaddregstruct *postprocadds;
1220
mixGetOpt(const char * sec)1221 static uint32_t mixGetOpt(const char *sec)
1222 {
1223 uint32_t opt=0;
1224 if (cfGetProfileBool(sec, "mixresample", 0, 0))
1225 opt|=MIXRQ_RESAMPLE;
1226 return opt;
1227 }
1228
mixrInit(const char * sec)1229 static void mixrInit(const char *sec)
1230 {
1231 char regname[50];
1232 const char *regs;
1233
1234
1235 fprintf(stderr, "[devwmix] INIT, ");
1236 if (!quality)
1237 {
1238 #ifdef I386_ASM
1239 fprintf(stderr, "using dwmixa.c x86-asm version\n");
1240 #else
1241 #ifdef I386_ASM_EMU
1242 fprintf(stderr, "using dwmixa.c x86-emu-asm version\n");
1243 #else
1244 fprintf(stderr, "using dwmixa.c C version\n");
1245 #endif
1246 #endif
1247 } else {
1248 #ifdef I386_ASM
1249 fprintf(stderr, "using dwmixaq.c x86-asm version\n");
1250 #else
1251 fprintf(stderr, "using dwmixaq.c C version\n");
1252 #endif
1253 }
1254
1255 postprocs=0;
1256 regs=cfGetProfileString(sec, "postprocs", "");
1257
1258 while (cfGetSpaceListEntry(regname, ®s, 49))
1259 {
1260 void *reg=_lnkGetSymbol(regname);
1261 fprintf(stderr, "[%s] registering %s: %p\n", sec, regname, reg);
1262 if (reg)
1263 mixrRegisterPostProc((struct mixqpostprocregstruct*)reg);
1264 }
1265
1266 postprocadds=0;
1267 regs=cfGetProfileString(sec, "postprocadds", "");
1268 while (cfGetSpaceListEntry(regname, ®s, 49))
1269 {
1270 void *reg=_lnkGetSymbol(regname);
1271 if (reg)
1272 {
1273 ((struct mixqpostprocaddregstruct*)reg)->next=postprocadds;
1274 postprocadds=(struct mixqpostprocaddregstruct*)reg;
1275 }
1276 }
1277 }
1278
mixProcKey(unsigned short key)1279 static int mixProcKey(unsigned short key)
1280 {
1281 struct mixqpostprocaddregstruct *mode;
1282 for (mode=postprocadds; mode; mode=mode->next)
1283 {
1284 int r=mode->ProcessKey(key);
1285 if (r)
1286 return r;
1287 }
1288
1289 if (plrProcessKey)
1290 return plrProcessKey(key);
1291 return 0;
1292 }
1293
1294 struct devaddstruct mcpMixAdd = {mixGetOpt, mixrInit, 0, mixProcKey};
1295 struct sounddevice mcpMixer={SS_WAVETABLE|SS_NEEDPLAYER, 0, "Mixer", wmixDetect, wmixInit, wmixClose, &mcpMixAdd};
1296 char *dllinfo="driver mcpMixer";
1297
1298 struct linkinfostruct dllextinfo = {.name = "devwmix", .desc = "OpenCP Wavetable Device: Mixer (c) 1994-10 Niklas Beisert, Tammo Hinrichs, Stian Skjelstad", .ver = DLLVERSION, .size = 0};
1299