Sintetizador sonoro que toca redez vouz 4
Publicado por Matth (última atualização em 09/02/2016)
[ Hits: 2.000 ]
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.
#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; }
Enviar mensagem ao usuário trabalhando com as opções do php.ini
Meu Fork do Plugin de Integração do CVS para o KDevelop
Compartilhando a tela do Computador no Celular via Deskreen
Como Configurar um Túnel SSH Reverso para Acessar Sua Máquina Local a Partir de uma Máquina Remota
Configuração para desligamento automatizado de Computadores em um Ambiente Comercial
Compartilhamento de Rede com samba em modo Público/Anônimo de forma simples, rápido e fácil
Cups: Mapear/listar todas as impressoras de outro Servidor CUPS de forma rápida e fácil
Criando uma VPC na AWS via CLI
Tem como instalar o gerenciador AMD Adrenalin no Ubuntu 24.04? (6)