写入PCM数据@ 16KBps时的文件(.wav)持续时间

时间:2013-12-19 15:10:14

标签: objective-c c audio byte pcm

我正在文件 @ 16KBps 上写一些无声PCM数据。此文件是.wav格式。为此,我有以下代码:

#define DEFAULT_BITRATE 16000

long LibGsmManaged:: addSilence ()
{
    char silenceBuf[DEFAULT_BITRATE];

    if (fout) {
        for (int i = 0; i < DEFAULT_BITRATE; i++) {
            silenceBuf[i] = '\0';
        }

        fwrite(silenceBuf, sizeof(silenceBuf), 1, fout);
    }

    return ftell(fout);
}

更新: 这是我写标题的方法

void LibGsmManaged::write_wave_header( )
{
    if(fout) {
        fwrite("RIFF", 4, 1, fout);
        total_length_pos = ftell(fout);
        write_int32(0);     
        fwrite("WAVE", 4, 1, fout);
        fwrite("fmt ",4, 1, fout);
        write_int32(16);
        write_int16(1);
        write_int16(1);
        write_int32(8000);
        write_int32(16000);
        write_int16(2);
        write_int16(16);
        fwrite("data",4,1,fout);
        data_length_pos = ftell(fout);
        write_int32(0);
    }
    else {
        std::cout << "File pointer not correctly initialized";
    }
}

void LibGsmManaged::write_int32( int value)
{
    if(fout) {
        fwrite( (const char*)&value, sizeof(value), 1, fout);
    }
    else {
        std::cout << "File pointer not correctly initialized";
    }
}

我使用NSTimer在我的iOS设备上运行此代码,间隔为1.0秒。所以AFAIK,如果我运行60秒,我应该得到一个file.wav,当播放时应该显示60秒作为其持续时间(再次AFAIK)。但在实际测试中,它显示几乎两倍的持续时间,即2分钟。 (约)。我还测试过,当我将DEFAULT_BITRATE更改为8000时,文件持续时间几乎是正确的。

我无法确定这里发生了什么。我在这里遗漏了什么吗?我希望我的代码没有错。

1 个答案:

答案 0 :(得分:3)

您要做的事情(编写自己的WAV文件)应该完全可行。这是个好消息。但是,我对你的确切参数和约束感到有些困惑,正如评论中的许多其他人一样,这就是为什么他们一直试图充实细节。

您希望将原始的,未压缩的静音PCM写入WAV文件。好的。 PCM数据需要有多宽?您正在创建要写入文件的字符数组。 char是一个8位字节。那是你要的吗?如果是这样,那么您需要使用静默中心点0x80(128)。 WAV文件中的8位PCM是无符号的,即0..255,而128是无声的。

如果您打算存储静默的16位数据,那将是签名数据,因此中心点(-32768和32767之间)为0.此外,它将以小端字节格式存储。但由于它是沉默(全0),这无关紧要。

您的问题标题表明您想以16 kbps的速度写入数据(并且第一句重申)。 您确定要原始16 kbps音频吗?这是每秒16千比特,或每秒16000比特。根据您是在写8位还是16位PCM样本,只允许2000或1000 Hz音频,这可能不是您想要的。 您的意思是16 kHz音频吗? 16 kHz音频转换为每秒16000个音频样本,这与您的代码更加一致。然后,你的代码提到GSM(LibGsmManaged),所以你可能正在寻找16 kbps的音频。但我会假设我们正沿着原始PCM路线前进。

您是否事先知道需要写多少秒的音频?这使得这个过程非常简单。您可能已经注意到,WAV标头需要一些位置的长度信息。您可以提前写(如果您知道值)或稍后填写(如果您写的是不确定的金额)。

假设您正在为WAV文件写入2秒的原始,单声道,16000 Hz,16位PCM。中心点是0x0000。

WAV写作过程:

  1. 撰写'RIFF'
  2. 写入32位文件大小,即36(标题大小 - 前8个字节)+ 64000(有关该数字的步骤12)
  3. 'WAVEfmt '(带空格)
  4. 写入32位格式标题大小(16)
  5. 写入16位音频格式(1表示原始PCM音频)
  6. 写入16位通道计数(1因为它是单声道的)
  7. 写入32位采样率(每秒音频采样数= 16000)
  8. 写入32位字节速率(每秒字节数= 32000)
  9. 写入16位块对齐(每个样本2个字节* 1个通道= 2)
  10. 每个样本写入16位位(16)
  11. 撰写'data'
  12. 写入32位长的音频有效载荷数据(16000个样本/秒* 2个字节/样本* 2秒= 64000个字节)
  13. 写入64000个字节,全部为0
  14. 如果您需要编写动态数量的音频数据,请将步骤2和12中的长度字段保留为0,然后在完成写入后再搜索并填写。我不相信您的原始代码正在写长度字段。有些回放软件可能会忽略这些,有些则可能没有,因此您可能会得到不同的结果。

    希望有所帮助!如果您了解Python,那么我回答的另一个问题是如何write a WAV file using Python's struct library(我在编写上述步骤时大量提到了代码片段)。