Esta extensão pode converter rapidamente arquivos de ondas sonoras no formato PCM em arquivos de áudio no formato WAV. Atualmente, ela fornece soluções apenas para projetos de empresas.
A referência estendida está em helviojunior/WaveGenerator, um agradecimento especial a você!
composer require jade/pcm-to-wav
use PcmToWav e P cmToWave ;
$input_file = ' ./file/test.pcm ' ; // 准备输入的文件
$output_file = ' ./file/test.wav ' ; // 预计输出的文件
$data = PcmToWav e::init( $pcm_file , $wav_file ) ; // 调用转换
进入扩展包目录
cd vendor/jade/pcm-to-wav
composer install
cd test
php Test.php
PCM
e WAV
? PCM
: PCM (modulação de código de pulso ----gravação de modulação de código de pulso). A chamada gravação PCM
consiste em converter sinais analógicos, como som, em trens de pulsos simbólicos e depois gravá-los. PCM
é um sinal digital composto por 1
, 0
e outros símbolos sem qualquer codificação ou processamento de compressão. Comparado com sinais analógicos, é menos suscetível a ruídos e distorções no sistema de transmissão. A faixa dinâmica é ampla e a qualidade do som pode ser muito boa.
WAV
: WAV
é um formato de arquivo de áudio sem perdas WAV
está em conformidade com a especificação PIFF (Resource Interchange File Format). Todos WAV
possuem um cabeçalho de arquivo, que contém os parâmetros de codificação do fluxo de áudio. WAV não possui regras rígidas e rápidas para codificação de fluxos de áudio. Além do PCM
, quase todas as codificações que suportam ACM
podem codificar fluxos de áudio WAV.
PCM
e WAV
Simplificando, PCM
são os dados originais de áudio e WAV
é um contêiner que encapsula dados de áudio e seu formato é muito simples. Ele apenas adiciona algumas informações de cabeçalho relacionadas aos dados de áudio no início dos dados.
Primeiro, vamos dar uma olhada nas regras de formato do WAV, conforme mostrado abaixo
Depois de entender essas regras, podemos começar a codificar
1. ChunkID
ocupa 4 bytes, valor fixo "RIFF"
$ChunkID = array(0x52, 0x49, 0x46, 0x46); // RIFF 16进制的0x52等于10进制中的82,82对应的ASCII码为R
2. ChunkSize
ocupa 4 bytes e o valor é 4 + (8 + SubChunk1Size) + (8 + SubChunk2Size). Se os dados originais forem PCM, eles serão simplificados para 36 + SubChunk2Size).
$ChunkSize = array(0x0, 0x0, 0x0, 0x0);
$ChunkSize = self::getLittleEndianByteArray(36 + $dataSize);
3. Format
ocupa 4 bytes, valor fixo "WAVE"
$FileFormat = array(0x57, 0x41, 0x56, 0x45); // WAVE
4. Subchunk1ID
ocupa 4 bytes, valor fixo "ftm" (observe o preenchimento do espaço de 4 dígitos)
$Subchunk1ID = array(0x66, 0x6D, 0x74, 0x20); // fmt
5. Subchunk1Size
ocupa 4 bytes e quando os dados são PCM, o valor é 16
$Subchunk1Size = array(0x10, 0x0, 0x0, 0x0); // 16 little endian
6. AudioFormat
ocupa 2 bytes Quando os dados são PCM, o valor é 1. Outros valores indicam que os dados foram compactados de alguma forma.
$AudioFormat = array(0x1, 0x0); // PCM = 1 little endian
7. NumChannels
ocupa 2 bytes, correspondendo a channelConfig em AudioRecord, Mono = 1, Stereo = 2
if ($numchannels == 2) {
$fmt->NumChannels = array(0x2, 0x0); // 立体声为2
} else {
$fmt->NumChannels = array(0x1, 0x0); // 单声道为1
}
8. SampleRate
ocupa 4 bytes, correspondendo a sampleRateInHz em AudioRecord, que é a frequência de amostragem, como 8000, 16000, 44100
$SampleRate = self::getLittleEndianByteArray($samplerate);
9. ByteRate
ocupa 4 bytes e o valor é SampleRate * BlockAlign
self::getLittleEndianByteArray($samplerate * $numchannels * ($bitspersample / 8));
10. BlockAlign
ocupa 2 bytes e o valor é NumChannels * BitsPerSample / 8
self::getLittleEndianByteArray($numchannels * ($bitspersample / 8), true);
11. BitsPerSample
ocupa 2 bytes, correspondendo a audioFormat em AudioRecord, 8 bits = 8, 16 bits = 16
self::getLittleEndianByteArray($bitspersample, true);
12. Subchunk2ID
ocupa 4 bytes, "dados" de valor fixo, ou seja
$Subchunk2ID = array(0x64, 0x61, 0x74, 0x61); // data
13. Subchunk2Size
ocupa 4 bytes, que descreve o comprimento dos dados de áudio, que é o tamanho do arquivo pcm.
self::getLittleEndianByteArray(filesize($filename));
14. Data
representam bytes do tamanho do arquivo pcm, representando os dados de áudio PCM originais.
Descrição do método getLittleEndianByteArray
getLittleEndianByteArray
processa principalmente os números passados e os converte nos dados que precisam ser usados. O comprimento da matriz será retornado com base no número de bytes.
private static function getLittleEndianByteArray($lValue, $short = false)
{
$b = array(0, 0, 0, 0);
$running = $lValue / pow(16, 6);
$b[3] = floor($running);
$running -= $b[3];
$running *= 256;
$b[2] = floor($running);
$running -= $b[2];
$running *= 256;
$b[1] = floor($running);
$running -= $b[1];
$running *= 256;
$b[0] = round($running);
if ($short) { // 为 `true` 时返回长度为2的数组
$tmp = array_slice($b, 0, 2);
$b = $tmp;
}
return $b;
}
Os primeiros 44 bytes de informação em todo o arquivo foram basicamente explicados. Vamos falar sobre a implementação do processamento de arquivos de classe. A lógica de processamento aqui primeiro cria temporariamente um arquivo com apenas 44 bytes e, em seguida, anexa os dados do arquivo PCM
ao arquivo. Finalmente, de acordo com as regras do formato WAV, as informações reais do cabeçalho de 44 bytes são realmente calculadas e o ponteiro de modificação do arquivo aponta para o início do arquivo e, em seguida, modificado para os dados recém-gerados.