Dúvida Karplus-Strong

Dúvida Karplus-Strong

por Gabriel Sarti Massukado -
Número de respostas: 6

Olá! Estou com uma dúvida mais teórica na implementação da função perform do algoritmo.

Não estou entendendo exatamente como iterar pelas amostras geradas aleatóriamente. A ideia do algoritmo é iterar pelos L valores gerados aleatoriamente aplicando o filtro passa-baixas D*R vezes aproximadamente?

Como exatamente isso se relaciona com a frequência fundamental F? Ela é usada apenas para calcular L?

Obrigado!

Em resposta à Gabriel Sarti Massukado

Re: Dúvida Karplus-Strong

por Nicolas Figueiredo -
Oi Gabriel,

O algoritmo de Karplus-Strong é primeiramente "alimentado" com L amostras aleatórias (o "noise burst" no esquema do enunciado), que são copiadas no vetor de saída sem serem filtradas nem atrasadas. Depois disso, o que é usado como entrada do algoritmo é a própria saída (retroalimentação), porém essa saída é atrasada em L amostras e filtrada com um passa-baixas, como mostra o esquema. A dica de implementação do enunciado é primeiramente inicializar um ofTable() com L amostras aleatórias, e fazer o processamento dessa tabela amostra por amostra, a lendo ciclicamente e escrevendo em cima das amostras lidas a saída calculada (que depois das L amostras iniciais será a equação do filtro). Como o processamento é cíclico e esse ciclo demora L amostras para se repetir, o período da nota escutada é igual a L/R segundos, ou seja, a frequência escutada é de R/L Hertz.
Em resposta à Nicolas Figueiredo

Re: Dúvida Karplus-Strong

por Gabriel Sarti Massukado -
Acho que entendi... A função perform deve necessariamente ser chamada várias vezes ou seria melhor usar um ofArray correspondente a um array no pd para os resultados do algoritmo?
Em resposta à Gabriel Sarti Massukado

Re: Dúvida Karplus-Strong

por Marcelo Queiroz -

A função perform não deve ser chamada pelo nosso código: ela é chamada automaticamente pelo kernel do Pd a cada ciclo DSP (64 amostras). Não é possível usar nenhum ofArray(), pois isso serve para o acesso a um vetor no patch Pd, algo que é na verdade uma interface gráfica e que não faz parte da nossa implementação. Temos que fazer toda a computação em tabelas internas ao código em Lua, ou seja, tanto a tabela KS de tamanho L quanto a tabela de tamanho 64 devolvida pela função perform têm que ser ofTable()'s. Lembrem-se sempre que a indexação dessas tabelas começa em 1.

Detalhando um pouco mais a dica do Nicolas, podemos pensar na tabela do KS como o nosso espaço de trabalho principal para a produção do sinal de saída, e só nos preocuparmos em copiar o conteúdo de lá para o outro vetor de tamanho 64 devolvido pela função perform. Existem muitas maneiras de coordenar esse processo: podemos ir atualizando as amostras da tabela KS uma a uma à medida que também copiamos os valores para o bloco de saída, mas também poderíamos atualizar a tabela inteira de uma vez a cada L amostras, ou seja, a cada vez que completarmos um ciclo do algoritmo KS.

Sobre a periodicidade da saída, como parte do processo de codificação/depuração vocês podem experimentar ouvir o que seria a saída do KS sem o filtro passa-baixa: seria um sinal harmônico com frequência R/L Hz que teria a mesma altura musical de um oscilador puro com essa mesma frequência, apenas teria um timbre diferente (pois possui a forma de onda dos valores aleatórios da inicialização). Com o filtro passa-baixa o loop do KS fica um pouquinho mais comprido (L+0.5 amostras), como explicado no enunciado, então o som resultante pode ser comparado com um oscilador de frequência R/(L+0.5) Hz. A discrepância entre essa frequência observada de fato e a frequência F especificada na mensagem pode ser percebida facilmente se usarmos valores altos de F (valores pequenos de L): por exemplo, para F=1000 Hz teremos L=44, sendo que a saída do KS da primeira fase terá como frequência fundamental 1000/44.5 = 991 Hz, uma diferença de quase 1%, perceptível principalmente pelos batimentos em relação a um oscilador afinado em 1000 Hz.

Também é possível depurar a duração da saída colocando um [delay] com o valor D*R para checar se ele é acionado quando o som termina.

Em resposta à Marcelo Queiroz

Re: Dúvida Karplus-Strong

por Diego Ignacio Zurita Rojas -
Pra ver se ficou claro, na função ofelia.perform() devemos retornar uma tabela de tamanha 64 e não de tamanho L, correto?
Em resposta à Diego Ignacio Zurita Rojas

Re: Dúvida Karplus-Strong

por Marcelo Queiroz -
> Pra ver se ficou claro, na função ofelia.perform() devemos retornar uma tabela de tamanha 64 e não de tamanho L, correto?

Exato!