Sintetizador sonoro que toca redez vouz 4

Publicado por Matth (última atualização em 09/02/2016)

[ Hits: 1.826 ]

Download sound.c




Recentemente obtive ajuda do grande Paulo no tópico:

https://www.vivaolinux.com.br/topico/C-C++/Alguma-forma-de-criar-equivalentes-ao-sound-da-conioh-com...

Então, para divulgar a ideia de se usar as bibliotecas ao.h para gerar saída de áudio, decidi melhorar um pouco as coisas já que pretendo ainda escrever uma biblioteca para um sintetizador mais aprimorado.

Enquanto não crio coragem para isso, trago aqui um script em C que toca, ou pelo menos tenta, Render Vous 4(Jarre).

Experimentem brincar com as constantes no início do código e verão que o timbre pode ser modificado de várias maneiras. Não coloquem valores muito grandes em nenhuma das amplitudes, a menos que desejem ficar surdos.

  



Esconder código-fonte

#include <ao/ao.h>
#include <math.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>


//*constantes e variáveis globais para sintetizar a onda, modifique a vontade para ver o que acontece(não coloque valores muito altos >(5) nas amplitudes de cada onda):

const double s1=2, s2=0, s3=0; //Constantes que aplicam sobre os senos
const double c1=0, c2=0, c3=0; // Constantes ' '   '   '   '   '  cossenos
const double sa=0, sd=0.33333333; //modulam senóides em defasagem
const double ca=1, cd=0.66666666; //ca=amplitude, cd=defazagem de 0 (0) até 1 (2pi)
const double sq=0.5; // amplitude da onda quadrada
double m1=-0.0005; //modificador de frequência diminuindo-a se negativo e dando acréscimo se positivo
const double t1=1, t2=0; //onda triangular, t1 está a 90 graus de defazagem com t2 (que são suas amplitudes)
const double r1=0.5, r2=0; //constante para ondas rampa defasadas 90 similarmente
double fi=1; //fade in para entrada da nota, o quão suavemente a nota chega
double fo=2.5; //fade out para nota.
double tr=0, tf=0; //amplitude de tremulação e sua frequencia(não está em hertz)
double A=80; //amplitude

//*************************************************


                           //                             ---
double square(double wt){ ///Gera onda de pulso quadrado |   |    |
                                           //                 ----
        int n=0;
        while(wt-n*2*M_PI>0){n++;}//calculando o resto de wt/2pi

        double r=(wt-(n-1)*(2*M_PI))/(2*M_PI);//resto
    
        if (r<=0.5){
            return 1;
            
        }else{
            return -1;
        }
    
    
    
}
                                                    //               /\     */
double triang(double wt){ //função para gerar ondas triangulares    /  \    */
                                      //                 ----
        int n=0;
        while(wt-n*2*M_PI>0){n++;}//calculando o resto de wt/2pi

        double r=(wt-(n-1)*(2*M_PI))/(2*M_PI);//resto
    
        if(r>=0 && r<=0.5){ return (4*r-1)*0.5;}
        else{ return (-4*r+3)*0.5;}    
    
}

double ramp(double wt){ //função para gerar ondas na forma rampa(dente de serra) (/| /)
                                               //                / |/   ----
       int n=0;
        while(wt-n*2*M_PI>0){n++;}//calculando o resto de wt/2pi

        double r=(wt-(n-1)*(2*M_PI))/(2*M_PI);//resto
    
        return (4*r-1)*0.25;
         
           
    
}

static ao_device *sound_dev=NULL;

/*
  Uso: sound(frequencia, duracao);  // frequencia em Hz, duracao em segundos

  Equivalente ao seguinte código feito com funções declaradas em conio.h e dos.h:

    sound(frequencia);
    delay(duracao*1000);  // duracao em milissegundos
    nosound();
*/
void sound(double freq, double duration){
  static ao_sample_format format;
  static double sample_period;

  double w=2*M_PI*freq;

  if(!sound_dev){
    int default_driver;

    ao_initialize();
    default_driver = ao_default_driver_id();

    memset(&format, 0, sizeof(format));
    format.bits = 16;
    format.channels = 2;
    format.rate = 44100;
    format.byte_format = AO_FMT_BIG;

    sound_dev = ao_open_live(default_driver, &format, NULL);
    if(!sound_dev){
      fprintf(stderr, "Error opening sound device.\n");
      exit(1);
    }

    sample_period=1./(double)format.rate;
  }

  size_t n_frames=(size_t)(duration*format.rate);
  uint16_t *wave=malloc(format.channels*n_frames*sizeof *wave);
  double a=A;
  double traux=tr*tf/10000;
  
  
  for(size_t i=0; i<n_frames; i++){
    double wt=w*i*sample_period;
    
    
    //Função de modulação: ******************************************
    
    
    if(fi!=0 || fo!=0 ){ //modula a amplitude       
        a=(1-pow(2,-fi*i/10000))*pow(2,-fo*i/10000)*A;       
    }
    
    if(tr!=0){ //tremulação
        wt+=traux;        
    }
    
    int16_t sample=(int16_t)(a*((s1*sin(wt)+c1*cos(wt)+c2*cos(2*wt)+s2*sin(3*wt)+c3*cos(4*wt)+s3*sin(5*wt) + sa*sin(wt+sd*2*M_PI)+ca*cos(wt+cd*2*M_PI)) + 10*(t1*triang(wt) + t2*triang(wt+M_PI) + r1*ramp(wt)+r2*ramp(wt+M_PI)) + sq*square(wt)));
    if (m1!=0){   w+=m1;    }
    
     if(tr!=0){ //tremulação
         if(traux<tr && traux > -tr){
            traux+=tf; 
         }else if(traux>tr || traux < -tr){
            traux-=tf;
         }
    }
    

    
    
    //fim da modulação; ********************************************8
    
    
    
    
    for(int channel=0; channel<format.channels; channel++)
      wave[i*format.channels+channel]=sample;
  }

  ao_play(sound_dev, (char *)wave, format.channels*n_frames*sizeof *wave);

  free(wave);
}



double getnf(char n){
    
    /* Uso: getnf("c" ) retorna a frequência da primeira nota Dó. Para utilizar oitavas superiores pasta multiplicar a saída da função pelo número, por exemplo: queremos a nota D2, basta fazer 2*getnf('d'). 
     
     Para notas sustenidas, basta escrever o maiúsculo da nota correspondente, por exemplo, getnf("C") representa dó sustenido
     */
    
    int b;
    switch(n){
        
        case 'c':
            b=0;
            break;
        case 'C':
            b=1;
            break;
        case 'd':
            b=2;
            break;
        case 'D':
            b=3;
            break;
        case 'e':
            b=4;
            break;
        case 'E':
            b=5;
            break;
        case 'f':
            b=5;
            break;
        case 'F':
            b=6;
            break;
        case 'g':
            b=7;
            break;
        case 'G':
            b=8;
            break;
        case 'a':
            b=9;
            break;
        case 'A':
            b=10;
            break;
        case 'b':
            b=11;
            break;
        case 'B':
            b=12; 
            break;
        
    }
    double freq=2.72525*b+32.703;   //Frequecia do primeiro dó mais b vezes saltos de 2.72 que é a medida de um dozeavo do intervalo entre C1 e C2   

    return freq;
}



int main(){
int cord=0; //para coordenara música programada a la espagueti.
int end=1; //0 significa ultima vez
goto test;
intro:

sound(7*getnf('c'), 0.8);//C
sound(7*getnf('f'), 0.4);//F
sound(7*getnf('a'), 0.8);//A
sound(7*getnf('c'), 0.4);//C
sound(7*getnf('A'), 0.6);//A#
sound(7*getnf('a'), 0.3);//A
sound(7*getnf('c'), 0.8);//C
usleep(500000);
sound(7*getnf('f'), 0.3);//C
sound(7*getnf('A'), 0.6);//A#
sound(7*getnf('a'), 0.3);//A
sound(7*getnf('c'), 0.8);//C
fo=4;
sound(7*getnf('a'), 0.3);//A
usleep(100000);
fo=2.5;
sound(7*getnf('a'), 0.8);//A
fo=1.0;
fi=0.5;
sound(7*getnf('g'), 2);//G
fo=2.5;
fi=1;
if(cord==0 || cord==3){ cord++; goto intro; }

reflex:
cord++;
fo=3;
sound(7*getnf('c'), 0.4);
fo=1.0;
fi=0.5;
sound(7*getnf('f'), 1.8);
fi=1;
fo=2.5;
usleep(500000);
if(cord==2 || cord==5){ goto reflex; }
if(cord==3){ goto intro; }

climax1:
sound(7*getnf('e'), 0.4);//E
sound(7*getnf('f'), 0.4);//F
sound(7*getnf('e'), 0.4);//E
sound(7*getnf('f'), 0.4);//F
fo=2.0;
sound(7*getnf('d'), 1);//C
fo=2.5;
if(cord==6){ cord++; goto climax1; }

//transição
sound(7*getnf('e'), 0.4);//E
sound(7*getnf('f'), 0.4);//F
sound(7*getnf('e'), 0.4);//E
sound(7*getnf('f'), 0.4);//F
sound(7*getnf('A'), 0.6);
sound(7*getnf('a'), 0.6);
sound(7*getnf('g'), 0.6);
sound(7*getnf('f'), 0.6);
fo=2.0;
sound(7*getnf('e'), 1.2);
fo=2.5;

ending:
cord++;
fo=2.0;
sound(7*getnf('f'), 1.2);
fo=2.5;

end:
sound(7*getnf('g'), 0.4);
sound(7*getnf('a'), 0.4);
sound(7*getnf('A'), 0.4);
sound(7*getnf('a'), 0.4);
sound(7*getnf('g'), 0.4);
sound(7*getnf('a'), 0.4);
if(cord<10){goto ending;}

cord++;
sound(7*getnf('f'), 0.6);
sound(7*getnf('A'), 0.4);
sound(7*getnf('a'), 0.5);
sound(7*getnf('A'), 0.4);
sound(7*getnf('a'), 0.4);
if(cord<=13){goto end;}

fo=2.0;
sound(7*getnf('f'), 1.2);
fo=2.5;

if  (cord==14 && end){cord=0; end=0; goto intro;}
test:
m1=-0.01;
fo=0.2;
fi=1.5;
sound(7*getnf('c'), 1);
fo=1.5;
fi=3;
m1=0.0001;
sound(7*getnf('f'), 1.5);
fo=2.5;

return 0;

}

Scripts recomendados

Fractal Estocástico

Jogo Tetris em C - parte 3

Cor da letra

Calcular determinante de matrizes

Exibe quantos números perfeitos foram digitados


  

Comentários
[1] Comentário enviado por balani em 13/05/2016 - 13:40h

Código bacana! Ha um tempo que eu procurava algo assim.

Obrigado, pessoas como vc engrandecem a comunidade!


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts