Preview only show first 10 pages with watermark. For full document please download

Ep04

Enunciado do quarto EP de MAC2166 Introdução à computação para engenharia(2005). Sintetizador de audio digital.

   EMBED


Share

Transcript

MAC2166 – Introdu¸c˜ ao ` a Computa¸c˜ ao para Engenharia Escola Polit´ ecnica – Primeiro Semestre de 2005 Quarto Exerc´ıcio Programa (EP4) – Data de entrega: 25/6/2005 ´ Sintetizador de Audio Digital Neste EP vamos desenvolver um sintetizador de a´udio digital. Este sintetizador converte uma representa¸ca˜o simb´olica de sons em uma representa¸ca˜o expl´ıcita dos mesmos sons na forma de um arquivo de a´udio. O som, como sabemos, ´e transmitido por uma onda mecˆanica que se propaga no ar e causa vibra¸co˜es em nosso aparelho auditivo, que podem ser percebidas como m´ usica, fala, ou um barulho qualquer. O sinal sonoro corresponde ao gr´afico da varia¸ca˜o da press˜ao do ar em fun¸ca˜o do tempo. Alguns sons correspondem a oscila¸co˜es peri´odicas ou quase-peri´odicas que d˜ao origem a` sensa¸ca˜o de altura musical. Estes sons podem ser caracterizados grosseiramente por alguns parˆametros: a forma b´asica de onda correspondente ao sinal sonoro medido durante um per´ıodo completo da oscila¸ca˜o; a amplitude da oscila¸ca˜o que est´a associada a` sensa¸ca˜o de volume; a freq¨ uˆencia da oscila¸ca˜o, medida em Hertz (Hz), que determina a altura musical percebida e corresponde ao n´ umero de repeti¸co˜es da forma b´asica de onda por segundo (em outras palavras, a freq¨ uˆencia em Hz ´e o inverso do per´ıodo, medido em segundos); e a dura¸ca˜o do som. Tal caracteriza¸ca˜o fornece uma representa¸ca˜o simb´olica do fenˆomeno oscilat´orio, reduzindo-o a um n´ umero pequeno de parˆametros. Um arquivo de a´udio, por outro lado, ´e uma representa¸ca˜o expl´ıcita do sinal sonoro que permite seu armazenamento utilizando espa¸co de mem´oria (digital) finito. A representa¸ca˜o aqui descrita ´e conhecida como Pulse Code Modulation (PCM) e utiliza a t´ecnica de amostragem, que consiste em medir o sinal sonoro regularmente a intervalos de tempo pequenos obtendo amostras do sinal. O n´ umero de amostras obtidas para cada segundo do som ´e chamado de taxa de amostragem do sinal e est´a associado a` precis˜ao da representa¸ca˜o do sinal sonoro no eixo horizontal (do tempo); quanto maior a taxa de amostragem, melhor a representa¸ca˜o do som original e maior a fidelidade obtida na hora de reproduzir o sinal armazenado1 . O n´ umero de bits utilizados para armazenar cada amostra est´a associado a` precis˜ao da representa¸ca˜o do gr´afico no eixo vertical (da varia¸ca˜o de press˜ao do ar). Um arquivo de a´udio pode armazenar v´arios canais diferentes contendo sinais sonoros que ser˜ao reproduzidos simultaneamente em um sistema com v´arias caixas ac´ usticas. Como exemplo, se armazenamos 44100 amostras por segundo, com 16 bits por amostra, em um arquivo de a´udio est´ereo, ent˜ao cada segundo de som ocupa 44100 ∗ 16 ∗ 2 bits = 176400 bytes deste arquivo2 . O objetivo deste EP ´e escrever um programa (em linguagem C) que lˆe um arquivo de entrada contendo parˆametros que descrevem um ou mais sons e produz um arquivo de a´udio no formato WAVE (detalhado adiante) que representa o sinal sonoro correspondente ao arquivo de entrada. O arquivo de entrada ´e um arquivo texto contendo as seguintes informa¸co˜es: 1 A taxa de amostragem define n˜ao apenas a qualidade da representa¸ca˜o da onda sonora como tamb´em a m´axima freq¨ uˆencia sonora represent´avel, que ´e conhecida como freq¨ uˆencia de Nyquist e vale R/2 Hz. 2 Estes valores correspondem `a qualidade de CD; outro padr˜ao comum ´e 8000 amostras de 8 bits por segundo em um u ´nico canal, que ´e aproximadamente a qualidade do telefone. • trˆes inteiros positivos: R (taxa de amostragem, em Hz), B (n´ umero de bits de cada amostra: 8 ou 16) e C (n´ umero de canais: 1 ou 2); • um inteiro Nw ∈ {1, . . . , MAX = 4096} e uma lista de Nw valores reais w0 , . . . , wNw −1 entre −1 e 1 que representam uma vers˜ao discretizada de uma forma b´asica de onda; • um inteiro Np ∈ {1, . . . , MAX} e uma lista de Np valores reais p0 , . . . , pNp −1 entre 0 e 1 que representam uma vers˜ao discretizada de uma trajet´oria panorˆamica; • um inteiro Ne ∈ {0, . . . , MAX} e uma lista de Ne eventos sonoros, onde cada evento sonoro j = 0, . . . , Ne − 1 ´e descrito por trˆes n´ umeros reais: – dura¸ca˜o (dj ≥ 0), em segundos; – freq¨ uˆencia (fj ≥ 0), em Hertz; e – amplitude (aj ∈ [0, 1]), correspondente a uma fra¸ca˜o da amplitude m´axima represent´avel. Musicalmente falando, a forma b´asica de onda est´a relacionada com a descri¸ca˜o de um timbre, a trajet´oria panorˆamica serve para “espacializar” o som e a lista de eventos sonoros corresponde a uma partitura. N˜ao se preocupe: vocˆe n˜ao precisa conhecer estes termos para entender e fazer o EP. O arquivo de sa´ıda produzido pelo seu EP dever´a conter uma representa¸ca˜o do som correspondente aos dados da entrada. O sinal sonoro que ser´a sintetizado consiste de v´arias c´opias da forma b´asica de onda que ser˜ao ajustadas de acordo com a dura¸ca˜o, a freq¨ uˆencia e a amplitude dos eventos sonoros, bem como de acordo com a trajet´oria panorˆamica. Em particular, os d0 primeiros segundos do sinal de a´udio representar˜ao o evento sonoro j = 0, que possui f0 ∗ d0 c´opias da forma b´asica de onda (f0 c´opias por segundo durante d0 segundos), adaptadas pela amplitude a0 e pela trajet´oria panorˆamica; e assim sucessivamente para os eventos j = 1, . . . , Ne − 1. O formato espec´ıfico do arquivo de sa´ıda ´e detalhado na pr´oxima se¸ca˜o; os detalhes sobre a s´ıntese do sinal sonoro e ajustes correspondentes a` dura¸ca˜o, freq¨ uˆencia, amplitude e trajet´oria panorˆamica dos eventos sonoros s˜ao dados nas se¸co˜es seguintes. Formato de arquivos WAVE Arquivos WAVE seguem o padr˜ao RIFF (Resource Interchange File Format) e consistem em um cabe¸calho e uma seq¨ uˆencia de amostras3 . O cabe¸calho define, entre outras coisas, a taxa de amostragem R, o n´ umero de bits B e o n´ umero de canais C. A descri¸ca˜o a seguir ´e meramente informativa: 4 vocˆe deve utilizar a fun¸ca˜o void escreve_cabecalho_wav (FILE *output, int R, int B, int C, int num_amostras); dispon´ıvel em http://www.ime.usp.br/~mac2166/ep4/cabecalho, para gerar o cabe¸calho do seu arquivo de sa´ıda. 3 Esta organiza¸ca˜o da informa¸ca˜o em cabe¸calho + dados ´e muito comum em computa¸ca˜o e ´e utilizada em v´arios contextos: arquivos de som, imagem e v´ıdeo, pacotes de transmiss˜ao de dados em redes, etc. 4 Deve ´e sinˆonimo de deve obrigatoriamente, este u ´ltimo sendo considerado pela maioria dos autores um pleonasmo desnecess´ario. 2 Byte 0 4 8 12 16 20 22 24 28 32 34 36 40 44 Conte´ udo "RIFF" tamanho do bloco RIFF "WAVE" "fmt " tamanho do bloco de formato formato das amostras n´ umero de canais taxa de amostragem em Hz bytes por segundo n´ umero total de bytes por amostra n´ umero de bits por amostra "data" no total de bytes das amostras ¯ amostras Observa¸ co ~es identificador do bloco RIFF = 36 + no total de bytes das amostras ¯ identificador do bloco WAVE identificador do bloco de formato = 16 = 1 (PCM) = C (1 ou 2) = R = R*C*(B/8) = C*(B/8) = B (8 ou 16) identificador do bloco de amostras = num_amostras*C*(B/8) Observa¸co˜es: 1. O n´ umero total de amostras do arquivo ´e NX e −1 Dj , onde Dj = bR ∗ dj c ´e o n´ umero de amostras j=0 referentes ao evento j (R amostras por segundo durante dj segundos). O s´ımbolo bxc (leia-se ch˜ao de x) denota o maior inteiro menor ou igual a x. 2. Consideraremos apenas C = 1 ou C = 2 canais (arquivo mono ou est´ereo). Para arquivos com dois canais, as amostras devem aparecer no arquivo de sa´ıda na ordem amostra1 -canal1 , amostra1 -canal2 , amostra2 -canal1 , amostra2 -canal2 , . . . A conven¸ca˜o para arquivos est´ereo ´e canal1 =esquerdo e canal2 =direito. Nossos arquivos est´ereo possuir˜ao duas c´opias distintas da onda sonora, por causa do controle associado a` trajet´oria panorˆamica. 3. Todos os valores inteiros do arquivo WAVE (tanto no cabe¸calho quanto no bloco de amostras) s˜ao armazenados no formato little-endian, que significa que os bytes aparecem na ordem inversa a` usual, do menos significativo ao mais significativo (especificamente, isso quer dizer que uma seq¨ uˆencia de bytes b0 , b1 , . . . , bq no arquivo corresponde ao n´ umero inteiro b0 + 256 ∗ b1 + . . . + q 256 ∗ bq ). 4. Amostras de 8 bits podem armazenar os valores −128, . . . , −1, 0, . . . , 127, por´em os mesmos s˜ao representados no formato WAVE pelos c´odigos 0, . . . , 127, 128, . . . , 255, respectivamente. Conhecendo-se um valor pode-se escrever o c´odigo correspondente em um arquivo de referˆencia output com o comando fprintf(output, "%c", valor+128); J´a as amostras de 16 bits podem armazenar os valores −32768, . . . , 32767, que s˜ao codificados em um formato conhecido como complemento de 2 † . Especificamente, os c´odigos 00000000 00000000, 00000001 00000000, . . . , 11111111 01111111, 00000000 10000000, † Este nome refere-se ao modo de representar n´ umeros negativos que ´e equivalente a inverter todos os bits e somar 1 ao resultado. 3 00000001 10000000, . . . , 11111111 11111111 representam, respectivamente, os valores 0, 1, . . . , 32767, −32768, −32767, . . . , −1 (a ordem dos bytes nos c´odigos em bin´ario j´a est´a em nota¸ca˜o little-endian). Resumindo, se valor ∈ {0, 1, . . . , 32767}, o c´odigo bin´ario correspondente pode ser escrito no arquivo output com o comando fprintf(output, "%c%c", valor%256, valor/256); se valor ∈ {−32768, . . . , −1}, o comando correspondente ´e fprintf(output, "%c%c", (65536+valor)%256, (65536+valor)/256); Para mais informa¸co˜es sobre o formato WAVE, consulte os sites: http://sox.sourceforge.net/AudioFormats.html http://ccrma-www.stanford.edu/CCRMA/Courses/422/projects/WaveFormat/ Para gerar os valores do sinal sonoro a partir da forma b´asica de onda e da descri¸ca˜o dos eventos sonoros, utilizaremos um algoritmo chamado de oscilador por consulta a tabela. Oscilador por consulta a tabela Uma fun¸ca˜o peri´odica pode ser representada de forma aproximada por uma lista finita w0 , w1 , . . . , wNw −1 de valores que corresponde a uma vers˜ao discretizada de um per´ıodo completo da fun¸ca˜o. Como exemplo, uma onda senoidal pode ser representada de forma aproximada pela 2 62 1 2π), sen( 63 2π), . . . , sen( 63 2π). Observe que o lista de 63 valores que correspondem a sen(0), sen( 63 pr´oximo valor seria sen(2π) = sen(0), pois esta fun¸ca˜o ´e peri´odica com per´ıodo 2π ‡ . 1 seno 0.8 0.6 0.4 0.2 0 -0.2 -0.4 -0.6 -0.8 -1 0 10 20 30 40 50 60 70 Usaremos agora a lista obtida da entrada (n˜ao necessariamente da fun¸ca˜o seno) para gerar valores interpolados de um sinal de a´udio x(t). Durante o processamento do evento sonoro j, devemos gerar Dj = bR ∗ dj c valores da fun¸ca˜o peri´odica representada pela forma b´asica de onda, utilizando a freq¨ uˆencia fj correspondente ao evento j. Em particular no evento 0 devemos utilizar a ‡ Tais representa¸co˜es s˜ao muito utilizadas na pr´atica em s´ıntese digital por raz˜oes de eficiˆencia: mesmo uma fun¸ca˜o t˜ao simples quanto sen(x), calculada por uma s´erie de Taylor truncada, chega a custar v´arias dezenas de opera¸co˜es em ponto flutuante por chamada, enquanto o oscilador aqui apresentado custa pouco mais de meia-d´ uzia de opera¸co˜es. 4 freq¨ uˆencia f = f0 Hz. A lista de valores w0 , . . . , wNw −1 , armazenada na tabela (vetor) w, ´e indexada por um valor i em [0, Nw ); este ´ındice n˜ao representa o tempo, mas sim uma posi¸ca˜o da tabela. A rela¸ca˜o dos valores armazenados em w com o sinal x(t), cujo per´ıodo dura f1 segundos, ´e dada por à ! à ! à ! 1 1 2 1 (Nw − 1) 1 w0 = x(0), w1 = x , w2 = x , . . . , wNw −1 = x . Nw f Nw f Nw f Queremos no entanto digitalizar o sinal numa taxa de R valores/segundo. Ou seja, a lista de valores que gostar´ıamos de produzir ´e 1 2 x(0), x , x , ... R R µ ¶ µ ¶ Usando uma simples regra-de-trˆes, podemos determinar a varia¸ca˜o dos ´ındices da tabela que gera os valores desejados. Para uma varia¸ca˜o de 1 unidade no ´ındice da tabela, a varia¸ca˜o de tempo correspondente ´e N1w f . Por outro lado, a varia¸ca˜o de tempo entre os valores que desejamos produzir ´e R1 , o que corresponde a uma varia¸ca˜o ∆f do ´ındice da tabela que deve satisfazer ∆f = 1 1 R 1 Nw f = Nw f . R Desta forma obteremos a lista de valores pretendida: 1 x(0) = w0 , x R µ ¶ 2 = w ∆f , x R µ ¶ = w2∆f , . . . Observe que a freq¨ uˆencia f determina a “velocidade de varredura” da tabela: quanto maior a freq¨ uˆencia f do sinal x(t), maior a varia¸ca˜o de ´ındice ∆f e portanto mais rapidamente os valores da tabela w s˜ao “varridos” pelos ´ındices i = 0, ∆f , 2∆f , . . . N˜ao h´a nada que garanta que a varia¸ca˜o de ´ındice ∆f ´e inteira; na maioria dos casos ela ´e fracion´aria, o que indica que os valores da tabela w dever˜ao ser interpolados de alguma maneira. Adotaremos neste EP a interpola¸ca˜o linear: se por exemplo o ´ındice atual ´e 4.2 ent˜ao o valor de x(t) produzido pelo algoritmo ser´a 0.8 ∗ w4 + 0.2 ∗ w5 . Em geral, se o ´ındice fracion´ario i est´a entre os valores indice anterior=bic e indice sucessor=(bic + 1)%Nw ent˜ao a interpola¸ca˜o ser´a dada por ((indice anterior + 1) − i) ∗ windice anterior + (i − indice anterior) ∗ windice sucessor . Atrav´es da inicializa¸ca˜o do ´ındice fracion´ario i com o valor 0 e da atualiza¸ca˜o dada pela regra i ←− i + ∆f , o oscilador gera a lista de valores interpolados correspondente a` digitaliza¸ca˜o do sinal x(t). Deve-se tomar o cuidado de verificar se o ´ındice fracion´ario est´a na faixa [0, N w ) antes de se calcular ca˜o k o valor de x(t) interpolado; para corrigir um valor de i ≥ N w , utilize a atribui¸ j i i ←− i − Nw ∗ Nw . ´ importante observar que o sinal gerado pelo oscilador ser´a “peri´odico” apenas no intervalo de E tempo dj que corresponde a` dura¸ca˜o do evento j. Na transi¸ca˜o entre dois eventos consecutivos, poder´a haver uma mudan¸ca abrupta na freq¨ uˆencia do sinal, que modifica a varia¸ca˜o ∆f correspondente a` velocidade de varredura da tabela. Uma propriedade importante deste oscilador ´e a de 5 que ele permite tais mudan¸cas s´ ubitas sem que se perceba uma “descontinuidade aud´ıvel”5 no sinal gerado, pois o novo ´ındice ´e definido exclusivamente a partir de informa¸ca˜o local (´ındice anterior e velocidade instantˆanea de varredura). Uma mudan¸ca s´ ubita de freq¨ uˆencia, como a que pode ocorrer na transi¸ca˜o de um evento sonoro para o pr´oximo, corresponder´a a` situa¸ca˜o ilustrada abaixo: 1 sinal 0.8 0.6 0.4 0.2 0 -0.2 -0.4 -0.6 -0.8 -1 0 100 200 300 400 500 600 Justamente para obter esta transi¸ca˜o “suave” entre dois eventos adjacentes, devemos garantir que o ´ındice fracion´ario do oscilador que gera o sinal x(t) n˜ao seja reinicializado na transi¸ca˜o entre os eventos: a inicializa¸ca˜o i ←− 0 ocorre apenas no in´ıcio do programa. Cada valor gerado por este oscilador ser´a modificado ainda por controles de volume e espacializa¸ca˜o, de acordo com as se¸co˜es a seguir. Ajuste do volume de sa´ıda do oscilador O volume de som est´a relacionado com a amplitude da onda. A sa´ıda do oscilador, que se refere apenas a` forma da onda, tem amplitude igual a` da tabela w que armazena a forma b´asica de onda. Esta sa´ıda ser´a multiplicada por um valor de amplitude associado a` lista de eventos sonoros. Lembrese que cada evento sonoro da entrada ´e descrito por uma tripla (dj , fj , aj ), onde aj ´e a amplitude associada ao evento j. Para evitar “descontinuidades aud´ıveis”, iremos interpolar linearmente os valores de amplitude: por exemplo, se 3 eventos sucessivos possuem amplitudes 0.5, 1 e 0.25, ent˜ao a sa´ıda se parecer´a com o gr´afico a seguir: 1 sinal envel 0.8 0.6 0.4 0.2 0 -0.2 -0.4 -0.6 -0.8 -1 0 5 50 100 150 200 250 Tecnicamente conhecidas como “clicks”, “pops”, etc. 6 300 350 400 450 500 A fun¸ca˜o formada por trechos lineares ligando os valores sucessivos de amplitude ´e chamada de envelope dinˆamico do sinal. Para cada valor produzido pelo oscilador, devemos calcular o envelope dinˆamico correspondente, a fim de ajustar sua amplitude, para que a amplitude no in´ıcio do evento j seja aj e a amplitude no final do evento j seja aj+1 . O valor do envelope dinˆamico correspondente a` k-´esima amostra relativa ao in´ıcio do evento j ´e à k 1− Dj ! ∗ aj + k ∗ aj+1 . Dj No u ´ltimo evento, considere aNe = 0, assim durante este evento a amplitude chegar´a linearmente at´e 0. O valor obtido dessa interpola¸ca˜o ser´a multiplicado pela sa´ıda do oscilador, e estar´a sujeito ao controle panorˆamico, explicado a seguir. Controle panorˆ amico O controle panorˆamico refere-se a um ajuste mais fino da amplitude dos canais de som, permitindo a espacializa¸ca˜o dos eventos sonoros. Tal controle ser´a feito por meio da lista p0 , . . . , pNp −1 de valores, lida do arquivo de entrada. Essa lista descreve a trajet´oria panorˆamica de cada evento, ou seja, como o evento sonoro j “transitar´a” entre os canais durante os dj segundos de sua existˆencia. A id´eia ´e mais naturalmente ilustrada no caso de dois canais, mas pode ser utilizada inclusive quando a sa´ıda ´e mono. A figura a seguir fornece um exemplo de valores de uma trajet´oria panorˆamica: 1 panor 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1 0 0 10 20 30 40 50 60 70 Quando C = 2, a trajet´oria panorˆamica ´e usada para controlar o volume de cada um dos dois canais de som de um arquivo est´ereo. Especificamente, a trajet´oria panorˆamica descreve os ajustes que ser˜ao aplicados a` amplitude de cada uma das amostras de um evento. Para cada novo valor α produzido pelo oscilador e associado ao valor β do envelope dinˆamico, devemos gerar um valor γ correspondente a` trajet´oria panorˆamica. A amostra produzida para o canal 1 (esquerdo) ser´a sen(γ π2 ) ∗ β ∗ α, enquanto que a amostra produzida para o canal 2 (direito) ser´a cos(γ π2 ) ∗ β ∗ α. Na figura acima, isso significa que cada evento “come¸ca” no lado direito (note que a amplitude do canal esquerdo ´e zero), “transita” para o lado esquerdo e volta para o lado direito6 . Este “movimento” 6 Estes ajustes correspondem a um modelo de espacializa¸ca˜o que descreve um movimento semi-circular da fonte sonora a uma distˆancia fixa do ouvinte: isso faz com que percebamos de fato um “movimento” do som ao inv´es de simples mudan¸cas de volume. 7 acontece durante os dj segundos correspondentes ao evento j. A figura a seguir ilustra a aplica¸ca˜o da trajet´oria panorˆamica anterior a trˆes eventos de dura¸co˜es e freq¨ uˆencias distintas, e o sinal produzido no canal esquerdo e no canal direito, respectivamente. 1 1 sinal pandir envel 0.8 sinal panesq envel 0.8 0.6 0.6 0.4 0.4 0.2 0.2 0 0 -0.2 -0.2 -0.4 -0.4 -0.6 -0.6 -0.8 -0.8 0 50 100 150 200 250 300 350 400 450 0 50 100 150 200 250 300 350 400 450 Quando C = 1, aplicaremos o ajuste descrito pela trajet´oria panorˆamica ao canal 1 (esquerdo), que ´e o u ´nico canal dispon´ıvel7 . A sa´ıda do exemplo acima, se fosse mono, corresponderia ao gr´afico da esquerda. Ainda podemos pensar em espacializa¸ca˜o neste caso: o gr´afico representa afastamentos e aproxima¸co˜es do evento sonoro. Os valores γ da trajet´oria panorˆamica podem ser calculados utilizando o mesmo mecanismo do oscilador por consulta a tabela, por´em com parˆametros distintos, como descrito a seguir. Durante o processamento do evento j, a freq¨ uˆencia utilizada na gera¸ca˜o da trajet´oria panorˆamica deve ser R/Dj ; isso determinar´a uma velocidade de varredura que far´a com que o oscilador leve Dj amostras (ou ainda Dj /R ≈ dj segundos) para percorrer a tabela da trajet´oria panorˆamica. Observe que o ´ındice fracion´ario utilizado na varredura da trajet´oria panorˆamica deve ser independente do ´ındice fracion´ario da gera¸ca˜o do sinal (ou seja, deve ser uma outra vari´avel), pois as velocidades de varredura destas tabelas s˜ao diferentes. Note ainda que o ´ındice fracion´ario da trajet´oria panorˆamica deve valer 0 no in´ıcio de cada novo evento sonoro. A freq¨ uˆencia de varredura R/Dj “quase” garante que isso aconte¸ca automaticamente, por´em a imprecis˜ao da representa¸ca˜o float garante que o valor do ´ındice ao final de um evento “quase nunca” ´e exatamente zero; por esta raz˜ao o seu programa deve zerar o ´ındice fracion´ario da trajet´oria panorˆamica no in´ıcio de cada novo evento sonoro. Modo de depura¸ c˜ ao O seu programa deve funcionar de duas maneiras: no modo de depura¸ca˜o ou no modo normal. Quando no modo de depura¸ca˜o, o seu programa deve imprimir na tela algumas informa¸co˜es: • no in´ıcio da execu¸ca˜o, seu programa deve imprimir os valores de R, B e C, os valores de w0 , . . . , wNw −1 , os valores de p0 , . . . , pNp −1 , os valores de dj , fj e aj para os eventos j = 0, . . . , Ne − 1 e o n´ umero de amostras que ser˜ao produzidas no total; 7 Os softwares que tocam arquivos WAVE normalmente duplicam o sinal de arquivos mono, de tal forma que escutamos o mesmo sinal nas duas caixas. 8 • no ´ınicio do processamento de cada evento, seu programa deve imprimir uma mensagem informando o n´ umero do evento processado e quantas amostras ser˜ao produzidas para esse evento; • para cada amostra gerada, seu programa deve imprimir os valores α, β e γ correspondentes a` gera¸ca˜o de sinal, ao envelope dinˆamico e a` trajet´oria panorˆamica, respectivamente. Al´em destes deve imprimir tamb´em, para cada canal, o valor inteiro devolvido pela fun¸ca˜o escreve_amostra, descrita na pr´oxima se¸ca˜o. O que seu programa dever´ a fazer Vocˆe deve escrever um programa em C que leia um arquivo de entrada textual contendo as informa¸co˜es espec´ıficas do in´ıcio do enunciado, e gere o arquivo WAVE correspondente a esta entrada. Para o c´alculo do valor de ajuste do controle panorˆamico, vocˆe deve utilizar as fun¸co˜es sin(x) e cos(x) da biblioteca de fun¸co˜es matem´aticas (#include). Sua fun¸ca˜o principal deve 1. perguntar ao usu´ario se ele quer que o seu programa execute em modo normal (para padronizar a entrada, ele deve digitar 0 neste caso) ou em modo de depura¸ca˜o (ele deve digitar 1 neste caso); se o usu´ario escolher o modo de depura¸ca˜o, o seu programa dever´a imprimir todas as informa¸co˜es descritas na se¸ca˜o Modo de depura¸c˜ ao, durante o processamento; 2. ler os nomes dos arquivos de entrada (.txt) e sa´ıda (.wav) do teclado, utilizando os comandos scanf("%s", entrada) e scanf("%s", saida); para isso declare duas vari´aveis char entrada[20], saida[20]; (Note a ausˆencia do s´ımbolo & nestas leituras.) 3. abrir o arquivo de entrada com arq_entrada = fopen(entrada, "r"); e ler dele as informa¸co˜es de taxa de amostragem, n´ umero de bits por amostra e n´ umero de canais; al´em disso vocˆe deve ler o valor de Nw e armazenar a forma de onda b´asica em um vetor chamado float w[MAX]; depois disso ler o valor de Np e armazenar a trajet´oria panorˆamica em um vetor chamado float p[MAX]; e finalmente ler o valor de Ne e armazenar a lista de eventos em uma matriz chamada float e[MAX][3]; Vocˆe n˜ao precisa testar se Nw , Np e Ne s˜ao menores que MAX. Por comodidade, utilize as defini¸co˜es 9 #define PI 3.141593 #define MAX 4096 /* tamanho maximo dos vetores */ #define DUR 0 /* primeira coluna da matriz evento */ #define FRQ 1 /* segunda coluna da matriz evento */ #define AMP 2 /* terceira coluna da matriz evento */ 4. calcular o n´ umero de amostras total, abrir o arquivo de sa´ıda com arq_saida = fopen(saida, "wb"); e gerar o cabe¸calho da sa´ıda usando a fun¸ca˜o escreve_cabecalho_wav (output, R, B, C, num_amostras); dispon´ıvel no endere¸co http://www.ime.usp.br/~mac2166/ep4/cabecalho. 5. gerar as listas de amostras para cada evento j em {0, . . . , Ne − 1}. No seu programa, vocˆe deve implementar e usar, obrigatoriamente, as seguintes fun¸co˜es: • float oscilador (float *indice, float frequencia, float tab[MAX], int Ntab, int R); Esta fun¸ca˜o corrige o *indice fracion´ario atual, se necess´ario, para garantir que esteja na faixa apropriada [0, Ntab), devolve o valor interpolado da tabela tab correspondente ao *indice e atualiza o valor *indice, de acordo com a frequencia, o tamanho Ntab da tabela tab e a taxa de amostragem R. Esta fun¸ca˜o ser´a usada em dois contextos distintos: para gerar o valor α correspondente ao sinal de a´udio (repeti¸co˜es da forma b´asica de onda) e para gerar o valor γ da trajet´oria panorˆamica. • float envelope (float fracao, float amp_inicial, float amp_final); Esta fun¸ca˜o recebe uma fracao (n´ umero real entre 0 e 1) correspondente a` posi¸ca˜o da amostra atual em rela¸ca˜o a` dura¸ca˜o total do evento atual (este ´e o valor Dkj da se¸ca˜o Ajuste do volume de sa´ıda do oscilador) e devolve o valor β interpolado entre amp_inicial e amp_final. • int escreve_amostra (FILE *output, float amostra, int B); Esta fun¸ca˜o recebe um n´ umero real amostra entre −1 e 1 e converte este n´ umero para um inteiro valor na faixa adequada, dependendo do n´ umero B de bits. A faixa adequada para B = 8 ´e (−127, . . . , +127), enquanto que, para B = 16, ´e (−32767, . . . , +32767); desconsideramos os valores −128 e −32768 para manter a simetria da representa¸ca˜o. A convers˜ao deve utilizar a t´ecnica de arredondamento, que consiste em aproximar o valor fracion´ario x por (int)(x+0.5) se x ≥ 0 ou por (int)(x-0.5) se x < 0. A fun¸ca˜o ent˜ao escreve no arquivo cuja referˆencia ´e output o c´odigo que representa o valor calculado, como explicado na observa¸ca˜o 4 da se¸ca˜o Formato de arquivos WAVE. Esta fun¸ca˜o devolve valor. 10 Execut´ avel e conversor de WAVE para texto Durante a depura¸ca˜o, vocˆe naturalmente vai querer olhar o conte´ udo do arquivo WAVE gerado pelo seu programa, e compar´a-lo com outros arquivos WAVE; como estes n˜ao s˜ao arquivos de texto, mas sim arquivos bin´arios, eles n˜ao podem ser visualizados de maneira adequada por processadores de texto usuais. Para ajudar, disponibilizamos um programa, que chamamos de wav2txt, para exibir o conte´ udo de arquivos WAVE em formato de texto; ele exibe as principais informa¸co˜es do cabe¸calho e tamb´em os valores das amostras usando a nota¸ca˜o usual, an´aloga a` utilizada no modo de depura¸ca˜o do seu programa. O execut´avel wav2txt est´a dispon´ıvel no endere¸co http://www.ime.usp.br/~mac2166/ep4/wav2txt. Os execut´aveis do EP encontram-se em http://www.ime.usp.br/~mac2166/ep4/executaveis. Estes programas est˜ao dispon´ıveis nos sabores Windows e Linux. No endere¸co http://www.ime.usp.br/~mac2166/ep4/entradas est˜ao dispon´ıveis v´arios arquivos de entrada para teste. Alguns destes s˜ao pequenos e por isso convenientes para a fase de depura¸ca˜o do seu programa. Outros s˜ao mais longos e por isso interessantes de ouvir com algum software de a´udio. Vocˆe pode criar outros arquivos de entrada e disponibiliz´a-los no f´orum de discuss˜ao do EP4, no site da disciplina. Bom trabalho e divirta-se! 11