【问题标题】:Creating a .wav file from PCM data从 PCM 数据创建 .wav 文件
【发布时间】:2018-11-29 06:30:40
【问题描述】:

我正在尝试从 SPH0645LM4H-B https://www.knowles.com/docs/default-source/model-downloads/sph0645lm4h-b-datasheet-rev-c.pdf?sfvrsn=4 读取数据 并将其转换为 .wav 格式,以便我可以验证我的传感器是否正常工作。 到目前为止,我已经设法通过 i2s-dma 传输连接传感器并读取数据样本。

另外,我发现大多数主流计算机声音文件格式都包含一个标头(包含长度等),然后是 16 位 双补码 PCM @987654322 @

为了将 PCM 数据转换为波形格式,我参考了converting PCM to wav file

现在,传感器数据格式是 I2S,24 位,2 的补码,MSB 在前。数据精度为18位;未使用的位是 零。 我已将传感器数据转换为 32 位(MSB 是符号位)

我已使用以下链接(以及其中提到的链接)中的代码来创建 .wav 文件:- Append .pcm audio raw data into wav (in C)

//.wav文件头数据

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);
}

//将音频传感器数据附加到这个.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 标头值设置正确,然后是来自音频传感器的 PCM 数据。

但是,当我播放 .wav 文件时,我无法播放输入音频。相反,我听到了一个恒定的音调。 我尝试更改输入音频(播放不同的音乐、歌曲),但生成的 .wav 文件播放相同的恒定音调。

为了将麦克风播放的输入音乐重新创建为 wav 文件,我应该做哪些修改?

提前致谢。

编辑:-

根据 42LeapsOfFaith 的回答,要将我的样本转换为十六进制,我使用了以下代码:-

hexValue = strtoll(sample, NULL, 16);

我转换了缓冲区中的每个值,然后将其写入我的 .wav 文件。现在我的 .wav 文件看起来像 modified .wav file in hex editor

但是,即使是这个 wav 文件也不会播放音频。 有什么进一步的建议可以将麦克风播放的输入音乐重新创建为 wav 文件?

非常感谢您的帮助

【问题讨论】:

    标签: c audio wav binary-data pcm


    【解决方案1】:

    对于初学者,您将 PCM 数据作为 ascii-hex 存储在文件中。我希望这会有所帮助。

    这是您可以使用的“黑客”...

    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))
    

    【讨论】:

    • 嗨@42LeapsOfFaith。我一直在使用我的数据,尝试转换它(strtoll()、atoi() 等)。但是,我仍然无法理解您的意思。您能否详细说明在将数据复制到我的 .wav 文件之前应该如何修改数据?
    • 答案在您的“十六进制编辑器中的.wav 文件”图像中。您的 infile 中的数据格式错误 - 它是 ascii-hex 格式(字符串)。您需要在使用它之前将其转换回十六进制(int)(即“A5”> 0xA5)。或者,先以正确的格式将其存储在 infile 中......我希望这会有所帮助。
    • 字符 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 时。您的通道数和位数不清楚...您知道数据的字节序吗?
    猜你喜欢
    • 2011-06-14
    • 1970-01-01
    • 2011-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多