|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1992 Media Vision, Inc
4:
5: Module Name:
6:
7: mvmix.c
8:
9: Abstract:
10:
11: This module contains code for controlling the Media Vision Mixer
12: hardware. Media Vision has used only two software-controllable
13: mixer chips so far. The MV 508 is used on the PAS 16 only. All
14: other chips use the National part XXXX. Programming the
15: Nationial mixer chip is VOODOO BLACK MAGIC and will be very slow
16: under NT.
17:
18: Environment:
19:
20: Kernel mode
21:
22: Revision History:
23:
24: 27-Sep-1992
25: Initial revision
26:
27: --*/
28:
29: #include <sound.h>
30:
31: void SetEq(PFOUNDINFO pFI, USHORT P_output, USHORT P_EQtype,USHORT P_level);
32: void SetEqMode(PFOUNDINFO pFI, USHORT P_loudness, USHORT P_enhance);
33: void NationalMix(PFOUNDINFO pFI, USHORT wData);
34: void NationalVolume(PFOUNDINFO pFI, USHORT wVolume,UCHAR wVolumeRegister);
35: ULONG Scale100ToFFFF(USHORT wVal);
36: BYTE ScaleFFFFTo100(USHORT wVal);
37:
38: #ifdef ALLOC_PRAGMA
39: #pragma alloc_text(init,SetOutput)
40: #pragma alloc_text(init,SetFilter)
41: #endif
42:
43: //
44: //-------------------------========================---------------------------
45: //------------------------====< DATA SECTION >====---------------------------
46: //-------------------------========================---------------------------
47: //
48: //
49: // These variables are DMA/Buffer control variables
50: //
51:
52: //
53: // These variables mirror the hardware state
54: //
55: UCHAR audiomixr= SERIAL_MIX_CLOCK+SERIAL_MIX_DUALFM ;
56: UCHAR audiofilt; // B8A Audio Filter Control Register
57:
58: //
59: // a linear table of filter values - from mute to high
60: //
61: UCHAR FilterTable[]=
62: {
63: 0x00, // 000000b mute - goes to PC speaker
64: 0x24, // 100100b 20hz to 2.9khz
65: 0x39, // 111001b 20hz to 5.9khz
66: 0x31, // 110001b 20hz to 8.9khz
67: 0x29, // 101001b 20hz to 11.9khz
68: 0x22, // 100010b 20hz to 15.9khz
69: 0x21, // 100001b 20hz to 17.8khz
70: };
71: //
72: //Mixer settings (0 - 12)
73: //
74: UCHAR mixersettings[]=
75: {
76: 0x00, // level 0
77: 0x20, // level 1
78: 0x10, // level 2
79: 0x08, // level 3
80: 0x04, // level 4
81: 0x02, // level 5
82: 0x12, // level 6
83: 0x2A, // level 7
84: 0x16, // level 8
85: 0x01, // level 9
86: 0x29, // level A
87: 0x1D, // level B
88: 0x2F // level C
89: };
90:
91: UCHAR SampleFilterSetting=0; // default setting based on sample rate
92:
93: //
94: // Volume settings (0 - 12)
95: //
96:
97: UCHAR volsettings[]=
98: {
99: 0x00, // level 0
100: 0x60, // level 1
101: 0x50, // level 2
102: 0x48, // level 3
103: 0x44, // level 4
104: 0x42, // level 5
105: 0x52, // level 6
106: 0x6A, // level 7
107: 0x56, // level 8
108: 0x41, // level 9
109: 0x69, // level A
110: 0x5D, // level B
111: 0x6F // level C
112: };
113:
114: //
115: // Xlat table lookup= 0-31
116: // result= 0-12
117: //
118:
119: UCHAR Scale32To12[]=
120: {
121: 0 , 1, 1, 2, 2, 3, 3, 3, // 0- 7
122: 4 , 4, 4, 5, 5, 5, 6, 6, // 8-15
123: 6 , 7, 7, 7, 8, 8, 8, 9, // 16-23
124: 9 , 9,10,10,11,11,12,12 // 24-31
125: };
126:
127:
128: UCHAR Scale64To40[]=
129: {
130: 0 , 1, 2, 3, 4, 5, 6, 7, // 0- 7
131: 8 , 8, 9,10,10,11,12,12, // 8-15
132: 13,14,14,15,16,16,17,18, // 16-23
133: 18,19,20,20,21,22,22,23, // 24-31
134: 24,24,25,26,26,27,28,28, // 32-39
135: 29,29,30,30,31,31,32,32, // 40-47
136: 32,33,33,34,34,35,35,35, // 48-55
137: 36,36,37,37,38,38,39,40 // 56-63
138: };
139:
140: UCHAR BassTreb32to13[]=
141: {
142: 0 , 1, 1, 2, 2, 3, 3, 3, // 0- 7
143: 4 , 4, 4, 5, 5, 5, 6, 6, // 8-15
144: 6 , 7, 7, 7, 8, 8, 8, 9, // 16-23
145: 9 , 9,10,10,11,11,12,12 // 24-31
146: };
147:
148:
149: /*\
150: ;---|*|-=< void SetInput (USHORT P_input_num, USHORT P_volume_lvl,USHORT P_channel,
151: ;---|*| USHORT P_crossover,USHORT P_output_num )
152: ;---|*|
153: ;---|*| Set the selected channel within the Input Mixer
154: ;---|*|
155: ;---|*| Entry Conditions:
156: ;---|*| P_input_num = Input # (0-6 for serial mixer, 0-7 for 508)
157: ;---|*| P_volume_lvl = volume level (0-FFFF)
158: ;---|*| P_channel = LEFT, RIGHT or BOTH
159: ;---|*| P_crossover = Crossover Info (required onlby for 508)
160: ;---|*| P_output_num = Output # (0-1 for either mixer)
161: ;---|*|
162: ;---|*| Exit Conditions:
163: ;---|*| None
164: ;---|*|
165: ; \*/
166:
167: void
168: SetInput (PFOUNDINFO pFI, UCHAR P_input_num, USHORT P_volume_lvl,USHORT P_channel,
169: USHORT P_crossover,UCHAR P_output_num )
170: {
171: UCHAR bTemp,bTemp1;
172:
173: P_volume_lvl>>=(16-5); // convert 0-ffff to 0-31
174:
175: if (pFI->Caps.CapsBits.Mixer_508)
176: {
177: bTemp=(UCHAR) P_input_num; // Channel #
178:
179: bTemp|=(P_channel<<5); // get left/right
180: bTemp|=MV_508_ADDRESS; // 508 ADDRESS BIT
181: bTemp|=MV_508_INPUT; // 508 INPUT BIT
182:
183: dprintf4(("Input Mixer 508 Address : %04x", bTemp));
184: PASX_OUT(pFI, MIXER_508_REG, bTemp);
185:
186: bTemp=P_volume_lvl; // get volume level reduced to (0-31 range)
187:
188: bTemp1=P_crossover; // get CROSSOVER
189:
190: if (bTemp1==MIXCROSSCAPS_NORMAL_STEREO)
191: {
192: }
193: else
194: if (bTemp1 & MIXCROSSCAPS_REVERSE_STEREO)
195: {
196: bTemp |= MV_508_SWAP; // this channel's swapped
197: }
198: else
199: {
200: if (P_channel==_LEFT)
201: {
202: if (bTemp1 & MIXCROSSCAPS_LEFT_TO_RIGHT)
203: bTemp |= MV_508_SWAP; // this channel's swapped
204: }
205: else
206: {
207: if (bTemp1 & MIXCROSSCAPS_LEFT_TO_RIGHT)
208: bTemp |= MV_508_SWAP; // this channel's swapped
209: }
210: }
211:
212: bTemp|=((P_output_num & 1 )<<5); // select output number
213: dprintf4(("Input Mixer 508 Data : %04x", bTemp));
214: PASX_OUT(pFI, MIXER_508_REG,bTemp);
215:
216: }
217: else // National (serially programmed) mixer
218: {
219: dprintf2(("-----------Using Serial Mixer!"));
220: //
221: // send out the mixer channel #
222: //
223:
224: bTemp=P_input_num; // Channel #
225: bTemp++; // channel 0 was XXX
226:
227: if (P_channel==_RIGHT)
228: bTemp+=7; // this magic number is the offset to right channel
229:
230: bTemp|=NATIONAL_COMMAND;
231: NationalMix(pFI, bTemp);
232:
233: // select the correct mixer
234: bTemp1=P_output_num<<6; // get output number
235:
236: //
237: // send out the mixer data
238: //
239:
240: bTemp=P_volume_lvl &= 0x1F; // limit to 31
241: bTemp=Scale32To12[bTemp];
242: bTemp=mixersettings[bTemp];
243:
244: NationalMix(pFI, bTemp);
245: }
246: }
247:
248: /*\
249: ;---|*|--------====< void SetOutput (line, level, channel ) >====--------
250: ;---|*|
251: ;---|*| This routine outputs a new setting for a volume channel.
252: ;---|*|
253: ;---|*| Entry Conditions:
254: ;---|*| WParm1 is a value from 0 - 1
255: ;---|*| WParm2 is a value to be written to the control (0-63)
256: ;---|*| WParm3 signifies left or right
257: ;---|*|
258: ;---|*| Exit Conditions:
259: ;---|*| None
260: ;---|*|
261: ; \*/
262: void
263: SetOutput (PFOUNDINFO pFI, UCHAR P_output_num,USHORT P_volume_lvl,USHORT P_channel )
264: {
265: UCHAR bTemp,bTemp1;
266:
267: dprintf2(("SetOutput Entered"));
268: P_volume_lvl>>=(16-6); // convert 0-ffff to 0-63
269:
270: if (pFI->Caps.CapsBits.Mixer_508)
271: {
272: //EnterCrit /// don't interrupt me!
273:
274: // investigate keSynchronizeExecution
275:
276: bTemp=(UCHAR) P_output_num;
277: bTemp++; // Output number need to be 1 based
278:
279: bTemp|=(P_channel<<5); // get left/right
280: bTemp|=MV_508_ADDRESS;
281:
282: dprintf4(("Output Mixer 508 Address : %04x", bTemp));
283: PASX_OUT(pFI, MIXER_508_REG,bTemp);
284:
285: #if 0
286: if (fMuting)
287: {
288: bTemp=0;
289: }
290: else
291: #endif
292: {
293: bTemp=P_volume_lvl; // get volume level (0-63 range)
294:
295: if (P_output_num!=OUT_AMPLIFIER)
296: bTemp>>=2; // output B of MV508 has 0-15 range
297: }
298: dprintf4((" Mixer 508 Data : %04x", bTemp));
299: PASX_OUT(pFI, MIXER_508_REG,bTemp);
300: }
301: else // NATIONAL (SERIAL PROGRAMMED) MIXER
302: {
303: dprintf2(("Using Serial Mixer!"));
304: if (P_output_num==0) // serial device has volume on output 0 only
305: {
306: #if 0
307: if (fMuting)
308: {
309: bTemp=0;
310: }
311: else
312: #endif
313: {
314: bTemp=Scale64To40[P_volume_lvl];
315: }
316: NationalVolume(pFI, (USHORT)bTemp,(UCHAR)((P_channel&1)+NATIONAL_LEFT_VOL_REG)); // see Pas-1 spec p.15 (LEFT VOLUME CONTROL)
317: }
318: }
319:
320: }
321:
322: /*\
323: ;---|*|--------====< void SetEQ (line, EQ, level ) >====--------
324: ;---|*|
325: ;---|*| This routine outputs a new setting for a volume channel.
326: ;---|*|
327: ;---|*| Entry Conditions:
328: ;---|*| WParm1 is line number (range 0 - 1; 1 is don't care)
329: ;---|*| WParm2 is EQ type (ie. Loudness, Stereo Enhance, BMT)
330: ;---|*| WParm3 is level (range 0-31)
331: ;---|*|
332: ;---|*| Exit Conditions:
333: ;---|*| None
334: ;---|*|
335: ; \*/
336:
337: void
338: SetEq(PFOUNDINFO pFI, USHORT P_output, USHORT P_EQtype,USHORT P_level)
339: {
340: UCHAR bTemp;
341:
342: if (P_output!=0)
343: return;
344:
345: if (pFI->Caps.CapsBits.Mixer_508)
346: {
347: switch (P_EQtype)
348: {
349: case _BASS:
350: PASX_OUT(pFI, MIXER_508_REG,MV_508_ADDRESS + MV_508_BASS);
351: PASX_OUT(pFI, MIXER_508_REG, BassTreb32to13[P_level]);
352: break;
353:
354: case _TREBLE:
355: PASX_OUT(pFI, MIXER_508_REG,MV_508_ADDRESS + MV_508_TREBLE);
356: PASX_OUT(pFI, MIXER_508_REG, BassTreb32to13[P_level]);
357: break;
358: }
359: }
360: else // NATIONAL (SERIAL PROGRAMMED) MIXER
361: {
362: bTemp=Scale32To12[P_level];
363: NationalVolume(pFI, (USHORT)bTemp,(UCHAR)((P_EQtype&1)+NATIONAL_BASS_REG) ); // see Pas-1 spec p.15 (LEFT VOLUME CONTROL)
364: }
365: }
366:
367:
368: /*\
369: ;---|*|--------====< void SetEqMode (Loudness, Enhance ) >====--------
370: ;---|*|
371: ;---|*| This routine sets loundess and stereo enhance modes
372: ;---|*|
373: ;---|*| Entry Conditions:
374: ;---|*| loudness (Z vs NZ)
375: ;---|*| Stereo Enhance (range 0-3)
376: ;---|*|
377: ;---|*| Exit Conditions:
378: ;---|*| None
379: ;---|*|
380: ; \*/
381:
382: void
383: SetEqMode(PFOUNDINFO pFI, USHORT P_loudness, USHORT P_enhance)
384: {
385: UCHAR bTemp=0;
386:
387: if (pFI->Caps.CapsBits.Mixer_508)
388: {
389: PASX_OUT(pFI, MIXER_508_REG,MV_508_ADDRESS + MV_508_EQMODE);
390: if (P_loudness)
391: bTemp+=MV_508_LOUDNESS;
392:
393: bTemp+=P_enhance & MV_508_ENHANCE;
394: PASX_OUT(pFI, MIXER_508_REG,bTemp);
395: }
396: else
397: {
398: if (P_loudness)
399: bTemp=NATIONAL_LOUDNESS; // Loudness bit
400:
401: if (P_enhance)
402: bTemp|=NATIONAL_ENHANCE; // stereo enhance bit
403:
404: NationalVolume(pFI, bTemp,NATIONAL_LOUD_ENH_REG); // see Pas-1 spec p.15 (LEFT VOLUME CONTROL)
405: }
406: }
407:
408: /* ----------------------====< NationalMix >====-------------------------- */
409: /*\ |
410: ;---|*| NationalMix -- Load The National Mixer |
411: ;---|*| |
412: ;---|*| Entry Conditions |
413: ;---|*| wData = index/data |
414: ;---|*| |
415: ; \*/
416: void
417: NationalMix(PFOUNDINFO pFI, USHORT wData)
418: {
419: USHORT i,bTemp=0;
420:
421: // EnterCrit
422:
423: bTemp = audiomixr; // get current hardware state
424: // bTemp &= SERIAL_MIX_REALSOUND+SERIAL_MIX_DUALFM; // save state of only these bits
425: bTemp|=~(SERIAL_MIX_REALSOUND+SERIAL_MIX_DUALFM); // turn on all other bits
426: // all clocks and strobes should be 1
427: PASX_OUT(pFI, SERIAL_MIXER,bTemp);
428: KeStallExecutionProcessor(5); // wait 5 us
429:
430: for (i=0; i<8; i++) {
431:
432: // output clock is 0
433: PASX_OUT(pFI, SERIAL_MIXER,bTemp & (~SERIAL_MIX_CLOCK));
434: KeStallExecutionProcessor(5); // wait 5 us
435:
436: PASX_OUT(pFI, SERIAL_MIXER,(wData>>i)& 1); //send data, clock is 0
437: KeStallExecutionProcessor(5); // wait 5 us
438:
439: PASX_OUT(pFI, SERIAL_MIXER,
440: ((wData>>i)& 1)^SERIAL_MIX_CLOCK); //send data, clock is 1
441: KeStallExecutionProcessor(5); // wait 5 us
442: }
443:
444: PASX_OUT(pFI, SERIAL_MIXER,
445: ((wData>>i)& 1)|SERIAL_MIX_CLOCK|SERIAL_MIX_STROBE); //strobe it in
446: KeStallExecutionProcessor(5); // wait 5 us
447:
448: PASX_OUT(pFI, SERIAL_MIXER,bTemp);
449: audiomixr=bTemp; // save the last state
450: KeStallExecutionProcessor(5); // wait 5 us
451:
452: }
453: /* ---;--------------------====< NationalVolume >====------------------------------- */
454: /*\;
455: ;---|*|; NationalVolume -- Load Volume control Register
456: ;---|*|;
457: ;---|*|; Entry Conditions:
458: ;---|*|; bl = parameter register (volume control channel 0-7)
459: ;---|*|; ah = data to transfer (new channel setting)
460: ; \*/
461:
462: void
463: NationalVolume(PFOUNDINFO pFI, USHORT wVolume, UCHAR wLeftRight)
464: {
465: //
466: // pass everything, but left/right volume directly to the device
467: //
468: // left & right volume are presented
469: // to the logical level as 0 - 40,
470: // where 0 is the lowest, and 40 is
471: // the highest. In reality, this
472: // is backwards, that is, 40 is the
473: // lowest, and 0 is the highest. We will
474: // correct the value here...
475:
476: USHORT bTemp,i;
477: short sVolume=wVolume;
478:
479: // Perform the volume control output
480:
481: if (( wLeftRight==NATIONAL_LEFT_VOL_REG) ||
482: (wLeftRight==NATIONAL_RIGHT_VOL_REG ))
483: {
484: sVolume -=0x40; // is backwards, that is, 40 is the
485: sVolume = -sVolume; // lowest, and 0 is the highest. We will
486: // correct the value here...
487: }
488: //
489: // all 1s but volume enable and clock
490: //
491: bTemp=audiomixr; // save the realsound & dual fm bits
492: bTemp &= SERIAL_MIX_REALSOUND+SERIAL_MIX_DUALFM;
493: bTemp |= ~ (SERIAL_MIX_REALSOUND+SERIAL_MIX_DUALFM+SERIAL_MIX_MASTER+SERIAL_MIX_CLOCK);
494:
495: // EnterCrit
496: PASX_OUT(pFI, SERIAL_MIXER,bTemp); // note: clock is off
497:
498: for (i=0; i<8; i++) {
499:
500: bTemp=(wLeftRight>>i)& 1;
501: PASX_OUT(pFI, SERIAL_MIXER,(bTemp | SERIAL_MIX_CLOCK)); // clock's on
502: KeStallExecutionProcessor(5); // wait 5 us
503:
504: PASX_OUT(pFI, SERIAL_MIXER,(bTemp)); // clock's off
505: KeStallExecutionProcessor(5); // wait 5 us
506: }
507:
508: // write with volume control enable
509: // which starts data loading
510: PASX_OUT(pFI, SERIAL_MIXER,bTemp|SERIAL_MIX_MASTER);
511: KeStallExecutionProcessor(6); // wait 6 us
512:
513: for (i=0; i<8; i++) {
514:
515: bTemp=bTemp & (~D0); // mask off D0
516: bTemp |= ((sVolume>>i) & D0); // move current bit into D0
517:
518: PASX_OUT(pFI, SERIAL_MIXER,bTemp+SERIAL_MIX_CLOCK);
519: KeStallExecutionProcessor(6); // wait 6 us
520:
521: PASX_OUT(pFI, SERIAL_MIXER,bTemp);
522: KeStallExecutionProcessor(6); // wait 5 us
523: }
524:
525: for (i=0; i<12; i++) {
526:
527: PASX_OUT(pFI, SERIAL_MIXER,bTemp);
528: KeStallExecutionProcessor(6); // wait 6 us
529: }
530:
531: // toggle volume control enable
532:
533: PASX_OUT(pFI, SERIAL_MIXER,bTemp|SERIAL_MIX_MASTER);
534: KeStallExecutionProcessor(6); // wait 6 us
535:
536: PASX_OUT(pFI, SERIAL_MIXER,bTemp|SERIAL_MIX_MASTER);
537: KeStallExecutionProcessor(6); // wait 6 us
538:
539: PASX_OUT(pFI, SERIAL_MIXER,bTemp|SERIAL_MIX_MASTER);
540: KeStallExecutionProcessor(6); // wait 6 us
541:
542: PASX_OUT(pFI, SERIAL_MIXER,bTemp);
543: KeStallExecutionProcessor(6); // wait 6 us
544:
545: audiomixr=bTemp; // save the last state
546: }
547:
548: /*\
549: ;---|*|--------------====< void SetFilter (int setting ) >===---------------
550: ;---|*|
551: ;---|*| This routine selects a filter setting from mute to high freq filter.
552: ;---|*|
553: ;---|*| Entry Conditions:
554: ;---|*| WParm1 is a value from 0 - 6
555: ;---|*|
556: ;---|*| Exit Conditions:
557: ;---|*| None
558: ;---|*|
559: ;---|*|
560: ; \*/
561:
562: void
563: SetFilter(PFOUNDINFO pFI, USHORT wSetting)
564: {
565: USHORT wTemp;
566:
567: if (wSetting <= FILTERMAX) {
568:
569: wSetting=FilterTable[wSetting];
570:
571: wTemp = audiofilt; // get current bits
572: wTemp &= ~(fFIdatabits+fFImutebits); // save everthing but
573:
574: wSetting|=wTemp;
575:
576: // EnterCrit
577: PASX_OUT(pFI, FILTER_REGISTER, wSetting);
578: KeStallExecutionProcessor(6); // wait 6 us
579:
580: audiofilt=wSetting; // set current bits
581: }
582:
583: }
584: #if 0
585: ULONG
586: Scale100ToFFFF(WORD wVal)
587: {
588: ULONG dwScaled;
589:
590: dwScaled=((ULONG)wVal) * (0xFFFFL/100L);
591: dwScaled=(dwScaled & 0xff00L)+ (dwScaled >>8);
592:
593: return(dwScaled);
594: }
595:
596: UCHAR
597: ScaleFFFFTo100(WORD wVal)
598: {
599: UCHAR bScaled;
600:
601: bScaled=((wVal>>8)*100)/255;
602:
603: return(bScaled);
604: }
605: #endif
606:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.