home *** CD-ROM | disk | FTP | other *** search
/ Audio 4.94 - Over 11,000 Files / audio-11000.iso / msdos / sndbords / proaudio / mvsa / mvsa.c < prev    next >
Text File  |  1993-06-10  |  32KB  |  1,158 lines

  1.  
  2. ;   /*\
  3. ;---|*|----====< MVSA.C >====----
  4. ;---|*|
  5. ;---|*| An simple program to drive the Pro Audio "Spectrum Sound"
  6. ;---|*| Copyright (c) 1991-1993 Media Vision, Inc. All rights reserved.
  7. ;---|*|
  8. ;---|*| This code is provided as freeware for anyone wishing to implement
  9. ;---|*| the "Spectrum Sound" technique on the Pro Audio Spectrum.
  10. ;---|*|
  11. ;---|*| The Pro Audio Spectrum's mixer has the ability to perform a
  12. ;---|*| close approximation of Dolby's Surround Sound (r) encoding
  13. ;---|*| process.
  14. ;---|*|
  15. ;---|*| The Dolby Surround Sound (r) technique involves filter
  16. ;---|*| the signal, and shifting both the left and right channels 180
  17. ;---|*| degrees out of phase. Any Surround Sound (r) decoder, sees the
  18. ;---|*| signal out of phase, and places the audio in rear speaker.
  19. ;---|*|
  20. ;---|*| The Pro Audio Spectrum mixer architecture has the ability to
  21. ;---|*| create a phase delay in the signal. On all Pro Audio Spectrums,
  22. ;---|*| every audio channel mixer can be connected to a "PLAY ONLY" path,
  23. ;---|*|
  24. ;---|*| or "PLAY and RECORD" path. The actual "PLAY and RECORD" path
  25. ;---|*| involves a longer path through the recording circuitry before it
  26. ;---|*| is sent out the PLAY path. This longer path creates a delay in
  27. ;---|*| the signal that can be used as a Surround Sound (r) Encoder!  The
  28. ;---|*| technique is now simple: send the left channel through the "PLAY
  29. ;---|*| ONLY" path, and the right channel through the "PLAY and RECORD"
  30. ;---|*| path!
  31. ;---|*|
  32. ;---|*| The routine, "MoveMixers" takes the joystick X,Y coordinates,
  33. ;---|*| calculates the audio's position, then places it in 3d space
  34. ;---|*| via the mixer.
  35. ;---|*|
  36. ;---|*| REMEMBER! you need to connect the stereo output of the Pro Audio
  37. ;---|*| to a Surround Sound receiver/decoder that has 4 speakers hooked up
  38. ;---|*| in the LEFT/CENTER/RIGHT and REAR positions.
  39. ;---|*|
  40. ;---|*| Dolby Surround Sound is a registered trademark of Dolby Labs, Inc.
  41. ;---|*|
  42. ;   \*/
  43.  
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <signal.h>
  47.  
  48. #include "binary.h"
  49.  
  50.     // position controls
  51.  
  52.         static unsigned int Xpos = 128;     // column center position
  53.         static unsigned int Ypos = 128;     // row center position
  54.         static unsigned int Xmid = 128;     // col center position
  55.         static unsigned int Ymid = 128;     // row center position
  56.         static unsigned int JoyXScale = 50; // joystick X range scaler
  57.         static unsigned int JoyYScale = 50; // joystick Y range scaler
  58.  
  59.     // our buffer management data
  60.  
  61.         static char far  *SourceData;
  62.         static char far  *DMABuffPtr;
  63.         static char huge *StartOfDMABuffer;
  64.  
  65. #define MAXDIV  64
  66. #define DMASIZE 16
  67.         static int  MaxBuffCount = MAXDIV;                  // max dma buffer count
  68.         static long DmaSize      = DMASIZE*1024L;           // dma buffer size
  69.         static int  DivisionSize = DMASIZE*1024L/(MAXDIV);
  70.  
  71.     // misc global variables
  72.  
  73.         static char *FileName = 0;             // source file name
  74.         static long SampleRate = 11025;        // the output sample rate
  75.         static int  swaplr = 0;                // swap left/right channels
  76.  
  77.     // joystick stuff...
  78.  
  79.         static int  ButtonState  = 0;          // joystick button states
  80.         static int  keyboardonly = 0;
  81.  
  82.     // our prototypes
  83.  
  84.         static void far _saveregs FillNextBlock ( );
  85.         static int GetKey ( int );
  86.  
  87.     // low level access routines
  88.  
  89.         void UserFunc                 ( void (far*)() );
  90.         void InitPCM                  ( );
  91.         void InitMVSound              ( );
  92.         void far *DMABuffer           ( char far *, int, int );
  93.         char huge *FindDMABuffer      ( char huge *, int );
  94.         int  PCMInfo                  ( long ,int, int, int );
  95.         void huge *_memmalloc         ( long );
  96.  
  97.         static void SurroundFill      ( char far *, char far *, int );
  98.  
  99.     // this table is a quarter wave staring at 75h down to 0h
  100.  
  101.         unsigned char scalers[] = {
  102.  
  103.             0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75,
  104.             0x75, 0x73, 0x75, 0x73, 0x73, 0x75, 0x73, 0x73,
  105.             0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73,
  106.             0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x71,
  107.             0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71,
  108.             0x71, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
  109.             0x70, 0x70, 0x70, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e,
  110.             0x6e, 0x6e, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
  111.  
  112.             0x6c, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x69, 0x69,
  113.             0x69, 0x69, 0x69, 0x69, 0x69, 0x67, 0x67, 0x67,
  114.             0x67, 0x67, 0x65, 0x65, 0x65, 0x65, 0x63, 0x63,
  115.             0x63, 0x63, 0x63, 0x62, 0x62, 0x62, 0x62, 0x62,
  116.             0x60, 0x60, 0x60, 0x60, 0x5e, 0x5e, 0x5e, 0x5e,
  117.             0x5e, 0x5c, 0x5c, 0x5c, 0x5c, 0x5b, 0x5b, 0x5b,
  118.             0x59, 0x59, 0x59, 0x59, 0x57, 0x57, 0x57, 0x57,
  119.             0x55, 0x55, 0x55, 0x54, 0x54, 0x54, 0x54, 0x52,
  120.  
  121.             0x52, 0x52, 0x50, 0x50, 0x50, 0x50, 0x4e, 0x4e,
  122.             0x4e, 0x4d, 0x4d, 0x4d, 0x4b, 0x4b, 0x4b, 0x49,
  123.             0x49, 0x49, 0x49, 0x47, 0x47, 0x47, 0x46, 0x46,
  124.             0x46, 0x44, 0x44, 0x44, 0x42, 0x42, 0x42, 0x40,
  125.             0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3d, 0x3d, 0x3d,
  126.             0x3b, 0x3b, 0x3b, 0x39, 0x39, 0x39, 0x38, 0x38,
  127.             0x36, 0x36, 0x36, 0x34, 0x34, 0x32, 0x32, 0x32,
  128.             0x31, 0x31, 0x31, 0x2f, 0x2f, 0x2d, 0x2d, 0x2d,
  129.  
  130.             0x2b, 0x2b, 0x2b, 0x2a, 0x2a, 0x28, 0x28, 0x28,
  131.             0x26, 0x26, 0x26, 0x24, 0x24, 0x23, 0x23, 0x23,
  132.             0x21, 0x21, 0x21, 0x1f, 0x1f, 0x1d, 0x1d, 0x1d,
  133.             0x1c, 0x1c, 0x1a, 0x1a, 0x1a, 0x18, 0x18, 0x16,
  134.             0x16, 0x16, 0x15, 0x15, 0x13, 0x13, 0x13, 0x11,
  135.             0x11, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0c, 0x0c,
  136.             0x0c, 0x0a, 0x0a, 0x08, 0x08, 0x07, 0x07, 0x07,
  137.             0x05, 0x05, 0x03, 0x03, 0x03, 0x01, 0x01, 0x00
  138.  
  139.         };
  140.  
  141.     // mixer selection
  142.  
  143.         char mixerchannels[16] = {
  144.             BI_L_FM,      BI_R_FM,      // 0
  145.             -1,           -1,           // 1
  146.             BI_L_EXT,     BI_R_EXT,     // 2
  147.             BI_L_INT,     BI_R_INT,     // 3
  148.             BI_L_MIC,     BI_R_MIC,     // 4
  149.             BI_L_PCM,     BI_R_PCM,     // 5
  150.             BI_L_SPEAKER, BI_R_SPEAKER, // 6
  151.             BI_L_SBDAC,   BI_R_SBDAC    // 7
  152.         };
  153.  
  154.         int mixerselect  = 5;   // PCM
  155.  
  156.         char *mixernames[8] = {
  157.             "FM",
  158.             " ",
  159.             "External Line-in",
  160.             "Internal Line-in jack",
  161.             "Microphone",
  162.             "Pro Audio PCM",
  163.             "PC Speaker",
  164.             "SB PCM"
  165.         };
  166.  
  167.         int LastLeftPos  = 128;
  168.         int LastRitPos   = 128;
  169.  
  170.  
  171. ;   /*\
  172. ;---|*|----====< main >====----
  173. ;---|*|
  174. ;---|*| Removes the PCM system & deallocates the buffer memory.
  175. ;---|*| There is no return value.
  176. ;---|*|
  177. ;   \*/
  178.  
  179. void main(argc,argv)
  180.     int argc;
  181.     char *argv[];
  182. {
  183. int looping = -1;
  184.  
  185.     // process any switches, etc.
  186.  
  187.         CommandLine(argc,argv);
  188.  
  189.     // setup the underlying driver...
  190.  
  191.         if (!SetupSound()) {
  192.             printf ("Unable to setup the sound routines!\n");
  193.             exit(-1);
  194.         }
  195.  
  196.     // calibrate the joystick
  197.  
  198.         Calibrate();
  199.  
  200.     // setup the buffers, etc.
  201.  
  202.         LoadDataBuffers ( );
  203.  
  204.     // disable the ^C
  205.  
  206.         signal (SIGINT,SIG_IGN);
  207.  
  208.     // let'er rip...
  209.  
  210.         PCMPlay();
  211.  
  212.     // loop until time to exit
  213.  
  214.         PrintStats (0x07);
  215.  
  216.         while (looping) {
  217.  
  218.             // process any user keys, and break out if desired
  219.  
  220.                 if (kbhit())
  221.                     if (ProcessKeys())
  222.                         break;
  223.  
  224.             // read the joystick if one is available
  225.  
  226.                 if (!keyboardonly) {
  227.                     DelayTimer(1);
  228.                     ReadJoyStick ( JoyXScale, JoyYScale );
  229.                     MoveMixers   ( mixerselect );
  230.                 }
  231.  
  232.             // then print the coordinates
  233.  
  234.                 PrintStats (0x03);
  235.  
  236.         }
  237.  
  238.     // kill the PCM & exit
  239.  
  240.         StopPCM();
  241.  
  242. }
  243.  
  244.  
  245. ;   /*\
  246. ;---|*|----====< Calibrate >====----
  247. ;---|*|
  248. ;---|*| Calibrate the joystick position and scale down to 0-256
  249. ;---|*|
  250. ;   \*/
  251. Calibrate()
  252. {
  253. int y;
  254. char *s,*t;
  255.  
  256.     // exit if there is no joystick
  257.  
  258.         if (keyboardonly) {
  259.             Xmid = Ymid = Xpos = Ypos = 128;
  260.             JoyXScale = 25600/416;
  261.             JoyYScale = 25600/416;
  262.             return(0);
  263.         }
  264.  
  265.     // ask the user to position, then read the setting
  266.  
  267.         y = CursorYPos();
  268.         printf ("Please position the Joystick in the bottom right corner.\n");
  269.         printf ("Press a fire button when in position\n\n");
  270.  
  271.         PrintStats (0x01);
  272.  
  273.         while (1) {
  274.  
  275.             // get the whole coordinates
  276.  
  277.             ReadJoyStick(100,100);
  278.             PrintStats (0x01);
  279.  
  280.             // check for an exit request
  281.  
  282.             if (kbhit()) {
  283.                 if (getch() == 0x1b)
  284.                     return(0);
  285.             }
  286.  
  287.             // we're done when a button is depressed
  288.  
  289.             if (ButtonState & 0x0f)
  290.                 break;
  291.  
  292.         }
  293.  
  294.     // remove our user directions from the screen
  295.  
  296.         SetCursor (0,y);
  297.         printf ("                                                          \n");
  298.         printf ("                                                          \n");
  299.  
  300.     // we want a scale between 0 & 256
  301.  
  302.         if (Xpos > 255)
  303.             JoyXScale = 25600/Xpos;
  304.  
  305.         if (Ypos > 255)
  306.             JoyYScale = 25600/Ypos;
  307.  
  308.         JoyXScale--;
  309.         JoyYScale--;
  310.  
  311.         Ymid = Ypos * JoyYScale / 100 / 2;
  312.         Xmid = Xpos * JoyXScale / 100 / 2;
  313.  
  314. }
  315.  
  316.  
  317. ;   /*\
  318. ;---|*|----====< CommandLine >====----
  319. ;---|*|
  320. ;---|*| process the command line switches
  321. ;---|*|
  322. ;   \*/
  323.  
  324. int CommandLine(argc,argv)
  325.     int argc;
  326.     char *argv[];
  327. {
  328. char *s;
  329. int n,temp;
  330. long l;
  331.  
  332.     // print the helps, then exit if no additional parameters
  333.  
  334.         if (argc < 2) {
  335.             GiveHelps(0x07);
  336.             exit(-1);
  337.         }
  338.  
  339.         GiveHelps(0x01);
  340.  
  341.     // process the rest...
  342.  
  343.         n = 1;
  344.         while (n < argc) {
  345.  
  346.             s = argv[n++];
  347.  
  348.             if (*s == '/') s++;
  349.             if (*s == '-') s++;
  350.  
  351.             switch (*s & 0x5f) {
  352.  
  353.                 case '?' & 0x5f:
  354.                 case 'H':
  355.                     GiveHelps(0x06);
  356.                     exit(0);
  357.  
  358.                 case 'F':
  359.                     FileName = ++s;
  360.                     printf ("Will play the file, \"%s\"\n",FileName);
  361.                     break;
  362.  
  363.                 case 'K':
  364.                     keyboardonly = -1;
  365.                     printf ("Taking input from the keyboard only\n");
  366.                     break;
  367.  
  368.                 case 'M':
  369.                     if (sscanf (++s,"%d",&temp) == 1) {
  370.  
  371.                         mixerselect = temp & 0x07;
  372.  
  373.                         if (mixerchannels[mixerselect] == -1)
  374.                             mixerselect = 5;
  375.  
  376.                         printf ("mixer index %d\n", mixerselect);
  377.                     }
  378.                     break;
  379.  
  380.                 case 'R':
  381.                     if (sscanf (++s,"%ld",&l) == 1) {
  382.                         SampleRate = l;
  383.                         printf ("Using %ld sample rate\n",l);
  384.                     }
  385.                     break;
  386.  
  387.                 case 'X':
  388.                     swaplr = -1;
  389.                     printf ("Swapping left and right channels\n");
  390.                     break;
  391.  
  392.                 default:
  393.                     break;
  394.             }
  395.         }
  396.  
  397.         printf ("\n");
  398.  
  399. }
  400.  
  401. ;   /*\
  402. ;---|*|----====< CursorYPos >====----
  403. ;---|*|
  404. ;---|*|  Return the curreny cursor Y position on the screen
  405. ;---|*|
  406. ;   \*/
  407.  
  408. CursorYPos()
  409. {
  410. int retval;
  411.  
  412.     // get it from the video bios
  413.  
  414.         _asm {
  415.             mov     ah,03h
  416.             mov     bx,0
  417.             int     10h
  418.             sub     dl,dl
  419.             xchg    dl,dh
  420.             mov     [retval],dx
  421.         }
  422.  
  423.         return(retval);
  424. }
  425.  
  426.  
  427. ;   /*\
  428. ;---|*|----====< DelayTimer >====----
  429. ;---|*|
  430. ;---|*| Delay this many clock ticks
  431. ;---|*|
  432. ;   \*/
  433. DelayTimer(ticks)
  434.     int ticks;
  435. {
  436. int timer = -1;
  437. int delta = -1;
  438.  
  439.     // while we have time to waste...
  440.  
  441.         DeltaTime();
  442.  
  443.         while (ticks) {
  444.  
  445.             // if the clock ticked, count down one...
  446.  
  447.                 if (DeltaTime())
  448.                     ticks--;
  449.  
  450.         }
  451.  
  452. }
  453.  
  454.  
  455. ;   /*\
  456. ;---|*|----====< DeltaTime >====----
  457. ;---|*|
  458. ;---|*| Return the delta of clock ticks
  459. ;---|*|
  460. ;   \*/
  461. DeltaTime()
  462. {
  463. int retval;
  464. static int timer = -1;
  465.  
  466.     // get the clock tick, save, sub from last tick & return the value
  467.  
  468.         _asm {
  469.             mov     ah,0
  470.             int     1ah
  471.             xchg    dx,[timer]
  472.             sub     dx,[timer]
  473.             mov     [retval],dx
  474.         }
  475.  
  476.     // return the delta
  477.  
  478.         return(retval);
  479. }
  480.  
  481.  
  482. ;   /*\
  483. ;---|*|----====< FillNextBlock >====----
  484. ;---|*|
  485. ;---|*|  Fill the DMA buffer with the next block
  486. ;---|*|
  487. ;   \*/
  488. void far _saveregs FillNextBlock()
  489. {
  490. static int next = 0;
  491. static char far *src = 0;
  492. static char far *trg = 0;
  493.  
  494.     // first time in checks...
  495.  
  496.         if (!trg) {
  497.             trg = StartOfDMABuffer;
  498.             src = SourceData;
  499.         }
  500.  
  501.     // fill the buffer with data
  502.  
  503.         SurroundFill(trg,src,DivisionSize);
  504.  
  505.     // move the pointer for the next call...
  506.  
  507.         if (++next == MaxBuffCount) {
  508.             trg = StartOfDMABuffer;
  509.             src = SourceData;
  510.             next = 0;
  511.         }
  512.         else {
  513.             (int)src += DivisionSize;
  514.             (int)trg += DivisionSize*4;
  515.         }
  516. }
  517.  
  518.  
  519. ;   /*\
  520. ;---|*|----====< GetKey >====----
  521. ;---|*|
  522. ;---|*| Return a keystroke
  523. ;---|*|
  524. ;   \*/
  525. static int GetKey(flag)
  526.     int flag;
  527. {
  528. int c = 0;
  529.  
  530.     // flush if flag is set, then wait for a key
  531.  
  532.         if (flag) {
  533.  
  534.             while (kbhit()) getch();
  535.  
  536.             while (!kbhit()) ;
  537.  
  538.         }
  539.  
  540.     // if there is a key, return 16 bits of it...
  541.  
  542.         if (kbhit()) {
  543.             if ((c = getch()) == 0)
  544.                 c = getch() << 8;
  545.         }
  546.  
  547.     // return the character
  548.  
  549.         return(c);
  550. }
  551.  
  552.  
  553. ;   /*\
  554. ;---|*|----====< GetMixers >====----
  555. ;---|*|
  556. ;---|*| See if the Pro Audio is installed, and setup the mixer code
  557. ;---|*|
  558. ;   \*/
  559. GetMixers   ( )
  560. {
  561.     // get the mixer vectors
  562.  
  563.         if (!MVInitMixerCode()) {
  564.             printf ("Cannot find MVSOUND.SYS\n");
  565.             return(0);
  566.         }
  567.  
  568.     // set both channels through the record path
  569.  
  570.         cMVSetMixerFunction( 100, BI_INPUTMIXER, BI_L_PCM );
  571.         cMVSetMixerFunction( 100, BI_INPUTMIXER, BI_R_PCM );
  572.  
  573.     // set the monitor setting to full on
  574.  
  575.         cMVSetMixerFunction( 100, BI_OUTPUTMIXER, BI_L_IMIXER );
  576.         cMVSetMixerFunction( 100, BI_OUTPUTMIXER, BI_R_IMIXER );
  577.  
  578.     // return hunky-dory
  579.  
  580.         return(-1);
  581. }
  582.  
  583.  
  584. ;   /*\
  585. ;---|*|----====< GiveHelps >====----
  586. ;---|*|
  587. ;---|*| Tell the user how to use this program.
  588. ;---|*|
  589. ;   \*/
  590.  
  591. GiveHelps(flags)
  592.     int flags;
  593. {
  594.  
  595.     if (flags & 0x01) {
  596.  
  597.         printf ("\n\n\n\n\n\n\n\n\n\n\n");
  598.  
  599.         printf ("Media Vision Pro Audio Spectrum Sound Demo Program, V1.0\n");
  600.         printf ("Copyright (c) 1993. Media Vision, Inc. All Rights Reserved. V1.0\n\n");
  601.  
  602.         printf ("This program demonstrates a close approximation of Dolby Surround Sound (r)\n");
  603.         printf ("encoding using the Pro Audio's on-board mixer. The output of the Pro Audio\n");
  604.         printf ("can plugged into any stereo receiver that supports Dolby Surround. With\n");
  605.         printf ("four speakers attached, the audio signal can be placed on any of the\n");
  606.         printf ("speakers.\n\n");
  607.     }
  608.  
  609.     if (flags & 0x02) {
  610.  
  611.         printf ("The Dolby Surround Sound (r) technique involves filter the signal, and\n");
  612.         printf ("shifting both the left and right channels 180 degrees out of phase. Any\n");
  613.         printf ("Surround Sound (r) decoder, sees the signal out of phase, and places\n");
  614.         printf ("the audio in rear speaker.\n\n");
  615.  
  616.         printf ("Type a key to continue...");
  617.         GetKey (1);
  618.         printf ("\r                         \n");
  619.  
  620.         printf (" The Pro Audio Spectrum mixer    ┌───────────────────────────────────────────┐\n");
  621.         printf (" architecture has the ability    │                                           │\n");
  622.         printf (" to create a phase delay in      │                                           │\n");
  623.         printf (" the audio signal. On all Pro    │linein ══════╦═══════════╗                 │\n");
  624.         printf (" Audio Spectrum cards, every     │CD-in  ════╦═║═════════╗ ║                 │\n");
  625.         printf (" audio mixer channel can be      │FM     ══╦═║═║═══════╗ ║ ║                 │\n");
  626.         printf (" connected to a \"PLAY ONLY\"      │         ║ ║ ║       ║ ║ ║                 │\n");
  627.         printf (" path or \"PLAY and RECORD\"       │                                     │\n");
  628.         printf (" path. The actual \"PLAY and      │       ┌──────┐    ┌──────┐  ┌────────┐ ┌─│\n");
  629.         printf (" RECORD\" path involves a longer  │       │play &╞═╦═>╡ play ╞═>╡ Master ╞═╡  │\n");
  630.         printf (" path through the recording      │       │record│ ║  │ only │  │ Volume │ └─│\n");
  631.         printf (" circuitry before it is sent     │       └──────┘ ║  └──────┘  └────────┘    │\n");
  632.         printf (" out the play path. This longer  │             ║                       │\n");
  633.         printf (" path creates a delay in the     │         ║ ║ ║  ║    ║ ║ ║                 │\n");
  634.         printf (" signal that can be used as a    │PCM    ══╩═║═║═══════╝ ║ ║                 │\n");
  635.         printf (" Surround Sound (r) Encoder!     │Mic    ════╩═║═════════╝ ║                 │\n");
  636.         printf (" The technique is now simple:    │SB PCM ══════╩═══════════╝                 │\n");
  637.         printf (" send the left channel           │                ║                          │\n");
  638.         printf (" through the \"PLAY ONLY\"         │                                          │\n");
  639.         printf (" path, and the right channel     │               PCM                         │\n");
  640.         printf (" through the \"PLAY and           │              record                       │\n");
  641.         printf (" RECORD\" path!                   └───────────────────────────────────────────┘\n\n");
  642.  
  643.         printf ("Type a key to continue...");
  644.         GetKey (1);
  645.         printf ("\r                         \n");
  646.  
  647.         printf ("REMEMBER! you need to connect the stereo output of the Pro Audio\n");
  648.         printf ("to a Surround Sound receiver/decoder that has 4 speakers hooked up\n");
  649.         printf ("in the LEFT/CENTER/RIGHT and REAR positions.\n\n");
  650.  
  651.         printf ("                                         ╓─ Left\n");
  652.         printf ("   ┌──────────│    ┌─────────────────┐   ╟─ Center\n");
  653.         printf ("   │Pro Audio │═══>│ Stereo Surround ╞══>╣         \n");
  654.         printf ("   │Spectrum  │    │ Sound Receiver  │   ╟─ Rear  \n");
  655.         printf ("   └──────────│    └─────────────────┘   ╙─ Right \n\n");
  656.  
  657.         printf ("NOTE: Dolby Surround Sound is a registered trademark of Dolby Labs, Inc.\n\n");
  658.  
  659.         printf ("Type a key to continue...");
  660.         GetKey (1);
  661.         printf ("\r                         \n");
  662.  
  663.     }
  664.  
  665.     if (flags & 0x04) {
  666.  
  667.         printf ("To Use: DOS> MVSA -Fxxxxx -K -Mxx -Rxxxxx -X\n\n");
  668.  
  669.         printf ("Where:  -Fxxxxx is a raw PCM file to be played.\n");
  670.         printf ("        -K      Use this if you don't have a joystick.\n");
  671.         printf ("        -Mxx    is the mixer channel:\n");
  672.         printf ("                  0 = for FM channels.       4 = Microphone.\n");
  673.         printf ("                  2 = External Line-in jack. 5 = Pro Audio PCM. (default)\n");
  674.         printf ("                  3 = Internal Line-in jack. 6 = PC Speaker.\n");
  675.         printf ("        -Rxxxxx is the sample rate.\n");
  676.         printf ("        -X      to swap left and right channels\n\n");
  677.  
  678.         printf ("This program uses a joystick to position the sound around the four speaker.\n");
  679.         printf ("If you do not have a joystick, then use the -K switch to use keyboard input.\n");
  680.         printf ("Other devices, such as, the FM chip may be selected via keys 0-7.\n\n");
  681.  
  682.     }
  683. }
  684.  
  685.  
  686. ;   /*\
  687. ;---|*|----====< LoadDataBuffers >====----
  688. ;---|*|
  689. ;---|*| Load the buffers with the data from disk
  690. ;---|*|
  691. ;   \*/
  692. LoadDataBuffers ( )
  693. {
  694. FILE *inf;
  695. char far *fp;
  696. int n;
  697.  
  698.     // get the block memory for the source data
  699.  
  700.         if ((fp = SourceData = (char far *)_memmalloc(DmaSize)) == 0)
  701.             return(0);
  702.  
  703.     // fill with silence
  704.  
  705.         for (n=0;n<DmaSize;n++)
  706.             *fp++ = 0x80;
  707.  
  708.     // load the file, if present
  709.  
  710.         if (FileName) {
  711.  
  712.             // open the file via a stream call...
  713.  
  714.                 if ((inf = fopen (FileName,"rb")) == 0) {
  715.                     printf ("Unable to open the input file!!!\n");
  716.                     return(0);
  717.                 }
  718.  
  719.             // read the entire file into the DMA buffer
  720.  
  721.                 n  = fileno(inf);
  722.                 fp = SourceData;
  723.  
  724.                 _asm {
  725.                     push    ds
  726.  
  727.                     mov     ah,03fh
  728.                     mov     bx,[n]
  729.                     mov     cx,0x20
  730.                     lds     dx,[fp]
  731.                     int     21h
  732.  
  733.                     pop     ds
  734.                     push    ds
  735.  
  736.                     mov     ah,03fh
  737.                     mov     bx,[n]
  738.                     mov     cx,[DmaSize]
  739.                     lds     dx,[fp]
  740.                     mov     di,dx
  741.                     add     di,cx
  742.                     sub     di,2
  743.                     int     21h
  744.  
  745.                     mov     bx,dx
  746.                     mov     ax,[bx]
  747.                     mov     [di],ax
  748.  
  749.                     pop     ds
  750.                 }
  751.  
  752.                 fclose (inf);
  753.         }
  754.  
  755.     // Prime the system with the data for the start.
  756.  
  757.         for (n=0;n<MaxBuffCount;n++)
  758.             FillNextBlock();
  759.  
  760. }
  761.  
  762.  
  763. ;   /*\
  764. ;---|*|----====< PrintStats >====----
  765. ;---|*|
  766. ;---|*| Print several lines of statistics
  767. ;---|*|
  768. ;   \*/
  769. PrintStats(flags)
  770.     int flags;
  771. {
  772.  
  773. static int oldy = -1;
  774.  
  775.     // move the screen up if first pass
  776.  
  777.         if (oldy == -1)
  778.             printf ("\n\n\n\n");
  779.  
  780.     // on the first pass, get the old cursor row position
  781.  
  782.         if (oldy == -1) {
  783.             oldy = CursorYPos() - 4;    // give us four lines to work with
  784.             if (oldy < 0)
  785.                 oldy = 0;
  786.         }
  787.  
  788.     // position the cursor
  789.  
  790.         SetCursor (0,oldy);
  791.  
  792.     // print the data
  793.  
  794.         if (flags & 0x01)
  795.             printf ("Joystick:   x=%d y=%d    \n",Xpos,Ypos);
  796.         else
  797.             printf ("\n");
  798.  
  799.         if (flags & 0x02)
  800.             printf ("Left/Right: l=%d r=%d    \n",LastLeftPos,LastRitPos);
  801.         else
  802.             printf ("\n");
  803.  
  804.         if (flags & 0x04)
  805.             printf ("Mixer channel is %s (%d)                        \n",mixernames[mixerselect],mixerselect);
  806.         else
  807.             printf ("\n");
  808.  
  809. }
  810.  
  811.  
  812. ;   /*\
  813. ;---|*|----====< ProcessKeys >====----
  814. ;---|*|
  815. ;---|*| process the keystrokes
  816. ;---|*|
  817. ;   \*/
  818. ProcessKeys()
  819. {
  820. int c;
  821.  
  822.     // process the keys...
  823.  
  824.         if ((c = GetKey(0)) != 0) {
  825.  
  826.             if (c < 0x100) {
  827.  
  828.                 // escape will exit
  829.  
  830.                 if (c == 0x1B)
  831.                     return(-1);
  832.  
  833.                 // process any of the keys 0-9
  834.  
  835.                 if (isdigit(c)) {
  836.  
  837.                     c -= '0';
  838.  
  839.                     if ( !((mixerchannels[c<<1] == -1) || (c > 7)) )
  840.                         mixerselect = c;
  841.  
  842.                     PrintStats (0x04);
  843.                 }
  844.             }
  845.  
  846.             else {
  847.  
  848.                 switch (c) {
  849.  
  850.                     // left arrow
  851.  
  852.                     case 0x4B00:
  853.                         if (Xpos)
  854.                             Xpos--;
  855.                         break;
  856.  
  857.                     // right arrow
  858.  
  859.                     case 0x4D00:
  860.                         if (Xpos < 256)
  861.                             Xpos++;
  862.                         break;
  863.  
  864.                     // up arrow
  865.  
  866.                     case 0x4800:
  867.                         if (Ypos)
  868.                             Ypos--;
  869.                         break;
  870.  
  871.                     // down arrow
  872.  
  873.                     case 0x5000:
  874.                         if (Ypos < 256)
  875.                             Ypos++;
  876.                         break;
  877.  
  878.                     default:
  879.                         break;
  880.                 }
  881.             }
  882.  
  883.             MoveMixers   ( mixerselect );
  884.         }
  885.  
  886.         return(0);
  887. }
  888.  
  889.  
  890. ;   /*\
  891. ;---|*|----====< MoveMixers >====----
  892. ;---|*|
  893. ;---|*| Move the mixer channels around with the Joystick. This routine
  894. ;---|*| does the magic of simulating surround sound encoding.
  895. ;---|*|
  896. ;   \*/
  897. MoveMixers(ch)
  898.     int ch;
  899. {
  900. unsigned int l;
  901. unsigned int r;
  902. unsigned int cheat = 50; // MVA508 adjustment to keep the volumes up higher
  903.  
  904. int path = BI_INPUTMIXER;
  905. int y;
  906.  
  907.     // convert linear Xpos to a curve for both left and right channels
  908.  
  909.         r = scalers[0] - (l = scalers[Xpos]);
  910.  
  911.     // we want to give the Y coordinate a half curve so it is loudest when
  912.     // directly in front of us.
  913.  
  914.         y =  Ymid - ((Ypos > Ymid) ? (Ymid*2 - Ypos) : Ypos);
  915.  
  916.     // y is now some value between 0 & 127, where 127 is loudest, 0 is off
  917.  
  918.         y =  scalers[y<<1]; // get the curve by multiplying by 2
  919.  
  920.     // The proaudio mixer API works on a percentage scale, so...
  921.     // ...scale it into 0-100
  922.  
  923.         r = r * 100 / 256 * y / 100 + cheat;
  924.         l = l * 100 / 256 * y / 100 + cheat;
  925.  
  926.     // make sure the percentage stays within range
  927.  
  928.         if (l > 100) l = 100;
  929.         if (l < 0)   l = 0;
  930.  
  931.         if (r > 100) r = 100;
  932.         if (r < 0)   r = 0;
  933.  
  934.     // If the Y position is behind us, send the right channel
  935.     // to the record path of the mixer.
  936.  
  937.         if (Ypos >= Ymid)
  938.             path = BI_OUTPUTMIXER;
  939.  
  940.     // swap left and right, if the users wants this done...
  941.  
  942.         if (swaplr) {
  943.             l ^= r;
  944.             r ^= l;
  945.             l ^= r;
  946.         }
  947.  
  948.     // move the volumes in the mixer. The right channel gets delayed if
  949.     // the joystick is moved behind us.
  950.  
  951.         cMVSetMixerFunction( LastLeftPos=l, BI_INPUTMIXER, mixerchannels[(ch<<1)+0] );
  952.         cMVSetMixerFunction( LastRitPos =r, path,          mixerchannels[(ch<<1)+1] );
  953.  
  954. }
  955.  
  956.  
  957. ;   /*\
  958. ;---|*|----====< ReadJoyStick >====----
  959. ;---|*|
  960. ;---|*| We will now read the joystick settings from the BIOS
  961. ;---|*|
  962. ;   \*/
  963.  
  964. ReadJoyStick(xscale,yscale)
  965.     int xscale;
  966.     int yscale;
  967. {
  968. int  AXpos; // joystick A X position
  969. int  AYpos; // joystick A Y position
  970. int  BXpos; // joystick B X position
  971. int  BYpos; // joystick B Y position
  972.  
  973.         _asm {
  974.  
  975.         // get the coordinates
  976.  
  977.             mov     ah,84h
  978.             mov     dx,1
  979.             int     15h
  980.  
  981.             mov     AXpos,ax
  982.             mov     AYpos,bx
  983.             mov     BXpos,cx
  984.             mov     BYpos,dx
  985.  
  986.             mov     ah,84h
  987.             sub     dx,dx
  988.             int     15h
  989.             shr     al,4
  990.             cbw
  991.             xor     al,0x0f
  992.             mov     [ButtonState],ax
  993.  
  994.         // scale them down to 0-256
  995.  
  996.             mov     ax,[AXpos]
  997.             mov     cx,[xscale]
  998.             mul     cx
  999.             mov     cx,100
  1000.             div     cx
  1001.             inc     ax
  1002.             mov     [Xpos],ax
  1003.  
  1004.             mov     ax,[AYpos]
  1005.             mov     cx,[yscale]
  1006.             mul     cx
  1007.             mov     cx,100
  1008.             div     cx
  1009.             inc     ax
  1010.             mov     [Ypos],ax
  1011.  
  1012.         }
  1013. }
  1014.  
  1015.  
  1016. ;   /*\
  1017. ;---|*|----====< SetCursor >====----
  1018. ;---|*|
  1019. ;---|*| position the cursor to a new X/Y
  1020. ;---|*|
  1021. ;   \*/
  1022.  
  1023. SetCursor (x,y)
  1024.     int x,y;
  1025. {
  1026.  
  1027.     // go through the bios
  1028.  
  1029.          _asm {
  1030.                 mov     ah,02h
  1031.                 mov     bx,0
  1032.                 mov     dh,byte ptr [y]
  1033.                 mov     dl,byte ptr [x]
  1034.                 int     10h
  1035.         }
  1036. }
  1037.  
  1038.  
  1039. ;   /*\
  1040. ;---|*|----====< SetupSound >====----
  1041. ;---|*|
  1042. ;---|*| Setup the sound output routines
  1043. ;---|*|
  1044. ;   \*/
  1045. SetupSound()
  1046. {
  1047.  
  1048.     // setup the sound routines
  1049.  
  1050.         InitMVSound();
  1051.         InitPCM();
  1052.         if (!GetMixers())
  1053.             return(0);
  1054.  
  1055.     // setup our callback routine
  1056.  
  1057.         UserFunc( ((void(far*)())&FillNextBlock) );
  1058.  
  1059.     // allocate and verify the dma buffer memory
  1060.  
  1061.         if ((DMABuffPtr = (char huge *)_memmalloc((unsigned long)DmaSize*8)) == 0)
  1062.             return(0);
  1063.  
  1064.         if ((StartOfDMABuffer=FindDMABuffer(DMABuffPtr,(DmaSize*4)/1024)) == 0)
  1065.             return (0);
  1066.  
  1067.     // if the low level code doesn't like it, bomb out
  1068.  
  1069.         if (!DMABuffer ( StartOfDMABuffer, DmaSize*4/1024, MaxBuffCount ))
  1070.             return(0);
  1071.  
  1072.     // variable rate, stereo, no compression, and 16 bit PCM
  1073.  
  1074.         PCMInfo( SampleRate , 1, 0, 16 );
  1075.  
  1076.         return(-1);
  1077.  
  1078. }
  1079.  
  1080.  
  1081. ;   /*\
  1082. ;---|*|----====< SurroundFill >====----
  1083. ;---|*|
  1084. ;---|*|  This routine fill the next portion of the DMA buffer.
  1085. ;---|*|
  1086. ;   \*/
  1087.  
  1088. void SurroundFill(trg,src,len)
  1089.     char far *trg;
  1090.     char far *src;
  1091.     int len;
  1092. {
  1093. int Lmul;
  1094. int Rmul;
  1095. unsigned int Rinv = 0x00;
  1096. char far *tp = scalers;
  1097.  
  1098.     // calculate the multiplyers based on the current X/Y
  1099.  
  1100.         Lmul = 255;
  1101.         Rmul = 255;
  1102.  
  1103.     // move all the data into the target buffer
  1104.  
  1105.         _asm {
  1106.                 push    si
  1107.                 push    di
  1108.                 push    es
  1109.                 push    ds
  1110.  
  1111.                 mov     cx,[len]
  1112.                 les     di,[trg]            // get the target pointer
  1113.                 lds     si,[src]            // get the source buffer
  1114.                 cld
  1115.  
  1116.             ;
  1117.             sufi05:
  1118.  
  1119.                 mov     ds,word ptr [src+2] // reload the target segment
  1120.                 mov     al,[si]             // get the first sample
  1121.                 xor     al,0x80
  1122.                 cbw
  1123.  
  1124.                 mov     bx,[Lmul]
  1125.                 mul     bl                  // scale it...
  1126.  
  1127.                 stosw
  1128.  
  1129.                 mov     ds,word ptr [src+2] // reload the target segment
  1130.                 lodsb                       // reload the first sample
  1131.                 xor     al,0x80
  1132.                 cbw
  1133.  
  1134.                 mov     bx,[Rmul]
  1135.                 mul     bl                  // scale it...
  1136.  
  1137.                 xor     ax,[Rinv]           // maybe invert the right channel
  1138.                 sub     ax,[Rinv]
  1139.  
  1140.                 stosw
  1141.  
  1142.                 loop    sufi05              // do all the samples
  1143.  
  1144.                 pop     ds
  1145.                 pop     es
  1146.                 pop     di
  1147.                 pop     si
  1148.         }
  1149.  
  1150. }
  1151.  
  1152. ;   /*\
  1153. ;---|*| end of MVSA.C
  1154. ;   \*/
  1155.  
  1156.  
  1157.  
  1158.