基于MTK平台的工厂模式代码编写的一个正弦波wav音频文件生成代码片
struct WavHead{
char RIFF[4]; //头部分那个RIFF
int size0;//存的是后面所有文件大小
char WAVE[4];
char FMT[4];
int size1;//存的是fmt保存的大小,包含这之后,data前面几个,共16个
short fmttag;
short channel;
int samplespersec;//每秒采样数
int bytepersec;
short blockalign;
short bitpersamples;
char DATA[4];
int size2;//剩下文件大小
};
int MakeWaveData2(int freq, float amp, int time_ms, unsigned char* p, int len, int sampleRate = 44100, int channels = 2, int BitsPerSample = 16)
{
int ret = 0;
ALOGD(TAG"%s Enter\n", __FUNCTION__);
int SAMPLE_NUM = sampleRate * time_ms / 1000; //采集样本总数
int AUDIO_CYCLE = sampleRate / freq; //一个正弦波采集样本个数
int ACCURACY = (BitsPerSample == 16) ? INT16_MAX : INT8_MAX; //精度
//int BUFF_SIZE = sampleRate * durations * channels * BitsPerSample/8;
ALOGD(TAG"amp=%0.2f SAMPLE_NUM=%d AUDIO_CYCLE=%d ACCURACY=%d len=%d\n", amp, SAMPLE_NUM, AUDIO_CYCLE, ACCURACY, len);
if(amp > 1.0){
ALOGW(TAG"amp>1.0 set to 1.0\n");
amp = 1.0;
} else if (amp <= 0.01){
ALOGW(TAG"amp < 0.01 set to 0.01\n");
amp = 0.01;
}
for (int i = 0; i < SAMPLE_NUM; i++){ //实际上只要采集AUDIO_CYCLE 个点就可以得到一个完整正弦波
int16_t v = (int16_t)( amp * ACCURACY * sin( 2 * MATH_PI * (i % AUDIO_CYCLE * 1.0)/AUDIO_CYCLE )); //正弦函数y = k sin x
if (BitsPerSample == 16) {//16位
if (channels == 1){//16位单通道
p[i*2] = (v & 0xFF); //低字节在前 16bits量化,低字节8位
p[1+i*2] = ((v >>8) & 0xFF); //高字节在后,高字节8位
}else{//16位双通道
p[i*4] = (v & 0xFF); //低字节在前 16bits量化,低字节8位
p[1+i*4] = ((v >>8) & 0xFF); //高字节在后,高字节8位
p[2+i*4] = (v & 0xFF); //低字节在前 16bits量化,低字节8位
p[3+i*4] = ((v >>8) & 0xFF); //高字节在后,高字节8位
}
if (i < AUDIO_CYCLE){
if (channels == 1){
ALOGD(TAG"v:%d p[0]:%d(0x%02X) p[1]:%d(0x%02X)", v, p[i*2], p[i*2], p[1+i*2], p[1+i*2]);
} else {
ALOGD(TAG"v:%d p[0]:%d(0x%02X) p[1]:%d(0x%02X)", v, p[i*4], p[i*4], p[1+i*4], p[1+i*4]);
}
}
}else{
if (channels == 1){//8位单通道
p[i] = (v & 0xFF);
}else{//8位双通道
p[i*2] = (v & 0xFF);
p[1+i*2] = (v & 0xFF);
}
if (i < AUDIO_CYCLE){
ALOGD(TAG"v:%d p:%d", v, p[i*2]);
}
}
}
return ret;
}
int MakeWaveFile(const char * filename, int freq, float amp, int time_ms, int sampleRate = 44100, int channels = 2, int BitsPerSample = 16)
{
int ret = 0;
short blockalign = (short)channels*BitsPerSample/8;
WavHead wavHead = {{'R','I','F','F'},
sampleRate * time_ms/1000*channels*BitsPerSample/8+36, //文件长度=该字段+ 8
{'W','A','V','E'},
{'f','m','t',' '},
16, //格式长度,在此之前成员的大小
1, //编码格式为PCM
(short)channels, //声道
sampleRate, //采样频率
channels*sampleRate*BitsPerSample/8,// 数据传输速率
blockalign, //数据块对齐单位(一个sample所占字节数)
(short)BitsPerSample,//采样位数(数度)
{'d','a','t','a'},
sampleRate * time_ms/1000*channels*BitsPerSample/8};//采样数据的大小
ALOGD(TAG"%s Enter\n", __FUNCTION__);
ALOGD(TAG"filename=%s freq=%d amp=%0.2f time_ms=%d sampleRate=%d channels=%d BitsPerSample=%d size0=%d size1=%d size2=%d bytepersec=%d blockalign=%d\n",
__FUNCTION__, filename, freq, amp, time_ms, sampleRate, channels, BitsPerSample,
wavHead.size0, wavHead.size1, wavHead.size2, wavHead.bytepersec, wavHead.blockalign);
FILE * fd= fopen(filename, "wb");
if(NULL == fd){
ALOGE(TAG"fopen %s failed %s %d\n", filename, strerror(errno), errno);
return -1;
}
int write = fwrite(&wavHead, sizeof(wavHead), 1, fd);
ALOGD(TAG"fwrite sizeof(wavHead)=%d writed=%d\n", sizeof(wavHead), write);
unsigned char * data = new unsigned char[wavHead.size2];
MakeWaveData2(freq, amp, time_ms, data, wavHead.size2, sampleRate, channels, BitsPerSample);
write = fwrite(data, wavHead.size2, 1, fd);
ALOGD(TAG"fwrite sizeof(wavHead)=%d writed=%d\n", wavHead.size2, write);
delete [] data;
fclose(fd);
return ret;
}
测试代码:
int freq = 5000;
float amp = 0.8;
int BitsPerSample = 16;
int durations = 1000;
int totalLen = (sampleRate * 2 * BitsPerSample / 8) * durations /1000;
/*
07-24 14:51:19.160: W/AudioALSAPlaybackHandlerBase(1204): doDcRemoval(), inBytes 960000 > mDcRemoveBufferSize 131072
07-24 14:51:19.160: E/AudioALSAPlaybackHandlerBase(1204): AUD_ASSERT(0) fail: "vendor/mediatek/proprietary/hardware/audio/common/V3/aud_drv/AudioALSAPlaybackHandlerBase.cpp", 521L
*/
unsigned char * audiodata = new unsigned char[totalLen]; //doDcRemoval(), inBytes 960000 > mDcRemoveBufferSize 131072
//MakeWaveData(freq, amp, durations, inBuffer, ReadBlockLen);
//PCM_decode_data(&pWavePlaydata->mWaveHeader, inBuffer, ReadBlockLen, outBuffer, &out_size);
MakeWaveFile("/data/liu.wav", freq, amp, durations, sampleRate, 2, BitsPerSample);
MakeWaveData2(freq, amp, durations, audiodata, totalLen, sampleRate);
int outlen = 0;
int writelen = 0;
for (int i = 0; i< 1; i ++){
writelen = streamOutput->write(audiodata, totalLen);
//writelen = streamOutput->write(inBuffer, ReadBlockLen);
//writelen = streamOutput->write(outBuffer, out_size);
ALOGD(TAG"Audio_Wave_Playabck_routine make_wave_data write to hardware... i=%d totalLen = %d writelen = %d outlen = %d\n", i, totalLen, writelen, outlen);
}
delete [] audiodata;
audiodata = NULL;
8bit单声道波形在Cool Edit Pro中查看会变形,负数显示成正数了。不知道是Cool Edit Pro的问题还是生成数据有问题,看图形是负数被当成正数显示在图形上了。
16bit的看起来很正常
扫描二维码关注公众号,回复:
2429160 查看本文章
参考:
《WAV 文件格式分析》 https://blog.csdn.net/zgyggy/article/details/70050280
《手工制作Wav文件以及生成播放数据》 https://blog.csdn.net/zouli415/article/details/80177280
《C++生成简单WAV文件(一)》https://www.cnblogs.com/shibuliao/p/3815210.html
《wav文件格式分析与详解》 https://www.cnblogs.com/ranson7zop/p/7657874.html