This article comes from:
Http://blog.csdn.net/jtlyr/article/details/5321884
Here are some other websites that introduce wav files, which are recorded below:
Https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
Http://blog.csdn.net/zhihu008/article/details/7854529
There are many methods for compressing PCM audio files into ADPCM files (such as ms acm and SOx). This article mainly introduces the public algorithm (as shown below, if you need to search for it on the Internet:
========================================================
** Intel/dvi adpcm coder/decoder.
**
** The algorithm for this coder was taken from the IMA compatability Project
** Proceedings, vol 2, number 2; May 1992.
**
** Version 1.2, 18-dec-92.
==========================================) The method for converting PCM to ADPCM.
First, you need to understand the composition of the. Wav file in the pcmformat and adpcmformat. For details, refer:
A non-PCM file must contain at least one "fact" block to record the size of the extracted data. (Data rather than files) This "fact" block is usually added before the "data" block.
1. The internal structure of WAV Files in PCM format
2. Understanding of the waveformat Structure
The main difference between PCM and non-PCM is that the sound data is organized differently, which can be distinguished by the waveformat structure of the two. The following is a comparison of PCM and IMA-ADPCM:
The basic structure of wave is defined as follows:
Typedef struct
{
Word wformatag; // The encoding format, including wave_format_pcm, // waveformat_adpcm, etc.
Word nchannls; // number of audio channels. The single channel is 1 and the double channel is 2;
DWORD nsamplespersec; // sampling frequency;
DWORD navgbytespersec; // data volume per second;
Word nblockalign; // block alignment;
Word wbitspersample; // The sampling size of the wave file;
Word sbsize; // ignore this value in PCM
} Waveformatex;
The structure of PCM is the basic structure;
The imaadpcmwaveformat structure is defined as follows:
Typedef struct
{
Waveformatex wfmt;
Word nsamplesperblock;
} Imaadpcmwaveformat;
The wfmt-> cbsize of the IMA-ADPCM cannot be ignored. Generally, the value is 2, indicating that this type of waveformat is 2 more bytes than the general waveformat. The two characters are nsamplesperblock.
3. Internal Organization of "fact" chunk
In a non-PCM file, a "fact" chunk is usually added after the waveformat structure. The structure is as follows:
Typedef struct {
Char [4]; // "fact" String
DWORD chunksize;
DWORD datafactsize; // The size after data is converted to PCM format.
} Factchunk;
Datafactsize is the most important data in this chunk. If it is a sound file in a certain compression format, you can know the size of the decompressed file. It will be of great benefit to the computation during decompression!
4. Internal Organization of "data" chunk
Starting from the 9th bytes of the "data" chunk, it stores the sound information data, (The first eight bytes store the identifier "data" and the size (DWORD) of the followed data ). The data may be compressed or not compressed.
The audio data in PCM is not compressed. If it is a single-channel file, the sampling data is stored in sequence by time. (Its basic organization unit is byte (8 bit) or word (16 bit). If it is a dual-channel file, the sample data is saved in chronological order.
The IMA-ADPCM is a compression format, which is compressed from PCM 16-bit sampling to 4-bit. For a mono IMA-ADPCM, it is to compress PCM Data in chronological order and write it into the file, each byte contains two samples, the lower four corresponds to the first sample, the four digits in height correspond to the second sampling. For dual-channel IMA-ADPCM, its storage is relatively troublesome, it is to the PCM left channel of the first eight samples in turn compressed and written into a DWORD, then write the data into the chunk. Followed by the first eight samples of the right audio channel. In this cycle, when the number of samples is less than 8 (to the end of the data), the extra sampling should be filled with 0.
In the IMA-ADPCM, the data in "data" Chuck is organized in block form, and I call it "segment", that is to say, during compression, it does not compress and save all the data in sequence, but segments. This is very important: When you only need a piece of information in the file, you can extract only the segments where the required data is located. You do not need to decompress the files one by one. This will have considerable advantages in processing large files. At the same time, this can also ensure the sound effect.
A block is generally composed of block header and data. Block header is a structure, which is defined in the single channel as follows:
Typedef struct
{
Short sample0; // The first sample value in the block (uncompressed)
Byte index; // The last index of the previous block. The index of the first block is 0;
Byte reserved; // not used
} Monoblockheader;
With the blockheader information, you can easily solve the compressed data in the block without knowing the data before and after the block. For dual-channel, its blockheader should contain two monoblockheaders. Its definition is as follows:
Typedaf struct
{
Monoblockheader leftbher;
Monoblockheader rightbher;
} Stereoblockheader;
During decompression, the left and right audio channels are processed separately, so there must be two monoblockheaders;
For the above content, refer to "Examples.
================================================= Gorgeous line ====================================
The next step is to implement the conversion from PCM to ADPCM. (Take 8 kHz, 16 bits, single channel as an example)
Definition structure:
#define ADPCM_BLOCKSIZE 252 //256 - 4;typedef unsigned long ULONG;typedef unsigned short USHORT;typedef unsigned char BYTE;typedef struct { long chunkid; long chunksize; long wave_id;} RIFFCHUNK;typedef struct tagDATA{ long ID; unsigned long Size;}DATA;typedef struct{ long chunkid; unsigned long chunksize; unsigned long timelength;} FACTCHUNK;typedef struct tagWaveFormat{ //long chunkSize; short wFormatTag; unsigned short wChannels; unsigned long dwSamplesPerSec; unsigned long awAvgBytesPerSec; unsigned short wBlockAlign; unsigned short wBitsPerSample; unsigned short cbsize; int headerSize ; long dataLength ;} WAVEFMT;typedef struct{ RIFFCHUNK riff; long chunkid; unsigned long chunksize; USHORT wformattag; /* format type */ USHORT nchannels; /* number of channels (i.e. mono, stereo...) */ ULONG nsamplespersec; /* sample rate */ ULONG navgbytespersec; /* for buffer estimation */ USHORT nblockalign; /* block size of data */ USHORT wbitspersample; /* number of bits per sample of mono data */ USHORT cbsize; /* the count in bytes of the extra size */ USHORT wsamplesperblock; FACTCHUNK fact; DATA data;}INTELADPCM_HEADER;
Key code:
Void adpcmencoder () {file * infile, * OUTFILE; infile = fopen ("C: // input.wav", "rb"); If (! Infile) {printf ("can't open the input file."); Return-2;} wavefmt; If (! Checkwavefileheaderformat (infile, & wavefmt) {printf ("input file's format is wrong. "); Return-1;} OUTFILE = fopen (" C: // output.wav "," WB + "); If (! OUTFILE) {printf ("can't open the output file. "); Return-2;} setadpcmheader (OUTFILE, wavefmt. datalength); int Len; short indata [adpcm_blocksize * 2]; byte outdata [adpcm_blocksize]; adpcm_state State; State. index = 0; State. valprev = 0; long samples = wavefmt. datalength; while (samples> 0) {/* read two frames worth of samples */Len = fread (indata, (size_t) 1, sizeof (indata), infile ); if (LEN <= 0) {perror ("error reading input"); exit (1);} samples-= Len; If (LEN <sizeof (indata) {printf ("memset. /n "); memset (char *) indata + Len, 0, sizeof (indata)-len);} fwrite (& State, 4, 1, OUTFILE ); len = adpcm_coder (indata, outdata, Len/2, & State); writefile (OUTFILE, outdata, Len); // The High and Low Bits must be exchanged here} fclose (infile ); fclose (OUTFILE); Return 0;} void setadpcmheader (File * OUTFILE, ulong datasize) {Ulong FLEN = 0; inteladpcm_header adpcmhead; adpcmhead. riff. chunkid = wav_id_riff; // 4 byte adpcmhead.riff.wav e_id = wav_id_wave; // 4 byte adpcmhead. chunkid = wav_id_fmt; // 4 byte adpcmhead. chunksize = 0x14; // 2 byte adpcmhead. wformattag = 0x11; // 2 byte adpcmhead. nchannels = 1; // 2 byte adpcmhead. nsamplespersec = 8000; // 4 byte adpcmhead. navgbytespersec = 4055; // = nsamplespersec/wsamplesperblock * nblockal IGN, adjustable, I use 4064 for better adpcmhead. nblockalign = 0x100; // 2 byte adpcmhead. wbitspersample = 4; // 2 byte adpcmhead. cbsize = 2; // 2 byte adpcmhead. wsamplesperblock = 505; // Why is this number? Did not understand adpcmhead. fact. chunkid = wav_id_fact; adpcmhead. fact. chunksize = 4; adpcmhead. data. id = wav_id_data; int adpcmdatasize = (datasize/(adpcm_blocksize * 4) * (adpcm_blocksize + 4 ); // blockcount * 256 // determine whether the last block is a 1008 (252*4) byte. If not, set int lastblocksize = datasize % (adpcm_blocksize * 4) according to the actual size ); if (lastblocksize> 0) {adpcmdatasize + = lastblocksize/4 + 4 (sizeof (State);} adpcmhead. riff. chunksize = adpcmdatasize + sizeof (inteladpcm_header)-8; adpcmhead. fact. timelength = datasize/2; adpcmhead. data. size = adpcmdatasize; fwrite (& adpcmhead, sizeof (adpcmhead), 1, OUTFILE );}