Eu estava precisando de um programa para gerar uma lista de freqüências a partir de um conjunto de notas musicais, e sintetizar essas freqüências na caixa de som do computador, para testar como a música iria ficar.
Criei então um programa em C que calcula a freqüência de cada nota musical, e depois sintetiza esse som, que pode ser jogado diretamente em /dev/dsp.
Se você está curioso em como se faz para calcular a freqüência de uma nota musical, ou como sintetizar uma freqüência na caixa de som, vale a pena conferir.
A escala musical de freqüências é exponencial. Precisamos apenas saber a posição da nota na escala e aplicar a fórmula que é mostrada no programa abaixo.
Para sintetizar a freqüência, geramos um senóide de freqüência freq, ou seja, que se repete a cada tempo 1/freq.
/*
* Musical Note Synthesizer
* Copyright (c) 2006 Paulo Matias
*
* This program is free, under the terms of GPLv2.
*
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int pos_note[256];
#define NOTE_FACTOR ((double)1.059463094359295264561825294946341700779204317494)
#define FIRST_A_FREQ ((double)27.500000000000000)
/* presume 8000 samples/second, mono, 8 bits/sample */
int main(int argc, char **argv) {
double f, freq, scale;
int i, j, durat;
char note;
/* initializes the note conversion table with the note scale.
* lowcase letters are # notes.
*/
memset
(pos_note,
0,
sizeof(pos_note
));
pos_note['A'] = 0;
pos_note['a'] = 1;
pos_note['B'] = 2;
pos_note['C'] = 3;
pos_note['c'] = 4;
pos_note['D'] = 5;
pos_note['d'] = 6;
pos_note['E'] = 7;
pos_note['F'] = 8;
pos_note['f'] = 9;
pos_note['G'] = 10;
pos_note['g'] = 11;
for(i = 1; i < argc; i+=2)
{
note = argv[i][0];
durat =
round(1000*atof
(argv
[i+
1]));
if(note == 'P') {
freq = 0;
fprintf(stderr, "Pause (");
}
else {
scale = (double)atoi(argv[i]+1);
freq = FIRST_A_FREQ *
pow(NOTE_FACTOR,
12*scale + pos_note
[note
]);
fprintf
(stderr,
"%d Hz (",
(int
)round(freq
));
}
fprintf(stderr, "%d ms)\n", durat);
/* puts on stdout a senoid of frequency freq */
for(f = 0.0, j = 0; j < durat*8; j++, f += 6.28/8000.0*freq)
putchar
(sin(f
)*
126.
0 +
128);
}
}
O programa deve receber como parâmetros uma lista de notas seguidas de sua duração em segundos. Por exemplo:
./freq C4 .2 D4 .2 E4 .2 F4 .2 P .2 F4 .1 P .1 F4 .1 > /dev/dsp