home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / utility / 650 / wave / wave.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-10  |  11.5 KB  |  381 lines

  1. /**************************************************************
  2. *       this program will play a "wave" file on an ATARI TT   *
  3. *                                                             *
  4. *  Algorithm:                                                 *
  5. *      open file                                              *
  6. *      Read the header of the file.                           *
  7. *      if the header is not valid report that and exit        *
  8. *      If file is an "RIFF" file convert to motorola integers *
  9. *      allocate memory (ST-RAM) for PCM data                  *
  10. *      Read the PCM data                                      *
  11. *      close the file                                         *
  12. *      If sample is 8 bit then convert data to ATARI format   *
  13. *      play the Sample                                        *
  14. *      wait until sample is completed                         *
  15. *      free memory                                            *
  16. *      exit                                                   *
  17. *                                                             *
  18. **************************************************************/
  19. /*
  20.     The correct method of reading a WAV file is to
  21.     read in the RIFF/RIFX chunk id and size along with
  22.     the WAVE identifier.
  23.     while not the end of the file (WAV files can contain multiple samples)
  24.     Begin
  25.       Read in the next chunk identifier
  26.       while the identifier is not "fmt\0"
  27.       Begin       (typically this section willnever be used)
  28.         report type of chunk encountered.
  29.         skip this chunk.
  30.         read in the next chunk identifier
  31.         End (ckID not "fmt\0")
  32.       read in the "fmt\0" chunk data
  33.       Read in the next chunk identifier
  34.       while the identifier is not "data"
  35.       Begin
  36.         report type of chunk encountered.
  37.         skip this chunk.
  38.         read in the next chunk identifier
  39.         End (ckID not "data")
  40.       read in the data
  41.       one second of sample at a time
  42.       Begin
  43.         re-sample the data (if needed otherwise copy)
  44.         play the 1 second
  45.         End (One second at a time)
  46.       End (Not end of file)
  47. */
  48.  
  49. /*
  50.   Things to be added:
  51.     1) take filenames from STDIN
  52.     2) optionally supress messages to stdout/stderr
  53. */
  54.  
  55. #include <stdio.h>
  56. #include <stdlib.h>
  57. #include <string.h>
  58. #include <tos.h>
  59. #include "stereo.h"
  60. #include "riff.h"
  61.  
  62. #define FALSE 0
  63. #define TRUE  1
  64. #define MAX_FNAME_LENGTH 132
  65.  
  66. void FatalError (char * id) ;
  67. void MSC_cnvrt_int(INTEGER * i) ;
  68. void MSC_cnvrt_long(LONG * i) ;
  69. void Convert_MSC_ATARI_8_Bit(unsigned char * c, unsigned long i) ;
  70. long Play_PCM_Sample() ;
  71. void process_file(char * fname) ;
  72.  
  73. char * cmd ;
  74. char *id_riff = "RIFF";
  75. char *id_rifx = "RIFX";
  76. char *id_wave = "WAVE";
  77. char *id_fmt  = "fmt";
  78. WAVE_DEFINITION  *wave ;
  79. PCM_Samples       origSample ;
  80.  
  81. main(argc, argv)
  82. int argc ;
  83. char *argv[] ;
  84. {
  85. unsigned long   i ;
  86. char            fname[MAX_FNAME_LENGTH] ;
  87.  
  88.   cmd = argv[0];
  89.   fname[0] = '\0' ;
  90.   if (argc > 1)
  91.     for (i = 1; i < argc; i++) 
  92.     {
  93.       if (argv[i][0] != '-') 
  94.         process_file(argv[i]) ;
  95.     }
  96.   else
  97.   while (fgets(fname, MAX_FNAME_LENGTH, stdin) != NULL)
  98.     process_file(fname) ;
  99.   return 0 ;
  100. }
  101.  
  102. void process_file(char * fname)
  103. {
  104. long            num_read ;
  105. int             motorola_fmt ;
  106. unsigned long   nSamples ;
  107. double          Sample_length ;
  108. long            BytesPerSample ;
  109. PCM_Samples     Dest ;
  110. WAVE_FILE       riffChk ;
  111. CHK_DEF         fmtChk ;
  112. FILE          * fp ;
  113.  
  114.   motorola_fmt = FALSE ;
  115.   if (strcmp(fname,"-")==0) 
  116.   { 
  117.     fp = stdin;  
  118.     fname = "<stdin>"; 
  119.   }
  120.   else 
  121.     fp = fopen(fname,"rb");
  122.  
  123.   if (fp == NULL)
  124.     FatalError("could not open file.") ;    
  125.  
  126.   wave = (WAVE_DEFINITION *) malloc(sizeof(WAVE_DEFINITION)) ;
  127.   if (!wave)
  128.     FatalError("not enough memory to read '*.WAV' file header");
  129.  
  130.   num_read = fread(&riffChk, 1, sizeof(WAVE_FILE), fp) ;
  131.   if (num_read != sizeof(WAVE_FILE))
  132.     FatalError("WAV 'riff' header read failed");
  133.  
  134.   if (strncmp(riffChk.riffStr, id_riff, 4))
  135.   {
  136.     if (strncmp(riffChk.riffStr, id_rifx, 4))
  137.       FatalError("not an RIFF file");
  138.     else
  139.       motorola_fmt = TRUE ;
  140.   }
  141.   if (strncmp(riffChk.waveStr, id_wave, 4))
  142.     FatalError("not a WAVE file");
  143.  
  144.  
  145.   num_read = fread(&fmtChk, 1, sizeof(CHK_DEF), fp) ;
  146.   if (num_read != sizeof(CHK_DEF))
  147.     FatalError("chunk header read failed");
  148.  
  149.   if (strncmp(fmtChk.ckStr, id_fmt, 3))
  150.     FatalError("missing 'fmt' in file");
  151.  
  152.   num_read = fread(&(wave->hdr),1, sizeof(WAVE_HDR), fp) ;
  153.   if (num_read != sizeof(WAVE_HDR))
  154.     FatalError("WAVE header read failed");
  155.  
  156.   num_read = fread(&(wave->data),1, sizeof(CHK_DEF), fp) ;
  157.   if (num_read != sizeof(CHK_DEF))
  158.     FatalError("data chunk id read failed");
  159.  
  160.  
  161. /* do we need to change the integer storage format to motorola? */
  162.   if (motorola_fmt == FALSE)
  163.   {
  164.     MSC_cnvrt_long(&riffChk.ckSize) ;
  165.     MSC_cnvrt_long(&fmtChk.ckSize) ;
  166.     MSC_cnvrt_int(&wave->hdr.formatTag) ;
  167.     MSC_cnvrt_int(&wave->hdr.nChannels) ;
  168.     MSC_cnvrt_long(&wave->hdr.nSamplesPerSec) ;
  169.     MSC_cnvrt_long(&wave->hdr.nAvgBytesPerSec) ;
  170.     MSC_cnvrt_int(&wave->hdr.nBlockAlign) ;
  171.     MSC_cnvrt_int(&wave->hdr.nBitsPerSample) ;
  172.     MSC_cnvrt_long(&wave->data.ckSize) ;
  173.   }
  174.  
  175.   if (wave->hdr.nChannels > 2)
  176.     FatalError("can not accept more than 2 channels in file") ;
  177.  
  178.  
  179. /* 
  180.     Since the STe/TT only support 8 bit PCM codes
  181.     We need to determine the correct amount of memory.
  182.     We also must take into consideration that that WAVE
  183.     file may not be sampled at the same rate the STe/TT
  184.     can play it back. So we may need to peform a little
  185.     DSP to recontruct the sample so the Atari can play it
  186.     correctly.
  187. */
  188.  
  189. /* Determine memory requirements */
  190.   BytesPerSample = (wave->hdr.nBitsPerSample + 7) / 8 ;
  191.   if (BytesPerSample > 2)
  192.     FatalError("can not accept more than 2 bytes per sample") ;
  193.  
  194.   if ( wave->hdr.nSamplesPerSec <= SSS_RATE_50kHz )
  195.     wave->Target_SpS = SSS_RATE_50kHz ;
  196.   if ( wave->hdr.nSamplesPerSec <= SSS_RATE_25kHz )
  197.     wave->Target_SpS = SSS_RATE_25kHz ;
  198.   if ( wave->hdr.nSamplesPerSec <= SSS_RATE_12kHz )
  199.     wave->Target_SpS = SSS_RATE_12kHz ;
  200.   if ( wave->hdr.nSamplesPerSec <= SSS_RATE_6kHz )
  201.     wave->Target_SpS = SSS_RATE_6kHz ;
  202.  
  203. /*
  204.    determine the number of seconds the sample will play for 
  205. */
  206.   nSamples = (wave->data.ckSize / wave->hdr.nChannels)/ BytesPerSample ;
  207.   Sample_length = (double)nSamples / (double)wave->hdr.nSamplesPerSec ;
  208.  
  209.   printf("WAVE file contents:\n") ;
  210.   printf("  %d bit", wave->hdr.nBitsPerSample) ;
  211.   if (wave->hdr.nChannels == 2)
  212.     printf(" Stereo\n") ;
  213.   else
  214.     printf(" Mono\n") ;
  215.   printf("  %lf seconds playing time\n", Sample_length) ;
  216.  
  217. /*
  218.    determine the number of bytes required to hold
  219.    sample at a rate that the Atari can play back.
  220. */
  221.   wave->required_memory = (unsigned long)((double)wave->Target_SpS * Sample_length) ;
  222.   wave->required_memory = wave->required_memory * wave->hdr.nChannels ;
  223.  
  224. /* Allocate memory for the PCM Data */
  225.   wave->PCM.Mono8 = (unsigned char *)Mxalloc(wave->required_memory,0) ;
  226.   if (!wave->PCM.Mono8)
  227.     FatalError("not enough memory to read samples");
  228.  
  229.   if (wave->Target_SpS == wave->hdr.nSamplesPerSec)
  230.   { /* no psuedo DSP algorithm required */
  231.     num_read = fread(wave->PCM.Mono8,1, wave->data.ckSize, fp) ;
  232.     if (num_read != wave->data.ckSize)
  233.       FatalError("error reading WAVE data") ;
  234.   }
  235.   else
  236. /*
  237.   determine the amount of memory required to read in the
  238.   entire WAVE file. Use TT-RAM if available (mode = 3)
  239. */
  240.   {
  241.     origSample.Mono8 = (unsigned char *)Mxalloc(wave->data.ckSize,3) ;
  242.     if (!origSample.Mono8)
  243.       FatalError("not enough memory to read 1 second of sample");
  244.  
  245.     Dest.Mono8 = wave->PCM.Mono8 ;
  246.     num_read = fread(origSample.Mono8,1, wave->data.ckSize, fp) ;
  247.     if (num_read != wave->data.ckSize)
  248.       FatalError("error reading 1 second of WAVE data") ;
  249. /*
  250.    If we only had object oriented programming this next section
  251.    would have only one line
  252. */
  253.     switch (wave->hdr.nChannels)
  254.     {
  255.       case 1 : switch ((int)BytesPerSample)
  256.                {
  257.                  case 1: Resample8bitMono(&Dest, &origSample, wave->required_memory, wave->data.ckSize) ;
  258.                          break ;
  259.                  case 2: Resample16bitMono(&Dest, &origSample, wave->required_memory, wave->data.ckSize) ;
  260.                          break ;
  261.                  default:
  262.                    FatalError("can not convert this # bytes per sample") ;
  263.                }
  264.                break ;
  265.       case 2 : switch ((int)BytesPerSample)
  266.                {
  267.                  case 1: Resample8bitStereo(&Dest, &origSample, wave->required_memory, wave->data.ckSize) ;
  268.                          break ;
  269.                  case 2: Resample16bitStereo(&Dest, &origSample, wave->required_memory, wave->data.ckSize) ;
  270.                          break ;
  271.                  default:
  272.                    FatalError("can not convert this # bytes per sample") ;
  273.                }
  274.                break ;
  275.       default :
  276.          FatalError("Incorrect # of channels") ;
  277.     }
  278.   }
  279.   Supexec(Play_PCM_Sample) ;
  280.  
  281.   free(wave->PCM.Mono8) ;
  282.   free(wave) ;
  283.   free(origSample.Mono8) ;
  284.   fclose(fp) ;
  285. }
  286.  
  287.  
  288. /***********************************/
  289. void FatalError (identifier)
  290.        char *identifier;
  291. {
  292.   if (wave != NULL)
  293.   {
  294.     if (wave->PCM.Mono8 != NULL)
  295.       free(wave->PCM.Mono8) ;
  296.     free(wave) ;
  297.   if (origSample.Mono8 != NULL)
  298.     free(origSample.Mono8) ;
  299.   }
  300.   fprintf(stderr, "%s: %s\n",cmd, identifier);
  301.   exit(-1);
  302.   return ;
  303. }
  304.  
  305.  
  306. /*
  307.   The next two routines convert an integer and a long
  308.   that is stored in Intel format to Motorola format
  309. */
  310. void MSC_cnvrt_int(i)
  311. INTEGER * i ;
  312. {
  313. char tmp ;
  314.  
  315.   tmp = i->MSC[0] ;
  316.   i->MSC[0] = i->MSC[1] ;
  317.   i->MSC[1] = tmp ;
  318.  
  319. void MSC_cnvrt_long(LONG * i) 
  320. {
  321. char tmp ;
  322.  
  323.   tmp = i->MSC[0] ;
  324.   i->MSC[0] = i->MSC[3] ;
  325.   i->MSC[3] = tmp ;
  326.   tmp = i->MSC[1] ;
  327.   i->MSC[1] = i->MSC[2] ;
  328.   i->MSC[2] = tmp ;
  329. }
  330.  
  331. /*
  332.   Since the following routine accesses the hardware registers
  333.   it must be executed in supervisory mode.
  334. */
  335. long Play_PCM_Sample()
  336. {
  337. SOUND_REGS    *hardware = (SOUND_REGS *)0xff8900l ;
  338. unsigned int   mode ;
  339. unsigned long  tmp ;
  340.  
  341. /*
  342.   hardware = (SOUND_REGS *)malloc(sizeof(SOUND_REGS)) ;
  343. */
  344.   switch (wave->Target_SpS)
  345.   {
  346.     case SSS_RATE_6kHz  : mode = SSS_RATE_06258Hz ; /* 0x0 */
  347.                           break ;
  348.     case SSS_RATE_12kHz : mode = SSS_RATE_12517Hz ; /* 0x1 */
  349.                           break ;
  350.     case SSS_RATE_25kHz : mode = SSS_RATE_25033Hz ; /* 0x2 */
  351.                           break ;
  352.     case SSS_RATE_50kHz : mode = SSS_RATE_50066Hz ; /* 0x3 */
  353.                           break ;
  354.     default : FatalError("can not play sample rate") ;
  355.   }
  356.  
  357.   if (wave->hdr.nChannels == 1)
  358.     mode = mode | SSS_MONO ;
  359.  
  360.   tmp = (unsigned long)wave->PCM.Mono8 + wave->required_memory ;
  361.  
  362.   hardware->Frame_base_high = ((unsigned long) wave->PCM.Mono8 >> 16) & 0x3f ;
  363.   hardware->Frame_base_med = ((unsigned long) wave->PCM.Mono8 >> 8) & 0xff ;
  364.   hardware->Frame_base_low = (unsigned long) wave->PCM.Mono8 & 0xfe ;
  365.  
  366.   hardware->Frame_end_high = ((unsigned long) tmp >> 16) & 0x3f ;
  367.   hardware->Frame_end_med = ((unsigned long) tmp >> 8) & 0xff ;
  368.   hardware->Frame_end_low = (unsigned long) tmp & 0xfe ;
  369.  
  370.   hardware->Mode_cntrl = mode ;
  371.   hardware->DMA_cntrl = 0x01 ;
  372.  
  373. /* wait for the sample to complete */
  374.   while(hardware->DMA_cntrl != 0) ;
  375.  
  376.   return 0l ;
  377.  
  378. }
  379.  
  380.