# 6 Re: Crazy, how to convert the PCM raw data into wav?
i use libmad to help work. but it doesn't support 8bit 8khz mono wav format.
most of coders know it well, i think.
the main code shows as below:
/* WAV structure
* Used in CbMpegAudioDecoder when instructed to write a
* WAV header to the output file.
*/
struct WAV_HEADER {
int RIFF; // 'R','I','F','F'
int size; // size of wave file from here on
int WAVE; // 'W','A','V','E'
int fmt; //'f','m','t',' '
int wFormatLength; // The length of the TAG format
short wFormatTag; // should be 1 for PCM type data
short nChannels; // Mono = 1, Stereo = 2, etc.
int nSampleRate; // 8000, 44100, etc.
int nAvgBytesPerSec; // Average Data Rate
short nBlockAlign; // 1 for 8 bit data, 2 for 16 bit
short wBitsPerSample; // 8 for 8 bit data, 16 for 16 bit
int data; // 'd','a','t','a'
int datasize; // size of data from here on
};
WAV_HEADER wav_header; /* my WAV header */
... ...
wav_header.nChannels = 1;
wav_header.nSampleRate = 8000;
/* Once decoded the frame is synthesized to PCM samples. No errors
* are reported by mad_synth_frame();
*/
mad_synth_frame(&Synth, &Frame);
/* Synthesized samples must be converted from libmad's fixed
* point number to the consumer format. Here we use unsigned
* 16 bit big endian integers on two channels. Integer samples
* are temporarily stored in a buffer that is flushed when
* full.
*/
for(i=0; i < Synth.pcm.length; i++)
{
signed short Sample;
/* Left channel */
Sample=Scale(Synth.pcm.samples[0][i], &gRand);
/* output in 16 bit little-endian */
/*
*(OutputPtr++)=Sample>>8; //Originally big-endian
*(OutputPtr++)=Sample&0xff;
*/
*(OutputPtr++)=((Sample>>0) & 0xff);
*(OutputPtr++)=((Sample>>8) & 0xff);
//char leftsample = Sample && 0xff;
/* Right channel. If the decoded stream is monophonic then
* the right output channel is the same as the left one.
*/
if(MAD_NCHANNELS(&Frame.header)==2)
Sample=Scale(Synth.pcm.samples[1][i], &gRand);
/* output in 16 bit little-endian */
/*
*(OutputPtr++)=Sample>>8; //Originally big-endian
*(OutputPtr++)=Sample&0xff;
*/
*(OutputPtr++)=((Sample>>0) & 0xff);
*(OutputPtr++)=((Sample>>8) & 0xff);
/* Flush the output buffer if it is full. */
if(OutputPtr == OutputBufferEnd)
{
if(fwrite(OutputBuffer, 1, OUTPUT_BUFFER_SIZE,
OutputFp)!=OUTPUT_BUFFER_SIZE)
{
sprintf(StatMsg, "PCM write error (%s).\n",
strerror(errno));
Status=2;
break;
}
OutputPtr=OutputBuffer;
}
}
}while(1);
and the Scale() is as following:
/***************************************************************************
*
* A little more advanced scaling routine based on madplay's
* audio_linear_dither() function. Rather than simply rounding the 24 bit
* number down to 16 bits (as MadFixedToSshort() in madlld does), it
performs
* dithering, which is the addition of a random number to the least
* significant bits (LSB) of the sample that targets the LSB at the 16 bit
* mark. CbMpegAudioDecoder() uses this to perform its scaling before
output.
****************************************************************************
/
static inline signed short Scale(mad_fixed_t sample, mad_fixed_t *gRandom)
{
unsigned int scalebits;
mad_fixed_t output, mask, rnd;
/* bias */
output = sample + (1L << (MAD_F_FRACBITS + 1 - 16 - 1));
//output = sample + (1L << (MAD_F_FRACBITS + 1 - 8 - 1));
scalebits = MAD_F_FRACBITS + 1 - 16;
//scalebits = MAD_F_FRACBITS + 1 - 8;
mask = (1L << scalebits) - 1;
/* dither */
rnd = Prng(*gRandom);
output += (rnd & mask) - (*gRandom & mask);
*gRandom = rnd;
/* clip */
if (output >= MAD_F_ONE)
output = MAD_F_ONE - 1;
else if (output < -MAD_F_ONE)
output = -MAD_F_ONE;
/* quantize */
output &= ~mask;
/* scale */
return output >> scalebits;
}
i'm new to audio programming, i don't know how to resample, worse, i haven't
found any stuff about
audio conversation in converting other format into 8bit 8000hz mono wav
format.
i think, it would fit my need if modifying the above code properly.
i tried for many times, unfortunately, it sounds strange:-(
how to modify the code to fit my need?
thank you very much.