Tutorial Adicionar Música nos Jogos Baseados em SDL

1. Introdução

A SDL Mixer, é uma biblioteca que oferece suporte à reprodução de músicas (uma por vez), e de efeitos sonoros com mixagem, permitindo a reprodução de diversos efeitos simultaneamente. Utilizaremos esta biblioteca para os nossos jogos, em conjunto com um código escrito para facilitar o seu uso.

O suporte a formatos é o seguinte:

• Música:

o Tracked (.it, .mod, .s3m, etc)
o Ogg Vorbis (superior a MP3 e 100% livre)
o MP3 (lembre-se, MP3 em software comercial paga licença de uso)
o Midi
o Wave

• Efeitos sonoros:

o Wave
o Ogg
o Aiff
o Riff
o Voc

Vale lembrar dos avisos gerais. Se você tem uma música num CD, não é porquê o CD é seu que você pode utilizá-la como bem entender. A música pertence ao artista e você deve obter autorização para utilizá-la. Existem diversos sites com músicas e efeitos sonoros para livre uso (alguns no próprio site da tutoria!), faça uso deles para o seu jogo.

Enfim, escolha uma música e efeitos sonoros adequados ao jogo. Se parecer que não combina, escolha outra e tente novamente. O importante é o áudio refletir o estilo do seu jogo.

2. Configurando o Projeto

A primeira coisa a fazer é preparar o projeto para utilizar a SDL_Mixer. Primeiro, devemos instalar o binário e include da biblioteca no DevCPP, o que já foi feito ao instalarmos o pacote da SDL disponibilizado no site da tutoria. O segundo passo consiste em indicar ao DevCPP que deve ser utilizada a biblioteca SDL_Mixer na ligação de objetos. Esta opção é configurada nos parâmetros de compilação e do linker, conforme mostrado na Figura 1. Para acessar esta janela, vá no menu Project (projeto), opção Project Options (opções de projeto) e na aba Parameters (parâmetros) informe a opção –lSDL_Mixer nos três quadros (compilador, compilador C++ e linker). Note, a letra depois do sinal de menos é um “ele”, não um número um.

Opções de projeto, aba de parâmetros

Em seguida, inclua no seu projeto os arquivos audio.h e audio.cpp. Estes arquivos encontram-se junto com este documento, anexados neste documento e, mais importante, no projeto exemplo (12-musica). Estes arquivos encapsulam a SDL_Mixer para facilitar o seu uso de uma maneira prática e simples.

3. Programando o Jogo

Uma vez configurado o projeto, basta utilizarmos o sistema de áudio. Isto é feito em três etapas distintas. Primeiramente, devemos inicializar o áudio. Em seguida, devemos carregar músicas, efeitos e reproduzi-los de acordo com a nossa necessidade. Uma vez que isto tenha sido feito, devemos encerrar o sistema de áudio, eliminando músicas e efeitos que tenham sido carregados anteriormente. Nota: o código demonstrado gerencia automaticamente as músicas e efeitos sonoros, então não precisamos gerenciar os ponteiros no nosso código.

3.1. Iniciando o Áudio

Para iniciar o sistema de áudio, utilizamos a função inicia_audio(). Esta função retorna um booleano para indicar se o sistema de áudio foi iniciado corretamente ou não (caso em que não há uma placa de som instada, por exemplo). Esta função deve ser chamada Obrigatoriamente Após ter sido iniciada a Chien2DLite, conforme mostrado no código abaixo:

// Inicia o vídeo
Chien2DLite *video = Chien2DLite::pegaInstancia();
video->inicia (640, 480, Chien2DLite::janela,
true,”Exemplo 10 – Lógica”);
// inicia o sistema de áudio
inicia_audio();

O áudio deve ser iniciado após a Chien2D porquê esta inicia a SDL e o subsistema de vídeo, sendo que o código de áudio inicia apenas o subsistema de áudio, que depende da SDL ter sido iniciada.

Apesar da função retornar um booleano indicando se foi iniciado o áudio corretamente ou não, não precisamos nos preocupar com efeitos colaterais caso sejam executadas outras funções do arquivo audio.h quando o sistema de áudio não tiver sido iniciado. O código é preparado para esta situação, ignorando as chamadas e não causando error no sistema. Assim, o valor booleano serve apenas para indicar ao usuário que não haverá suporte de áudio, se for o caso. Para o programador, este pode trabalhar considerando que o sistema de áudio estará ativo, já que os comandos para executar áudio e encerrar não irão executar quando não houver placa de som.

Apenas a partir da chamada de inicia_audio() que podemos executar as demais funcionalidades de som e esperar que elas produzam algum resultado.

3.2. Carregando uma Música

Para carregar uma música utilizamos a função carrega_musica. Esta função recebe uma string (vetor de caracteres) indicando o nome do arquivo a ser carregado, retornando um booleano que indica se a música foi carregada com sucesso (true) ou não (false). Abaixo, temos um exemplo de como carregar uma música:

carrega_musica(“AulaPaulo_byPiovezan.it”);

A detecção do formato da música (.ogg, .it, .mp3, etc) é feita de maneira automática, basta passar o nome do arquivo que este será carregado automaticamente. Se desejarmos carregar uma outra música para ser tocada no jogo, basta chamar a função carrega_musica novamente, indicando o nome do novo arquivo. Note-se que apenas UMA música é suportada no sistema de áudio, ao carregar uma nova música, a anterior é eliminada da memória e será preciso carregá-la novamente para que ela possa ser tocada outra vez.

3.3. Reproduzindo a Música

A reprodução da música deve ser feita apenas após termos carregado uma música. Existem duas funções associadas, sendo a primeira toca_musica, que simplesmente inicia a reprodução da música. A segunda função é fade_musica, que recebe um valor inteiro que indica um tempo em milisegundos para encerrar a música abaixando o volume.

Para tocar a música carregada basta chamar o seguinte código:

toca_musica( );

Para encerrar a música, abaixando o volume até 0 durante dois segundo, chamamos:

fade_musica (2000);

Enfim, para encerrarmos a música imediatamente, basta chamar:

fade_musica (0);

3.4. Carregando efeitos

Para carregar efeitos sonoros, utilizamos a função carrega_efeitos. Esta função recebe um vetor de strings indicando o nome dos arquivo a serem carregados e um inteiro, que indica o número de efeitos a carregar. A função retorna um booleano indicando, retornando um booleano que indica se os efeitos foram carregados ao menos parcialmente com sucesso (true) ou não (false). Abaixo, temos um exemplo de como carregar uma lista de efeitos:

// Carrega os efeitos sonoros
char* efeitos[4] = {“pula.wav”, “bate.wav”, “venceu.wav”,
“morreu.wav”};
carrega_efeitos (efeitos, 4);

No exemplo, o vetor efeitos indica o nome dos arquivos, no total de 4, a serem carregados. Cada efeito é associado a um índice equivalente a sua posição no vetor (por exemplo, bate.wav é associado ao índice 1). Este índice será utilizado na reprodução dos efeitos A detecção do formato dos arquivos dos efeitos é feita automaticamente, sendo possível, inclusive, utilizar diferentes formatos de áudio nos efeitos carregados sem problemas.

3.5. Reproduzindo os Efeitos

Para reproduzir os efeitos, utilizamos a função toca_efeito. Esta função recebe um inteiro que indica o índice do efeito a ser reproduzido pelo sistema de áudio. Este inteiro é relacionado ao índice do vetor de efeito sonoros carregados por carrega_efeitos. Por exemplo, para reproduzir o efeito associado ao arquivo bate.wav no exemplo anterior, basta utilizar:

toca_efeito(1);

É permitida a execução de vários efeitos simultaneamente, então não é preciso esperar que um efeito encerre antes de reproduzir outro. Se por acaso você chegar ao limite de canais do sistema, o efeito mais antigo será encerrado automaticamente. Caso você passe o número de um efeito inválido (negativo ou acima do limite), o sistema irá ignorar o valor e não tocará nenhum efeito.

3.6. Encerrando o Áudio

Antes de encerra o jogo é necessário encerrar o sistema de áudio. Isto deve ser feito, OBrigatoriamente, antes de encerrar a Chien2DLite. A função que realiza esta tarefa é a encerra_audio, que além de fechar o subsistema de áudio, elimina da memória a música e efeitos que tenham sido carregados anteriormente. Abaixo temos um segmento de código que realiza esta funcionalidade.

encerra_audio( );
// Fecha a janela
video->encerra();
// Finaliza a instância de vídeo
video->removeInstancia();

4. Discussão

O sistema de áudio discutido visa facilitar o uso das funcionalidades de áudio da SDL_Mixer. Caso você queira modificá-lo para seu uso, leia a documentação da SDL_Mixer para conhecer as funcionalidade das suas funções.

Anexo 1 – Arquivo audio.h

#ifndef AUDIO
#define AUDIO
bool inicia_audio();
bool encerra_audio();

bool carrega_musica(char *arquivo);
bool carrega_efeitos(char **lista, int num);

void toca_musica();
void fade_musica(int milisegundos);
void toca_efeito(int num);
#endif

Anexo 2 – Arquivo audio.cpp

#include
#include
#include “audio.h”

// Indica se o sistema de áudio foi iniciado ou não bool audio_iniciado = false;
// Variável para armazenar a música a tocar no jogo Mix_Music *musica=0;
// Variável para armazenar os efeitos sonoros Mix_Chunk **efeitos=0; int num_efeitos=0;

// Esta função inicializa o sistema de áudio. Ela retorna true se funcionou
// e false se não conseguiu.

bool inicia_audio()
{
// Tenta inicializar o sistema de áudio da SDL. Se der errado, retorna false if(SDL_InitSubSystem(SDL_INIT_AUDIO)!=0) audio_iniciado = false;
// Tenta iniciar a SDL_Mixer em estério, 16 bits, 44.1kHz, 4kb de buffer
// Se falhar, retorna false else if(Mix_OpenAudio(44100, AUDIO_S16SYS , 2, 4096)!=0) audio_iniciado = false; else
// Se chegou até aqui, deu certo. audio_iniciado = true;
// REtorna o valor de iniciado return audio_iniciado;
}
bool encerra_audio()
{
// Iniciou o sistema de áudio??
if(!audio_iniciado)
return false;
// Verifica se existe uma música para apagar if(musica!=0)
{
Mix_HaltMusic();
Mix_FreeMusic(musica);
musica=0;
}
// Apaga os efeitos válidos if(efeitos!=0)
{
Mix_HaltChannel(-1);
for(int i=0;i
if(efeitos[i]!=0)
Mix_FreeChunk(efeitos[i]);
// apaga o vetor de efeitos delete efeitos;
efeitos=0;
num_efeitos=0;
}
// Encerra o mixer Mix_CloseAudio();
// Encera o áudio da SDL SDL_QuitSubSystem(SDL_INIT_AUDIO);
// Marca como não iniciado audio_iniciado = false;
// Indica sucesso return true;
}
bool carrega_musica(char *arquivo)
{
if(!audio_iniciado)
{
printf(“Tentou carregar a música %s antes de iniciar o sistema de áudio.n”, arquivo);
return false;
}
// Verifica se já existe uma música if(musica!=0)
{
Mix_HaltMusic();
Mix_FreeMusic(musica);
musica=0;
}
// Tenta carregar a música, se voltar zero, falhou
if((musica=Mix_LoadMUS(arquivo)) == 0)
{
printf(“Não conseguiu carregar o arquivo %s.
Erro: %sn”, arquivo, Mix_GetError());
return false;
}
return true;
}
bool carrega_efeitos(char **lista, int num)
{
// Apaga os efeitos anteriores
if(efeitos!=0)
{
Mix_HaltChannel(-1);
for(int i=0;i
if(efeitos[i]!=0)
Mix_FreeChunk(efeitos[i]);
// apaga o vetor de efeitos delete efeitos;
// Valores default efeitos=0;
num_efeitos=0;
}
// Cria o vetor de efeitos efeitos = new Mix_Chunk*[num];
// Se não consegui criar, dá erro if(efeitos==0) return false;
num_efeitos=num;
// Tenta carregar os efeitos. Se falhar algum, deixa o efeito vazio for(int i=0;i
if((efeitos[i]=Mix_LoadWAV(lista[i]))==0)
printf(“Falhou ao carregar o efeito %s.n”,
lista[i]);
return true;
}
void toca_musica()
{
// Testa se iniciou o sistema de áudio corretamente ou se carregou a música if(!audio_iniciado || musica==0) return;
// Toca a música com repetição Mix_PlayMusic(musica, -1);
}
void fade_musica(int milisegundos)
{
// Testa se iniciou o sistema de áudio corretamente ou se carregou a música if(!audio_iniciado || musica==0) return;
if(milisegundos >=0)
Mix_FadeOutMusic(milisegundos);
else
Mix_HaltMusic();
}
void toca_efeito(int num)
{
// Testa se iniciou o sistema de áudio corretamente ou se carregou a música if(!audio_iniciado || musica==0) return;
if(efeitos != 0 && num >=0 && num
if(efeitos[num] != 0)
Mix_PlayChannel(-1, efeitos[num], 0);
}
Boa Sorte!

1 comentário a "Tutorial Adicionar Música nos Jogos Baseados em SDL"

  1. Fernando | às | Responder

    Muito massa, cara. Parabéns. To começando agora a programar jogos em SDL e esses tutoriais que encontro são bastante úteis. Se você puder fazer uma de como implementar um cutscene dentro de um rpg (2D) eu agradeceria. kkkkk VLW 😀

Comentar

O seu endereço de email não será publicado.


*