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, &regs, 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, &regs, 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