简体   繁体   English

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

[英]File (.wav) duration while writing PCM data @16KBps

I am writing some silent PCM data on a file @16KBps . 我正在一个文件@ 16KBps上写一些无声的PCM数据。 This file is of .wav format. 此文件是.wav格式。 For this I have the following code: 为此,我有以下代码:

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

Updated : Here is how I write the header 更新 :以下是我编写标题的方法

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

I run this code on my iOS device using NSTimer with interval 1.0 sec. 我使用NSTimer在我的iOS设备上运行此代码,间隔为1.0秒。 So AFAIK, if I run this for 60 sec, I should get a file.wav that when played should show 60 sec as its duration (again AFAIK). 所以AFAIK,如果我运行60秒,我应该得到一个file.wav,当播放时应该显示60秒作为其持续时间(再次AFAIK)。 But in actual test it displays almost double duration ie 2 min. 但在实际测试中,它显示几乎两倍的持续时间,即2分钟。 (approx). (约)。 I have also tested that when I change the DEFAULT_BITRATE to 8000, then the file duration is almost correct. 我还测试了当我将DEFAULT_BITRATE更改为8000时,文件持续时间几乎是正确的。

I am unable to identify what is going on here. 我无法确定这里发生了什么。 Am I missing something bad here? 我在这里遗漏了什么吗? I hope my code is not wrong. 我希望我的代码没有错。

What you're trying to do (write your own WAV files) should be totally doable . 您要做的事情(编写自己的WAV文件)应该是完全可行的 That's the good news. 这是个好消息。 However, I'm a bit confused about your exact parameters and constraints, as are many others in the comments, which is why they have been trying to flesh out the details. 但是,我对你的确切参数和约束感到有点困惑,正如评论中的许多其他人一样,这也是他们试图充实细节的原因。

You want to write raw, uncompressed, silent PCM to a WAV file. 您希望将原始的,未压缩的静音PCM写入WAV文件。 Okay. 好的。 How wide does the PCM data need to be? PCM数据需要有多宽? You are creating an array of chars that you are writing to the file. 您正在创建要写入文件的字符数组。 A char is an 8-bit byte. char是一个8位字节。 Is that what you want? 那是你要的吗? If so, then you need to use a silent center point of 0x80 (128). 如果是这样,那么您需要使用静默中心点0x80(128)。 8-bit PCM in WAV files is unsigned, ie, 0..255, and 128 is silent. WAV文件中的8位PCM是无符号的,即0..255,而128是静音的。

If you intend to store silent 16-bit data, that will be signed data, so the center point (between -32768 and 32767) is 0. Also, it will be stored in little endian byte format. 如果您打算存储静默的16位数据,那将是签名数据,因此中心点(在-32768和32767之间)为0.此外,它将以小端字节格式存储。 But since it's silence (all 0s), that doesn't matter. 但由于它是沉默(全0),这无关紧要。

The title of your question indicates (and the first sentence reiterates) that you want to write data at 16 kbps. 您的问题的标题表明(并且第一句重申)您想要以16 kbps写入数据。 Are you sure you want raw 16 kbps audio? 您确定要原始的16 kbps音频吗? That's 16 kiloBITs per second, or 16000 bits per second. 这是每秒16千比特,或每秒16000比特。 Depending on whether you are writing 8- or 16-bit PCM samples, that only allows for 2000 or 1000 Hz audio, which is probably not what you want. 根据您是在写8位还是16位PCM样本,只允许2000或1000 Hz音频,这可能不是您想要的。 Did you mean 16 kHz audio? 你的意思是16 kHz音频吗? 16 kHz audio translates to 16000 audio samples per second, which more closely aligns with your code. 16 kHz音频转换为每秒16000个音频采样,更接近您的代码。 Then again, your code mentions GSM ( LibGsmManaged ), so maybe you are looking for 16 kbps audio. 然后,你的代码提到GSM( LibGsmManaged ),所以也许你正在寻找16 kbps的音频。 But I'll assume we're proceeding along the raw PCM route. 但我会假设我们正沿着原始PCM路线前进。

Do you know in advance how many seconds of audio you need to write? 你知道你需要写几秒钟的音频吗? That makes this process really easy. 这使得这个过程非常简单。 As you may have noticed, the WAV header needs length information in a few spots. 您可能已经注意到,WAV标头需要一些位置的长度信息。 You either write it in advance (if you know the values) or fill it in later (if you are writing an indeterminate amount). 您可以提前写入(如果您知道值)或稍后填写(如果您写的是不确定的金额)。

Let's assume you are writing 2 seconds of raw, monophonic, 16000 Hz, 16-bit PCM to a WAV file. 假设您正在为WAV文件写入2秒的原始,单声道,16000 Hz,16位PCM。 The center point is 0x0000. 中心点是0x0000。

WAV writing process: WAV写作过程:

  1. Write 'RIFF' 'RIFF'
  2. Write 32-bit file size, which will be 36 (header size - first 8 bytes) + 64000 (see step 12 about that number) 写入32位文件大小,即36(标题大小 - 前8个字节)+ 64000(有关该数字的步骤12)
  3. Write 'WAVEfmt ' (with space) 'WAVEfmt ' (带空格)
  4. Write 32-bit format header size (16) 写32位格式标题大小(16)
  5. Write 16-bit audio format (1 indicating raw PCM audio) 写入16位音频格式(1表示原始PCM音频)
  6. Write 16-bit channel count (1 because it's monophonic) 写入16位通道计数(1因为它是单声道的)
  7. Write 32-bit sample rate (number of audio sample per second = 16000) 写入32位采样率(每秒音频采样数= 16000)
  8. Write 32-bit byte rate (number of bytes per second = 32000) 写32位字节速率(每秒字节数= 32000)
  9. Write 16-bit block alignment (2 bytes per sample * 1 channel = 2) 写16位块对齐(每个样本2个字节* 1个通道= 2)
  10. Write 16-bit bits per sample (16) 每个样本写入16位(16)
  11. Write 'data' 'data'
  12. Write 32-bit length of audio payload data (16000 samples/second * 2 bytes/sample * 2 seconds = 64000 bytes) 写入32位长度的音频有效载荷数据(16000个样本/秒* 2个字节/样本* 2秒= 64000个字节)
  13. Write 64000 bytes, all 0 values 写入64000个字节,全部为0

If you need to write a dynamic amount of audio data, leave the length field from steps 2 and 12 as 0, then seek back after you're done writing and fill those in. I'm not convinced that your original code was writing the length fields correctly. 如果您需要编写动态数量的音频数据,请将步骤2和12中的长度字段保留为0,然后在完成写入后再搜索并填写。我不相信您的原始代码正在编写长度字段正确。 Some playback software might ignore those, others might not, so you could have gotten varying results. 有些回放软件可能会忽略这些,有些则可能没有,因此您可能会得到不同的结果。

Hope that helps! 希望有所帮助! If you know Python, here's another question I answered which describes how to write a WAV file using Python's struct library (I referred to that code fragment a lot while writing the steps above). 如果您了解Python,那么我回答的另一个问题描述了如何使用Python的结构库编写WAV文件 (在编写上述步骤时我提到了很多代码片段)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM