[SDL] Sound and Music in games

Chris Nystrom cnystrom at gmail.com
Fri Jun 10 11:22:22 PDT 2005


On 6/10/05, Alan Wolfe <atrix2 at cox.net> wrote:
> Heya everyone,
> 
> For the first time ever im going to take a stab at making music and sound
> effects in my code.
> 
> What i have right now is a 2d side scroller made in opengl (getting to
> opengl via sdl) that takes up very little cpu/gpu so lots of resources are
> still left available.
> 
> What im looking for is just something simple like being able to play .wav
> files as sound effects and .mid for background music.
> 
> I've heard from some people SDL_Mixer is the way to go, and then also heard
> from other people that SDL_Mixer is unwieldy and doesnt work so great.

SDL_Mixer works fine for me.

Here is my C code for music and sounds. It should be pretty easy to
bolt on, and straightforward to use. I have an overall header file,
and then 3 C files, one for general audio device control, one for
music, and one for sound.  It do not use all features of SDL_Mixer,
but it is certianly enough to get you started if you have not done it
before.

Chris

--
/******************************************************************************
 *
 *    audio_lib.h
 *
 *    Copyright (C) 2002, 2005  Chris Nystrom
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU Lessor General Public License as published
 *    by the Free Software Foundation; either version 2.1 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but without any warranty whatsoever.
 *
 *    For more license information see:
 *
 *      http://www.gnu.org/copyleft/lessor.html
 *
 *    Contact Author at:
 *
 *    Chris Nystrom
 *    11013 Prairie Dove Circle
 *    Austin, Texas  78758
 *
 *    E-Mail: cnystrom at gmail.com
 *    Blog:   http://conversazione.blogspot.com
 *    AIM:    nystromchris
 *
 *    Soli Deo Gloria
 *
 */

#ifndef _AUDIO_LIB_H
#define _AUDIO_LIB_H

#ifndef _SDL_H
#include "SDL.h"
#endif

#ifndef _MIXER_H
#include "SDL_mixer.h"
#endif

#ifndef PRIVATE
#define PRIVATE static
#endif

#ifndef PUBLIC
#define PUBLIC
#endif

#ifndef _BOOL_H
#define _BOOL_H

typedef unsigned char bool;

#ifndef FALSE
#define FALSE  (0)
#endif

#ifndef TRUE
#define TRUE  !FALSE
#endif

#endif                          // _BOOL_H

#ifndef OFF
#define OFF  (0)
#endif

#ifndef ON
#define ON   (!OFF)
#endif

#define MAX_NUM_CHANNELS (25)
#define MAX_NUM_SOUNDS   (25)

PUBLIC int init_audio(void);
PUBLIC void close_audio(void);

PUBLIC bool audio_avail(void);

PUBLIC int load_sound(const char *filename);
PUBLIC void delete_sound(int i);

PUBLIC int sound_channel_done(int channel);
PUBLIC int play_sound(int i, int loops);

PUBLIC int load_music(const char *filename);
PUBLIC void play_music(int loops);
PUBLIC void stop_music(void);
PUBLIC bool music_playing(void);

PUBLIC void set_sound_volume(int v);
PUBLIC int get_sound_volume(void);

PUBLIC void set_music_volume(int v);
PUBLIC int get_music_volume(void);

#endif                          // _AUDIO_LIB_H
--
/******************************************************************************
 *
 *    audio.c
 *
 *    Copyright (C) 2002, 2005  Chris Nystrom
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU Lessor General Public License as published
 *    by the Free Software Foundation; either version 2.1 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but without any warranty whatsoever.
 *
 *    For more license information see:
 *
 *      http://www.gnu.org/copyleft/lessor.html
 *
 *    Contact Author at:
 *
 *    Chris Nystrom
 *    11013 Prairie Dove Circle
 *    Austin, Texas  78758
 *
 *    E-Mail: cnystrom at gmail.com
 *    Blog:   http://conversazione.blogspot.com
 *    AIM:    nystromchris
 *
 *    Soli Deo Gloria
 *
 */

#include <stdio.h>
#include "SDL.h"
#include "SDL_mixer.h"
#include "audio_lib.h"

PRIVATE bool audio_init = FALSE;

PUBLIC int init_audio(void)
{
        if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 512) < 0) {
                fprintf(stderr, "init_audio(): %s\n", Mix_GetError());
                return (-1);
        }

        audio_init = TRUE;

        return (0);
}

PUBLIC void close_audio(void)
{
        if (audio_init) {
                Mix_CloseAudio();
        }
        audio_init = FALSE;
}

PUBLIC bool audio_avail(void)
{
        return (audio_init);
}
--
/******************************************************************************
 *
 *    music.c
 *
 *    Copyright (C) 2002, 2005  Chris Nystrom
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU Lessor General Public License as published
 *    by the Free Software Foundation; either version 2.1 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but without any warranty whatsoever.
 *
 *    For more license information see:
 *
 *      http://www.gnu.org/copyleft/lessor.html
 *
 *    Contact Author at:
 *
 *    Chris Nystrom
 *    11013 Prairie Dove Circle
 *    Austin, Texas  78758
 *
 *    E-Mail: cnystrom at gmail.com
 *    Blog:   http://conversazione.blogspot.com
 *    AIM:    nystromchris
 *
 *    Soli Deo Gloria
 *
 */

#include <stdlib.h>
#include "SDL.h"
#include "SDL_mixer.h"
#include "audio_lib.h"

extern bool file_exists(const char *s);

PRIVATE Mix_Music *song;
PRIVATE int music_volume;

PUBLIC int load_music(const char *filename)
{
        if (!audio_avail()) {
                fprintf(stderr, "load_music(): audio not initialized.\n");
                return (-1);
        }

        if (!file_exists(filename)) {
                fprintf(stderr, "load_music(): file not available.\n");
                return (-2);
        }

        song = Mix_LoadMUS(filename);

        if (NULL == song) {
                fprintf(stderr, "load_song(): %s\n", Mix_GetError());
                return (-1);
        }

        return (0);
}

// Notes: loops == -1 is infinite loops.
//        loops == 1 plays the sample twice (1 loop).
PUBLIC void play_music(int loops)
{
        if (!audio_avail()) {
                fprintf(stderr, "play_music(): audio not initialized.\n");
                return;
        }

        if (-1 == Mix_PlayMusic(song, loops)) {
                fprintf(stderr, "play_music(): %s\n", Mix_GetError());
                fflush(stderr);
        }
}

PUBLIC void stop_music(void)
{
        if (!audio_avail()) {
                fprintf(stderr, "stop_music(): audio not initialized.\n");
                return;
        }

        Mix_HaltMusic();
}

PUBLIC bool music_playing(void)
{
        if (!audio_avail()) {
                fprintf(stderr,
                        "music_playing(): audio not initialized.\n");
                return (FALSE);
        }

        return (Mix_PlayingMusic());
}

PUBLIC void set_music_volume(int v)
{
        if (!audio_avail()) {
                fprintf(stderr,
                        "set_music_volume(): audio not initialized.\n");
                return;
        }

        if (v < 0)
                v = 0;

        // Note MIX_MAX_VOLUME defined in SDL_mixer.h
        if (v > MIX_MAX_VOLUME)
                v = MIX_MAX_VOLUME;

        music_volume = v;

        Mix_VolumeMusic(music_volume);
}

PUBLIC int get_music_volume(void)
{
        return (music_volume);
}
--
/******************************************************************************
 *
 *    sound.c
 *
 *    Copyright (C) 2002, 2005  Chris Nystrom
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU Lessor General Public License as published
 *    by the Free Software Foundation; either version 2.1 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but without any warranty whatsoever.
 *
 *    For more license information see:
 *
 *      http://www.gnu.org/copyleft/lessor.html
 *
 *    Contact Author at:
 *
 *    Chris Nystrom
 *    11013 Prairie Dove Circle
 *    Austin, Texas  78758
 *
 *    E-Mail: cnystrom at gmail.com
 *    Blog:   http://conversazione.blogspot.com
 *    AIM:    nystromchris
 *
 *    Soli Deo Gloria
 *
 */

#include <stdio.h>
#include "SDL.h"
#include "SDL_mixer.h"
#include "audio_lib.h"

extern bool file_exists(const char *s);

PRIVATE Mix_Chunk *sound[MAX_NUM_SOUNDS];
PRIVATE bool s_flag[MAX_NUM_SOUNDS] = { FALSE };        // Sound loaded for use

PRIVATE int done[MAX_NUM_CHANNELS] = { TRUE };  // Channel completed

PRIVATE int sound_volume;

PUBLIC int next_free_sound_num(void)
{
        int i_num;

        for (i_num = 0; i_num < MAX_NUM_SOUNDS; i_num++) {
                if (FALSE == s_flag[i_num]) {
                        s_flag[i_num] = TRUE;
                        return (i_num);
                }
        }

        fprintf(stderr,
                "next_free_sound_num(): No more sounds available.\n");
        return (-1);
}

PUBLIC int load_sound(const char *filename)
{
        int i;

        if (!audio_avail()) {
                fprintf(stderr, "load_sound(): audio not initialized.\n");
                return (-1);
        }

        if (!file_exists(filename)) {
                fprintf(stderr, "load_sound(): file not available.\n");
                return (-2);
        }

        i = next_free_sound_num();

//  printf("load_sound(): i = %d\n", i);

        if (i < 0)
                return (i);

        sound[i] = Mix_LoadWAV(filename);

        if (NULL == sound[i]) {
                fprintf(stderr, "load_sound(): %s\n", Mix_GetError());
                fflush(stderr);
                return (-1);
        }

        return (i);
}

PUBLIC int sound_channel_done(int channel)
{
        return (done[channel]);
}

PUBLIC void sound_channel_callback(int channel)
{
//  printf("sound_channel_callback(): sound on channel %d should be
done now.\n", channel);

        done[channel] = TRUE;
}

// Notes: loops == -1 is infinite loops.
//        loops == 1 plays the sample twice (1 loop).
PUBLIC int play_sound(int i, int loops)
{
        int channel = -1;

        if (!audio_avail()) {
                fprintf(stderr, "play_sound(): audio not initialized.\n");
                return (-1);
        }

        Mix_ChannelFinished(sound_channel_callback);

//  printf("play_sound(): i = %d\n", i);
//  printf("play_sound(): loops = %d\n", loops);

        channel = Mix_PlayChannel(-1, sound[i], loops);

//  printf("play_sound(): channel = %d\n", channel);

        if (-1 == channel) {
                fprintf(stderr, "play_sound(): %s\n", Mix_GetError());
                fflush(stderr);
        } else {
                done[channel] = FALSE;
        }

        return (channel);
}

PUBLIC void delete_sound(int i)
{
        if (i < 0 || i >= MAX_NUM_SOUNDS) {
                fprintf(stderr, "delete_sound(): bad sound number: %d.\n",
                        i);
                return;
        }

        s_flag[i] = FALSE;
}

PUBLIC void set_sound_volume(int v)
{
        int i;

        if (!audio_avail()) {
                fprintf(stderr,
                        "set_sound_volume(): audio not initialized.\n");
                return;
        }

        if (v < 0)
                v = 0;

        // Note MIX_MAX_VOLUME defined in SDL_mixer.h
        if (v > MIX_MAX_VOLUME)
                v = MIX_MAX_VOLUME;

        sound_volume = v;

        for (i = 0; i < MAX_NUM_SOUNDS; i++) {
                if (NULL != sound[i]) {
                        Mix_VolumeChunk(sound[i], sound_volume);
                }
        }
}

PUBLIC int get_sound_volume(void)
{
        return (sound_volume);
}

-- 
E-Mail: Chris Nystrom <cnystrom at gmail.com>
Business: http://www.shaklee.net/austin
Blog: http://conversazione.blogspot.com/
AIM: nystromchris




More information about the SDL mailing list