home *** CD-ROM | disk | FTP | other *** search
/ Game Developers Magazine 3 / GDM003.ZIP / VOC-IT.C < prev    next >
C/C++ Source or Header  |  1994-02-16  |  8KB  |  291 lines

  1. /*
  2.  
  3.      VOC-IT.C - Plays soundblaster .VOC files through PC speaker.
  4.      Also works with Windows .WAV files, and all other types of
  5.      digital sound file, I expect.
  6.  
  7.      Written by Phil Inch for Game Developers Magazine (issue 3).
  8.      Contributed to the public domain.  If you use this program
  9.      or a derivation thereof in your own programs, please put in
  10.          a credit for me and/or the magazine.
  11.  
  12.      Thanks to Dave Harvey for suggesting a better oversampling
  13.      method than I had, which has increased the maximum size of
  14.          the file playable to be the limit of available memory!
  15.  
  16.      This program written and compiled with Borland C++ v3.1 and
  17.      Turbo Assembler v3.0.  Compatibility with other compilers is
  18.          not guaranteed.
  19.  
  20.      Usage of this program is subject to the disclaimer printed
  21.      in the magazine.  You assume all risks associated with the use
  22.      of this program.
  23.  
  24.      Known problems: In order to be able to run the timer at such
  25.      a high rate without upsetting the rest of the processes running
  26.      in the machine (eg: screen savers), this program simply shuts
  27.      down the clock, so while a sound is playing, your real time
  28.      clock will not be updated.
  29.  
  30.          I'm sure there's a way around this, but my experiments with
  31.          calling the original Int 8 handler at the correct rate
  32.          introduced an unacceptable level of "noise" into the playback.
  33.  
  34.      If any reader knows a better way of handling this problem,
  35.      please send it to me care of the magazine.
  36.  
  37.  
  38.  
  39.      Usage: VOC-IT filename[.VOC] [/F:f] [/O:o] [/M:m] [/?]
  40.         where:
  41.           f = frequency in Hz, default 16000
  42.           o = oversample rate, default 1
  43.           m = muting factor (almost always 2), default 2
  44.  
  45. */
  46.  
  47.  
  48. #include <stdio.h>
  49. #include <conio.h>
  50. #include <string.h>
  51. #include <stdlib.h>
  52. #include <alloc.h>
  53. #include <dos.h>
  54. #include <io.h>
  55.  
  56.  
  57. /* The ranges and defaults for the parameters */
  58.  
  59. #define MIN_FREQ 1
  60. #define MAX_FREQ 32000
  61. #define DEF_FREQ 16000
  62.  
  63. #define MIN_OVER 1
  64. #define MAX_OVER 6
  65. #define DEF_OVER 1
  66.  
  67. #define MIN_MUTE 0
  68. #define MAX_MUTE 6
  69. #define DEF_MUTE 2
  70.  
  71.  
  72. /* This structure holds everything we want to know about the VOC file */
  73.  
  74. typedef struct {
  75.     char filename[64];
  76.     char huge *data;
  77.     long frequency;
  78.     long file_length;
  79.     long sample_length;
  80. }    VOCFILE;
  81.  
  82.  
  83. /* Functions in the assembler file */
  84.  
  85. extern void interrupt NewInt8Function( void );
  86. extern void PlaySound( char huge *, int, int );
  87.  
  88. /* Interrupt pointer which will "remember" where the old int 8 routine is */
  89.  
  90. void interrupt (*OldInt8Function)();
  91.  
  92. /* Declare global variables with "default" values */
  93.  
  94. long frequency = DEF_FREQ;
  95. int oversample = DEF_OVER;
  96. int mute = DEF_MUTE;
  97. char filename[64] = "\0";
  98.  
  99. /* Load_Voc opens and reads the named VOC file, and returns a pointer to
  100. a VOCFILE structure which has been filled in.  If the file cannot be
  101. opened, or the memory cannot be allocated, Load_Voc returns NULL */
  102.  
  103. VOCFILE *Load_Voc( char *filename ) {
  104.     VOCFILE *vf;
  105.     FILE    *f;
  106.     long    fl, cfl;
  107.     char    ch;
  108.     char    huge *fptr;
  109.     int        cnt;
  110.  
  111. /* Allocate memory for the VOCFILE structure */
  112.  
  113.     vf = malloc( sizeof(VOCFILE) );
  114.     if ( vf == NULL ) return ( (VOCFILE *)NULL );
  115.  
  116.     strcpy( vf->filename, filename );
  117.  
  118. /* Open the VOC file */
  119.  
  120.     f = fopen( filename, "rb" );
  121.     if ( f == NULL ) {
  122.         free( vf );
  123.         return ( (VOCFILE *)NULL );
  124.         }
  125.  
  126. /* Get the length, and allocate memory for the file */
  127.  
  128.     fl = filelength( fileno(f) ) - 26;
  129.     fptr = farmalloc( fl+1 );
  130.  
  131. /* If we got the memory OK, read through the file and fill in the memory */
  132.  
  133.     if ( fptr != NULL ) {
  134.         vf->data = fptr;
  135.         vf->file_length = fl;
  136.         vf->frequency = frequency;
  137.  
  138.         fseek( f, 26, SEEK_SET );
  139.         cfl = fl;
  140.  
  141.         while ( cfl-- > 0 )    *fptr++ = (fgetc(f) >> mute);
  142.  
  143.         *fptr = 0xFF;  /* Indicates end of sound */
  144.         vf->sample_length = 1 + (fptr-vf->data);
  145.         }
  146.  
  147. /* Close up and exit */
  148.  
  149.     fclose(f);
  150.     return( vf );
  151. }
  152.  
  153.  
  154. /* Play_Voc shows the user the parameters that will be used for playback,
  155. re-directs the interrupt 8 handler to our own, plays the sound and then
  156. restores the handler. */
  157.  
  158. void    Play_Voc( VOCFILE *vf ) {
  159.     int countdown=(int)(1193180L / vf->frequency);
  160.  
  161. /* Tell the user what we're up to */
  162.  
  163.     printf( "Filename: %s\n\n", vf->filename );
  164.     printf( "File Length: %ld\n", vf->file_length );
  165.     printf( "Sample Length: %ld\n\n", vf->sample_length );
  166.     printf( "Frequency: %ld\n", vf->frequency );
  167.     printf( "Oversample: %d\n", oversample );
  168.     printf( "Muting: %d\n\n", mute );
  169.  
  170. /* And get into it! */
  171.  
  172.     OldInt8Function = getvect( 0x08 );
  173.   setvect( 0x08, NewInt8Function );
  174.     PlaySound(vf->data, countdown, oversample);
  175.   setvect( 0x08, OldInt8Function );
  176. }
  177.  
  178.  
  179. /* Delete_Voc is used to free up the memory allocated to a VOC file */
  180.  
  181. void Delete_Voc( VOCFILE *vf ) {
  182.     if ( vf ) {
  183.         if ( vf->data ) free( vf->data );
  184.         free(vf);
  185.         }
  186. }
  187.  
  188.  
  189. /* Check_CLP interprets a given command line parameter */
  190.  
  191. int Check_CLP( char *parm ) {
  192.  
  193.     if ( !strncmpi( parm, "/F:", 3 ) ) {
  194.         frequency = atol( parm+3 );
  195.         if ( frequency < MIN_FREQ  || frequency > MAX_FREQ ) {
  196.             printf( "\nIllegal frequency specified - Valid range is %d to %d!\n", MIN_FREQ, MAX_FREQ );
  197.             return(0);
  198.             }
  199.         return(1);
  200.         }
  201.  
  202.     if ( !strncmpi( parm, "/O:", 3 ) ) {
  203.         oversample = atoi( parm+3 );
  204.         if ( oversample < MIN_OVER || oversample > MAX_OVER ) {
  205.             printf( "\nIllegal oversample specified - valid range is %d - %d!\n", MIN_OVER, MAX_OVER );
  206.             return(0);
  207.             }
  208.         return(1);
  209.         }
  210.  
  211.     if ( !strncmpi( parm, "/M:", 3 ) ) {
  212.         mute = atoi( parm+3 );
  213.         if ( mute < MIN_MUTE || mute > MAX_MUTE ) {
  214.             printf( "\nIllegal mute specified - valid range is %d - %d\n", MIN_MUTE, MAX_MUTE );
  215.             return(0);
  216.             }
  217.         return(1);
  218.         }
  219.  
  220.     if ( !strncmpi( parm, "/?", 3 ) || !strncmpi( parm, "/h", 3 ) || !strncmpi( parm, "/H", 3 ) ) {
  221.     printf( "Usage:  " );
  222.  
  223.         highvideo();
  224.         cprintf( "VOC-IT filename [/F:frequency] [/O:oversample] [/M:mute]\n\n\r" );
  225.     normvideo();
  226.  
  227.     printf( "The frequency is the speed in Hertz at which to play the sample.  Valid\n" );
  228.         printf( "frequency range is %d to %d and the default is %d.\n\n", MIN_FREQ, MAX_FREQ, DEF_FREQ );
  229.  
  230.     printf( "The oversample is how many times to repeat each byte.  To remove the\n" );
  231.     printf( "\"whine\" generated by playing a sample at a low frequency (eg 8,000Hz)\n" );
  232.     printf( "you can double the frequency and double the oversample.  Various other\n" );
  233.     printf( "effects can be created by experimenting with these parameters.  Valid\n" );
  234.         printf( "oversample range is %d - %d and the default is %d.\n\n", MIN_OVER, MAX_OVER, DEF_OVER );
  235.  
  236.     printf( "Muting \"quietens\" the sample.  The larger the muting factor, the quieter\n" );
  237.     printf( "the sound will become.  Valid mute range is %d - %d and the default\n", MIN_MUTE, MAX_MUTE );
  238.         printf( "is %d.\n\n", DEF_MUTE );
  239.         return(0);
  240.         }
  241.  
  242.  
  243.     if ( !strncmpi( parm, "/", 1 ) ) {
  244.         printf( "\nUnknown command specified: %s\n", parm );
  245.         return(0);
  246.         }
  247.  
  248.     /* Otherwise, we assume it's a filename */
  249.     strcpy( filename, parm );
  250.     if ( !strchr( parm, '.' ) ) strcat( filename, ".VOC" );
  251.     strupr(filename);
  252.     return(1);
  253. }
  254.  
  255.  
  256. /* The main program */
  257.  
  258. void main( int argc, char **argv ) {
  259.     VOCFILE *vf;
  260.     int pc;
  261.  
  262.   highvideo();
  263.   cprintf( "\n\rVOC-IT   Copyright (c) 1993 Imperial Software\n\r" );
  264.     cprintf( "Written by Phil Inch for \"Game Developers Magazine\"\n\r" );
  265.   normvideo();
  266.   printf( "Donated for free use to the public domain, but please credit\n\r" );
  267.   printf( "Phil Inch or Game Developers Magazine if you use this program\n\r" );
  268.   printf( "in your own programs.\n\n\r" );
  269.  
  270.     if ( argc < 1 ) {
  271.         printf( "You must at least specify a VOC filename!\n" );
  272.         return;
  273.         }
  274.  
  275.     for ( pc = 1; pc < argc; pc++ )
  276.         if ( !Check_CLP( argv[pc] ) ) return;
  277.  
  278.     if ( strlen(filename) == 0 ) {
  279.         printf( "You must at least specify a VOC filename!\n" );
  280.         return;
  281.         }
  282.  
  283.     vf = Load_Voc( filename );
  284.     if ( vf ) {
  285.         Play_Voc( vf );
  286.         Delete_Voc( vf );
  287.         }
  288.     else
  289.         printf( "\n\nCouldn't load the VOC for some reason...\n\n" );
  290. }
  291.