I found there is no detail discussion for extra data of wave format. Here I post a explicit (for myself) wave header in below:
Data in each column are all in little endian.
Sample Value | size in byte | Description | offset |
---|---|---|---|
Chunk ID | 4 | Marks the file as a riff file.,Characters are each 1 byte long That should be "RIFF". |
0 |
Chunk Size | 4 | 4 + (8 + SubChunk1Size) + (8 + SubChunk2Size) | 4 |
Format | 4 | File Type Header.,For wave purposes, it always equals "WAVE". | 8 |
Format Mark | 4 | Format chunk marker.,Includes trailing null. should be "fmt " | 12 |
Sub-chunk 1 Size | 4 | Length of format data | 16 |
Audio Format | 2 | PCM = 1 (i.e. Linear quantization),Values other than 1 indicate some,form of compression. | 20 |
Number of Channels | 2 | Mono = 1, Stereo = 2, etc. | 22 |
Sampling Rate | 4 | Number of Samples per second | 24 |
Byte Rate | 4 | Byte per second, it should be SamplingRate*NumberOfChannel*BitsPerSample/8 | 28 |
Block Align | 2 | Byte for whole sampling point,, it should be NumberOfChannel*BitsPerSample/8 | 32 |
Bits Per Sample | 2 | 8 bits = 8, 16 bits = 16 | 34 |
Extra Data Header | ?(2) | Extra wave note, in most,case, that "size" is 0 (no extra data), or 2. This size could be computed by "Subchunk1Size - 16 " |
36 |
Extra Data | ? | extra data, most for audio notes(artist, album, publish year, music type. etc) | ? |
Sub chunk 2 ID | 4 | Contains the letters "data" | ?? |
Sub chunk 2 size | 4 | Audio data length | ?? + 4 |
Audio data | Audio data length | Audio data | ?? + 8 |
Lots posts has discuss wave file without extra data, in here, I just note about extra data:
Length of extra data is various,
Extra data is useful for audience, it is not junk. If your wave file is within extra data, just print that data in your console or window.
To find where is the end of extra data, is to find where is the beginning of sub-chunk2. That is, to find the "data" string.
Below is my implement to read a wave file in C.
#include <stdio.h> #include <stdlib.h> #include <string.h> #ifndef TRUE #define TRUE (1) #define FALSE (0) #endif #define MAX_STR_LEN (256) #ifdef _MSC_VER #pragma warning(disable:4996) /*fuss*/ #include <stdarg.h> int snprintf(char *pBuf, size_t maxN, const char *pFmt, ...) { int len; va_list argList; va_start(argList, pFmt); len = vsprintf_s(pBuf, maxN, pFmt, argList); va_end(argList); return len; }/*snprintf*/ #endif unsigned int GetFileSize(FILE *pFile) { unsigned int currentLen, fileSize; currentLen = ftell(pFile); fseek(pFile,0, SEEK_END); fileSize = ftell(pFile); fseek(pFile,currentLen ,SEEK_SET); return (unsigned int)fileSize; }/*GetFileSize*/ unsigned int GetRemainderFileSize(FILE *pFile) { unsigned int currentLen, fileSize; currentLen = ftell(pFile); fseek(pFile,0, SEEK_END); fileSize = ftell(pFile); fseek(pFile,currentLen ,SEEK_SET); return (unsigned int)(fileSize - currentLen ); }/*GetRemainderFileSize*/ typedef struct _WaveFeature { char ChunkID[4]; /* "RIFF" Header */ unsigned int ChunkSize; /* 36 + SubChunk2Size, or more precisely:4 + (8 + SubChunk1Size) + (8 + SubChunk2Size) */ char Format[4]; /* "WAVE" */ char fmt[4]; /* "fmt "*/ unsigned int Subchunk1Size; /* Size of the fmt chunk */ unsigned short AudioFormat; /* Audio format 1=PCM,6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM */ unsigned short NumChannels; /* Number of channels 1=Mono 2=Sterio */ unsigned int SampleRate; /* Sampling Frequency in Hz*/ unsigned int ByteRate; /* bytes per second, SampleRate * NumChannels * BitsPerSample/8*/ unsigned short BlockAlign; /* 2=16-bit mono, 4=16-bit stereo, NumChannels * BitsPerSample/8*/ unsigned short BitsPerSample; /* Number of bits per sample */ } WaveFeature; typedef struct _WaveData { char Subchunk2ID[4]; /* "data" string */ unsigned int Subchunk2Size; /* Sampled data length */ } WaveData; int GetWaveFeatures(unsigned char *pWaveHead, unsigned short *pNumChannel, unsigned int *pNumSamplesPerSec, unsigned short *pBitsPerSample, unsigned int *pBytesPerSec) { char charWord[MAX_STR_LEN]; snprintf(&charWord[0], MAX_STR_LEN, "RIFF"); if(0 != memcmp( &pWaveHead[0], &charWord[0], 4) ) return -1; snprintf(&charWord[0], MAX_STR_LEN, "WAVE"); if(0 != memcmp( &pWaveHead[8], &charWord[0], 4) ) return -1; snprintf(&charWord[0], MAX_STR_LEN, "fmt "); if(0 != memcmp( &pWaveHead[12], &charWord[0], 4) ) return -1; unsigned int chunkSize; memcpy( &chunkSize, &pWaveHead[16], 4); *pNumChannel = *((unsigned short*)(pWaveHead + 22)); *pNumSamplesPerSec = *((unsigned int*)(pWaveHead + 24)); *pBitsPerSample = *((unsigned short*)(pWaveHead + 34)); *pBytesPerSec = *((unsigned int*)(pWaveHead + 28)); /*ByteRate */ if(*pBytesPerSec != (*pNumSamplesPerSec)*(*pNumChannel)*(*pBitsPerSample/8)) return -2; int blockAlign; blockAlign = *((unsigned short*)(pWaveHead + 32)); if(blockAlign != (*pNumChannel)*(*pBitsPerSample/8)) return -2; return 0; }/*GetWaveInfo*/ int GetWaveLength(unsigned char *pWaveHead, unsigned int *pAudioDataLen) { char charWord[MAX_STR_LEN]; snprintf(&charWord[0], MAX_STR_LEN, "data"); if(0 != memcmp( &pWaveHead[0], &charWord[0], 4) ) return -1; *pAudioDataLen = *((unsigned int*)(pWaveHead + 4)); return 0; }/*GetWaveLength*/ int main(int argc, char *argv[]) { char inputFileName[MAX_STR_LEN]; snprintf(&inputFileName[0], MAX_STR_LEN, "03 Rondeau in C Minor.wav"); #if defined(__MACH__) && defined(_DEBUG)/*xcode stupid...*/ char tempStr[MAX_STR_LEN]; snprintf(&tempStr[0], MAX_STR_LEN, "../../../../../"); strncat(&tempStr[0], &inputFileName[0], strnlen(&inputFileName[0],MAX_STR_LEN)); memset(&inputFileName[0], 0, MAX_STR_LEN); strncpy(&inputFileName[0], &tempStr[0], strnlen(&tempStr[0],MAX_STR_LEN)); #endif int k; k = 0; while (k < argc) { if( 0 == strncmp("-i",argv[k], MAX_STR_LEN)) { if(k + 1 < argc) { snprintf(inputFileName, MAX_STR_LEN, "%s", argv[k + 1]); } else { printf("-i should be fellowed by input wav file."); }/*if*/ }/*if strncmp*/ k++; }/*while opt*/ FILE *pWaveFile; pWaveFile = fopen(&inputFileName[0], "rb"); if(NULL == pWaveFile) { printf("open file %s error \n", inputFileName); return -1; }/*if NULL == pWaveFile*/ printf("file : %s\n", inputFileName); WaveFeature wavFea; fread(&wavFea, sizeof(WaveFeature), 1, pWaveFile); unsigned short nChannel; unsigned int nSamplesPerSec; unsigned short bitsPerSample; unsigned int audioDataLen; unsigned int bytesPerSec; int isContentExtaBytes; int sts; sts = GetWaveFeatures((unsigned char*)&wavFea, &nChannel, &nSamplesPerSec, &bitsPerSample,&bytesPerSec); if(-1 == sts) { printf("not a wav format\n"); return -1; } else if(-2 == sts) { printf("wav format do not be consisted\n"); return -1; } else if(-3 == sts) { printf("extra parameters are not known\n"); }/*if -1 == sts*/ printf("%u channel\n", nChannel); printf("simpling frequency = %u\n", nSamplesPerSec); printf("%u bits Per Sample\n", bitsPerSample); {/*scan the data flag, and print extra infomation...*/ char readBuff[MAX_STR_LEN]; char charWorddata[8]; unsigned int ii, jj; memset(&readBuff[0], 0, MAX_STR_LEN); memset(&charWorddata[0], 0, 8); snprintf(&charWorddata[0], 8, "data"); unsigned int remainLen; int isFoundDataFlag; isFoundDataFlag = FALSE; remainLen = GetRemainderFileSize(pWaveFile); ii = 0; while(MAX_STR_LEN < remainLen) { fread(&readBuff[0], 1, MAX_STR_LEN, pWaveFile); jj = 0; while(jj < MAX_STR_LEN) { if(0 == memcmp(&readBuff[jj], &charWorddata[0], 4)) { isFoundDataFlag = TRUE; break; } else { if(0 != jj && 0 == readBuff[jj] && 0 != readBuff[jj - 1]) printf("\n"); else printf("%c", readBuff[jj]); }/*if */ jj++; } if(FALSE != isFoundDataFlag) break; remainLen -= MAX_STR_LEN; ii++; } if(FALSE == isFoundDataFlag) { printf("no data flag has been found\n"); return -2; }/*if FALSE == isFoundDataFlag*/ fseek(pWaveFile, -(MAX_STR_LEN-jj), SEEK_CUR); }/*local variables*/ WaveData wavData; fread(&wavData, sizeof(WaveData), 1, pWaveFile); sts = GetWaveLength((unsigned char*)&wavData, &audioDataLen); if(-1 == sts) { printf("not a wav format\n"); return -1; } audioDataLen = wavData.Subchunk2Size; if(GetRemainderFileSize(pWaveFile) != audioDataLen) { printf("warning: data length is not consistency\n"); unsigned int remainderLen; remainderLen = GetRemainderFileSize(pWaveFile); printf("remainderLen = %u\n", remainderLen); printf("audioDataLen = %u\n", audioDataLen); if((unsigned int)audioDataLen > remainderLen) audioDataLen = remainderLen; }/*if */ float audioPlayTime; audioPlayTime = (float)audioDataLen/bytesPerSec; printf("audio time = %3.2f sec", audioPlayTime); if(audioPlayTime > 60.0f) printf(" (%4.3fmins)\n", audioPlayTime/60.0f); else printf("\n"); return 0; }/*main*/
You could use command line -i XXX.wav to specified what file you want to read.
Above is the result when I read a wave file, 03 Rondeau in C Minor.wav.
沒有留言:
張貼留言