Diferenças
Aqui você vê as diferenças entre duas revisões dessa página.
| c:processamento_de_audio [2023/08/01 19:13] – criada maziero | c:processamento_de_audio [2023/08/01 19:23] (atual) – edição externa 127.0.0.1 | ||
|---|---|---|---|
| Linha 1: | Linha 1: | ||
| + | ====== Processamento de áudio ====== | ||
| + | |||
| + | {{ progc_proj_audio.mkv |Video deste projeto}} | ||
| + | |||
| + | Este projeto consiste em criar filtros para arquivos de áudio em formato WAV, implementando operações como ajuste de volume, eco e normalização. | ||
| + | |||
| + | ===== Áudio digital ===== | ||
| + | |||
| + | Em um sistema digital, um som é normalmente codificado como um vetor de amostras (// | ||
| + | |||
| + | Trecho de áudio (duração 45 s): | ||
| + | |||
| + | {{ audio1.png | ||
| + | |||
| + | Detalhe do trecho de áudio acima (duração 300 ms): | ||
| + | |||
| + | {{ audio2.png | ||
| + | |||
| + | Detalhe do trecho de áudio acima (duração 30 ms): | ||
| + | |||
| + | {{ audio3.png | ||
| + | |||
| + | Detalhe do trecho de áudio acima (duração 0,3 ms): | ||
| + | |||
| + | {{ audio4.png | ||
| + | |||
| + | Visão conceitual da amostragem de áudio: | ||
| + | |||
| + | {{ amostragem.png? | ||
| + | |||
| + | Nessa figura podem ser identificados o **sinal analógico**, | ||
| + | |||
| + | [0, 10, 15, 9, -5, -9, -10, 0, 10, 14, 15, 5, 0, -5, ... ] | ||
| + | |||
| + | O padrão PCM ([[https:// | ||
| + | |||
| + | * **Taxa de amostragem**: | ||
| + | * **Resolução**: | ||
| + | |||
| + | No caso de sons com vários canais (estéreo ou // | ||
| + | |||
| + | ===== O formato WAV ===== | ||
| + | |||
| + | Para facilitar a leitura e escrita dos arquivos de áudio, neste projeto será adotado o [[https:// | ||
| + | |||
| + | Um arquivo WAV típico é organizado nos seguintes //chunks// (pedaços) básicos: | ||
| + | |||
| + | ^ Chunk ID ^ tamanho (bytes) ^ conteúdo ^ | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | |||
| + | <note important> | ||
| + | Em alguns arquivos WAV podem haver outros chunks, como LIST e INFO, que não precisam ser considerados neste projeto. | ||
| + | </ | ||
| + | |||
| + | Esses //chunks// têm os seguintes campos internos: | ||
| + | |||
| + | ^ Chunk ^ nome ^ tamanho ^ tipo ^ valor ^ significado ^ | ||
| + | | '' | ||
| + | | ::: | ChunkSize | 4 | '' | ||
| + | | ::: | Format | 4 | '' | ||
| + | | '' | ||
| + | | ::: | SubChunk1Size | 4 | '' | ||
| + | | ::: | Audio format | 2 | '' | ||
| + | | ::: | Number of channels | 2 | '' | ||
| + | | ::: | Sample rate | 4 | '' | ||
| + | | ::: | Byte rate | 4 | '' | ||
| + | | ::: | Block align | 2 | '' | ||
| + | | ::: | Bits per sample | 2 | '' | ||
| + | | '' | ||
| + | | ::: | SubChunk2Size | 4 | '' | ||
| + | | ::: | Audio data | variável | ||
| + | |||
| + | <note important> | ||
| + | Observe que os campos de tipo '' | ||
| + | </ | ||
| + | |||
| + | As amostras de áudio são armazenadas no //chunk// de dados ('' | ||
| + | |||
| + | L[0], R[0], L[1], R[1], L[2], R[2], L[3], R[3], ... | ||
| + | |||
| + | <note tip> | ||
| + | Para ler facilmente o cabeçalho de um arquivo WAV, basta definir um //struct// com os mesmos campos, tamanhos e ordem do cabeçalho descrito acima, e então ler os primeiros bytes do arquivo para dentro desse //struct//, usando a função de leitura '' | ||
| + | </ | ||
| + | |||
| + | Documentação adicional sobre o formato WAV: | ||
| + | |||
| + | * [[http:// | ||
| + | * [[http:// | ||
| + | |||
| + | Alguns exemplos de arquivos de áudio WAV para usar no projeto: | ||
| + | |||
| + | * {{music.wav? | ||
| + | * {{batida.wav? | ||
| + | * {{numbers.zip|Numbers}} (mono, 22050 KHz) | ||
| + | |||
| + | Você pode gerar seus próprios arquivos WAV usando programas de processamento de áudio, como o " | ||
| + | |||
| + | ===== Filtros ===== | ||
| + | |||
| + | Um filtro de áudio é um programa simples, que recebe como entrada um arquivo de áudio (que pode vir da entrada padrão //stdin//), realiza algum tipo de [[https:// | ||
| + | |||
| + | <note important> | ||
| + | Lembre-se que o filtro deve atuar em todos os canais do áudio da entrada. | ||
| + | </ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== Informações ==== | ||
| + | |||
| + | Este programa não é exatamente um filtro, pois produz como saída uma listagem das principais informações do áudio informado como entrada. | ||
| + | |||
| + | Forma de chamada: | ||
| + | |||
| + | wavinfo -i input | ||
| + | |||
| + | Exemplo de saída (para o arquivo '' | ||
| + | |||
| + | < | ||
| + | $ wavinfo -i music.wav | ||
| + | |||
| + | riff tag (4 bytes): " | ||
| + | riff size (4 bytes): 8061776 | ||
| + | wave tag (4 bytes): " | ||
| + | form tag (4 bytes): "fmt " | ||
| + | fmt_size | ||
| + | audio_format | ||
| + | num_channels | ||
| + | sample_rate | ||
| + | byte_rate | ||
| + | block_align | ||
| + | bits_per_sample (2 bytes): 16 | ||
| + | data tag (4 bytes): " | ||
| + | data size (4 bytes): 8061740 | ||
| + | bytes per sample | ||
| + | samples per channel | ||
| + | </ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== Ajuste de volume ==== | ||
| + | |||
| + | O filtro de ajuste de volume permite aumentar ou diminuir o volume de áudio do arquivo, de acordo com um fator de ajuste V (0.0 ≤ V ≤ 10.0, com default em 1.0). Ele consiste basicamente em multiplicar o valor de cada amostra de áudio por V. | ||
| + | |||
| + | Forma de chamada ('' | ||
| + | |||
| + | wavvol -l V -i input -o output | ||
| + | |||
| + | Exemplo de uso e saída: {{music-vol.wav? | ||
| + | |||
| + | wavvol -l 0.1 -i music.wav -o music-vol.wav | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== Normalização ==== | ||
| + | |||
| + | Este filtro faz a normalização do áudio, ou seja, o ajuste automático de volume. Para tal, é necessário encontrar o valor do maior pico no sinal de áudio (em todos os canais) e usá-lo para calcular um fator de ajuste, de modo que todas as amostras de todos os canais fiquem no intervalo de 16 bits com sinal [-32767 ... +32767]. | ||
| + | |||
| + | Forma de chamada: | ||
| + | |||
| + | wavnorm -i input -o output | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== Reversão ==== | ||
| + | |||
| + | Este filtro produz como saída um áudio invertido, ou seja, "de trás para a frente" | ||
| + | |||
| + | Forma de chamada: | ||
| + | |||
| + | wavrev -i input -o output | ||
| + | |||
| + | Exemplo de uso e saída: {{music-rev.wav? | ||
| + | |||
| + | wavrev -i music.wav -o music-rev.wav | ||
| + | |||
| + | <note tip> | ||
| + | Muitos músicos se divertiram com esse efeito, como nesta [[https:// | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== Eco ==== | ||
| + | |||
| + | Este filtro produz como saída um áudio com eco. O eco é controlado pelos parâmetros //delay// ( inteiro ≥ 0, default 1000 ms), que define o atraso do eco em milissegundos, | ||
| + | |||
| + | O efeito de eco pode ser definido por esta equação: sample< | ||
| + | |||
| + | Forma de chamada ('' | ||
| + | |||
| + | wavecho -t delay -l level -i input -o output | ||
| + | |||
| + | Exemplo de uso e saída (ambos com t=500ms e l=50%): {{batida-echo.wav? | ||
| + | |||
| + | wavecho -t 500 -l 0.5 -i music.wav -o music-echo.wav | ||
| + | |||
| + | <note tip> | ||
| + | Experimente aplicar este filtro a um arquivo de voz, com um atraso bem pequeno (10 a 50 ms) =) | ||
| + | </ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== Estéreo ampliado ==== | ||
| + | |||
| + | O filtro de estéreo ampliado permite aumentar a separação de canais em um sinal estéreo, gerando um som mais aberto. Este filtro só pode ser aplicado a sinais estéreo (com 2 canais). | ||
| + | |||
| + | Sendo R(t) e L(t) as amostras de entrada do canal direito e esquerdo em um instante t, a saída R'(t), L'(t) é calculada da seguinte forma: | ||
| + | |||
| + | diff = R(t) - L(t) | ||
| + | R'(t) = R(t) + k * diff | ||
| + | L'(t) = L(t) - k * diff | ||
| + | |||
| + | onde '' | ||
| + | |||
| + | Forma de chamada ('' | ||
| + | |||
| + | wavwide -l k -i input -o output | ||
| + | |||
| + | Exemplo de uso e saída: {{music-wide.wav? | ||
| + | |||
| + | cat music.wav | wavvol -l 0.5 | wavwide -l 5 | wavnorm > music-wide.wav | ||
| + | |||
| + | O exemplo acima mostra o uso de vários filtros concatenados: | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== Concatenação ==== | ||
| + | |||
| + | O filtro de concatenação recebe como entrada **um ou mais arquivos de áudio** e gera uma saída contendo a concatenação das entradas na sequência indicada. | ||
| + | |||
| + | Forma de chamada: | ||
| + | |||
| + | wavcat arq1.wav arq2.wav arq3.wav ... -o output | ||
| + | |||
| + | <note important> | ||
| + | A combinação de sinais de áudio com taxas de amostragem diferentes exige um procedimento chamado // | ||
| + | </ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== Mistura ==== | ||
| + | |||
| + | O filtro de mistura (mixagem) recebe como entrada um ou mais arquivos de áudio e gera uma saída contendo a mistura (mixagem) das entradas. | ||
| + | |||
| + | Forma de chamada: | ||
| + | |||
| + | wavmix arq1.wav arq2.wav arq3.wav ... -o output | ||
| + | |||
| + | <note important> | ||
| + | Ao somar as amostras, cuide para não saturar a saída, o que pode gerar distorção ([[https:// | ||
| + | </ | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ==== Outros filtros (ideias) ==== | ||
| + | |||
| + | * extrair um canal de um áudio stereo | ||
| + | * juntar dois áudios mono em um áudio stereo | ||
| + | * recortar um áudio de t1 a t2 | ||
| + | * aplicar um atraso //t// a um áudio (t pode ser negativo, para adiantar o áudio) | ||
| + | * // | ||
| + | * efeito //phaser//, // | ||
| + | * compressor | ||
| + | * filtro de ruído: reduzir o volume de todas as amostras com nível abaixo de um certo valor (dado em % do volume máximo). | ||
| + | * ... (outras ideias são bem-vindas) | ||
| + | |||
| + | Mais conteúdo sobre efeitos de áudio: | ||
| + | |||
| + | * {{http:// | ||
| + | * {{http:// | ||
| + | * {{https:// | ||
| + | * {{http:// | ||
| + | * ... | ||
| + | |||
| + | ---- | ||
| + | |||
| + | ===== Atividade ===== | ||
| + | |||
| + | O projeto consiste em implementar os filtros acima definidos. | ||
| + | |||
| + | ==== Requisitos ==== | ||
| + | |||
| + | * Cada filtro é um comando separado. Por exemplo, o filtro de volume deve ser implementado em um arquivo '' | ||
| + | * Os filtros devem aceitar como entrada sons no formato WAV PCM 16 bits com sinal e devem gerar como saída sons nesse mesmo formato. | ||
| + | * As rotinas comuns (leitura/ | ||
| + | * Sempre que possível, as informações do som necessárias às funções devem ser transferidas como parâmetros (por valor ou por referência, | ||
| + | * Use alocação dinâmica de memória para os sons, para poder processar arquivos grandes. Só aloque a memória para as amostras após encontrar o número de amostras no cabeçalho. | ||
| + | * Construir um '' | ||
| + | * Ao menos os alvos '' | ||
| + | * CFLAGS = '' | ||
| + | * Compilar e ligar separadamente (gerar arquivos '' | ||
| + | * O que deve ser entregue ao professor: | ||
| + | * arquivos '' | ||
| + | * arquivo '' | ||
| + | * **não enviar** os sons de teste | ||
| + | |||
| + | <note tip> | ||
| + | Para simplificar a implementação e evitar erros, sugere-o o uso dos tipos inteiros de tamanho fixo ('' | ||
| + | </ | ||
| + | |||
| + | ==== Linha de comando ==== | ||
| + | |||
| + | * A opção '' | ||
| + | * A opção '' | ||
| + | * Todas as mensagens de erro devem ser enviadas para a saída de erro (// | ||
| + | |||
| + | Essas opções podem ser usadas em qualquer combinação, | ||
| + | |||
| + | < | ||
| + | // entrada e saída em arquivos | ||
| + | wavvol -i inputfile.wav | ||
| + | wavvol -o outputfile.wav -i inputfile.wav | ||
| + | |||
| + | // entrada em arquivo, saída em stdout, vice-versa ou ambos | ||
| + | wavvol -i inputfile.wav | ||
| + | wavvol -o outputfile.wav < inputfile.wav | ||
| + | wavvol | ||
| + | |||
| + | // as opções podem estar em qualquer ordem | ||
| + | wavvol -l 0.3 -i inputfile.wav -o outputfile.wav | ||
| + | wavvol -i inputfile.wav -l 0.3 -o outputfile.wav | ||
| + | wavvol -o outputfile.wav -i inputfile.wav -l 0.3 | ||
| + | </ | ||
| + | |||
| + | <note tip> | ||
| + | Para ler e tratar mais facilmente as opções da linha de comando, sugere-se usar funções já prontas para isso, como '' | ||
| + | </ | ||
| + | |||
| + | Como os filtros devem tratar a entrada e saída padrão, é possível combinar filtros usando //pipes// UNIX. Por exemplo, podemos usar pipes para construir o efeito [[https:// | ||
| + | |||
| + | wavrev -i input.wav | wavecho -t 500 -l 0.5 | wavrev -o output.wav | ||
| + | |||
| + | Caso a adição de eco provoque // | ||
| + | |||
| + | wavvol -l 0.5 -i input.wav | wavrev | wavecho -t 500 -l 0.5 | wavrev | wavnorm -o output.wav | ||
| + | |||
| + | <note tip> | ||
| + | Para tocar facilmente os arquivos de áudio, pode-se usar os comandos '' | ||
| + | </ | ||
| + | |||
| + | ==== Estrutura do código-fonte ==== | ||
| + | |||
| + | O código-fonte deve ser estruturado em diversos arquivos '' | ||
| + | |||
| + | {{ estrutura-wav.png? | ||