Sintetizando notas musicais

C / C++Linux
Enviado por thotypous em Seg, 05/06/2006 - 18:42.C / C++ | Linux

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.

  1.  
  2. /*
  3. * Musical Note Synthesizer
  4. * Copyright (c) 2006 Paulo Matias
  5. *
  6. * This program is free, under the terms of GPLv2.
  7. *
  8. */
  9.  
  10. #include <math.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13.  
  14. int pos_note[256];
  15.  
  16. #define NOTE_FACTOR ((double)1.059463094359295264561825294946341700779204317494)
  17. #define FIRST_A_FREQ ((double)27.500000000000000)
  18.  
  19. /* presume 8000 samples/second, mono, 8 bits/sample */
  20. int main(int argc, char **argv) {
  21.    
  22.     double f, freq, scale;
  23.     int i, j, durat;
  24.     char note;
  25.    
  26.         /* initializes the note conversion table with the note scale.
  27.          * lowcase letters are # notes.
  28.          */
  29.     memset(pos_note, 0, sizeof(pos_note));
  30.     pos_note['A'] = 0;
  31.     pos_note['a'] = 1;
  32.     pos_note['B'] = 2;
  33.     pos_note['C'] = 3;
  34.     pos_note['c'] = 4;
  35.     pos_note['D'] = 5;
  36.     pos_note['d'] = 6;
  37.     pos_note['E'] = 7;
  38.     pos_note['F'] = 8;
  39.     pos_note['f'] = 9;
  40.     pos_note['G'] = 10;
  41.     pos_note['g'] = 11;
  42.        
  43.     for(i = 1; i < argc; i+=2)
  44.     {
  45.        
  46.         note = argv[i][0];
  47.         durat = round(1000*atof(argv[i+1]));
  48.  
  49.         if(note == 'P') {
  50.             freq = 0;
  51.             fprintf(stderr, "Pause (");
  52.         }
  53.         else {
  54.             scale = (double)atoi(argv[i]+1);
  55.             freq = FIRST_A_FREQ * pow(NOTE_FACTOR, 12*scale + pos_note[note]);
  56.             fprintf(stderr, "%d Hz (", (int)round(freq));
  57.         }
  58.        
  59.         fprintf(stderr, "%d ms)\n", durat);
  60.        
  61.                 /* puts on stdout a senoid of frequency freq */
  62.        for(f = 0.0, j = 0; j < durat*8; j++, f += 6.28/8000.0*freq)
  63.             putchar(sin(f)*126.0 + 128);
  64.     }
  65. }
  66.  

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