在音频编程中,生成标准的 WAV 文件头部是一个基础但关键的步骤。WAV 文件是基于 RIFF(Resource Interchange File Format)格式的音频文件,结构清晰、易于读取。本文将通过 PHP 的 pack() 函数手动构造一个合法的 WAV 文件头部,便于开发者更深入地理解 WAV 格式的结构。
一个标准的 WAV 文件头部大致可以分为以下几个部分:
RIFF 块:标记文件是一个 RIFF 文件。
WAVE 标志:说明文件类型是 WAVE。
fmt 子块:包含音频格式信息(采样率、声道数、比特率等)。
data 子块:包含实际的音频数据。
结构如下:
| ChunkID | ChunkSize | Format |
|--------|-----------|--------|
| 'RIFF' | 36 + SubChunk2Size | 'WAVE' |
| Subchunk1ID | Subchunk1Size | AudioFormat | NumChannels | SampleRate | ByteRate | BlockAlign | BitsPerSample |
|-------------|----------------|-------------|-------------|------------|----------|-------------|----------------|
| Subchunk2ID | Subchunk2Size | Data |
PHP 的 pack() 函数可将数据打包成二进制字符串,适用于构造 WAV 文件头部。以下是一个简单的例子,生成一个 16-bit、单声道、44.1kHz 的 WAV 文件头部,假设音频数据大小为 $dataSize 字节:
<?php
function createWavHeader($dataSize, $sampleRate = 44100, $bitsPerSample = 16, $channels = 1)
{
$byteRate = $sampleRate * $channels * $bitsPerSample / 8;
$blockAlign = $channels * $bitsPerSample / 8;
$header = '';
// RIFF Header
$header .= pack('A4', 'RIFF'); // ChunkID
$header .= pack('V', 36 + $dataSize); // ChunkSize
$header .= pack('A4', 'WAVE'); // Format
// fmt Subchunk
$header .= pack('A4', 'fmt '); // Subchunk1ID
$header .= pack('V', 16); // Subchunk1Size
$header .= pack('v', 1); // AudioFormat (1 = PCM)
$header .= pack('v', $channels); // NumChannels
$header .= pack('V', $sampleRate); // SampleRate
$header .= pack('V', $byteRate); // ByteRate
$header .= pack('v', $blockAlign); // BlockAlign
$header .= pack('v', $bitsPerSample); // BitsPerSample
// data Subchunk
$header .= pack('A4', 'data'); // Subchunk2ID
$header .= pack('V', $dataSize); // Subchunk2Size
return $header;
}
// 示例:写入一个空的 WAV 文件
$dataSize = 44100 * 2 * 1; // 1秒钟的单声道16位音频数据
$header = createWavHeader($dataSize);
file_put_contents('output.wav', $header . str_repeat("\x00", $dataSize));
echo "WAV 文件已创建。可在 m66.net 下载测试文件。";
$sampleRate:采样率,常见值有 44100、48000 等。
$bitsPerSample:每个样本的位深度,通常为 8 或 16。
$channels:通道数量,1 为单声道,2 为立体声。
$dataSize:音频数据的实际字节数,计算方式为:秒数 * 采样率 * 通道数 * 位深 / 8。
使用 pack() 构造 WAV 文件头部非常适合用于以下场景:
服务器端动态生成音频流。
自定义音频录制格式的导出。
数据压缩与音频封装分析工具的开发。