Alguma forma de criar equivalentes ao sound() da conio.h com ncurses [RESOLVIDO]

1. Alguma forma de criar equivalentes ao sound() da conio.h com ncurses [RESOLVIDO]

Matth
MattF

(usa Slackware)

Enviado em 18/01/2016 - 23:43h

No windows foi fácil criar um código que tocasse rendez vouz 4 com as funções Beep e sound. Queria tentar fazer o mesmo no linux, mas pelo visto não há algo similar para a ncurses visto que a beep() disponível é bem rudimentar. Queria fazer um código que rodasse em qualquer linux, não sendo dependente de chamadas a função system, ou bibliotecas do OSS ou alsa. O idela seria alguma biblioteca que tivesse uma função permitindo a seleção da frequência do beep e sua duração.

Seria muito importante também a criação de sons simultâneos. Há alguma maneira portável de fazer isso?


  


2. MELHOR RESPOSTA

Paulo
paulo1205

(usa Ubuntu)

Enviado em 19/01/2016 - 04:23h

Um site bem interessante que eu achei foi https://jan.newmarch.name/LinuxSound/. Lendo lá, o que vi de mais simples para geração de sons à la ConIO foi a libao.

Usando a libao, você poderia fazer um arquivo “.c” mais ou menos com a seguinte cara, e incluí-lo no seu programa.

#include <ao/ao.h>

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;

const 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);
for(size_t i=0; i<n_frames; i++){
double wt=w*i*sample_period;
int16_t sample=(int16_t)(21365*(sin(wt)+sin(3*wt)*0.33333333333333+sin(5*wt)*.2));
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);
}


3. Re: Alguma forma de criar equivalentes ao sound() da conio.h com ncurses [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 19/01/2016 - 02:18h

Há um programa para Linux chamado Beep.
Ele usa exatamente os recursos da máquina que você deseja.
Ele trabalha com o módulo pcspkr do kernel.

Você pode baixar o código-fonte deste link: https://packages.debian.org/jessie/beep
É pouca coisa. Você estuda o código e cria um programa com partes dele.
Se bem que se você manjar de Física pode fazer o Beep tocar o que você desejar.

Você pode tentar instalar o Beep e ver se o módulo pcspkr está carregado para ver como ele é.

----------------------------------------------------------------------------------------------------------------
http://24.media.tumblr.com/tumblr_m62bwpSi291qdlh1io1_250.gif

# apt-get purge systemd

Encryption works. Properly implemented strong crypto systems are one of the few things that you can rely on. Unfortunately, endpoint security is so terrifically weak that NSA can frequently find ways around it. — Edward Snowden



4. Re: Alguma forma de criar equivalentes ao sound() da conio.h com ncurses [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 19/01/2016 - 12:28h

Legal. Vou anotar.

----------------------------------------------------------------------------------------------------------------
http://24.media.tumblr.com/tumblr_m62bwpSi291qdlh1io1_250.gif

# apt-get purge systemd

Encryption works. Properly implemented strong crypto systems are one of the few things that you can rely on. Unfortunately, endpoint security is so terrifically weak that NSA can frequently find ways around it. — Edward Snowden



5. Re: Alguma forma de criar equivalentes ao sound() da conio.h com ncurses

Matth
MattF

(usa Slackware)

Enviado em 19/01/2016 - 14:40h

O programa beep simplesmente não fez nada aqui. Eu quero produzir audio para os auto-falantes mesmo. Estou otimista quanto a libao, mas ainda não consegui nada. A fim de de testá la deixei o código assim:


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

static ao_device static 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;

const double w=2*M_PI*freq;

if(!sound_dev){
int default_driver;

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);
for(size_t i=0; i<n_frames; i++){
int16_t sample=(int16_t)(32767*sin(w*(i*sample_period)));
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);
}


int main(){

sound(440, 2);

}



Enfim, só coloquei algumas bibliotecas para que reconhecesse M_PI e tal. O problema esta sendo que quando tento compilar tenho alguns problemas:


$ gcc sound.c -lao -ldl -lm -o sound
sound.c:6:1: error: variable ‘sound_dev’ has initializer but incomplete type
static ao_device sound_dev = NULL;
^
sound.c: In function ‘sound’:
sound.c:23:3: error: ‘sound_dev’ has an incomplete type
if(!sound_dev){
^
sound.c:34:5: error: ‘sound_dev’ has an incomplete type
sound_dev = ao_open_live(default_driver, &format, NULL);
^
sound.c:35:5: error: ‘sound_dev’ has an incomplete type
if(!sound_dev){
^
sound.c:51:3: error: ‘sound_dev’ has an incomplete type
ao_play(sound_dev, (char *)wave, format.channels*n_frames*sizeof *wave);


Na verdade 1 problema com aquela linha( static ao_device sound_dev = NULL;)o resto decorre disso. Há algum problema na importação a biblioteca ao ou pode ser alguma outra coisa? Fico grato.


6. Re: Alguma forma de criar equivalentes ao sound() da conio.h com ncurses

Paulo
paulo1205

(usa Ubuntu)

Enviado em 19/01/2016 - 22:16h

Erro meu. A declaração de sound_dev deve ser como ponteiro, isto é:

static ao_device *sound_dev=NULL; 


Editei minha primeira postagem para corrigir o exemplo.

Note, porém, que eu não testei aquele código, mas o escrevi diretamente no fórum. Eu procurei deixar claro que era um exemplo só para dar uma ideia geral de como a coisa poderia ficar. É possível que haja outros erros.


7. Re: Alguma forma de criar equivalentes ao sound() da conio.h com ncurses [RESOLVIDO]

Matth
MattF

(usa Slackware)

Enviado em 19/01/2016 - 23:46h

Sei que é era só um exemplo, mas fui testar o código na parte do libao no site que você sitou e tive uma baita dor de cabeça. Acho que está mais fácil de arrumar o esse. Agora ele compilou sem erro, mas tive um baita de um segmentation fault ao executar.

Continuo a insistir aqui porque levo a programação somente como um hobby que ainda estou aprendendo( pelo menos tentando). Essa parte de mais baixo nível eu sou completamente leigo e por isso não consigo acompanhar muito bem aquilo tudo. Só precisava de uma maneira portável de criar beeps para um simples jogo para terminal que ando tentando desenvolver.

Enfim, deixei o código como você descreveu:



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

static ao_device* sound_dev = NULL;

void sound(double freq, double duration){
static ao_sample_format format;
static double sample_period;

const double w=2*M_PI*freq;

if(!sound_dev){
int default_driver;

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);
for(size_t i=0; i<n_frames; i++){
int16_t sample=(int16_t)(32767*sin(w*(i*sample_period)));
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);
}


int main(){

sound(440, 2);

}



E depois de compilar com o gcc com a opção -g, tive a saída de debug:

Starting program: sound
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7bd3d9d in ao_default_driver_id () from /usr/lib/x86_64-linux-gnu/libao.so.4
(gdb) quit



O que é SIGSEGV e o que será que pode estar errado?


8. Re: Alguma forma de criar equivalentes ao sound() da conio.h com ncurses

Paulo
paulo1205

(usa Ubuntu)

Enviado em 20/01/2016 - 10:55h

Faltou uma chamada a ao_initialize() antes de definir o driver default. Editei o código novamente para corrigir isso.

Além disso, na hora de calcular as amostras da forma de onda, incluí o terceiro e o quinto harmônicos, para deixá-la mais parecida com a onda quadrada dos velhos PCs, em vez de usar senoide pura.


9. Re: Alguma forma de criar equivalentes ao sound() da conio.h com ncurses [RESOLVIDO]

Matth
MattF

(usa Slackware)

Enviado em 20/01/2016 - 11:27h

paulo1205 escreveu:

Faltou uma chamada a ao_initialize() antes de definir o driver default. Editei o código novamente para corrigir isso.

Além disso, na hora de calcular as amostras da forma de onda, incluí o terceiro e o quinto harmônicos, para deixá-la mais parecida com a onda quadrada dos velhos PCs, em vez de usar senoide pura.


Agora você falou minha língua. Se funcionar vou tentar editar aquela senoide para tentar imitar o timbre de um piano, que é o mais simples na minha opinião.


10. Re: Alguma forma de criar equivalentes ao sound() da conio.h com ncurses [RESOLVIDO]

Matth
MattF

(usa Slackware)

Enviado em 20/01/2016 - 11:35h

Agora funcionou, mas o que tive não foi um beep simples. Quando puder vou tentar em outro computador porque acho que agora é um problema mas no meu som mesmo. O som saiu, mas estava mais para um white noise, não importando a frequência que eu colocasse. Você testou já testou isso ai? ficou um beep bonitinho? Vou tentar dar umas editadas aqui, quando poder me dá um help aqui.


11. Re: Alguma forma de criar equivalentes ao sound() da conio.h com ncurses

Matth
MattF

(usa Slackware)

Enviado em 20/01/2016 - 13:54h

haha!, muito bom!

Consegui após modificar um pouquinho da onda. Testem só meu resultado:

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


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;

const 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);
for(size_t i=0; i<n_frames; i++){
double wt=w*i*sample_period;
int16_t sample=(int16_t)(100*(sin(wt)+sin(3*wt)*0.33333333333333+cos(5*wt)*.2));
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);
}

int main(){

sound(440, 0.6);//C
sound(623, 0.3);//F
sound(770, 0.6);//A
sound(440, 0.3);//C
sound(806, 0.6);//A#
sound(770, 0.3);//A
sound(440, 0.6);//C
usleep(500000);
sound(440, 0.3);//C
sound(806, 0.6);//A#
sound(770, 0.3);//A
sound(440, 0.6);//C
sound(770, 0.3);//A
usleep(500000);
sound(770, 0.6);//A
sound(696, 0.6);//G


}





Em breve coloco a música completa na seção de scripts. Vou só implementar para obter notas de uma maneira mais simples(vou fazer uma função para isso) e encontrar uma onda mais legal para dar um som melhor.


12. Re: Alguma forma de criar equivalentes ao sound() da conio.h com ncurses [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 22/01/2016 - 00:23h

Suas frequências não correspondem às notas. Normalmente, 440Hz é a frequência do lá (A), não do dó (C).

Como você deve saber, a escala temperada usa intervalos para cada semitom que crescem numa progressão geométrica com razão 2^(1/12) (em C, pow(2.0, 1.0/12.0)), o que é aproximadamente igual a 1.0594630943593.

O seguinte programa imprime as frequências de todas as notas correspondentes às teclas de um piano.

#include <cmath>
#include <iomanip>
#include <iostream>


using namespace std;


int main(){
static const char *notes[]={"A", "Bb", "B", "C", "C#", "D", "Eb", "E", "F", "F#", "G", "Ab"};
double f=27.5;
int i=0;

while(i<88){
for(auto &e: notes){
cout << setw(2) << note << ": " << f*pow(2., i/12.) << '\n';
if(++i==88)
break;
}
}
}




01 02



Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts