将读取的字节数转换为读取的秒数

Converting Bytes read to seconds read

我正在从 Riff wav fmt 文件中读取数据,我有一个 wav 文件的数据块数组 DataBuffer,如何将数据读取的字节数转换为从 wav 文件中读取的秒数。

int size_buffer = (Subchunk2Size / (NumOfChan * bitsPerSample / 8));
FILE* WavResult = fopen(FileNom, "rb");
u8* DataBuffer = new u8[size_buffer];
size_t nRead = fread(DataBuffer, sizeof DataBuffer[0], size_buffer, WavResult);

我觉得你有点搞混了。假设 WAV header 中的字段名称如 http://soundfile.sapp.org/doc/WaveFormat 中所述:

ChunkID - "RIFF"
ChunkSize
    Format - "WAVE"
    Subchunk1ID - "fmt "
    Subchunk1Size
        AudioFormat
        NumChannels
        SampleRate
        ByteRate
        BlockAlign
        BitsPerSample
    Subchunk2ID - "data"
    Subchunk2Size
        data

你这行:

int size_buffer = (Subchunk2Size / (NumOfChan * bitsPerSample / 8));

计算单个通道中的多个样本。或多个块,其中块是一个结构,每个通道包含一个样本。如果您使用它从 data 块中分配 字节 的内存,那么仅在 8 位单声道音频的情况下就足够了。

如果为 字节 分配内存确实是您想要的,那么只需使用 Subchunk2Size 作为大小即可。

如果您想为 样本 分配内存,那么它会根据音频是 8 位还是 16 位而有所不同(我忽略了其他可能性)。对于 8 位:

const uint32_t num_of_samples = Subchunk2Size / (BitsPerSample / 8);
uint8_t *samples = new uint8_t[num_of_samples];

对于 16 位:

const uint32_t num_of_samples = Subchunk2Size / (BitsPerSample / 8);
int16_t *samples = new int16_t[num_of_samples];

就个人而言,我宁愿使用 std::vector 而不是 c-arrays:

const uint32_t num_of_samples = Subchunk2Size / (BitsPerSample / 8);
std::vector<int16_t> samples;
samples.resize(num_of_samples);    // could be done in the constructor, but I am afraid of vector constructors ;-)

我在这里还假设音频采用最流行的编码(我认为),即 8 位无符号和 16 位有符号。我也忽略了字节顺序的问题。


但回到秒数。我们可以使用块总数和 SampleRate 来计算。 SampleRate 告诉我们每秒有多少样本(在单个通道中)。或者换句话说,每秒有多少块。所以秒数是:

const double num_of_seconds = 1.0 * num_of_blocks / SampleRate;

您可以使用第一行中的公式计算块数:

const uint32_t num_of_blocks = Subchunk2Size / (NumChannels * BitsPerSample / 8);

或者,因为我们已经有了 num_of_samples,这是来自所有通道的样本总数,我们可以将其除以 NumChannels:

const uint32_t num_of_blocks = num_of_samples / NumChannels;

最后,如果您真正想要的只是从 字节数 中获取秒数,那么有 2 个选项。您可以计算块大小:

const int block_size = NumChannels * BitsPerSample / 8;

应该和BlockAlign基本一样,然后用Subchunk2Size除以它,得到块数,再用SampleRate得到秒数:

const double num_of_seconds = 1.0 * Subchunk2Size / block_size / SampleRate;
// or
const double num_of_seconds = 1.0 * Subchunk2Size / BlockAlign / SampleRate;

或者你可以使用ByteRate,也就是每秒的字节数:

const double num_of_seconds = 1.0 * Subchunk2Size / ByteRate;