从PCM数据创建.wav文件
我正在尝试从SPH0645LM4H-B读取数据 并将其转换为.wav格式,以便验证传感器是否正常工作。 到目前为止,我已经设法接口传感器和读取数据样本通过i2s dma传输 此外,我发现大多数主流的计算机声音文件格式都由一个头文件(包含长度等)和16位的two's-complete PCM 对于将PCM数据转换为波形格式,我已参考 现在,传感器数据格式是I2S,24位,2的补充,MSB优先。数据精度为18位;未使用的位是零。 我已将传感器数据转换为32位(MSB是符号位) 我使用了以下链接(以及其中提到的链接)中的代码来创建.wav文件:- //.wav文件头数据从PCM数据创建.wav文件,c,audio,wav,binary-data,pcm,C,Audio,Wav,Binary Data,Pcm,我正在尝试从SPH0645LM4H-B读取数据 并将其转换为.wav格式,以便验证传感器是否正常工作。 到目前为止,我已经设法接口传感器和读取数据样本通过i2s dma传输 此外,我发现大多数主流的计算机声音文件格式都由一个头文件(包含长度等)和16位的two's-complete PCM 对于将PCM数据转换为波形格式,我已参考 现在,传感器数据格式是I2S,24位,2的补充,MSB优先。数据精度为18位;未使用的位是零。 我已将传感器数据转换为32位(MSB是符号位) 我使用了以下链接(以及
struct wavfile
{
char id[4]; // should always contain "RIFF"
int totallength; // total file length minus 8
char wavefmt[8]; // should be "WAVEfmt "
int format; // 16 for PCM format
short pcm; // WAVE_FORMAT_IEEE_FLOAT (3).
short channels; // channels
int frequency; // sampling frequency, 16000 in this case
int bytes_per_second;
short bytes_by_capture;
short bits_per_sample;
char data[4]; // should always contain "data"
int bytes_in_data;
};
//将标头写入输出.wav文件
void write_wav_header(char* name, int samples, int channels)
{
struct wavfile filler;
FILE *pFile;
strcpy(filler.id, "RIFF");
filler.totallength = (samples * channels) + sizeof(struct wavfile) - 8;
strcpy(filler.wavefmt, "WAVEfmt ");
filler.format = 16;
filler.pcm = 3; // WAVE_FORMAT_IEEE_FLOAT (3).
filler.channels = channels;
filler.frequency = 32000;
filler.bits_per_sample = 32;
filler.bytes_per_second = filler.channels * filler.frequency * filler.bits_per_sample/8;
filler.bytes_by_capture = filler.channels*filler.bits_per_sample/8;
filler.bytes_in_data = samples * filler.channels * filler.bits_per_sample/8;
strcpy(filler.data, "data");
pFile = fopen(name, "wb");
fwrite(&filler, 1, sizeof(filler), pFile);
fclose(pFile);
}
void write_pcm_data_to_file(char* inFile, char* outFile)
{
char buffer[SAMPLE_SIZE];
size_t n;
FILE *fin,*fout;
fin = fopen(inFile,"r");
fout = fopen(outFile,"a");
while((n = fread(buffer, 1, sizeof(buffer), fin)) > 0)
{
if(n != fwrite(buffer, 1, n, fout))
{
perror("fwrite");
exit(1);
}
}
fclose(fin);
fclose(fout);
}
//将音频传感器数据附加到此.wav文件
void write_wav_header(char* name, int samples, int channels)
{
struct wavfile filler;
FILE *pFile;
strcpy(filler.id, "RIFF");
filler.totallength = (samples * channels) + sizeof(struct wavfile) - 8;
strcpy(filler.wavefmt, "WAVEfmt ");
filler.format = 16;
filler.pcm = 3; // WAVE_FORMAT_IEEE_FLOAT (3).
filler.channels = channels;
filler.frequency = 32000;
filler.bits_per_sample = 32;
filler.bytes_per_second = filler.channels * filler.frequency * filler.bits_per_sample/8;
filler.bytes_by_capture = filler.channels*filler.bits_per_sample/8;
filler.bytes_in_data = samples * filler.channels * filler.bits_per_sample/8;
strcpy(filler.data, "data");
pFile = fopen(name, "wb");
fwrite(&filler, 1, sizeof(filler), pFile);
fclose(pFile);
}
void write_pcm_data_to_file(char* inFile, char* outFile)
{
char buffer[SAMPLE_SIZE];
size_t n;
FILE *fin,*fout;
fin = fopen(inFile,"r");
fout = fopen(outFile,"a");
while((n = fread(buffer, 1, sizeof(buffer), fin)) > 0)
{
if(n != fwrite(buffer, 1, n, fout))
{
perror("fwrite");
exit(1);
}
}
fclose(fin);
fclose(fout);
}
以下是生成的.wav文件在十六进制编辑器中的外观:-
我可以看到wav标题值设置正确,随后是来自音频传感器的PCM数据
但是,当我播放.wav文件时,我无法播放输入音频。相反,我听到了一个不变的音调。
我尝试更改输入音频(播放不同的音乐、歌曲),但生成的.wav文件播放相同的恒定音调
为了将麦克风播放的输入音乐重新创建为wav文件,我应该做哪些修改
提前谢谢
编辑:-
根据Soffith的回答,为了将示例转换为十六进制,我使用了以下代码:-
hexValue = strtoll(sample, NULL, 16);
我转换了缓冲区中的每个值,然后将其写入.wav文件。现在我的.wav文件看起来像
但是,即使这个wav文件也不会播放音频。
有没有进一步的建议将麦克风播放的输入音乐重新创建为wav文件
非常感谢您的帮助对于初学者,您将PCM数据存储在文件中作为ascii十六进制。我希望这有帮助 这是一个“黑客”你可以使用
char c[2];
while((n = fread(&c[0], 2, 1, fin)) > 0)
{
if (c[0] > 0x39) c[0] -= 7;
c[0] &= 0x0F;
if (c[1] > 0x39) c[1] -= 7;
c[1] &= 0x0F;
c[1] |= c[0] << 4;
if(1 != fwrite(&c[1], 1, 1, fout))
charc[2];
而((n=fread(&c[0],2,1,fin))>0)
{
如果(c[0]>0x39)c[0]=7;
c[0]&=0x0F;
如果(c[1]>0x39)c[1]=7;
c[1]&=0x0F;
c[1]|=c[0]对于初学者,您将PCM数据存储在文件中作为ascii十六进制。我希望这会有所帮助
这是一个“黑客”你可以使用
char c[2];
while((n = fread(&c[0], 2, 1, fin)) > 0)
{
if (c[0] > 0x39) c[0] -= 7;
c[0] &= 0x0F;
if (c[1] > 0x39) c[1] -= 7;
c[1] &= 0x0F;
c[1] |= c[0] << 4;
if(1 != fwrite(&c[1], 1, 1, fout))
charc[2];
而((n=fread(&c[0],2,1,fin))>0)
{
如果(c[0]>0x39)c[0]=7;
c[0]&=0x0F;
如果(c[1]>0x39)c[1]=7;
c[1]&=0x0F;
c[1]|=c[0]Hi@42Leapsofith。我一直在玩我的数据,试图转换它(strtoll(),atoi()等)。但是,我仍然无法理解你的意思。你能详细说明一下在将数据复制到.wav文件之前,我应该如何修改数据吗?答案在你的.wav文件中的十六进制编辑器中。”图像。您的填充文件中的数据格式错误-它是ascii十六进制格式(字符串)。在使用它之前,您需要将其转换回十六进制(int)(即“A5”>0xA5)。或者,首先以正确的格式存储在填充文件中…我希望这会有所帮助。char c[1];while((n=fread(&c[0],2,1,fin))>0{if(c[0]>0x39)c[0]-=7;c[0]&=0x0F;如果(c[1]>0x39)c[1]-=7;c[1]&=0x0F;c[0]|=c[1]为什么“filler.pcm=3;//WAVE_FORMAT_IEEE_FLOAT(3)”,当你在写INT时。你的通道数和位数都不清楚……你知道数据的尾数吗?嗨@42Leapsofith。我一直在玩我的数据,试图转换它(strtoll()、atoi()等)。但是,我仍然无法理解您的意思。请您详细说明一下,在将数据复制到.wav文件之前,我应该如何修改数据?答案在您的“十六进制编辑器中的.wav文件”图像中。填充文件中的数据格式错误-它是ascii十六进制格式(字符串)。在使用它之前,您需要将其转换回十六进制(int)(即“A5”>0xA5)。或者,首先以正确的格式将其存储在填充中…我希望这会有所帮助。char c[1];而((n=fread(&c[0],2,1,fin))>0){if(c[0]>0x39)c[0]=7;c[0]&=0x0F;if(c[1]>0x39)c[1]-=7;c[1]&=0x0F;c[0]&c[1]为什么“filler.pcm=3;//WAVE\u FORMAT\u IEEE\u FLOAT(3)。”当您写入INT时,通道数和位数不清楚……您知道数据的尾数吗?