1. 程式人生 > >wav音訊檔案頭解析

wav音訊檔案頭解析

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wav.h"

/* func		: endian judge
 * return	: 0-big-endian othes-little-endian
 */
int IS_LITTLE_ENDIAN(void) 
{
	int __dummy = 1;
	return ( *( (unsigned char*)(&(__dummy) ) ) );
}

unsigned int readHeader(void *dst, signed int size, signed int nmemb, FILE *fp) 
{
	unsigned int n, s0, s1, err;
	unsigned char tmp, *ptr;
	
	if ((err = fread(dst, size, nmemb, fp)) != nmemb) 
	{
		return err;
	}
	if (!IS_LITTLE_ENDIAN() && size > 1) 
	{
		//debug("big-endian \n");
		ptr = (unsigned char*)dst;
		for (n=0; n<nmemb; n++) 
		{
	  		for (s0=0, s1=size-1; s0 < s1; s0++, s1--) 
	  		{
	    		tmp = ptr[s0];
	    		ptr[s0] = ptr[s1];
	    		ptr[s1] = tmp;
	  		}
	  		ptr += size;
		}
	}
	else
	{
		//debug("little-endian \n");
	}
	
  	return err;
}

void dumpWavInfo(WAV_INFO wavInfo)
{
	debug("compressionCode:%d \n",wavInfo.header.compressionCode);
	debug("numChannels:%d \n",wavInfo.header.numChannels);
	debug("sampleRate:%d \n",wavInfo.header.sampleRate);
	debug("bytesPerSecond:%d \n",wavInfo.header.bytesPerSecond);
	debug("blockAlign:%d \n",wavInfo.header.blockAlign);
	debug("bitsPerSample:%d \n",wavInfo.header.bitsPerSample);

}

int wavInputOpen(WAV_INFO *pWav, const char *filename)
{
    signed int offset;
    WAV_INFO *wav = pWav ;

    if (wav == NULL) 
    {
      debug("Unable to allocate WAV struct.\n");
      goto error;
    }
    wav->fp = fopen(filename, "rb");
    if (wav->fp == NULL) 
    {
      debug("Unable to open wav file. %s\n", filename);
      goto error;
    }

	/* RIFF標誌符判斷 */
	if (fread(&(wav->header.riffType), 1, 4, wav->fp) != 4) 
	{
	  debug("couldn't read RIFF_ID\n");
	  goto error;  /* bad error "couldn't read RIFF_ID" */
	}
	if (strncmp("RIFF", wav->header.riffType, 4)) 
	{
	  	debug("RIFF descriptor not found.\n") ;
	  	goto error;
	}
	debug("Find RIFF \n");
	
	/* Read RIFF size. Ignored. */
    readHeader(&(wav->header.riffSize), 4, 1, wav->fp);
    debug("wav->header.riffSize:%d \n",wav->header.riffSize);

    /* WAVE標誌符判斷 */
    if (fread(&wav->header.waveType, 1, 4, wav->fp) !=4) 
    {
      	debug("couldn't read format\n");
      	goto error;  /* bad error "couldn't read format" */
    }
    if (strncmp("WAVE", wav->header.waveType, 4)) 
    {
      	debug("WAVE chunk ID not found.\n") ;
      	goto error;
    }
    debug("Find WAVE \n");

	/* fmt標誌符判斷 */
    if (fread(&(wav->header.formatType), 1, 4, wav->fp) != 4) 
    {
      	debug("couldn't read format_ID\n");
      	goto error;  /* bad error "couldn't read format_ID" */
    }
    if (strncmp("fmt", wav->header.formatType, 3)) 
    {
      	debug("fmt chunk format not found.\n") ;
     	goto error;
    }
    debug("Find fmt \n");

   	readHeader(&wav->header.formatSize, 4, 1, wav->fp);  // Ignored
   	debug("wav->header.formatSize:%d \n",wav->header.formatSize);

	/* read  info */
	readHeader(&(wav->header.compressionCode), 2, 1, wav->fp);
	readHeader(&(wav->header.numChannels), 2, 1, wav->fp);
	readHeader(&(wav->header.sampleRate), 4, 1, wav->fp);
	readHeader(&(wav->header.bytesPerSecond), 4, 1, wav->fp);
	readHeader(&(wav->header.blockAlign), 2, 1, wav->fp);
	readHeader(&(wav->header.bitsPerSample), 2, 1, wav->fp);

	offset = wav->header.formatSize - 16;

   	/* Wav format extensible */
   	if (wav->header.compressionCode == 0xFFFE) 
	{
	 	static const unsigned char guidPCM[16] = {
	 		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
		 	0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
	 	};
	 	unsigned short extraFormatBytes, validBitsPerSample;
	 	unsigned char guid[16];
	 	signed int i;

	 	/* read extra bytes */
	 	readHeader(&(extraFormatBytes), 2, 1, wav->fp);
	 	offset -= 2;

		if (extraFormatBytes >= 22) 
		{
			readHeader(&(validBitsPerSample), 2, 1, wav->fp);
			readHeader(&(wav->channelMask), 4, 1, wav->fp);
			readHeader(&(guid), 16, 1, wav->fp);

			/* check for PCM GUID */
			for (i = 0; i < 16; i++) if (guid[i] != guidPCM[i]) break;
			if (i == 16) wav->header.compressionCode = 0x01;

			offset -= 22;
		}
	}
	debug("wav->header.compressionCode:%d \n",wav->header.compressionCode);

    /* Skip rest of fmt header if any. */
    for (;offset > 0; offset--) 
    {
      	fread(&wav->header.formatSize, 1, 1, wav->fp);
    }

	#if 1
    do 
    {
      	/* Read data chunk ID */
		if (fread(wav->header.dataType, 1, 4, wav->fp) != 4) 
		{
			debug("Unable to read data chunk ID.\n");
			free(wav);
			goto error;
		}
      	/* Read chunk length. */
     	readHeader(&offset, 4, 1, wav->fp);

		/* Check for data chunk signature. */
		if (strncmp("data", wav->header.dataType, 4) == 0) 
		{
			debug("Find data \n");
			wav->header.dataSize = offset;
			break;
		}
		
		/* Jump over non data chunk. */
		for (;offset > 0; offset--) 
		{
			fread(&(wav->header.dataSize), 1, 1, wav->fp);
		}
    } while (!feof(wav->fp));
    debug("wav->header.dataSize:%d \n",wav->header.dataSize);
    #endif	
    
    /* return success */
    return 0;

/* Error path */
error:
    if (wav) 
    {
      if (wav->fp) 
      {
        fclose(wav->fp);
        wav->fp = NULL;
      }
      //free(wav);
    }
    return -1; 
}

#if 0
int main(int argc,char **argv)

{
	WAV_INFO wavInfo;
	char fileName[128];
	if(argc<2 || strlen(&argv[1][0])>=sizeof(fileName))
	{
		debug("argument error !!! \n");
		return -1 ;
	}
	debug("size : %d \n",sizeof(WAV_HEADER));
	strcpy(fileName,argv[1]);
	wavInputOpen(&wavInfo, fileName);
	return 0;
}
#endif

附:FIFF檔案知識點