home *** CD-ROM | disk | FTP | other *** search
/ TopWare 18: Liquid / Image.iso / liquid / top1120 / play.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-10  |  15.6 KB  |  646 lines

  1.  
  2. ;   /*\
  3. ;---|*|----====< Play >====----
  4. ;---|*|
  5. ;---|*| play small a list of wave files
  6. ;---|*|
  7. ;---|*| Copyright (c) 1993,1994  V.E.S.A, Inc. All Rights Reserved.
  8. ;---|*|
  9. ;---|*| VBE/AI 1.0 Specification
  10. ;---|*|    April 6, 1994. 1.00 release
  11. ;---|*|
  12. ;   \*/
  13.  
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <signal.h>
  18. #include <io.h>
  19.  
  20. #include "vbeai.h"
  21. #include "vesa.h"
  22.  
  23.  
  24. ;   /*\
  25. ;---|*| Global Variables
  26. ;   \*/
  27.  
  28.         int  CallBackOccured  = 0;
  29.         int  ErrorBackOccured = 0;
  30.  
  31.         VESAHANDLE  hWAVE   = 0;
  32.         FILE *rfile;
  33.         char far *memptr    = 0;
  34.  
  35.         GeneralDeviceClass gdc; // receives a copy of the VESA driver info block
  36.         fpWAVServ wfn;          // pointer to wave functions
  37.  
  38.  
  39. ;   /*\
  40. ;---|*| Local Variables
  41. ;   \*/
  42.  
  43.         typedef struct {
  44.             char *fname;        // file name
  45.             char huge *ptr;     // pointer to the buffer
  46.             long len;           // file length
  47.             int  han;           // registered handle
  48.             long sr;            // sample rate
  49.             int  ch;            // channels
  50.             int  sz;            // data size (8 or 16)
  51.             int  cp;            // compression
  52.         } wave;
  53.  
  54.         int MaxWaves   =  0;    // maximum number of registered waves
  55.         wave Waves[10] = {0};   // up to 10 registered waves
  56.  
  57.     // 4. Wave format control block
  58.  
  59.         typedef struct {
  60.             int  formatTag;     // format category
  61.             int  nChannels;     // stereo/mono
  62.             long nSamplesPerSec;    // sample rate
  63.             long nAvgBytesPerSec;   // stereo * sample rate
  64.             int  nBlockAlign;       // block alignment (1=byte)
  65.             int  nBitsPerSample;    // # byte bits per sample
  66.         } WaveInfo;
  67.  
  68.     // 3. Wave detailed information Block
  69.  
  70.         typedef struct {
  71.             char name[4];   // "fmt "
  72.             long length;
  73.             WaveInfo info;
  74.         } WaveFormat;
  75.  
  76.     // 3. Data header which follows a WaveFormat Block
  77.  
  78.         typedef struct {
  79.             char name[4];   // "data"
  80.             unsigned long length;
  81.         } DataHeader;
  82.  
  83.     // 2. Total Wave Header data in a wave file
  84.  
  85.         typedef struct {
  86.             char name[4];   // "WAVE"
  87.             WaveFormat fmt;
  88.             DataHeader data;
  89.         } WaveHeader;
  90.  
  91.     // 2. Riff wrapper around the WaveFormat Block (optional)
  92.  
  93.         typedef struct {
  94.             char name[4];   // "RIFF"
  95.             long length;
  96.         } RiffHeader;
  97.  
  98.     // 1. Riff wrapped WaveFormat Block
  99.  
  100.         typedef struct {
  101.             RiffHeader riff;
  102.             WaveHeader wave;
  103.         } RiffWave;
  104.  
  105. #define VALIDWAVE           0
  106. #define UNKNOWNFILETYPE     1
  107.  
  108. ;   /*\
  109. ;---|*| prototypes
  110. ;   \*/
  111.  
  112.         void far pascal OurCallback  ( int, void far *, long, long );
  113.         void far pascal ErrorCallback( int, void far *, long, long );
  114.         int  readblock               ( int, char huge *, int );
  115.         VESAHANDLE OpenTheDriver     ( int );
  116.         int ProcessWAVHeader         ( FILE *, int );
  117.  
  118.     // only allows us to run on this version of the VBE interface. This
  119.     // will be removed after the interface is ratified. Changes may be made
  120.     // that would cause this code to crash if run on other version. Again,
  121.     // this will be removed in the final software.
  122.  
  123.         int  VersionControl = 0x0100;
  124.  
  125.  
  126. ;   /*\
  127. ;---|*|------------------==============================-------------------
  128. ;---|*|------------------====< Start of execution >====-------------------
  129. ;---|*|------------------==============================-------------------
  130. ;   \*/
  131.  
  132. main(argc,argv)
  133.     int argc;
  134.     char *argv[];
  135. {
  136. int idx;
  137. int n;
  138.  
  139.     // process the command line
  140.  
  141.         CommandLine (argc,argv);
  142.  
  143.     // disable the ^C so the devices will close properly.
  144.  
  145.         signal (SIGINT,SIG_IGN);
  146.  
  147.     // do all the work to get a VESA driver
  148.  
  149.         if (!OpenTheDriver(0)) {    // open the highest driver
  150.             printf ("Cannot find any installed VAI devices!\n");
  151.             DoExit(-1);
  152.         }
  153.  
  154.     // Register all the blocks
  155.  
  156.         for (n=0;n<MaxWaves;n++)
  157.             Waves[n].han =
  158.                 (wfn->wsWaveRegister) (Waves[n].ptr,Waves[n].len);
  159.  
  160.     // present a list and play each sound as required
  161.  
  162.         while (1) {
  163.  
  164.             if ((idx = GetOption()) == -1)
  165.                 break;
  166.  
  167.             CallBackOccured = 0;    // no callbacks yet
  168.  
  169.             (wfn->wsPCMInfo)        // set the sample rate, etc.
  170.               (
  171.                 Waves[idx].ch,
  172.                 Waves[idx].sr,
  173.                 Waves[idx].cp,
  174.                 0,
  175.                 Waves[idx].sz
  176.               );
  177.  
  178.             (wfn->wsPlayBlock)(Waves[idx].han,0); // start output
  179.  
  180.             if (!DriverError()) {
  181.  
  182.                 printf ("Type ESC to stop, SPACE to pause ");
  183.  
  184.                 while (!CallBackOccured) {
  185.  
  186.                     if (kbhit()) {
  187.  
  188.                         switch (getch()) {
  189.  
  190.                             case 0x1b:  // escape
  191.                                 CallBackOccured++;
  192.                                 (wfn->wsStopIO)(Waves[idx].han);
  193.                                 break;
  194.  
  195.                             case 0x20:  // space
  196.                                 (wfn->wsPauseIO)(Waves[idx].han);
  197.                                 printf ("\nType SPACE to continue ");
  198.                                 while (getch() != 0x20) ;
  199.                                 (wfn->wsResumeIO)(Waves[idx].han);
  200.                                 break;
  201.  
  202.                             default:
  203.                                 break;
  204.                         }
  205.                     }
  206.                 }
  207.             }
  208.         }
  209.  
  210.  
  211.     // exit now...
  212.  
  213.         DoExit(0);
  214. }
  215.  
  216.  
  217. ;   /*\
  218. ;---|*|----------------------=======================----------------------
  219. ;---|*|----------------------====< Subroutines >====----------------------
  220. ;---|*|----------------------=======================----------------------
  221. ;   \*/
  222.  
  223. ;
  224. ;   /*\
  225. ;---|*|----====< CommandLine >====----
  226. ;---|*|
  227. ;---|*| Process the command line switches
  228. ;---|*|
  229. ;   \*/
  230. CommandLine(argc,argv)
  231.     int argc;
  232.     char *argv[];
  233. {
  234. int n,fhan;
  235. int vh,vl;
  236. char str[100];
  237.  
  238.         vh = VersionControl >> 8;
  239.         vl = VersionControl &  0xFF;
  240.  
  241.         printf ("\nVESA VBE/AI WAVE Output Program, %02x.%02x\n",vh,vl);
  242.         printf ("Copyright (c) 1993,1994  VESA, Inc. All Rights Reserved.\n\n");
  243.  
  244.     // exit in "GiveHelps" if no other parameters
  245.  
  246.         if (argc == 1) {
  247.             printf ("\nTo Use:  DOS>play [file.wav] [file.wav] [file.wav]...\n\n");
  248.             printf ("Where: [file.wav] is a list of up to 10 files to play.\n");
  249.             DoExit(0);
  250.         }
  251.  
  252.     // process all the switches...
  253.  
  254.         MaxWaves = 0;
  255.         while (MaxWaves+1<argc) {
  256.  
  257.             Waves[MaxWaves].fname = argv[MaxWaves+1];
  258.  
  259.             if ((rfile = fopen (Waves[MaxWaves].fname,"rb")) == 0) {
  260.  
  261.                 strcpy (str,Waves[MaxWaves].fname);
  262.                 strcat (str,".WAV");
  263.  
  264.                 if ((rfile = fopen (str,"rb")) == 0) {
  265.                     printf ("cannot open the WAVE file named \"%s\"\n",Waves[MaxWaves].fname);
  266.                     DoExit(1);
  267.                 }
  268.             }
  269.             fseek (rfile,0,SEEK_SET);   // point to the start
  270.  
  271.             if (ProcessWAVHeader(rfile,MaxWaves) != VALIDWAVE) {
  272.                 printf ("Invalid .WAV file: \"%s\"\n",&str[0]);
  273.                 DoExit(1);
  274.             }
  275.  
  276.             Waves[MaxWaves].ptr   = AllocateBuffer(Waves[MaxWaves].len);
  277.  
  278.             if (Waves[MaxWaves].ptr == 0) {
  279.                 printf ("Ran out of memory loading the files!\n");
  280.                 DoExit(1);
  281.             }
  282.  
  283.             readblock
  284.               (
  285.                 fileno(rfile),
  286.                 Waves[MaxWaves].ptr,
  287.                 (int)Waves[MaxWaves].len
  288.               );
  289.  
  290.             fclose (rfile);
  291.             MaxWaves++;
  292.         }
  293. }
  294.  
  295. ;
  296. ;   /*\
  297. ;---|*|----====< DoExit >====----
  298. ;---|*|
  299. ;---|*| Shut everything down, then exit to DOS
  300. ;---|*|
  301. ;   \*/
  302.  
  303. DoExit(cc)
  304.     int cc;
  305. {
  306.  
  307.     // close the device if already opened
  308.  
  309.         if (wfn)
  310.             VESACloseDevice(hWAVE);     // close the device
  311.  
  312.     // return to DOS, don't return to caller
  313.  
  314.         exit(cc);
  315. }
  316.  
  317.  
  318. ;
  319. ;   /*\
  320. ;---|*|----====< DriverError >====----
  321. ;---|*|
  322. ;---|*| Report any errors by the driver
  323. ;---|*|
  324. ;   \*/
  325.  
  326. int DriverError()
  327. {
  328. int err;
  329.  
  330.     if ( (err = (wfn->wsGetLastError)()) ) {
  331.         printf ("Driver reported an error! (code=%02X)\n",err);
  332.         return (err);
  333.     }
  334.     return(0);
  335. }
  336.  
  337. ;
  338. ;   /*\
  339. ;---|*|----====< ErrorCallback >====----
  340. ;---|*|
  341. ;---|*| If we get this, we received the wrong callback!
  342. ;---|*|
  343. ;   \*/
  344.  
  345. void far pascal ErrorCallback( han, fptr, len, filler )
  346.     int han;        // device handle
  347.     void far *fptr; // buffer that just played
  348.     long len;       // length of completed transfer
  349.     long filler;    // reserved...
  350. {
  351.  
  352.     // setup our data segment
  353.  
  354.         _asm {
  355.  
  356.             push    ds
  357.             mov     ax,seg ErrorBackOccured
  358.             mov     ds,ax
  359.             inc     [ErrorBackOccured]
  360.             pop     ds
  361.         }
  362. }
  363.  
  364. ;
  365. ;   /*\
  366. ;---|*|----====< GetOption >====----
  367. ;---|*|
  368. ;---|*| Ask the user for a file to be played.
  369. ;---|*|
  370. ;   \*/
  371. GetOption()
  372. {
  373. char str[100];
  374. int n;
  375.  
  376.     // print all the files
  377.  
  378.         printf ("\n  0. Exit\n");
  379.         for (n=0;n<MaxWaves;n++)
  380.             printf ("  %d. %s\n",n+1,Waves[n].fname);
  381.  
  382.     // ask the user for a file name
  383.  
  384.         while (1) {
  385.  
  386.             printf ("\nEnter an option # ");
  387.             fgets  (str,99,stdin);
  388.  
  389.             if (sscanf(str,"%d",&n) == 1)
  390.                 if (n<=MaxWaves)
  391.                     return(n-1);
  392.  
  393.             // if an out of range #, we'll keep trying
  394.  
  395.         }
  396. }
  397.  
  398. ;
  399. ;   /*\
  400. ;---|*|----====< OpenTheDriver >====----
  401. ;---|*|
  402. ;---|*| Find the driver with the highest user preference, and return it to
  403. ;---|*| the caller
  404. ;---|*|
  405. ;   \*/
  406. int OpenTheDriver(pref)
  407.     int pref;
  408. {
  409. int driverpref = 256;   // real low preference
  410. long l;
  411.  
  412.     // find a matching driver
  413.  
  414.         do {
  415.  
  416.             // Find one DAC device, else bail if non found
  417.  
  418.                 if ((hWAVE = VESAFindADevice(WAVDEVICE)) == 0)
  419.                     return(0);
  420.  
  421.             // get the device information
  422.  
  423.                 if (VESAQueryDevice(hWAVE, VESAQUERY2 ,&gdc) == 0) {
  424.                     printf ("Cannot query the installed VAI devices!\n");
  425.                     DoExit(-1);
  426.                 }
  427.  
  428.             // make sure its a wave device
  429.  
  430.                 if (gdc.gdclassid != WAVDEVICE) {
  431.                     printf ("The VESA find device query returned a NON DAC device!\n");
  432.                     DoExit(-1);
  433.                 }
  434.  
  435.             // make sure it's matches the beta version #
  436.  
  437.                 if (gdc.gdvbever != VersionControl) {
  438.                     printf ("The VESA device version # does not match, cannot continue!\n");
  439.                     DoExit(-1);
  440.                 }
  441.  
  442.             // get the drivers user preference level
  443.  
  444.                 driverpref = gdc.u.gdwi.widevpref;
  445.  
  446.             // if the caller is not expressing a preference, then use this one
  447.  
  448.                 if (pref == -1)
  449.                     break;
  450.  
  451.         } while (driverpref != pref);
  452.  
  453.     // get the memory needed by the device
  454.  
  455.         if (!(memptr = AllocateBuffer(gdc.u.gdwi.wimemreq))) {
  456.             printf ("We don't have memory for the device!\n");
  457.             DoExit(-1);
  458.         }
  459.  
  460.     // if the DAC device doesn't open, bomb out...
  461.  
  462.         if ((wfn = (fpWAVServ)VESAOpenADevice(hWAVE,0,memptr)) == 0) {
  463.             printf ("Cannot Open the installed devices!\n");
  464.             DoExit(-1);
  465.         }
  466.  
  467.     // setup the record and playback callbacks
  468.  
  469.         wfn->wsApplPSyncCB = &OurCallback;
  470.         wfn->wsApplRSyncCB = &ErrorCallback;
  471.  
  472.     // return the handle
  473.  
  474.         return(hWAVE);
  475. }
  476.  
  477.  
  478. ;   /*\
  479. ;---|*|----====< OurCallback >====----
  480. ;---|*|
  481. ;---|*| Block End callback. NOTE: No assumptions can be made about
  482. ;---|*| the segment registers! (DS,ES,GS,FS)
  483. ;---|*|
  484. ;   \*/
  485.  
  486. void far pascal OurCallback( han, fptr, len, filler )
  487.     VESAHANDLE han; // device handle
  488.     void far *fptr; // buffer that just played
  489.     long len;       // length of completed transfer
  490.     long filler;    // reserved...
  491. {
  492.  
  493.     // setup our data segment
  494.  
  495.         _asm {
  496.  
  497.             push    ds
  498.             mov     ax,seg CallBackOccured
  499.             mov     ds,ax
  500.             inc     [CallBackOccured]
  501.             pop     ds
  502.         }
  503. }
  504.  
  505. ;
  506. ;   /*\
  507. ;---|*|----====< ProcessWAVHeader >====----
  508. ;---|*|
  509. ;---|*| load the header from our WAV file format
  510. ;---|*|
  511. ;   \*/
  512.  
  513. int ProcessWAVHeader(f,idx)
  514.     FILE *f;
  515.     int idx;
  516. {
  517. int n;
  518. RiffWave rw;
  519.  
  520.     // eat the RIFF portion of the header
  521.  
  522.         readblock ( fileno(f), (void far *)&rw, sizeof (RiffWave) );
  523.  
  524.     // make sure its says RIFF
  525.  
  526.         n  = rw.riff.name[0] - 'R';
  527.         n += rw.riff.name[1] - 'I';
  528.         n += rw.riff.name[2] - 'F';
  529.         n += rw.riff.name[3] - 'F';
  530.  
  531.         if (n)
  532.             return(UNKNOWNFILETYPE);
  533.  
  534.     // make sure it says WAVE
  535.  
  536.         n  = rw.wave.name[0] - 'W';
  537.         n += rw.wave.name[1] - 'A';
  538.         n += rw.wave.name[2] - 'V';
  539.         n += rw.wave.name[3] - 'E';
  540.  
  541.         if (n)
  542.             return(UNKNOWNFILETYPE);
  543.  
  544.     // make sure it says 'fmt '
  545.  
  546.         n  = rw.wave.fmt.name[0] - 'f';
  547.         n  = rw.wave.fmt.name[1] - 'm';
  548.         n  = rw.wave.fmt.name[2] - 't';
  549.         n  = rw.wave.fmt.name[3] - ' ';
  550.  
  551.         if (n)
  552.             return(UNKNOWNFILETYPE);
  553.  
  554.         Waves[idx].ch    = rw.wave.fmt.info.nChannels;
  555.         Waves[idx].sr    = rw.wave.fmt.info.nSamplesPerSec;
  556.         Waves[idx].sz    = rw.wave.fmt.info.nBitsPerSample;
  557.         Waves[idx].cp    = 0;
  558.  
  559.     // make sure it says 'data'
  560.  
  561.         n  = rw.wave.data.name[0] - 'd';
  562.         n  = rw.wave.data.name[1] - 'a';
  563.         n  = rw.wave.data.name[2] - 't';
  564.         n  = rw.wave.data.name[3] - 'a';
  565.  
  566.         if (n)
  567.             return(UNKNOWNFILETYPE);
  568.  
  569.         Waves[idx].len   = rw.wave.data.length;
  570.  
  571.     // return OKAY
  572.  
  573.         return(VALIDWAVE);
  574.  
  575. }
  576.  
  577. ;
  578. ;   /*\
  579. ;---|*|----====< readblock >====----
  580. ;---|*|
  581. ;---|*| read a chunk of the PCM file into the huge buffer
  582. ;---|*|
  583. ;   \*/
  584. int readblock (han,tptr,len)
  585.     int han;
  586.     char huge *tptr;
  587.     int len;
  588. {
  589. int siz = 0;
  590.  
  591.     // go get it...
  592.  
  593.         _asm {
  594.             push    ds
  595.  
  596.             mov     cx,[len]
  597.             mov     ax,cx
  598.             add     cx,word ptr [tptr]  // wrap?
  599.             jnc     rdbl05              // no, go get the size
  600.  
  601.             sub     ax,cx               // ax holds the # of bytes to read
  602.             mov     cx,ax
  603.             sub     [len],ax
  604.  
  605.             mov     ah,03fh             // cx holds the length
  606.             mov     bx,[han]
  607.             lds     dx,[tptr]
  608.             int     21h
  609.  
  610.             mov     [siz],ax            // we moved this much
  611.             add     word ptr [tptr+2],0x1000
  612.  
  613.             cmp     ax,cx               // same size?
  614.             jnz     rdbldone            // no, exit...
  615.         ;
  616.         rdbl05:
  617.  
  618.             mov     ah,03fh
  619.             mov     bx,[han]
  620.             mov     cx,[len]
  621.  
  622.             jcxz    rdbldone
  623.  
  624.             lds     dx,[tptr]
  625.             int     21h
  626.  
  627.             add     [siz],ax            // we moved this much
  628.         ;
  629.         rdbldone:
  630.             pop     ds
  631.  
  632.         }
  633.  
  634.     // return the amount read
  635.  
  636.         return(siz);
  637. }
  638.  
  639. ;   /*\
  640. ;---|*| end of PLAY.C
  641. ;   \*/
  642.  
  643.  
  644.  
  645.  
  646.