E05 Polifonia com cordas
Na função tone() em PlayThatNote2.java dado abaixo, usamos uma senoide para criar o vetor a[] (esta função aparece também em PlayThatNote.java). Podemos usar algoritmos diferentes para criar sons com "timbres" diferentes. Por exemplo, podemos usar o algoritmo de Karplus e Strong, descrito brevemente a seguir.
Suponha que queremos gerar um som com tonalidade (frequência) hz e duração d. Crie um vetor a[] com capacidade para N + 1 doubles, onde N é a parte inteira de 44100 * d. Seja p a parte inteira de 44100/hz. Preencha as primeiras p posições de a[] com valores aleatórios sorteados no intervalo [-1, 1]. Para preencher as posições p até N do vetor a[], adote o seguinte algoritmo:
for (int i = p, j = 0; i <= N ; i++, j++)
a[i] = .997*(a[j] + a[j+1])/2;
O vetor a[] produzido dessa forma contém o som que podemos agora enviar para a saída de áudio executando StdAudio.play(a). Esse som terá a tonalidade dada por hz e duração dada por d.
A função wave(). Escreva uma função de assinatura
public static double[] wave(double hz, double d)
que devolve o vetor a[] obtido pelo processo descrito acima, isto é, obtido pelo algoritmo Karplus--Strong. A função wave() pode então ser usada no lugar de tone() em PlayThatTune2.java: substitua tone() em PlayThatTune2.java por wave() e chame esse novo programa de PlayThatTuneWave.java. Experimente executar PlayThatTuneWave.java usando como entrada os vários exemplos de S&W, também dados em
https://www.ime.usp.br/~yoshi/2021ii/ccm0118/sandbox/2021.09.22/DATA/MELODIES/
Observação. Você pode talvez achar melhor trocar a linha
double hz = 440 * Math.pow(2, pitch / 12.0);
por
double hz = 220 * Math.pow(2, pitch / 12.0);
em PlayThatTuneWave.java (as melodias ficarão uma oitava abaixo).
Variantes de Karplus--Strong. No algoritmo Karplus--Strong, você pode alterar o modo como a[i] é calculado. Por exemplo, experimente ver o que ocorre se usamos
a[i] = .997*(19*a[j] + a[j+1])/20;
ou
a[i] = .997*(a[j] + a[j+3])/2;
ou
a[i] = .997*(9*a[j] + a[j+5])/10;
ou
a[i] = .997*(8*a[j] + a[j+2] + a[j+8])/10;
etc.
Seu programa PlayThatChordDeluxe.java. Escreva uma versão incrementada de PlayThatChord.java, digamos PlayThatChordDeluxe.java, como segue. Seu programa PlayThatChordDeluxe.java deve usar a função wave() que você implementou acima em vez de tone(), que é usada em PlayThatChord.java. Além disso, PlayThatChordDeluxe.java deve tocar melodias, como PlayThatTune2.java ou PlayThatTuneWave.java.
Seu PlayThatChordDeluxe.java deve receber a entrada na entrada padrão. Cada linha de entrada (não vazia) deverá ser constituída de um certo número (positivo) de inteiros e um número real. Os inteiros indicam a tonalidade das notas a serem tocadas simultaneamente. O número real indica a duração dessas notas.
Por exemplo, os arquivos elise_fixed.txt ou looney.txt poderiam ser dados como entrada para seu programa PlayThatChordDeluxe.java, das seguintes formas:
$ java-introcs PlayThatChordDeluxe 1 < elise_fixed.txt
$ java-introcs PlayThatChordDeluxe 1.5 < elise_fixed.txt
$ java-introcs PlayThatChordDeluxe 1 < looney.txt
As execuções acima devem ser equivalentes às execuções
$ java-introcs PlayThatTuneWave 1 < elise_fixed.txt
$ java-introcs PlayThatTuneWave 1.5 < elise_fixed.txt
$ java-introcs PlayThatTuneWave 1 < looney.txt
Por outro lado, seu PlayThatChordDeluxe.java deve também aceitar entradas como Ascale2.txt dado abaixo. Nesse caso, várias notas são tocadas simultaneamente. Você pode ouvir o som esperado tocando o arquivo Ascale2.m4a abaixo.
Sugestão. Para ler uma linha da entrada padrão, use StdIn.readLine(). Se s é do tipo String, faça
s = s.trim();
para jogar fora os espaços no começo e no fim de s. Faça
String[] t = s.split("\\s+");
para "decompor s" nos strings sem espaço que compõe s (e são separados por espaços).
Observação. Você pode achar interessante visitar
https://en.wikipedia.org/wiki/Karplus%E2%80%93Strong_string_synthesis
Entrega. Entregue seus programas PlayThatTuneWave.java e PlayThatChordDeluxe.java.
- 28. September 2021, 22:16
- 28. September 2021, 22:08