home *** CD-ROM | disk | FTP | other *** search
/ HomeWare 14 / HOMEWARE14.bin / music / vaisdk.arj / TESTW.C < prev    next >
C/C++ Source or Header  |  1994-04-10  |  36KB  |  1,439 lines

  1.  
  2. ;   /*\
  3. ;---|*|----====< Play >====----
  4. ;---|*|
  5. ;---|*| play/record blocks of data
  6. ;---|*|
  7. ;---|*| Copyright (c) 1993,1994  V.E.S.A, Inc. All Rights Reserved.
  8. ;---|*|
  9. ;---|*| VBE/AI 1.0 Specification
  10. ;---|*|    February 2, 1994. 1.00 release
  11. ;---|*|
  12. ;   \*/
  13.  
  14. #include <stdio.h>
  15. #include <signal.h>
  16.  
  17. #include "vbeai.h"
  18. #include "vesa.h"
  19.  
  20. #define TRUE    -1
  21. #define FALSE    0
  22. #define ON      TRUE
  23. #define OFF     FALSE
  24.  
  25.     // compile-time record mode selection to generate a different test pgm
  26.  
  27. #ifndef RMODE
  28. #define RMODE   0
  29. #endif
  30.  
  31.  
  32. ;   /*\
  33. ;---|*| Global Variables
  34. ;   \*/
  35.  
  36. #define DEFBLEN         0x8000
  37. #define PCMMAXSIZE      65536
  38.         unsigned long   blocklen    = DEFBLEN;
  39.         unsigned long   maxblocklen = PCMMAXSIZE;
  40.         unsigned long   blockinc    = 0;
  41.         unsigned long   PassCount   = 0;
  42.         unsigned long   MaxPasses   = 1;
  43.  
  44.         int  CallBackOccured    = 0;
  45.         int  ErrorBackOccured   = 0;
  46.  
  47.         int  AutoInit           = FALSE;
  48.         long AutoDivide         = 8;
  49.         long SampleRate         = 22050;
  50.         long RealSampleRate     = 22050;
  51.         int  PCMSize            = 8;
  52.         int  SaveBuffer         = FALSE;
  53.         int  ReloadRate         = FALSE;
  54.         int  StereoState        = 1;
  55.         int  Compression        = 0;
  56.         int  DriverError        = 0;
  57.         int  VerboseMode        = FALSE;
  58.         int  UserPref           = 0;     // highest level to be used
  59.  
  60.         VESAHANDLE  hWAVE       = 0;
  61.         BLOCKHANDLE hBLOCK      = 0;
  62.  
  63.         FILE *rfile;
  64.         char far *dmaptr        = 0;
  65.         char far *memptr        = 0;
  66.         char *PCMFileName;
  67.         int  DelayTicks         = 0;
  68.  
  69.         GeneralDeviceClass gdc; // receives a copy of the VESA driver info block
  70.         fpWAVServ wfn;          // pointer to wave functions
  71.  
  72.     // callback routine stores data here...
  73.  
  74.         int  GlobalHandle       = 0;
  75.         void far *GlobalPtr     = 0;
  76.         long Globallen          = 0;
  77.         void far *OldGlobalPtr  = 0;
  78.         long OldGloballen       = 0;
  79.  
  80.  
  81. ;   /*\
  82. ;---|*| prototypes
  83. ;   \*/
  84.  
  85.         long GetValue               ( char *, long );
  86.         char huge *MakeZeroOffset   ( char huge *, long );
  87.         void far pascal OurCallback  ( int, void far *, long, long );
  88.         void far pascal ErrorCallback( int, void far *, long, long );
  89.         int  readblock              ( int, char huge *, int );
  90.         int  SaveToDisk             ( long );
  91.         int  writeblock             ( int, char huge *, int );
  92.         VESAHANDLE OpenTheDriver    ( int );
  93.  
  94.     // only allows us to run on this version of the VBE interface. This
  95.     // will be removed after the interface is ratified. Changes may be made
  96.     // that would cause this code to crash if run on other version. Again,
  97.     // this will be removed in the final software.
  98.  
  99.         int  VersionControl = 0x0100;
  100.  
  101.  
  102. ;   /*\
  103. ;---|*|------------------==============================-------------------
  104. ;---|*|------------------====< Start of execution >====-------------------
  105. ;---|*|------------------==============================-------------------
  106. ;   \*/
  107.  
  108. main(argc,argv)
  109.     int argc;
  110.     char *argv[];
  111. {
  112. int loop = TRUE;
  113. int n,c;
  114. int maxticks,ticks;
  115. int NotHalted;
  116. int exitcode = 0;
  117.  
  118.     // process the command line
  119.  
  120.         CommandLine (argc,argv);
  121.  
  122.     // disable the ^C so the devices will close properly.
  123.  
  124.         signal (SIGINT,SIG_IGN);
  125.  
  126.     // do all the work to get a VESA driver
  127.  
  128.         if (!OpenTheDriver(UserPref)) {    // get the user preference
  129.             printf ("Cannot find any installed VAI devices!\n");
  130.             DoExit(-1);
  131.         }
  132.  
  133.     // this block should play in this amount of time
  134.  
  135.         maxticks = CalcMaxTicks();
  136.  
  137.     // set the Sample rate & stuff, then start the next block
  138.  
  139.         if (!ReloadRate)
  140.             printf ("wsPCMInfo() returned %ld\n",
  141.                 (wfn->wsPCMInfo)(StereoState,SampleRate,Compression,0,PCMSize));
  142.  
  143.         if (!StartNextBlock(0x00))
  144.             BombOut(-1);
  145.  
  146.     // wait for the block to complete
  147.  
  148.         while (loop) {
  149.  
  150.             // show some of the stats on this block while the block is playing
  151.  
  152.                 GiveSomeStats();
  153.  
  154.             // wait here for an interrupt, or an exit message
  155.  
  156.                 DeltaTime();
  157.                 ticks = maxticks;
  158.  
  159.                 while (!CallBackOccured) {
  160.  
  161.                     if (kbhit()) {
  162.  
  163.                         switch (c = getch()) {
  164.  
  165.                             case ' ':  // pause the operation
  166.  
  167.                                 (wfn->wsPauseIO ) (0);
  168.                                 printf ("I/O paused. Type any key to restart...");
  169.                                 getch();
  170.                                 printf ("\n");
  171.                                 (wfn->wsResumeIO) (0);
  172.                                 ticks = maxticks;
  173.                                 break;
  174.  
  175.                             case 'r':  // restart the block
  176.                             case 'R':
  177.  
  178.                                 //PassCount--; // dont count the current pass
  179.                                 NotHalted = TRUE;
  180.                                 ticks = maxticks;
  181.                                 StartNextBlock(0x01);
  182.                                 ReportCallback();
  183.                                 break;
  184.  
  185.                             case 0x1b: // quit the program
  186.                                 loop = 0;
  187.                                 exitcode = TRUE;
  188.  
  189.                             default:
  190.                                 break;
  191.  
  192.                         }
  193.  
  194.                         if (ErrorBackOccured) {
  195.                             printf ("\aWe received the wrong callback!\n");
  196.                             ErrorBackOccured = 0;
  197.                         }
  198.                     }
  199.  
  200.                     // report the current position in the buffer
  201.  
  202.                     ReportCurrentPos();
  203.  
  204.                     // exit immediately if the user wants out...
  205.  
  206.                     if (!loop)
  207.                         break;
  208.  
  209.                     // if the driver posts an error, go report it
  210.  
  211.                     if ( (DriverError = (wfn->wsGetLastError)()) ) {
  212.                         printf ("Driver is reporting an internal error! (code=%d)\n",DriverError);
  213.                         break;
  214.                     }
  215.  
  216.                     // if we don't get our interrupt, bomb out...
  217.  
  218.                     if (DeltaTime()) {
  219.                         if (--ticks == 0) {
  220.                             printf ("No interrupt!\n");
  221.                             BombOut(-1);
  222.                         }
  223.                     }
  224.                 }
  225.  
  226.             // report the callback data
  227.  
  228.                 ReportCallback();
  229.  
  230.             // if we're to stay, do this...
  231.  
  232.                 if (loop) {
  233.  
  234.                     // after a record, dump some of the data...
  235.  
  236.                         if (RMODE) {
  237.  
  238.                             // if we have to prepare the data after record,
  239.                             //do it now...
  240. #if RMODE==1
  241.                             if (gdc.u.gdwi.wifeatures & WAVEPREPARE)
  242.                                 (wfn->wsWavePrepare)(0,PCMSize,StereoState,dmaptr,blocklen);
  243. #endif
  244.  
  245.                             DumpSomeSamples(16);
  246.  
  247.                             if (SaveBuffer)
  248.                                 SaveToDisk(blocklen/AutoDivide);
  249.                         }
  250.  
  251.                     // delay between blocks if required
  252.  
  253.                         if(DelayTicks)
  254.                             DelayTimer(DelayTicks);
  255.  
  256.                     // adjust the new block length, else give up on errors
  257.  
  258.                         if (blockinc) {
  259.  
  260.                             if (hBLOCK) // unregister first to adjust length
  261.                                 (wfn->wsWaveRegister)(0,hBLOCK);
  262.  
  263.                             blocklen += blockinc;
  264.  
  265.                             if (blocklen > maxblocklen)
  266.                                 blocklen = maxblocklen - blocklen;
  267.  
  268.                             if ((signed long)blocklen < 0)
  269.                                 blocklen = maxblocklen;
  270.  
  271.                             maxticks = CalcMaxTicks();
  272.  
  273.                             if (hBLOCK) // re-register with adjusted length
  274.                                 hBLOCK = (wfn->wsWaveRegister)(dmaptr,blocklen);
  275.  
  276.                         }
  277.                         else {
  278.                             if (DriverError)
  279.                                 BombOut(DriverError);
  280.                         }
  281.  
  282.                     // okay, if the user has typed an escape, exit now...
  283.  
  284.                         if (kbhit())
  285.                             if (getch() == 0x1b)
  286.                                 break;
  287.  
  288.                     // if not auto-dma, reload the dma & start the block
  289.  
  290.                         if (!AutoInit) {
  291.  
  292.                             // quit if now done
  293.  
  294.                             if (PassCount+1 >= MaxPasses)
  295.                                 break;
  296.  
  297.                             // restart if more to do
  298.  
  299.                             NotHalted = TRUE;
  300.                             if (!StartNextBlock(0x01))
  301.                                 break;
  302.  
  303.                         }
  304.                      // else
  305.                       //    CallBackOccured = 0;
  306.                 }
  307.  
  308.             // decrement the pass count
  309.  
  310.                 if (loop)
  311.                     if (++PassCount >= MaxPasses)
  312.                         loop = FALSE;
  313.  
  314.         }
  315.  
  316.     // exit now...
  317.  
  318.         DoExit(exitcode);
  319. }
  320.  
  321.  
  322. ;   /*\
  323. ;---|*|----------------------=======================----------------------
  324. ;---|*|----------------------====< Subroutines >====----------------------
  325. ;---|*|----------------------=======================----------------------
  326. ;   \*/
  327.  
  328. ;   /*\
  329. ;---|*|----====< BombOut >====----
  330. ;---|*|
  331. ;---|*| Give the error #, then bomb out...
  332. ;---|*|
  333. ;   \*/
  334. BombOut(cc)
  335.     int cc;
  336. {
  337.  
  338.     // give a message
  339.  
  340.         printf ("Bombing out! code = %d\n",cc);
  341.         DoExit (cc);
  342. }
  343.  
  344.  
  345. ;   /*\
  346. ;---|*|----====< CalcMaxTicks >====----
  347. ;---|*|
  348. ;---|*| Calculate the number of seconds to wait
  349. ;---|*|
  350. ;   \*/
  351. CalcMaxTicks()
  352. {
  353. long retval = 0;
  354.  
  355.     // calc the sample period, then the max time, the get clock ticks
  356.  
  357.         retval  = 1000000 / RealSampleRate; // sample period
  358.         retval  = retval * (blocklen+1);    // total time in Microseconds
  359.         retval  = retval / 55000;           // divided by 55mill
  360.         retval += 9;                        // give a half second slop time
  361.  
  362.         return((int)retval);
  363. }
  364.  
  365.  
  366. ;   /*\
  367. ;---|*|----====< CommandLine >====----
  368. ;---|*|
  369. ;---|*| Process the command line switches
  370. ;---|*|
  371. ;   \*/
  372. CommandLine(argc,argv)
  373.     int argc;
  374.     char *argv[];
  375. {
  376. int n;
  377. char *s;
  378. int vh,vl;
  379.  
  380.         vh = VersionControl >> 8;
  381.         vl = VersionControl &  0xFF;
  382.  
  383. #if RMODE
  384.         printf ("\nVESA VBE/AI WAVE Input Test Program, %02x.%02x\n",vh,vl);
  385. #else
  386.         printf ("\nVESA VBE/AI WAVE Output Test Program, %02x.%02x\n",vh,vl);
  387. #endif
  388.         printf ("Copyright (c) 1993,1994  VESA, Inc. All Rights Reserved.\n\n");
  389.  
  390.     // select the source/target PCM file name
  391.  
  392.         if (RMODE)
  393.             PCMFileName = "output.dmp";
  394.         else
  395.             PCMFileName = "guppy.wav";
  396.  
  397.     // exit in "GiveHelps" if no other parameters
  398.  
  399.         if (argc == 1)
  400.             GiveHelps();
  401.  
  402.     // process all the switches...
  403.  
  404.         n = 1;
  405.         while (n<argc) {
  406.  
  407.             s = argv[n++];
  408.  
  409.             if (*s == '-') s++;
  410.             if (*s == '/') s++;
  411.  
  412.             switch (*s & 0xDF) {
  413.  
  414.                 case '1' & 0xDF:
  415.                     if (*++s == '6') {
  416.                         PCMSize = 16;
  417.                         printf ("16 bit PCM\n");
  418.                     }
  419.                     break;
  420.  
  421.                 case 'A':
  422.                     AutoInit = TRUE;
  423.                     AutoDivide = (int) GetValue (++s,AutoDivide);
  424.                     printf ("Continuous driver I/O modes will be used (size divider=%ld)\n",AutoDivide);
  425.                     break;
  426.  
  427.                 case 'F':
  428.                     PCMFileName = ++s;
  429.                     printf ("Using \"%s\" file for play/record\n",PCMFileName);
  430.                     break;
  431.  
  432.                 case 'D':
  433.                     DelayTicks = (int) GetValue (++s,DelayTicks);
  434.                     printf ("Delay Timer Ticks = %d\n",DelayTicks);
  435.                     break;
  436.  
  437.                 case 'I':
  438.                     blockinc = GetValue (++s,blockinc);
  439.                     printf ("New block inc.   = %ld\n",blockinc);
  440.                     break;
  441.  
  442.                 case 'L':
  443.                     blocklen = GetValue (++s,blocklen) & 0x000FFFFF;
  444.                     printf ("New block length = %ld\n",blocklen);
  445.                     if (maxblocklen < blocklen) {
  446.                         maxblocklen = blocklen;
  447.                         printf ("New max block len= %ld\n",maxblocklen);
  448.                     }
  449.                     break;
  450.  
  451. #if RMODE
  452.                 case 'O':
  453.                     printf ("Saving each buffer to disk!\n");
  454.                     SaveBuffer = 1;
  455.                     if (*++s == '+')
  456.                         SaveBuffer++;
  457.                     break;
  458. #endif
  459.  
  460.                 case 'P':
  461.                     UserPref     = (int)GetValue (++s,0);
  462.                     printf ("Will use user preference level %d\n",UserPref);
  463.                     break;
  464.  
  465.                 case 'R':
  466.                     if (*s == '+') {
  467.                         printf ("Rate is reloaded after each block");
  468.                         ReloadRate = TRUE;
  469.                         s++;
  470.                     }
  471.                     SampleRate = GetValue (++s,(long)SampleRate);
  472.                     printf ("New Sample Rate  = %ld\n",SampleRate);
  473.                     break;
  474.  
  475.                 case 'S':
  476.                     StereoState = 2; // # of channels
  477.                     printf ("Running in stereo mode\n");
  478.                     break;
  479.  
  480.                 case 'T':
  481.                     MaxPasses  = GetValue (++s,MaxPasses );
  482.                     printf ("Number of Passes  = %ld\n",MaxPasses );
  483.                     break;
  484.  
  485.                 case 'V':
  486.                     VerboseMode = TRUE;
  487.                     break;
  488.  
  489.                 default:
  490.                     printf ("Unknown option - %s\n",s);
  491.                     BombOut(-1);
  492.             }
  493.         }
  494.  
  495.     // if doing auto-init buffer, then make the passes count complete buffers
  496.  
  497.         if (AutoInit)
  498.             MaxPasses *= AutoDivide;
  499.  
  500.     // separate the parameter text from the rest of the report
  501.  
  502.         printf ("\n");
  503. }
  504.  
  505.  
  506. ;   /*\
  507. ;---|*|----====< DelayTimer >====----
  508. ;---|*|
  509. ;---|*| Delay this many clock ticks
  510. ;---|*|
  511. ;   \*/
  512. DelayTimer(ticks)
  513.     int ticks;
  514. {
  515. int timer = -1;
  516. int delta = -1;
  517.  
  518.     // while we have time to waste...
  519.  
  520.         DeltaTime();
  521.  
  522.         while (ticks) {
  523.  
  524.             // watch the keyboard for an exit command
  525.  
  526.                 if (kbhit())
  527.                     if (getch() == 0x1b)
  528.                         DoExit(-1);
  529.  
  530.             // if the clock ticked, count down one...
  531.  
  532.                 if (DeltaTime())
  533.                     ticks--;
  534.  
  535.         }
  536.  
  537. }
  538.  
  539. ;
  540. ;   /*\
  541. ;---|*|----====< DelayUs >====----
  542. ;---|*|
  543. ;---|*| Delay this many microseconds
  544. ;---|*|
  545. ;   \*/
  546. DelayUs(ticks)
  547.     int ticks;
  548. {
  549.  
  550.     // while we have time to waste...
  551.  
  552.         _asm {
  553.             mov     cx,ticks
  554.             mov     dx,0x388
  555.         ;
  556.         dlyus05:
  557.  
  558.             in      al,dx
  559.             loop    dlyus05
  560.  
  561.         }
  562. }
  563.  
  564. ;
  565. ;   /*\
  566. ;---|*|----====< DeltaTime >====----
  567. ;---|*|
  568. ;---|*| Return the delta of clock ticks
  569. ;---|*|
  570. ;   \*/
  571. DeltaTime()
  572. {
  573. int retval;
  574. static int timer = -1;
  575.  
  576.     // get the clock tick, save, sub from last tick & return the value
  577.  
  578.         _asm {
  579.             mov     ah,0
  580.             int     1ah
  581.             xchg    dx,[timer]
  582.             sub     dx,[timer]
  583.             mov     [retval],dx
  584.         }
  585.  
  586.     // return the delta
  587.  
  588.         return(retval);
  589. }
  590.  
  591.  
  592. ;   /*\
  593. ;---|*|----====< DoExit >====----
  594. ;---|*|
  595. ;---|*| Shut everything down, then exit to DOS
  596. ;---|*|
  597. ;   \*/
  598. DoExit(cc)
  599.     int cc;
  600. {
  601.  
  602.     // close the device if already opened
  603.  
  604.         if (wfn) {
  605.  
  606.             (wfn->wsStopIO)(0);         // kill any running I/O
  607.  
  608.             if (hBLOCK)
  609.                 (wfn->wsWaveRegister)(0,hBLOCK);
  610.  
  611.             VESACloseDevice(hWAVE);     // close the device
  612.         }
  613.  
  614.     // save the output file data to disk
  615.  
  616.         if (SaveBuffer)
  617.             fclose (rfile);
  618.  
  619.     // make a distinguishing mark on the screen...
  620.  
  621.         printf ("\n-------------------------------------------------\n");
  622.  
  623.     // return to DOS, don't return to caller
  624.  
  625.         exit(cc);
  626. }
  627.  
  628.  
  629. ;   /*\
  630. ;---|*|----====< DumpSomeSamples >====----
  631. ;---|*|
  632. ;---|*| Dump some of the DMA'ed samples
  633. ;---|*|
  634. ;   \*/
  635. DumpSomeSamples(len)
  636.     int len;
  637. {
  638. char far *s;
  639. int n;
  640.  
  641.     // if we have the pointer, do it...
  642.  
  643.         if ((s = dmaptr) != 0) {
  644.  
  645.             for (n=0;n<len;n++) {
  646.  
  647.                 if ((n & 0x0F) == 0)
  648.                     printf ("\n%04x ",n);
  649.  
  650.                 printf ("%02x ",*s++ & 0xFF);
  651.  
  652.             }
  653.             printf ("\n");
  654.         }
  655. }
  656.  
  657.  
  658. ;   /*\
  659. ;---|*|----====< GetValue >====----
  660. ;---|*|
  661. ;---|*| Return a value from the string, or the last value
  662. ;---|*|
  663. ;   \*/
  664. long GetValue (s,orig)
  665.     char * s;
  666.     long orig;
  667. {
  668. long w;
  669. int NegateFlag = FALSE;
  670.  
  671.     // if the first character is negative, then set out neg flag
  672.  
  673.         if (*s == '-') {
  674.             s++;
  675.             NegateFlag = TRUE;
  676.         }
  677.  
  678.     // check the first character, if zero, then it's octal or hex
  679.  
  680.         if (*s == '0') {
  681.  
  682.             w = 0;
  683.  
  684.             if ((*++s & 0x5F) == 'X') {
  685.  
  686.                 if (sscanf (++s,"%lx",&w) != 1)
  687.                     w = orig;
  688.  
  689.             }
  690.             else {
  691.                 if (isdigit(*s)) {
  692.  
  693.                     if (sscanf (s,"%lo",&w) != 1)
  694.                         w = orig;
  695.                 }
  696.                 else {
  697.                     w = 0;
  698.                 }
  699.             }
  700.         }
  701.  
  702.     // return a decimal value
  703.  
  704.         else {
  705.  
  706.             if (sscanf (s,"%ld",&w) != 1)
  707.                 w = orig;
  708.  
  709.         }
  710.  
  711.     // we have something...
  712.  
  713.         if (NegateFlag)
  714.             w = 0 - w;
  715.  
  716.         return(w);
  717.  
  718. }
  719.  
  720.  
  721. ;   /*\
  722. ;---|*|----====< GiveHelps >====----
  723. ;---|*|
  724. ;---|*| Give the user the commandline option list
  725. ;---|*|
  726. ;   \*/
  727.  
  728. GiveHelps()
  729. {
  730.  
  731. #if RMODE
  732.         printf ("\nTo Use:  DOS>rec  [16] [Axxx] [Fxxx] [Dxxx] [Ixxx] [Lxxx] [O{+}] [R] [S] [Txxx]\n\n");
  733. #else
  734.         printf ("\nTo Use:  DOS>play [16] [Axxx] [Fxxx] [Dxxx] [Ixxx] [Lxxx] [R] [S] [Txxx]\n\n");
  735. #endif
  736.         printf ("Where: [16]   enables 16 bit audio (default=8 bit).\n");
  737.         printf ("       [Axxx] uses PlayCont/RecordCont. xxx is block size divisor (default=8).\n");
  738.         printf ("       [Fxxx] user selects a new File by the name of xxx.\n");
  739.         printf ("       [Dxxx] allows for delays between blocks of xxx clock ticks (18.2tps).\n");
  740.         printf ("       [Ixxx] after each block, Increment the next length by xxx.\n");
  741.         printf ("       [Lxxx] block Length of first pcm block.\n");
  742.  
  743. #if RMODE
  744.         printf ("       [O{+}] Save one recorded block. '+' saves all blocks.\n");
  745. #endif
  746.         printf ("       [R]    Reload the sample rate after each block finishes.\n");
  747.         printf ("       [S]    selects Stereo mode operation.\n");
  748.         printf ("       [Txxx] number of Times to play the block.\n");
  749.  
  750.         exit(0);
  751. }
  752.  
  753.  
  754. ;   /*\
  755. ;---|*|----====< GiveSomeStats >====----
  756. ;---|*|
  757. ;---|*| Print some useful information to the user
  758. ;---|*|
  759. ;   \*/
  760. GiveSomeStats()
  761. {
  762. register char far *vidptr = (char far *)0xb8000000;
  763. char sstr[80],*s;
  764.  
  765.     // create the string
  766.  
  767.         sprintf (sstr,"pass=%5lu len=%lx ",PassCount,blocklen);
  768.  
  769.     // blast it out...
  770.  
  771.         s = sstr;
  772.         while (*s) {
  773.             *vidptr++ = *s++;
  774.             *vidptr++ = 0x3F;
  775.         }
  776. }
  777.  
  778.  
  779. ;   /*\
  780. ;---|*|----====< LoadPCMFile >====----
  781. ;---|*|
  782. ;---|*| Load the pcm file into the DMA buffer
  783. ;---|*|
  784. ;   \*/
  785. LoadPCMFile()
  786. {
  787. char huge *t;
  788. int han,n;
  789. long l;
  790.  
  791.     // get some memory to hold the audio data
  792.  
  793.         l = maxblocklen;
  794.  
  795.         if (AutoInit)
  796.             l <<= 1;
  797.  
  798.         if ((dmaptr = t = AllocateBuffer( l+16 )) == 0) {
  799.             printf ("Unable to allocate DMA buffer memory!\n");
  800.             return (FALSE);
  801.         }
  802.  
  803.     // if in autoinit mode, we have to guarrantee no 64k crossings
  804.  
  805.         if (AutoInit)
  806.             dmaptr = t = MakeZeroOffset(t,maxblocklen);
  807.  
  808.     // load a triangle wave into the buffer
  809.  
  810.         for (l=maxblocklen>>1;l;l--)
  811.             *t++ = l & 0xff;
  812.  
  813.         for (l=maxblocklen>>1;l;l--)
  814.             *t++ = (255 - (l & 0xff));
  815.  
  816. #if RMODE==0
  817.  
  818.     // open the file. If we can't read it, then forget it...
  819.  
  820.         if ((rfile = fopen (PCMFileName,"rb")) == 0) {
  821.             printf ("Unable to load the PCM file named \"%s\"\n",PCMFileName);
  822.             return (FALSE);
  823.         }
  824.  
  825.     // read the entire file into the DMA buffer
  826.  
  827.         han = fileno(rfile);
  828.  
  829.     // flush the header from the file
  830.  
  831.         readblock (han,(t=dmaptr),0x20);// read past the .VOC header
  832.  
  833.         if ((*(int far *)t) == 0x4952)
  834.             readblock (han,t,0x0C);     // read more for a .WAV header
  835.  
  836.     // read the entire file into a far pointer
  837.  
  838.         for (l=maxblocklen;l>0;l-=0x1000) {
  839.  
  840.             if (readblock (han,t,0x1000) != 0x1000)
  841.                 break;
  842.  
  843.             t+= 0x1000;
  844.         }
  845.  
  846.         if (l < 0)
  847.             readblock (han,t,(int)l + 0x1000);
  848.  
  849.         fclose (rfile);
  850.  
  851. #else
  852.  
  853.     // open the file for output
  854.  
  855.         if ((rfile = fopen (PCMFileName,"wb")) == 0) {
  856.             printf ("Unable to load the PCM file named \"%s\"\n",PCMFileName);
  857.             return (FALSE);
  858.         }
  859.  
  860. #endif
  861.  
  862.     // register the block with the driver.
  863.  
  864.         if (!AutoInit) {
  865.             if ((hBLOCK = (wfn->wsWaveRegister)(dmaptr,blocklen)) == 0) {
  866.                 printf ("Block registration failed! error=%02x\n",(wfn->wsGetLastError)());
  867.                 return (FALSE);
  868.             }
  869.         }
  870.  
  871.     // all is okay...
  872.  
  873.         return(TRUE);
  874. }
  875.  
  876. ;
  877. ;   /*\
  878. ;---|*|----====< MakeZeroOffset >====----
  879. ;---|*|
  880. ;---|*| Make the buffer address linear, with a zero offset,
  881. ;---|*| not crossing a 64k boundary! (whew!). The true address pointer must
  882. ;---|*| be pointing to a buffer of the length of len*2+16
  883. ;---|*|
  884. ;   \*/
  885. char huge *MakeZeroOffset (addr,len)
  886.     char huge *addr;
  887.     long len;
  888. {
  889. long l;
  890.  
  891.         _asm {
  892.             mov     ax,word ptr [addr+0]
  893.             mov     dx,word ptr [addr+2]
  894.  
  895.             mov     bx,0xFFF0               // get the linear address
  896.             rol     dx,4
  897.             and     bx,dx
  898.             xor     dx,bx
  899.             add     ax,bx
  900.             adc     dx,0
  901.  
  902.             and     ax,0xFFF0               // go to the next 16 byte boundary
  903.             add     ax,0x0010
  904.  
  905.             mov     bx,dx                   // check to see if we wrap a
  906.             mov     cx,ax                   // 64k boundary
  907.             add     cx,word ptr [len+0]
  908.             adc     bx,word ptr [len+2]     // bx = dx, or bx = dx + 1
  909.  
  910.             sub     bx,dx                   // bx = 0x0000 if same, else 0x0001
  911.             neg     bx                      // bx = 0x0000 if same, else 0xFFFF
  912.             sub     dx,bx                   // add 1 if it wrapped
  913.             not     bx                      // bx = 0xFFFF if same, else 0x0000
  914.             and     ax,bx                   // flush if wrapped, else save
  915.  
  916.             ror     dx,4                    // make a seg:off out of the linear
  917.             add     dx,ax                   // address
  918.             sub     ax,ax
  919.  
  920.         }
  921.  
  922. }
  923.  
  924. ;
  925. ;   /*\
  926. ;---|*|----====< OpenTheDriver >====----
  927. ;---|*|
  928. ;---|*| Find the driver with the highest user preference, and return it to
  929. ;---|*| the caller
  930. ;---|*|
  931. ;   \*/
  932. int OpenTheDriver(pref)
  933.     int pref;
  934. {
  935. int driverpref = 256;   // real low preference
  936. long l;
  937.  
  938.     // find a matching driver
  939.  
  940.         do {
  941.  
  942.             // Find one DAC device, else bail if non found
  943.  
  944.                 if ((hWAVE = VESAFindADevice(WAVDEVICE)) == 0)
  945.                     return(0);
  946.  
  947.             // get the device information
  948.  
  949.                 if (VESAQueryDevice(hWAVE, VESAQUERY2 ,&gdc) == 0) {
  950.                     printf ("Cannot query the installed VAI devices!\n");
  951.                     DoExit(-1);
  952.                 }
  953.  
  954.             // make sure its a wave device
  955.  
  956.                 if (gdc.gdclassid != WAVDEVICE) {
  957.                     printf ("The VESA find device query returned a NON DAC device!\n");
  958.                     DoExit(-1);
  959.                 }
  960.  
  961.             // make sure it's matches the beta version #
  962.  
  963.                 if (gdc.gdvbever != VersionControl) {
  964.                     printf ("The VESA device version # does not match, cannot continue!\n");
  965.                     DoExit(-1);
  966.                 }
  967.  
  968.             // get the drivers user preference level
  969.  
  970.                 driverpref = gdc.u.gdwi.widevpref;
  971.  
  972.             // if the caller is not expressing a preference, then use this one
  973.  
  974.                 if (pref == -1)
  975.                     break;
  976.  
  977.         } while (driverpref != pref);
  978.  
  979.     // get the memory needed by the device
  980.  
  981.         if (!(memptr = AllocateBuffer(gdc.u.gdwi.wimemreq))) {
  982.             printf ("We don't have memory for the device!\n");
  983.             DoExit(-1);
  984.         }
  985.  
  986.     // if the DAC device doesn't open, bomb out...
  987.  
  988.         if ((wfn = (fpWAVServ)VESAOpenADevice(hWAVE,0,memptr)) == 0) {
  989.             printf ("Cannot Open the installed devices!\n");
  990.             DoExit(-1);
  991.         }
  992.  
  993.     // just for fun, report the driver state
  994.  
  995.         printf ("The driver state = %x\n",(wfn->wsDeviceCheck) (WAVEDRIVERSTATE,0) );
  996.  
  997.     // tell the user how close the driver comes to the requested sample rate
  998.  
  999.         if ( !(l = (wfn->wsDeviceCheck)(WAVESAMPLERATE,SampleRate)) )
  1000.             printf ("The driver does not support a %ldhz sample rate!\n",RealSampleRate=SampleRate);
  1001.         else
  1002.             printf ("The drivers closest playback sample rate is %ldhz!\n",RealSampleRate=l);
  1003.  
  1004.     // setup the record and playback callbacks
  1005.  
  1006.         if (RMODE) {
  1007.             wfn->wsApplRSyncCB = &OurCallback;
  1008.             wfn->wsApplPSyncCB = &ErrorCallback;
  1009.         }
  1010.         else {
  1011.             wfn->wsApplPSyncCB = &OurCallback;
  1012.             wfn->wsApplRSyncCB = &ErrorCallback;
  1013.         }
  1014.  
  1015.     // return the handle
  1016.  
  1017.         return(hWAVE);
  1018. }
  1019.  
  1020.  
  1021. ;   /*\
  1022. ;---|*|----====< OurCallback >====----
  1023. ;---|*|
  1024. ;---|*| Block End callback. NOTE: No assumptions can be made about
  1025. ;---|*| the segment registers! (DS,ES,GS,FS)
  1026. ;---|*|
  1027. ;   \*/
  1028.  
  1029. void far pascal OurCallback( han, fptr, len, filler )
  1030.     VESAHANDLE han; // device handle
  1031.     void far *fptr; // buffer that just played
  1032.     long len;       // length of completed transfer
  1033.     long filler;    // reserved...
  1034. {
  1035.  
  1036.     // setup our data segment
  1037.  
  1038.         _asm {
  1039.  
  1040.             push    ds
  1041.             mov     ax,seg CallBackOccured
  1042.             mov     ds,ax
  1043.  
  1044.         }
  1045.  
  1046.     // save for later reporting...
  1047.  
  1048.         OldGlobalPtr = GlobalPtr;
  1049.         OldGloballen = Globallen;
  1050.  
  1051.         GlobalHandle = han;
  1052.         GlobalPtr    = fptr;
  1053.         Globallen    = len;
  1054.         CallBackOccured++;
  1055.  
  1056.     // we're done here...
  1057.  
  1058.         _asm {
  1059.             pop     ds
  1060.         }
  1061. }
  1062.  
  1063.  
  1064. ;   /*\
  1065. ;---|*|----====< ErrorCallback >====----
  1066. ;---|*|
  1067. ;---|*| If we get this, we received the wrong callback!
  1068. ;---|*|
  1069. ;   \*/
  1070.  
  1071. void far pascal ErrorCallback( han, fptr, len, filler )
  1072.     int han;        // device handle
  1073.     void far *fptr; // buffer that just played
  1074.     long len;       // length of completed transfer
  1075.     long filler;    // reserved...
  1076. {
  1077.  
  1078.     // setup our data segment
  1079.  
  1080.         _asm {
  1081.  
  1082.             push    ds
  1083.             mov     ax,seg ErrorBackOccured
  1084.             mov     ds,ax
  1085.  
  1086.             inc     [ErrorBackOccured]
  1087.  
  1088.             pop     ds
  1089.         }
  1090. }
  1091.  
  1092.  
  1093. ;   /*\
  1094. ;---|*|----====< readblock >====----
  1095. ;---|*|
  1096. ;---|*| read a chunk of the PCM file into the huge buffer
  1097. ;---|*|
  1098. ;   \*/
  1099. int readblock (han,tptr,len)
  1100.     int han;
  1101.     char huge *tptr;
  1102.     int len;
  1103. {
  1104. int siz = 0;
  1105.  
  1106.     // go get it...
  1107.  
  1108.         _asm {
  1109.             push    ds
  1110.  
  1111.             mov     cx,[len]
  1112.             mov     ax,cx
  1113.             add     cx,word ptr [tptr]  // wrap?
  1114.             jnc     rdbl05              // no, go get the size
  1115.  
  1116.             sub     ax,cx               // ax holds the # of bytes to read
  1117.             mov     cx,ax
  1118.             sub     [len],ax
  1119.  
  1120.             mov     ah,03fh             // cx holds the length
  1121.             mov     bx,[han]
  1122.             lds     dx,[tptr]
  1123.             int     21h
  1124.  
  1125.             mov     [siz],ax            // we moved this much
  1126.             add     word ptr [tptr+2],0x1000
  1127.  
  1128.             cmp     ax,cx               // same size?
  1129.             jnz     rdbldone            // no, exit...
  1130.         ;
  1131.         rdbl05:
  1132.  
  1133.             mov     ah,03fh
  1134.             mov     bx,[han]
  1135.             mov     cx,[len]
  1136.  
  1137.             jcxz    rdbldone
  1138.  
  1139.             lds     dx,[tptr]
  1140.             int     21h
  1141.  
  1142.             add     [siz],ax            // we moved this much
  1143.         ;
  1144.         rdbldone:
  1145.             pop     ds
  1146.  
  1147.         }
  1148.  
  1149.     // return the amount read
  1150.  
  1151.         return(siz);
  1152. }
  1153.  
  1154.  
  1155. ;   /*\
  1156. ;---|*|----====< ReportCallback >====----
  1157. ;---|*|
  1158. ;---|*| Print some useful information to the user
  1159. ;---|*|
  1160. ;   \*/
  1161. ReportCallBack()
  1162. {
  1163. register char far *vidptr = (char far *)0xb80000A0;
  1164. char sstr[80],*s;
  1165.  
  1166. static int cbcnt = 0;
  1167.  
  1168.     // flush the callback indicator
  1169.  
  1170.         CallBackOccured = 0;
  1171.  
  1172.     // create the string
  1173.  
  1174.         sprintf (sstr,"%5d han=%5d ptr=%8lx len=%8ld ",cbcnt++,GlobalHandle,GlobalPtr,Globallen);
  1175.  
  1176.     // blast it out...
  1177.  
  1178.         s = sstr;
  1179.         while (*s) {
  1180.             *vidptr++ = *s++;
  1181.             *vidptr++ = 0x3F;
  1182.         }
  1183. }
  1184.  
  1185.  
  1186. ;   /*\
  1187. ;---|*|----====< ReportCurrentPos >====----
  1188. ;---|*|
  1189. ;---|*| Report the current block position reported via a DeviceCheck call
  1190. ;---|*|
  1191. ;   \*/
  1192. ReportCurrentPos()
  1193. {
  1194. register char far *vidptr = (char far *)0xb8000140;
  1195. char sstr[80],*s;
  1196. long length;
  1197.  
  1198. static int cbcnt = 0;
  1199.  
  1200.     // create the string
  1201.  
  1202.    #if 0
  1203.         _asm {
  1204.             mov     dx,0xb8a
  1205.             mov     cx,1024
  1206.         waithere:
  1207.             in      al,dx
  1208.             loop    waithere
  1209.  
  1210.             push    ax
  1211.  
  1212.             and     al,0x3F
  1213.             out     dx,al
  1214.  
  1215.         }
  1216.    #endif
  1217.  
  1218.         length = (wfn->wsDeviceCheck) (WAVEGETCURRENTPOS,0);
  1219.         sprintf (sstr,"%5d han=%5d offset=%8lx",cbcnt++,GlobalHandle,length);
  1220.  
  1221.     // blast it out...
  1222.  
  1223.         s = sstr;
  1224.         while (*s) {
  1225.             *vidptr++ = *s++;
  1226.             *vidptr++ = 0x3F;
  1227.         }
  1228.  
  1229.    #if 0
  1230.         _asm {
  1231.             mov     dx,0xb8a
  1232.             pop     ax
  1233.             out     dx,al
  1234.         }
  1235.    #endif
  1236.  
  1237. }
  1238.  
  1239.  
  1240. ;   /*\
  1241. ;---|*|----====< SaveToDisk >====----
  1242. ;---|*|
  1243. ;---|*| Save the buffer to disk
  1244. ;---|*|
  1245. ;   \*/
  1246.  
  1247. SaveToDisk(len)
  1248.     long len;
  1249. {
  1250. char huge *s;
  1251. int han,n;
  1252. long l;
  1253.  
  1254.     // if we have the pointer, do it...
  1255.  
  1256.         n = fileno(rfile);
  1257.  
  1258.     // if there is a buffer, write the data
  1259.  
  1260.         if ((s=dmaptr) != 0) {
  1261.  
  1262.             // point to the start of the file unless the user wants everything
  1263.  
  1264.             if (SaveBuffer != 2) {
  1265.  
  1266.                 _asm {
  1267.  
  1268.                     mov     ax,4200h    ; point to the start of the file
  1269.                     mov     bx,[n]      ; get the handle
  1270.                     sub     cx,cx
  1271.                     sub     dx,dx
  1272.                     int     21h         ; file points to zero
  1273.                 }
  1274.             }
  1275.  
  1276.             // write the data to disk
  1277.  
  1278.             han = fileno(rfile);
  1279.  
  1280.             for (l=len;l>0;l-=0x1000) {
  1281.  
  1282.                 if (writeblock (han,s,0x1000) != 0x1000)
  1283.                     break;
  1284.  
  1285.                 s+= 0x1000;
  1286.             }
  1287.  
  1288.             if (l < 0)
  1289.                 writeblock (han,s,(int)l + 0x1000);
  1290.         }
  1291. }
  1292.  
  1293.  
  1294. ;   /*\
  1295. ;---|*|----====< StartNextBlock >====----
  1296. ;---|*|
  1297. ;---|*| Just read the buffer during the record process
  1298. ;---|*|
  1299. ;   \*/
  1300.  
  1301. int StartNextBlock(flag)
  1302.     int flag;
  1303. {
  1304. int retval;
  1305.  
  1306. static int pass = 0;
  1307.  
  1308.     // on the 1st pass, load the playback data
  1309.  
  1310.         if (pass == 0) {
  1311.  
  1312.             // load the file into the DMA buffer, get the delay ticks
  1313.  
  1314.             if (!LoadPCMFile()) {
  1315.                 return(FALSE);
  1316.                 pass++;
  1317.             }
  1318.  
  1319.  
  1320.         }
  1321.         else {
  1322.  
  1323.     // else, every other pass, possibly setup the transfer type and rate
  1324.  
  1325.             if (ReloadRate)
  1326.                 printf ("wsPCMInfo() returned %ld\n",
  1327.                     (wfn->wsPCMInfo)(StereoState,SampleRate,Compression,0,PCMSize));
  1328.  
  1329.         }
  1330.  
  1331.     // if we have to prepare the data for playback, do it now...
  1332.  
  1333. #if RMODE==0
  1334.         if (pass == 0) {
  1335.             if (gdc.u.gdwi.wifeatures & WAVEPREPARE)
  1336.             (wfn->wsWavePrepare)(0,PCMSize,StereoState,dmaptr,blocklen);
  1337.         }
  1338. #endif
  1339.  
  1340.  
  1341.     // flush the old IRQ occured flag
  1342.  
  1343.      // CallBackOccured = 0;
  1344.  
  1345. #if RMODE==0
  1346.  
  1347.     // let it rip
  1348.  
  1349.         if (AutoInit)
  1350.             retval = (wfn->wsPlayCont)    (dmaptr,blocklen,blocklen/AutoDivide);
  1351.         else
  1352.             retval = (wfn->wsPlayBlock)   (hBLOCK,0);
  1353.  
  1354. #else
  1355.  
  1356.     // let it rip
  1357.  
  1358.         if (AutoInit)
  1359.             retval = (wfn->wsRecordCont)  (dmaptr,blocklen,blocklen/AutoDivide);
  1360.         else
  1361.             retval = (wfn->wsRecordBlock) (hBLOCK,0);
  1362.  
  1363. #endif
  1364.  
  1365.         if ( (DriverError = (wfn->wsGetLastError)()) )
  1366.             printf ("Driver is reporting an internal error! (code=%d)\n",DriverError);
  1367.  
  1368.         pass++;
  1369.         return(retval);
  1370.  
  1371. }
  1372.  
  1373.  
  1374. ;   /*\
  1375. ;---|*|----====< writeblock >====----
  1376. ;---|*|
  1377. ;---|*| write a chunk of the PCM buffer to the disk file.
  1378. ;---|*|
  1379. ;   \*/
  1380. int writeblock (han,tptr,len)
  1381.     int han;
  1382.     char huge *tptr;
  1383.     int len;
  1384. {
  1385. int siz = 0;
  1386.  
  1387.     // go get it...
  1388.  
  1389.         _asm {
  1390.             push    ds
  1391.  
  1392.             mov     cx,[len]
  1393.             mov     ax,cx
  1394.             add     cx,word ptr [tptr]  // wrap?
  1395.             jnc     rdbl05              // no, go get the size
  1396.  
  1397.             sub     ax,cx               // ax holds the # of bytes to read
  1398.             mov     cx,ax
  1399.             sub     [len],ax
  1400.  
  1401.             mov     ah,040h             // cx holds the length
  1402.             mov     bx,[han]
  1403.             lds     dx,[tptr]
  1404.             int     21h
  1405.  
  1406.             mov     [siz],ax            // we moved this much
  1407.             add     word ptr [tptr+2],0x1000
  1408.  
  1409.             cmp     ax,cx               // same size?
  1410.             jnz     rdbldone            // no, exit...
  1411.         ;
  1412.         rdbl05:
  1413.  
  1414.             mov     ah,040h
  1415.             mov     bx,[han]
  1416.             mov     cx,[len]
  1417.  
  1418.             jcxz    rdbldone
  1419.  
  1420.             lds     dx,[tptr]
  1421.             int     21h
  1422.  
  1423.             add     [siz],ax            // we moved this much
  1424.         ;
  1425.         rdbldone:
  1426.             pop     ds
  1427.  
  1428.         }
  1429.  
  1430.     // return the amount read
  1431.  
  1432.         return(siz);
  1433. }
  1434.  
  1435.  
  1436.  
  1437.  
  1438.  
  1439.