Reprodução de arquivos WAV com SDL_mixer e linguagem C
O objetivo deste artigo é explicar o funcionamento da biblioteca SDL_mixer na reprodução de arquivos de áudio WAV através de aplicações escritas em linguagem C. A SDL_mixer é uma biblioteca adicional da SDL, mais poderosa para tratamento de arquivos de áudio do que as funções de SDL_audio, possibilitando por exemplo a execução de vários arquivos de áudio simultaneamente.
SDL e motivação
A SDL (Simple DirectMedia Layer) é uma biblioteca que possibilita o desenvolvimento de aplicações multimídia e jogos fornecendo acesso de baixo nível a recursos como áudio, vídeo, teclado, joysticks, vídeo 3D (através de integração com Open GL) e vídeo 2D.
A motivação para a utilização de áudio em jogos é que a música e os sons de ambiente são elementos essenciais. Possibilitam que um jogo com zumbis se torne assustador e que um jogo de guerra em 1ª pessoa seja totalmente imersivo. Sem contar que em alguns casos, a música se torna a "cara" do jogo (ou até filme) e quando ouvirem a música, se lembrarão do game.
Para utilizar a SDL_Mixer é necessário ter já instaladas a SDL e a SDL_Mixer.
Ao iniciar o desenvolvimento do aplicativo em linguagem C, é necessário realizar o "include" de dois arquivos de cabeçalho. Esses arquivos são SDL.h e SDL_mixer.h. Quando a instalação é realizada corretamente, esses arquivos podem ser encontrados em /usr/include/SDL ou em /usr/local/include/SDL. Depois de incluídos os arquivos SDL, é necessário inicializar o SDL e o SDL_mixer.
Com SDL e SDL_mixer inicializados é possível então exibir uma janela onde podem ser adicionados novos elementos através da SDL e o som pode ser reproduzido através da SDL_mixer.
O código abaixo é uma adaptação do código disponível na Game Programming Wiki, com as linhas mais importantes do código comentadas.
A motivação para a utilização de áudio em jogos é que a música e os sons de ambiente são elementos essenciais. Possibilitam que um jogo com zumbis se torne assustador e que um jogo de guerra em 1ª pessoa seja totalmente imersivo. Sem contar que em alguns casos, a música se torna a "cara" do jogo (ou até filme) e quando ouvirem a música, se lembrarão do game.
SDL_mixer
A SDL_mixer é uma biblioteca de áudio multi-canal que possibilita a reprodução simultânea do áudio através de canais de 16 bit com qualidade estéreo, além de um canal único reservado para música. O SDL_mixer suporta além de WAV, os populares formatos Ogg Vorbis e MP3.Para utilizar a SDL_Mixer é necessário ter já instaladas a SDL e a SDL_Mixer.
Ao iniciar o desenvolvimento do aplicativo em linguagem C, é necessário realizar o "include" de dois arquivos de cabeçalho. Esses arquivos são SDL.h e SDL_mixer.h. Quando a instalação é realizada corretamente, esses arquivos podem ser encontrados em /usr/include/SDL ou em /usr/local/include/SDL. Depois de incluídos os arquivos SDL, é necessário inicializar o SDL e o SDL_mixer.
Com SDL e SDL_mixer inicializados é possível então exibir uma janela onde podem ser adicionados novos elementos através da SDL e o som pode ser reproduzido através da SDL_mixer.
O código abaixo é uma adaptação do código disponível na Game Programming Wiki, com as linhas mais importantes do código comentadas.
#include <SDL/SDL.h>
#include <SDL/SDL_mixer.h>
int main (int argv, char *argv[]) {
printf ("Inicializando o SDL e o SDL_mixer\n");
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) {
fprintf(stderr, "Nao foi possivel inicializar o SDL: %s", SDL_GetError());
return 1;
}
int audio_rate = 22050;
/* 22050 é o ideal para a frequência na maioria dos jogos. Se o seu objetivo for criar algum GuitarHero, talvez seja melhor aumentar esse valor. A qualidade de CD é 44100. */
Uint16 audio_format = AUDIO_S16SYS; /* Ajuste de amostras com 16 bits. Pode ser necessário alterar para 8 bits: AUDIO_S8 */
int audio_channels = 2; /* 1-Mono; 2-Stereo */
int audio_buffers = 4096; /* Buffer para armazenamento de trechos do audio*/
/* Mix_OpenAudio inicializa o sistema de audio de acordo com as configurações estabelecidas acima */
if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) != 0) {
fprintf(stderr, "Nao foi possivel inicializar o audio: %s\n", Mix_GetError());
exit(1);
}
/* Ponteiro que receberá a amostra de audio do arquivo WAV e armazenará essa amostra na memória */
Mix_Chunk *sound = NULL;
sound = Mix_LoadWAV("sound.wav"); /* Carrega a música a partir do arquivo WAV) */
if (sound == NULL) {
fprintf(stderr, "Impossível carregar arquivo WAV: %s\n", Mix_GetError());
}
/* Abrir janela em 320x240 */
SDL_Surface *screen;
screen = SDL_SetVideoMode(320, 240, 0, SDL_ANYFORMAT);
if (screen = NULL) {
fprintf(stderr, "Impossível configurar modo de vídeo: s\n", SDL_GetError());
return 1;
}
int channel;
channel = Mix_PlayChannel(-1, sound, 0);
if (channel == -1) {
fprintf(stderr, "Impossível reproduzir arquivo WAV: %s\n", Mix_GetError());
}
/* Aguarda o fim da reprodução e finaliza o programa liberando antes os recursos alocados. */
while (Mix_Playing(channel) != 0);
Mix_FreeChunk(sound);
Mix_CloseAUdio();
SDL_Quit();
}
#include <SDL/SDL_mixer.h>
int main (int argv, char *argv[]) {
printf ("Inicializando o SDL e o SDL_mixer\n");
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) {
fprintf(stderr, "Nao foi possivel inicializar o SDL: %s", SDL_GetError());
return 1;
}
int audio_rate = 22050;
/* 22050 é o ideal para a frequência na maioria dos jogos. Se o seu objetivo for criar algum GuitarHero, talvez seja melhor aumentar esse valor. A qualidade de CD é 44100. */
Uint16 audio_format = AUDIO_S16SYS; /* Ajuste de amostras com 16 bits. Pode ser necessário alterar para 8 bits: AUDIO_S8 */
int audio_channels = 2; /* 1-Mono; 2-Stereo */
int audio_buffers = 4096; /* Buffer para armazenamento de trechos do audio*/
/* Mix_OpenAudio inicializa o sistema de audio de acordo com as configurações estabelecidas acima */
if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) != 0) {
fprintf(stderr, "Nao foi possivel inicializar o audio: %s\n", Mix_GetError());
exit(1);
}
/* Ponteiro que receberá a amostra de audio do arquivo WAV e armazenará essa amostra na memória */
Mix_Chunk *sound = NULL;
sound = Mix_LoadWAV("sound.wav"); /* Carrega a música a partir do arquivo WAV) */
if (sound == NULL) {
fprintf(stderr, "Impossível carregar arquivo WAV: %s\n", Mix_GetError());
}
/* Abrir janela em 320x240 */
SDL_Surface *screen;
screen = SDL_SetVideoMode(320, 240, 0, SDL_ANYFORMAT);
if (screen = NULL) {
fprintf(stderr, "Impossível configurar modo de vídeo: s\n", SDL_GetError());
return 1;
}
int channel;
channel = Mix_PlayChannel(-1, sound, 0);
if (channel == -1) {
fprintf(stderr, "Impossível reproduzir arquivo WAV: %s\n", Mix_GetError());
}
/* Aguarda o fim da reprodução e finaliza o programa liberando antes os recursos alocados. */
while (Mix_Playing(channel) != 0);
Mix_FreeChunk(sound);
Mix_CloseAUdio();
SDL_Quit();
}
Linda iniciativa, mas o código não compila. Consegui reduzir o número de erros com a inclusão de stdlib, stdio e string.h no cabeçalho, mas isto não resolveu o problema. Não está claro também se tenho que instalar alguma biblioteca a parte.
Segue abaixo o código dos erros:
teste.c:1:21: error: SDL/SDL.h: Arquivo ou diretório não encontrado
teste.c:2:27: error: SDL/SDL_mixer.h: Arquivo ou diretório não encontrado
teste.c:7: error: conflicting types for ‘argv’
teste.c:7: note: previous definition of ‘argv’ was here
teste.c: In function ‘main’:
teste.c:10: warning: implicit declaration of function ‘SDL_Init’
teste.c:10: error: ‘SDL_INIT_VIDEO’ undeclared (first use in this function)
teste.c:10: error: (Each undeclared identifier is reported only once
teste.c:10: error: for each function it appears in.)
teste.c:10: error: ‘SDL_INIT_AUDIO’ undeclared (first use in this function)
teste.c:11: warning: implicit declaration of function ‘SDL_GetError’
teste.c:11: warning: format ‘%s’ expects type ‘char *’, but argument 3 has type ‘int’
teste.c:18: error: ‘Uint16’ undeclared (first use in this function)
teste.c:18: error: expected ‘;’ before ‘audio_format’
teste.c:23: warning: implicit declaration of function ‘Mix_OpenAudio’
teste.c:23: error: ‘audio_format’ undeclared (first use in this function)
teste.c:24: warning: implicit declaration of function ‘Mix_GetError’
teste.c:24: warning: format ‘%s’ expects type ‘char *’, but argument 3 has type ‘int’
teste.c:29: error: ‘Mix_Chunk’ undeclared (first use in this function)
teste.c:29: error: ‘sound’ undeclared (first use in this function)
teste.c:31: warning: implicit declaration of function ‘Mix_LoadWAV’
teste.c:33: warning: format ‘%s’ expects type ‘char *’, but argument 3 has type ‘int’
teste.c:37: error: ‘SDL_Surface’ undeclared (first use in this function)
teste.c:37: error: ‘screen’ undeclared (first use in this function)
teste.c:38: warning: implicit declaration of function ‘SDL_SetVideoMode’
teste.c:38: error: ‘SDL_ANYFORMAT’ undeclared (first use in this function)
teste.c:40: warning: too many arguments for format
teste.c:45: warning: implicit declaration of function ‘Mix_PlayChannel’
teste.c:47: warning: format ‘%s’ expects type ‘char *’, but argument 3 has type ‘int’
teste.c:51: warning: implicit declaration of function ‘Mix_Playing’
teste.c:53: warning: implicit declaration of function ‘Mix_FreeChunk’
teste.c:55: warning: implicit declaration of function ‘Mix_CloseAUdio’
teste.c:57: warning: implicit declaration of function ‘SDL_Quit’
Eu gostaria muito de que este programa funcionasse.