我觉得你把事情搞混了。假设 WAV 标头中的字段名称如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
其用作大小。
如果您想为samples分配内存,那么它会根据音频是 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;