Métodos de compressão / armazenamento de mídia em WAVE e JPEG, parte 1

Olá Minha primeira série de artigos terá como objetivo estudar métodos de compactação e armazenamento de imagens / som, como JPEG (imagem) e WAVE (som), e também incluirão exemplos de programas que utilizam esses formatos (.jpg, .wav) na prática. Nesta parte, consideraremos o WAVE.


A história


WAVE (Waveform Audio File Format) é um formato de arquivo contêiner para armazenar gravações de fluxo de áudio. Esse contêiner é normalmente usado para armazenar som não compactado na modulação do código de pulso. (Adaptado da Wikipedia)

Foi inventado e publicado em 1991 junto com o RIFF pela Microsoft e IBM (empresas líderes de TI da época).


Estrutura de arquivo


O arquivo tem uma parte do cabeçalho, os dados em si, mas não há rodapé. O cabeçalho pesa um total de 44 bytes.
O cabeçalho contém configurações para o número de bits na amostra, a frequência de descritização, a profundidade do som, etc. informações necessárias para uma placa de som. (Todos os valores numéricos da tabela devem ser escritos em ordem Little-Endian)


Nome do blocoTamanho do bloco (B)Descrição / FinalidadeValor (para alguns, é fixo
chunkId4Definindo um arquivo como um contêiner de mídia0x52494646 no Big-Endian ("RIFF")
chunkSize4O tamanho do arquivo inteiro sem chunkId e chunkSizeFILE_SIZE - 8
formato4Definição de tipo do RIFF0x57415645 no Big-Endian ("WAVE")
subchunk1Id4Para ocupar mais espaço no arquivo formato continuado0x666d7420 no Big-Endian ("fmt")
subchunk1Size4Cabeçalho restante (em bytes)16 por padrão (para o caso sem compressão de fluxo de áudio)
audioFormat2Formato de áudio (depende do método de compactação e da estrutura de dados de áudio)1 (para PCM, que estamos considerando)
numChannels2Número de canais1/2, pegamos 1 canal (3/4/5/6/7 ... - uma faixa de áudio específica, por exemplo, 4 para um som quad, etc.)
sampleRate4Frequência de amostragem de som (em Hertz)Quanto maior, melhor o som, mas mais memória será necessária para criar uma faixa de áudio do mesmo tamanho, o valor recomendado é 48000 (a qualidade de som mais aceitável)
byteRate4Número de bytes em 1 segundosampleRate numChannels bitsPerSample (doravante)
blockAlign2Número de bytes para 1 amostranumChannels * bitsPerSample: 8
bitsPerSample2O número de bits por 1 amostra (profundidade)Qualquer número múltiplo de 8. Quanto maior, melhor e mais difícil será o áudio; de 32 bits, não há diferença para uma pessoa.
subchunk2Id4A marca de referência do início dos dados (pois pode haver outros elementos de cabeçalho dependendo do audioFormat)0x64617461 no Big-Endian ("dados")
subchunk2Size4Tamanho da área de dadostamanho dos dados em int
dadosbyteRate * duração do áudioDados de áudio?

Exemplo WAVE


A tabela anterior pode ser facilmente traduzida em uma estrutura C, mas hoje nossa linguagem é Python. A coisa mais fácil de fazer usando a onda é um gerador de ruído. Para esta tarefa, não precisamos de alta byteRate e compactação.
Para começar, importamos os módulos necessários:


# WAV.py from struct import pack #  py-     C from os import urandom #    /dev/urandom,  windows: # from random import randint # urandom = lambda sz: bytes([randint(0, 255) for _ in range(sz)]) #   windows, .. urandom'    from sys import argv, exit #      if len(argv) != 3: # +1   (-1,   ) print('Usage: python3 WAV.py [num of samples] [output]') exit(1) 

Em seguida, precisamos criar todas as variáveis ​​necessárias da tabela de acordo com seus tamanhos. Os valores variáveis ​​dependem aqui apenas de numSamples (o número de amostras). Quanto mais houver, mais longo será o ruído.


 numSamples = int(argv[1]) output_path = argv[2] chunkId = b'RIFF' Format = b'WAVE' subchunk1ID = b'fmt ' subchunk1Size = b'\x10\x00\x00\x00' # 0d16 audioFormat = b'\x01\x00' numChannels = b'\x02\x00' # 2-    () sampleRate = pack('<L', 1000) # 1000 ,    ,     .  1000-  ,   bitsPerSample = b'\x20\x00' # 0d32 byteRate = pack('<L', 1000 * 2 * 4) # sampleRate * numChannels * bitsPerSample / 8 (32 bit sound) blockAlign = b'\x08\x00' # numChannels * BPS / 8 subchunk2ID = b'data' subchunk2Size = pack('<L', numSamples * 2 * 4) # * numChannels * BPS / 8 chunkSize = pack('<L', 36 + numSamples * 2 * 4) # 36 + subchunk2Size data = urandom(1000 * 2 * 4 * numSamples) #   

Resta apenas escrevê-los na sequência necessária (como na tabela):


 with open(output_path, 'wb') as fh: fh.write(chunkId + chunkSize + Format + subchunk1ID + subchunk1Size + audioFormat + numChannels + sampleRate + byteRate + blockAlign + bitsPerSample + subchunk2ID + subchunk2Size + data) #  

E então, pronto. Para usar o script, precisamos adicionar os argumentos de linha de comando necessários:
python3 WAV.py [num of samples] [output]
número de amostras - contagem amostras
output - caminho para o arquivo de saída


Aqui está um link para um arquivo de áudio de teste com ruído, mas para economizar memória, reduzi o BPS para 1b / s e reduzi o número de canais para 1 (com fluxo de áudio estéreo não compactado de 32k a 64kbs, resultou 80M de um arquivo .wav limpo e apenas 10): https: / /instaud.io/3Dcy


O código inteiro (WAV.py) (o código possui muitos valores duplicados de variáveis, isso é apenas um esboço):


 from struct import pack #  py-     C from os import urandom #    /dev/urandom,  windows: # from random import randint # urandom = lambda sz: bytes([randint(0, 255) for _ in range(sz)]) #   windows, .. urandom'    from sys import argv, exit #      if len(argv) != 3: # +1   (-1,   ) print('Usage: python3 WAV.py [num of samples] [output]') exit(1) numSamples = int(argv[1]) output_path = argv[2] chunkId = b'RIFF' Format = b'WAVE' subchunk1ID = b'fmt ' subchunk1Size = b'\x10\x00\x00\x00' # 0d16 audioFormat = b'\x01\x00' numChannels = b'\x02\x00' # 2-    () sampleRate = pack('<L', 1000) # 1000 ,    . bitsPerSample = b'\x20\x00' # 0d32 byteRate = pack('<L', 1000 * 2 * 4) # sampleRate * numChannels * bitsPerSample / 8 (32 bit sound) blockAlign = b'\x08\x00' # numChannels * BPS / 8 subchunk2ID = b'data' subchunk2Size = pack('<L', numSamples * 2 * 4) # * numChannels * BPS / 8 chunkSize = pack('<L', 36 + numSamples * 2 * 4) # 36 + subchunk2Size data = urandom(1000 * 2 * 4 * numSamples) #   with open(output_path, 'wb') as fh: fh.write(chunkId + chunkSize + Format + subchunk1ID + subchunk1Size + audioFormat + numChannels + sampleRate + byteRate + blockAlign + bitsPerSample + subchunk2ID + subchunk2Size + data) #     

Sumário


Então você aprendeu um pouco mais sobre o som digital e como ele é armazenado. Neste post, não usamos compactação (audioFormat), mas para revisar cada um dos artigos populares, você precisará dos artigos 10. Espero que você tenha aprendido algo novo e que isso o ajude em desenvolvimentos futuros.
Obrigada


Fontes

Estrutura de arquivos WAV
WAV - Wikipedia

Source: https://habr.com/ru/post/pt450774/


All Articles