home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 199.lha / GimmeLib / sound.c < prev    next >
C/C++ Source or Header  |  1988-12-27  |  5KB  |  247 lines

  1. /*
  2.  *  FILE: sound.c
  3.  *  Support routines for reading IFF/8SVX files.
  4.  *
  5.  *  Public Domain, but keep our names in it as the original authors.
  6.  *  09-Dec-87    Rico Mariani        original code (modified by JST)
  7.  *  31-Aug-88    Jan Sven Trabandt   first release version
  8.  */
  9.  
  10.  
  11. #define I_AM_SOUND
  12. #include "gimmelib/gimmefuncs.h"
  13. #include "gimmelib/sound.h"
  14. #include <stdio.h>
  15.  
  16.  
  17. #define GET(iffile)         getc( iffile )
  18.  
  19. #define getId            getLong
  20. #define getLen            getLong
  21. #define getByte         GET
  22. #define skip(len, file)     fseek(file, (long)(len), 1)
  23.  
  24. #define getV8H(v8h, file)   fread(v8h, sizeof(Voice8Header), 1, file)
  25.  
  26. /* requires an existent variable 'char *errmsg' and a label 'failure_return' */
  27. #define fail_and_return(msg)    {errmsg = msg; goto failure_return;}
  28.  
  29. /* forward declarations */
  30. static LONG getLong();
  31. static WORD getWord();
  32.  
  33. static char noMemMsg[] = "insufficient memory\n";
  34. static char badFileMsg[] = "corrupt or incomplete file\n";
  35.  
  36.  
  37. SOUND *gimmeSound( filename )
  38.     UBYTE   *filename;
  39. {
  40.     LONG    len, id;
  41.     SOUND   *snd = NULL;
  42.     BYTE    *p;
  43.     void    *mh = NULL;
  44.     FILE    *file = NULL;
  45.     char    *errmsg = " ";
  46.     SHORT   i;
  47.  
  48.     if( !(file = fopen(filename, "r")) ) {
  49.     fail_and_return( "unable to open iff sound file for read\n" );
  50.     }
  51.     if( getId(file) != ID_FORM ) {
  52.     fail_and_return( "not IFF format\n" );
  53.     }
  54.     getLen( file );
  55.     if( getId(file) != ID_8SVX ) {
  56.     fail_and_return( "not 8SVX format\n" );
  57.     }
  58.     for( ;; ) {
  59.     getChunk( &id, &len, file );
  60.     if( ferror(file) || feof(file) ) {
  61.         fail_and_return( badFileMsg );
  62.     }
  63.     switch( id ) {
  64.       case ID_VHDR:
  65.         snd = chainAllocMem( &mh, (ULONG)sizeof(SOUND),
  66.                     MEMF_PUBLIC | MEMF_CLEAR );
  67.         if( !snd ) {
  68.            fail_and_return( noMemMsg );
  69.         }
  70.         getV8H( &snd->vh, file );
  71.         if( len & 1 ) {
  72.         GET(file);
  73.         }
  74.         break;
  75.       case ID_BODY:
  76.         if( !snd ) {
  77.         fail_and_return( "didn't find VHDR chunk\n" );
  78.         }
  79.         switch( snd->vh.sCompression ) {
  80.           case sCmpNone:
  81.         snd->bodylen = len;
  82.         snd->body = chainAllocMem( &mh, len, MEMF_CHIP );
  83.         if( !snd->body ) {
  84.             fail_and_return( noMemMsg );
  85.         }
  86.         memget( snd->body, len, file );
  87.         break;
  88.           case sCmpFibDelta:
  89.         snd->bodylen = len << 1;
  90.         snd->body = chainAllocMem( &mh, (ULONG) snd->bodylen,
  91.                         MEMF_CHIP );
  92.         if( !snd->body ) {
  93.             fail_and_return( noMemMsg );
  94.         }
  95.         p = AllocMem( len, MEMF_PUBLIC );
  96.         if( !p ) {
  97.             fail_and_return( noMemMsg );
  98.         }
  99.         memget( p, len, file );
  100.         DUnpack( p, len, snd->body );
  101.         FreeMem( p, len );
  102.         break;
  103.           default:
  104.         fail_and_return( "unknown compression form\n" );
  105.         break;
  106.         } /* switch */
  107.         if( len & 1 ) {
  108.         GET(file);
  109.         }
  110.         if( ferror(file) ) {
  111.         fail_and_return( badFileMsg );
  112.         }
  113.         snd->memhead = mh;
  114.         fclose( file );
  115.         return( snd );
  116.         break;
  117.       case ID_NAME:
  118.       case ID_AUTH:
  119.       case ID_COPY:
  120.       case ID_ANNO:
  121.       case ID_ATAK:
  122.       case ID_RLSE:
  123.       default:        /* unimplemented chunk type */
  124.         skip( EVEN(len), file );
  125.         break;
  126.     } /* switch */
  127.     } /* for */
  128. failure_return: {}
  129.     if( Output() ) {
  130.     Write( Output(), errmsg, (ULONG)strlen(errmsg) );
  131.     }
  132.     if( mh ) {
  133.     chainFreeMem( mh );
  134.     }
  135.     if( file ) {
  136.     fclose( file );
  137.     }
  138.     return( NULL );
  139. } /* gimmeSound */
  140.  
  141.  
  142. short getRidOfSound( sound )
  143.     SOUND   *sound;
  144. {
  145. #ifdef GIMME_WIMPY
  146.     if( !sound ) {
  147.     return( -1 );
  148.     }
  149. #endif
  150.     chainFreeMem( sound->memhead );
  151.     return( 0 );
  152. } /* getRidOfSound */
  153.  
  154.  
  155. /* read an IFF Id */
  156. static LONG getLong( file )
  157.     FILE    *file;
  158. {
  159.     register UBYTE  p[4];
  160.  
  161.     p[0] = GET(file);
  162.     p[1] = GET(file);
  163.     p[2] = GET(file);
  164.     p[3] = GET(file);
  165.     return( (LONG) Mk(p[0],p[1],p[2],p[3]) );
  166. } /* getLong */
  167.  
  168.  
  169. /* read an IFF chunk header */
  170. static getChunk( id, len, file )
  171.     LONG    *id, *len;
  172.     FILE    *file;
  173. {
  174.     *id = getId( file );
  175.     *len = getLen( file );
  176. } /* getChunk */
  177.  
  178.  
  179. /* get len bytes from the file and put them into memory */
  180. static memget( p, len, file )
  181.     UBYTE   *p;
  182.     LONG    len;
  183.     FILE    *file;
  184. {
  185.     for( ; len > 0L; len -= 0x07fffL, p += 0x07fffL ) {
  186.     fread( p, (int) (len & 0x07fffL), 1, file );
  187.     } /* for */
  188. } /* memget */
  189.  
  190.  
  191. /* get a word */
  192. static WORD getWord( file )
  193.     FILE    *file;
  194. {
  195.     WORD    v;
  196.  
  197.     v = GET(file) << 8;
  198.     return( v | GET(file) );
  199. } /* getWord */
  200.  
  201.  
  202. /* get the EGPoint info */
  203. static getEGPoint( pnt, file )
  204.     EGPoint *pnt;
  205.     FILE    *file;
  206. {
  207.     pnt->duration = getWord( file );
  208.     pnt->dest = getLong( file );
  209. } /* getEGPoint */
  210.  
  211.  
  212. static BYTE codeToDelta[] = {-34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21};
  213.  
  214. /* unpack a part of a fibonacci delta encoded sound sample */
  215. static BYTE D1Unpack( source, n, dest, x )
  216.     BYTE    *source;
  217.     LONG    n;
  218.     BYTE    *dest;
  219.     BYTE    x;
  220. {
  221.     UBYTE   d;
  222.     LONG    i, lim;
  223.  
  224.     lim = n << 1;
  225.     for( i = 0; i < lim; ++i ) {
  226.     d = source[i>>1];
  227.     if( i & 1 ) {
  228.         d &= 0xf;
  229.     } else {
  230.         d >>= 4;
  231.     }
  232.     x += codeToDelta[d];
  233.     dest[i] = x;
  234.     } /* for */
  235.     return( x );                /* return last data value */
  236. } /* D1Unpack */
  237.  
  238.  
  239. /* unpack a fibonacci delta encoded sound sample */
  240. static DUnpack( source, n, dest )
  241.     BYTE    *source;
  242.     LONG    n;
  243.     BYTE    *dest;
  244. {
  245.     D1Unpack( source + 2, n - 2, dest, source[1] );
  246. } /* DUnpack */
  247.