Volume
Problema a Resolver
Em um arquivo chamado volume.c
em uma pasta chamada volume
, escreva um programa para modificar o volume de um
arquivo de áudio.
Começando
Passo a Passo
Eis aqui um passo a passo para a resolução do problema.
Contexto
Escreva um programa para modificar o volume de um arquivo de áudio.
$ ./volume INPUT.wav OUTPUT.wav 2.0
Onde INPUT.wav
é o nome de um arquivo de áudio original
e OUTPUT.wav
é o nome de um arquivo de áudio cujo volume
foi ajustado pelo fator fornecido (por exemplo, 2.0).
Arquivos WAV
Arquivos WAV são um formato de arquivo comum para representar áudio. Arquivos WAV armazenam áudio como uma sequência de "amostras": números que representam o valor de algum sinal de áudio em um determinado momento no tempo. Arquivos WAV começam com um "cabeçalho" de 44 bytes que contém informações sobre o arquivo em si, incluindo o tamanho do arquivo, o número de amostras por segundo e o tamanho de cada amostra. Após o cabeçalho, o arquivo WAV contém uma sequência de amostras, cada uma sendo um único inteiro de 2 bytes (16 bits) representando o sinal de áudio em um determinado momento no tempo.
Escalonar cada valor de amostra por um determinado fator tem o efeito de alterar o volume do áudio. Multiplicar cada valor de amostra por 2.0, por exemplo, terá o efeito de dobrar o volume do áudio original. Multiplicar cada amostra por 0.5, por outro lado, terá o efeito de reduzir o volume pela metade.
Tipos
Até agora, vimos vários tipos diferentes em C, incluindo int
, bool
, char
, double
, float
e long
. Dentro de um arquivo de cabeçalho chamado stdint.h
, estão as declarações de vários outros tipos que
nos permitem definir com precisão o tamanho (em bits) e o sinal (positivo ou negativo) de um inteiro. Dois tipos
em particular serão úteis para nós neste laboratório.
uint8_t
é um tipo que armazena um inteiro sem sinal (ou seja, não negativo) de 8 bits. Podemos tratar cada byte do cabeçalho de um arquivo WAV como um valoruint8_t
.int16_t
é um tipo que armazena um inteiro com sinal (ou seja, positivo ou negativo) de 16 bits. Podemos tratar cada amostra de áudio em um arquivo WAV como um valorint16_t
.
Começando
Abra o cs50.dev.
Comece clicando dentro da janela do terminal e, em seguida, execute cd
por si só. Você deve encontrar que seu "prompt" se
assemelha ao abaixo.
$
Clique dentro dessa janela de terminal e execute
wget https://cdn.cs50.net/2023/fall/psets/4/volume.zip
digite Enter para baixar um arquivo ZIP chamado volume.zip
em seu espaço de códigos. Tenha cuidado para
não ignorar o espaço entre wget
e a URL seguinte, ou
qualquer outro caractere!
Agora execute
unzip volume.zip
para criar uma pasta chamada volume
. Você não precisa
mais do arquivo ZIP, então pode executar
rm volume.zip
e responda com "y" seguido de Enter no prompt para remover o arquivo ZIP que você baixou.
Agora digite
cd volume
seguido de Enter para entrar (ou seja, abrir) nesse diretório. Seu prompt agora deve se parecer com o abaixo.
volume/ $
Se tudo foi bem sucedido, você deve executar
ls
e você deve ver um arquivo volume.c
ao lado de um
arquivo input.wav
.
Se você encontrar algum problema, siga novamente essas mesmas etapas e veja se pode determinar onde errou!
Detalhes da implementação
Complete a implementação de volume.c
, de modo que
altere o volume de um arquivo de som por um fator dado.
- O programa aceita três argumentos na linha de comando:
input
representa o nome do arquivo de áudio original,output
representa o nome do novo arquivo de áudio que deve ser gerado efactor
é a quantidade pela qual o volume do arquivo de áudio original deve ser escalado.- Por exemplo, se
factor
for2.0
, então seu programa deve dobrar o volume do arquivo de áudio eminput
e salvar o arquivo de áudio recém-gerado emoutput
.
- Por exemplo, se
- Seu programa deve primeiro ler o cabeçalho do arquivo de entrada e gravar o cabeçalho no
arquivo de saída. Lembre-se de que esse cabeçalho tem sempre exatamente 44 bytes.
- Observe que
volume.c
já define uma variável para você chamadaHEADER_SIZE
, igual ao número de bytes no cabeçalho.
- Observe que
- O seu programa deve ler o restante dos dados do arquivo WAV, um sample (amostra) de 16 bits (2
bytes) por vez. O seu programa deve multiplicar cada amostra pelo fator
factor
e escrever a nova amostra no arquivo de saída.- Você pode assumir que o arquivo WAV usará valores de 16 bits assinados como amostras. Na prática, arquivos WAV podem ter números variados de bits por amostra, mas para este laboratório assumiremos amostras de 16 bits.
- O seu programa, se utilizar
malloc
, não deve vazar memória.
Dicas
- Provavelmente, você vai querer criar um array de bytes para armazenar os dados do cabeçalho do
arquivo WAV que você lerá do arquivo de entrada. Usando o tipo
uint8_t
para representar um byte, você pode criar um array den
bytes para o seu cabeçalho com uma sintaxe como
uint8_t header[n];
Substituindo n
pelo número de bytes. Você pode então
usar header
como argumento para fread
ou fwrite
para ler ou escrever a partir do cabeçalho.
- Provavelmente, você desejará criar um "buffer" para armazenar as amostras de áudio que você lê
do arquivo WAV. Usando o tipo
int16_t
para armazenar uma amostra de áudio, você pode criar uma variável de buffer com uma sintaxe como
int16_t buffer;
Você pode então usar o &buffer
como um argumento
para fread
ou fwrite
para ler do buffer ou escrever nele. (Lembre-se de
que o operador &
é usado para obter o endereço da
variável.)
- Você pode achar a documentação do
fread
e dofwrite
útil aqui.- Em particular, observe que ambas as funções aceitam os seguintes argumentos:
ptr
: um ponteiro para o local na memória para armazenar dados (quando lendo de um arquivo) ou de onde escrever dados (quando escrevendo dados para um arquivo)size
: o número de bytes em um item de dadosnmemb
: o número de itens de dados (cada um desize
bytes) a serem lidos ou escritosstream
: o ponteiro do arquivo para ser lido ou escrito
- De acordo com sua documentação, o
fread
retornará o número de itens de dados lidos com êxito. Você pode achar isso útil para verificar quando atingiu o final do arquivo!
- Em particular, observe que ambas as funções aceitam os seguintes argumentos:
Como Testar o Seu Código
O seu programa deve se comportar de acordo com os exemplos abaixo.
$ ./volume input.wav output.wav 2.0
Quando você ouvir o arquivo output.wav
(por exemplo,
clicando com o botão direito em output.wav
no navegador
de arquivos, escolhendo Baixar, e depois abrindo o arquivo em um player de áudio no seu
computador), ele deve estar com o dobro do volume de input.wav
!
$ ./volume input.wav output.wav 0.5
Quando você ouvir o arquivo output.wav
, ele deve estar
com metade do volume de input.wav
!
Execute o código abaixo para avaliar a correção do seu programa usando check50
. Mas certifique-se de compilar e testar por conta
própria também!
check50 cs50/problems/2024/x/volume
Execute o seguinte para avaliar o estilo do seu código usando style50
.
style50 volume.c
Como enviar
No seu terminal, execute o seguinte para enviar seu trabalho.
submit50 cs50/problems/2024/x/volume