从 PCM 数据创建 .wav 文件
Creating a .wav file from PCM data
我正在尝试从 SPH0645LM4H-B 读取数据 https://www.knowles.com/docs/default-source/model-downloads/sph0645lm4h-b-datasheet-rev-c.pdf?sfvrsn=4
并将其转换为 .wav 格式,以便我可以验证我的传感器是否正常工作。
到目前为止,我已经设法连接传感器并通过 i2s-dma 传输读取数据样本。
此外,我发现大多数主流计算机声音文件格式由一个header(包含长度等)后跟16位两个's-complementPCMhttps://www.dsprelated.com/freebooks/mdft/Number_Systems_Digital_Audio.html
PCM数据转wave格式,我参考了converting PCM to wav file
现在,传感器数据格式为 I2S,24 位,2 的补码,MSB 在前。数据精度为18位;未使用的位是 零。
我已将传感器数据转换为 32 位(MSB 是符号位)
我使用了以下 link 中的代码(以及其中提到的 link)来创建 .wav 文件:-
Append .pcm audio raw data into wav (in C)
//.wav文件header数据
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;
};
//写入header输出.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);
}
//将音频传感器数据附加到此 .wav 文件
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 file in hex editor
我可以看到 wav header 值设置正确,然后是来自音频传感器的 PCM 数据。
但是,当我播放.wav 文件时,我无法播放输入的音频。相反,我听到一个恒定的音调。
我尝试更改输入音频(播放不同的音乐、歌曲),但生成的 .wav 文件播放相同的恒定音调。
为了将麦克风播放的输入音乐重新创建为 wav 文件,我应该做哪些修改?
提前致谢。
编辑:-
根据 42LeapsOfFaith 的回答,为了将我的示例转换为十六进制,我使用了以下代码:-
hexValue = strtoll(sample, NULL, 16);
我转换了缓冲区中的每个值,然后将其写入我的 .wav 文件中。现在我的 .wav 文件看起来像 modified .wav file in hex editor
但是,即使是这个wav文件也不能播放音频。
关于将播放到麦克风的输入音乐重新创建为 wav 文件的任何进一步建议?
非常感谢帮助
首先,您将 PCM 数据以 ascii-hex 格式存储在文件中。希望对您有所帮助。
这是一个'hack'你可以使用...
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))
我正在尝试从 SPH0645LM4H-B 读取数据 https://www.knowles.com/docs/default-source/model-downloads/sph0645lm4h-b-datasheet-rev-c.pdf?sfvrsn=4 并将其转换为 .wav 格式,以便我可以验证我的传感器是否正常工作。 到目前为止,我已经设法连接传感器并通过 i2s-dma 传输读取数据样本。
此外,我发现大多数主流计算机声音文件格式由一个header(包含长度等)后跟16位两个's-complementPCMhttps://www.dsprelated.com/freebooks/mdft/Number_Systems_Digital_Audio.html
PCM数据转wave格式,我参考了converting PCM to wav file
现在,传感器数据格式为 I2S,24 位,2 的补码,MSB 在前。数据精度为18位;未使用的位是 零。 我已将传感器数据转换为 32 位(MSB 是符号位)
我使用了以下 link 中的代码(以及其中提到的 link)来创建 .wav 文件:- Append .pcm audio raw data into wav (in C)
//.wav文件header数据
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;
};
//写入header输出.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);
}
//将音频传感器数据附加到此 .wav 文件
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 file in hex editor 我可以看到 wav header 值设置正确,然后是来自音频传感器的 PCM 数据。
但是,当我播放.wav 文件时,我无法播放输入的音频。相反,我听到一个恒定的音调。 我尝试更改输入音频(播放不同的音乐、歌曲),但生成的 .wav 文件播放相同的恒定音调。
为了将麦克风播放的输入音乐重新创建为 wav 文件,我应该做哪些修改?
提前致谢。
编辑:-
根据 42LeapsOfFaith 的回答,为了将我的示例转换为十六进制,我使用了以下代码:-
hexValue = strtoll(sample, NULL, 16);
我转换了缓冲区中的每个值,然后将其写入我的 .wav 文件中。现在我的 .wav 文件看起来像 modified .wav file in hex editor
但是,即使是这个wav文件也不能播放音频。 关于将播放到麦克风的输入音乐重新创建为 wav 文件的任何进一步建议?
非常感谢帮助
首先,您将 PCM 数据以 ascii-hex 格式存储在文件中。希望对您有所帮助。
这是一个'hack'你可以使用...
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))