Aprendendo Allegro 5
Início Janela Imagens Mensagem Fontes e texto Eventos Mouse Teclado Audio Timer Animações Sprites Jogo exemplo

Manipulando audio

Nesta lição iremos aprender como carregar arquivos de audio para nossos programas. As utilidades vão desde adicionar músicas de fundo até utilizar efeitos sonoros sob determinadas condições do programa.

No programa em questão, colocaremos na janela dois retângulos, um azul e um vermelho. Quando o usuário clica um deles um efeito sonoro diferente para cada um é reproduzido. Enquanto isso, uma música de fundo é tocada em repetição.

#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_audio.h>
#include <allegro5/allegro_acodec.h>

#define LARGURA_TELA 640
#define ALTURA_TELA 480

ALLEGRO_DISPLAY *janela = NULL;
//samples que guardam os efeitos sonoros
ALLEGRO_SAMPLE *som_azul=NULL;
ALLEGRO_SAMPLE *som_verm=NULL;
//musica de fundo
ALLEGRO_AUDIO_STREAM *musica = NULL;
ALLEGRO_BITMAP *bitmap_azul = NULL;
ALLEGRO_BITMAP *bitmap_verm = NULL;
ALLEGRO_EVENT_QUEUE *fila_eventos = NULL;

void error_msg(char *text){
	al_show_native_message_box(NULL,"ERRO",
		"Ocorreu o seguinte erro e o programa sera finalizado:",
		text,NULL,ALLEGRO_MESSAGEBOX_ERROR);
}

int inicializar(){
    if(!al_init()){
        error_msg("Falha ao inicializar a Allegro");
        return 0;
    }

    //addon de audio
    if(!al_install_audio()){
        error_msg("Falha ao inicializar o audio");
        return 0;
    }

    //addon que da suporte as extensoes de audio
    if(!al_init_acodec_addon()){
        error_msg("Falha ao inicializar o codec de audio");
        return 0;
    }

    //cria o mixer (e torna ele o mixer padrao), e adciona 5 samples de audio nele
    if (!al_reserve_samples(5)){
        error_msg("Falha ao reservar amostrar de audio");
        return 0;
    }

    //carrega os samples
    som_verm = al_load_sample( "wololo.ogg" );
    if (!som_verm){
        error_msg( "Audio nao carregado" );
        return 0;
    }
    som_azul = al_load_sample( "aiao.ogg" );
    if (!som_azul){
        error_msg( "Audio nao carregado" );
        al_destroy_sample(som_verm);
        return 0;
    }

    //carrega o stream
    musica = al_load_audio_stream("soundtrack.ogg", 4, 1024);
    if (!musica)
    {
        error_msg( "Audio nao carregado" );
        al_destroy_sample(som_azul);
        al_destroy_sample(som_verm);
        return 0;
    }
    //liga o stream no mixer
    al_attach_audio_stream_to_mixer(musica, al_get_default_mixer());
    //define que o stream vai tocar no modo repeat
    al_set_audio_stream_playmode(musica, ALLEGRO_PLAYMODE_LOOP);

    janela = al_create_display(LARGURA_TELA, ALTURA_TELA);
    if(!janela){
        error_msg("Falha ao criar janela");
        al_destroy_sample(som_azul);
        al_destroy_sample(som_verm);
        al_destroy_audio_stream(musica);
        return 0;
    }

    if (!al_install_mouse()){
        error_msg("Falha ao inicializar o mouse");
        al_destroy_display(janela);
        return -1;
    }

    bitmap_azul = al_create_bitmap(30, 80);
    if (!bitmap_azul){
        error_msg("Falha ao criar bitmap");
        al_destroy_sample(som_azul);
        al_destroy_sample(som_verm);
        al_destroy_audio_stream(musica);
        al_destroy_display(janela);
        return 0;
    }
    al_set_target_bitmap(bitmap_azul);
    al_clear_to_color(al_map_rgb(0, 0, 255));

    bitmap_verm = al_create_bitmap(30, 80);
    if (!bitmap_verm){
        error_msg("Falha ao criar bitmap");
        al_destroy_sample(som_azul);
        al_destroy_sample(som_verm);
        al_destroy_audio_stream(musica);
        al_destroy_display(janela);
        al_destroy_bitmap(bitmap_azul);
        return 0;
    }
    al_set_target_bitmap(bitmap_verm);
    al_clear_to_color(al_map_rgb(255, 0, 0));

    al_set_target_bitmap(al_get_backbuffer(janela));

    fila_eventos = al_create_event_queue();
    if(!fila_eventos) {
        error_msg("Falha ao criar fila de eventos");
        al_destroy_sample(som_azul);
        al_destroy_sample(som_verm);
        al_destroy_audio_stream(musica);
        al_destroy_display(janela);
        al_destroy_bitmap(bitmap_azul);
        al_destroy_bitmap(bitmap_verm);
        return 0;
    }

    al_register_event_source(fila_eventos, al_get_mouse_event_source());
    al_register_event_source(fila_eventos, al_get_display_event_source(janela));
    al_clear_to_color(al_map_rgb(0,0,0));
    al_flip_display();

    return 1;
}

int main(){
    int sair=0;
    //vai guardar quando o mouse esta sobre a area de algum dos bitmaps
    //0=nenhum, 1=azul, 2=vermelho
    int area=0;

    if (!inicializar()){
        return -1;
    }

    al_clear_to_color(al_map_rgb(0,0,0));

    //desenha bitmaps que serao clicados
    al_draw_bitmap(bitmap_azul,50,50,0);
    al_draw_bitmap(bitmap_verm,150,50,0);

    al_flip_display();

    while (!sair){
        ALLEGRO_EVENT evento;
        al_wait_for_event(fila_eventos, &evento);

        if (evento.type == ALLEGRO_EVENT_MOUSE_AXES){
            //y entre 50 e 130 significa na altura dos bitmaps
            if (evento.mouse.y >= 50 && evento.mouse.y <= 130){
                //x entre 50 e 80 representa a area do bitmap azul
                if (evento.mouse.x >= 50 && evento.mouse.x <= 80)
                    area=1;
                //x entre 150 e 180 representa a area do bitmap vermelho
                else if (evento.mouse.x >= 150 && evento.mouse.x <= 180)
                    area=2;
                else
                    area=0;
            }
            else
                area=0;
        }
        else if (evento.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP){
            if (area==1)
                //toca som_azul uma vez
                al_play_sample(som_azul, 1.0, 0.0,1.0,ALLEGRO_PLAYMODE_ONCE,NULL);

            if (area==2)
                //toca som_verm uma vez
                al_play_sample(som_verm, 1.0, 0.0,1.0,ALLEGRO_PLAYMODE_ONCE,NULL);

        }
        else if (evento.type == ALLEGRO_EVENT_DISPLAY_CLOSE){
            sair = 1;
        }
    }

    al_destroy_sample(som_azul);
    al_destroy_sample(som_verm);
    al_destroy_audio_stream(musica);
    al_destroy_display(janela);
    al_destroy_bitmap(bitmap_azul);
    al_destroy_bitmap(bitmap_verm);
    al_destroy_event_queue(fila_eventos);
    return 0;
}

Nas linhas 3 e 4 fazemos include nas bibliotecasdos addons allegro_audio e allegro_acodec, que permitem que utilizemos as funções de audio do allegro.

Antes de detalhar o código, vou explicar um pouco sobre a estrutura do addon de audio do allegro.

O som que ouvimos é o produto de uma mistura de 1 ou mais componentes sonoros. Existem dois tipos de componentes sonores, o ALLEGRO_SAMPLE (amostra de som), e o ALLEGRO_AUDIO_STREAM (faixa de audio).

O sample é o tipo de som utilizado para produzir efeitos sonoros rápidos, e seu carregamento é feito de uma vez só, O audio stream é utilizado para guardar sons mais longos, como por exemplo músicas de fundo, e o carregamento do conteúdo da faixa é feita aos poucos do arquivo, na medida do necessário. Isto é interessante pois não ocupa desnecessariamente a memória.

Os samples e audio stream são misturados em um mixer do tipo ALLEGRO_MIXER, e o produto deste é um buffer com parâmetros como frequencia, volume, etc. ao longo do tempo que então é jogado para o hardware de saída e podemos ouvir.

ALLEGRO_SAMPLE

Na linha 11 e linha 12 criamos variáveis do tipo ALLEGRO_SAMPLE. Este tipo de variável serve para guardar um efeito sonoro. Estes dois samples serão rproduzidos quando o usuário clicar nos retângulos azui e vermelho.

ALLEGRO_AUDIO_STREAM

Na linha 14

criamos uma variável do tipo ALLEGRO_AUDIO_STREAM, que receberá a música de fundo tocada.

al_install_audio() e al_init_acodec_addon()

Na linha 32 iniciamos o addon de audio do allegro, e na linha 38 o addon de codecs que permite que o allegro trabalhe com diferentes tipos de arquivos de audio

al_reserve_samples()

Na linha 44 chamamos a função al_reserve_samples() que recebe um número como parâmetro, e tenta reservar na memória espaço suficiente para guardar este número de samples. Ela também automaticamente cria um novo mixer (ver ALLEGRO_MIXER), anexa estes samples a ele, e o torna o mixer padrão. Note que o número passado por parâmetro será o número máximo de samples simultâneos que poderão ser reproduzidos.

al_load_sample()

Na linha 50 e linha 55 carregamos o sample do arquivo passado por parâmetro da função al_load_sample() e o atribuímos às variáveis sample som_verm e som_azul, respectivamente.

al_load_audio_stream()

Na linha 63 carregamos a faixa de audio do arquivo passado por parâmetro da função al_load_audio_stream() e o atribuímos à variável audio stream musica. O segundo e terceiro parâmetros da função são buffers e samples do stream. Há pouca documentação sobre o uso destes dois parâmetros, e todos exemplos que encontrei usam os valores 4 e 1024 para os dois, então usaremos estes mesmo valores.

al_attach_audio_stream_to_mixer()

Na linha 72 chamamos a função al_attach_audio_stream_to_mixer() que faz a ligação entre o audio stream e o mixer. Como parâmetro ele recebe o stream que queremos adicionar, e o mixer. Como não declaramos nenhuma variável do tipo ALLEGRO_MIXER, e estamos usando o mixer padrão criado pela função al_reserve_samples(), chamamos a função al_get_default_mixer(), que retorna o mixer padrão, para usar como parâmetro.

al_set_audio_stream_playmode()

Na linha 74 chamamos a função al_set_audio_stream_playmode() determina o modo de reprodução do stream passado no primeiro parâmetro. Este modo de reprodução é uma flag do tipo ALLEGRO_PLAYMODE, e os valores mais comuns de uso são:

  • ALLEGRO_PLAYMODE_ONCE - Reproduz a stream/sample uma única vez
  • ALLEGRO_PLAYMODE_LOOP - Reproduz a stream/sample em modo de repetição

al_set_audio_stream_playing()

Caso seja do desejo interromper ou continuar a reprodução de um stream, podemos usar a função al_set_audio_stream_playing(), que recebe por parâmetro a variável ALLEGRO_AUDIO_STREAM e um valor, sendo que 0/false representa que a stream deverá parar sua reprodução e 1/true que deverá continuar/começar a reprodução.

Lógica do programa

Na linha 160 testamos se existe um evento de movimento de mouse na lista de eventos, e então verificamos se as posições X e Y do mouse estão nos limites da área de um dos dois retângulos. Caso o mouse esteja dentro da área do retângulo azul (linhas 162 e 164) atribuímos o valor area=1, e caso esteja dentro da área do triângulo vermelho (linhas 162 e 167) atribuímos o valor area=2. Por fim, caso não esteja dentro da área de nenhum dos dois, area=0. Desta maneira, quando o clique do botão do mouse é detectado na linha 175, varificamos o valor de area para determinar em qual das duas áreas ele foi clicado.

al_play_sample()

Nas linhas 178 e 182 chamamos a função al_play_sample() que serve para reproduzir um sample. Ela recebe os seguintes parâmetros, em ordem:

  • Sample: A variável ALLEGRO_SAMPLE que será reproduzida.
  • Ganho: Volume da sample, onde 1.0 é o volume original.
  • Balanço: Distribuição do som no ambiente, onde -1.0 é lado esquerdo, 1.0 lado direito e 0.0 o centro.
  • Velocidade: Velocidade que o som é reproduzido, onde 1.0 significa a velocidade original.
  • Loop: Modo de reprodução (ALLEGRO_PLAYMODE). Veja acima para saber sobre os valores.
  • Id: Ponteiro para uma variável que receberá o id da sample sendo tocada, ou NULL caso não necessite desta informação.

al_stop_sample()

Caso seja do interesse interromper a reprodução de uma sample, chamamos a função al_stop_sample(), que recebe como parâmetro um ponteiro para a id da sample sendo reproduzida (variável tipo ALLEGRO_SAMPLE_ID), obtida através do último parâmetro da função al_play_sample().

al_set_audio_stream_gain()

A função al_set_audio_stream_gain() serve para determinar o volume de uma faixa de audio. Ela recebe uma faixa de audio como parâmetro, e um valor float, onde 1.0 significa volume original.

Download dos arquivos

Outros links