diff options
author | Bruno Coudoin <bruno.coudoin@free.fr> | 2009-07-17 23:34:17 (GMT) |
---|---|---|
committer | Bruno Coudoin <bruno.coudoin@free.fr> | 2009-07-17 23:34:17 (GMT) |
commit | 8963c5226c86c5b500f9cdf0638c1cec9b52a592 (patch) | |
tree | 4b1fe30a3b5131b0a3ec800058e66cc664d95976 /src/gcompris | |
parent | f3373a11998b5269a9fbf22ca717a3c33051d059 (diff) |
Added support for SDL Mixer audio backend.
The code is taken from the GCOMPRIS 8_3 branch.
Now at compilation time we can select the SDL backend or the
gstreamer one.
Diffstat (limited to 'src/gcompris')
-rw-r--r-- | src/gcompris/Makefile.am | 5 | ||||
-rw-r--r-- | src/gcompris/gstreamer.c | 19 | ||||
-rw-r--r-- | src/gcompris/sdlplayer.c | 222 | ||||
-rw-r--r-- | src/gcompris/soundutil.c | 15 | ||||
-rw-r--r-- | src/gcompris/soundutil_sdl.c | 405 | ||||
-rw-r--r-- | src/gcompris/soundutil_sdl.h | 99 |
6 files changed, 750 insertions, 15 deletions
diff --git a/src/gcompris/Makefile.am b/src/gcompris/Makefile.am index 4d4b1bc..f0f1305 100644 --- a/src/gcompris/Makefile.am +++ b/src/gcompris/Makefile.am @@ -54,8 +54,8 @@ INCLUDES = \ -DGNOME_DISABLE_DEPRECATED \ $(sqlite_cflags) \ $(GNET_CFLAGS) \ - $(cairo_cflags) \ $(AUDIO_CFLAGS) \ + $(cairo_cflags) \ $(NSBUNDLE_CPPFLAGS) gcompris_SOURCES = \ @@ -116,6 +116,9 @@ gcompris_SOURCES = \ soundutil.c \ soundutil.h \ gstreamer.c \ + soundutil_sdl.c \ + soundutil_sdl.h \ + sdlplayer.c \ timer.c \ timer.h \ wordlist.c \ diff --git a/src/gcompris/gstreamer.c b/src/gcompris/gstreamer.c index a904bea..01cce7b 100644 --- a/src/gcompris/gstreamer.c +++ b/src/gcompris/gstreamer.c @@ -16,6 +16,10 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +#include <config.h> + +#ifdef USE_GSTREAMER + #include "string.h" #include "gcompris.h" @@ -87,13 +91,6 @@ bg_bus(GstBus* bus, GstMessage* msg, gpointer data) } void -gc_sound_close() -{ - gc_sound_bg_close(); - gc_sound_fx_close(); -} - -void gc_sound_bg_close() { if (bg_pipeline) @@ -130,13 +127,6 @@ gc_sound_fx_reopen() } void -gc_sound_reopen() -{ - gc_sound_bg_reopen(); - gc_sound_fx_reopen(); -} - -void gc_sound_bg_pause() { if (bg_pipeline) @@ -267,3 +257,4 @@ fx_play() return; } +#endif // USE_GSTREAMER diff --git a/src/gcompris/sdlplayer.c b/src/gcompris/sdlplayer.c new file mode 100644 index 0000000..d346fc3 --- /dev/null +++ b/src/gcompris/sdlplayer.c @@ -0,0 +1,222 @@ +/* sdlplayer - sdlplayer.c + * + * Copyright (C) 2004 Bruno Coudoin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#ifdef USE_SDLMIXER + +#include "soundutil.h" + +#ifndef SDL_FRAMEWORKS +#include "SDL.h" +#include "SDL_thread.h" +#include "SDL_mixer.h" +#include "SDL_audio.h" +#else +/* we use SDL and SDL_mixer framework */ +#include <SDL/SDL.h> +#include <SDL/SDL_thread.h> +#include <SDL_mixer/SDL_mixer.h> +#include <SDL/SDL_audio.h> +#endif + +#include <stdarg.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include <glib.h> + +Sint16 stream[2][4096]; +int len=4096, bits=0, which=0; + +// set this to any of 512,1024,2048,4096 +// the higher it is, the more FPS shown and CPU needed +#define AUDIO_BUFFERS 2048 + +static gboolean sound_closed = FALSE; + +/******************************************************************************/ +/* some simple exit and error routines */ + +void errorv(char *str, va_list ap) +{ + //vfprintf(stderr,str,ap); + + if(strcmp(Mix_GetError(), "Unrecognized file type (not VOC)")==0) { + g_warning("*** You need a version of \"SDL_mixer\" with OGG Vorbis supported ***\n"); + exit(EXIT_FAILURE); + } + + g_warning(": %s.\n", Mix_GetError()); + g_warning(": %s.\n", SDL_GetError()); + +} + +int cleanExit(char *str,...) +{ + va_list ap; + va_start(ap, str); + errorv(str,ap); + va_end(ap); + Mix_CloseAudio(); + SDL_Quit(); + return(1); +} + +/******************************************************************************/ + +int sdlplayer_init() +{ + int audio_rate,audio_channels; + Uint16 audio_format; + + // initialize SDL for audio + if(SDL_Init(SDL_INIT_AUDIO)<0) + return(cleanExit("SDL_Init")); + + // initialize sdl mixer, open up the audio device + if(Mix_OpenAudio(44100,MIX_DEFAULT_FORMAT,2,AUDIO_BUFFERS)<0) + return(cleanExit("Mix_OpenAudio")); + + // print out some info on the audio device and stream + Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels); + bits=audio_format&0xFF; + g_warning("Opened audio at %d Hz %d bit %s, %d bytes audio buffer\n", audio_rate, + bits, audio_channels>1?"stereo":"mono", AUDIO_BUFFERS ); + return(0); +} + +int sdlplayer_quit(Mix_Music *music) +{ + // free & close + Mix_FreeMusic(music); + Mix_CloseAudio(); + g_warning("SDL PLAYER SDL_Quit\n"); + SDL_Quit(); + + return 0; +} + +int sdlplayer_music(char *filename, int volume) +{ + Mix_Music *music; + + g_warning("sdlplayer_bg %s\n", filename); + + // load the song + if(!(music=Mix_LoadMUS(filename))) + return(cleanExit("Mix_LoadMUS(\"%s\")",filename)); + + if(Mix_PlayMusic(music, 1)==-1) { + return(cleanExit("Mix_LoadMUS(0x%p,1)",music)); + } + + Mix_VolumeMusic(volume); + + // wait for the music to complete + while(Mix_PlayingMusic() || Mix_PausedMusic()) + { + SDL_Delay(50); + } + + return(0); +} + +int sdlplayer_fx(char *filename, int volume) +{ + Mix_Chunk *sample; + static int channel; + + g_warning("sdlplayer %s\n", filename); + + sample=Mix_LoadWAV_RW(SDL_RWFromFile(filename, "rb"), 1); + if(!sample) { + return(cleanExit("Mix_LoadWAV_RW")); + // handle error + } + + Mix_VolumeChunk(sample, MIX_MAX_VOLUME); + + if((channel=Mix_PlayChannel(-1, sample, 0))==-1) { + return(cleanExit("Mix_LoadChannel(0x%p,1)",channel)); + } + + while(Mix_Playing(channel)) + { + SDL_Delay(50); + } + + // free the sample + // Mix_Chunk *sample; + Mix_FreeChunk(sample); + + g_warning("sdlplayer complete playing of %s\n", filename); + + return(0); +} + +void sdlplayer_pause_music() +{ + if(!sound_closed && Mix_PlayingMusic()) + Mix_PauseMusic(); +} + +void sdlplayer_halt_music() +{ + if(!sound_closed) + Mix_HaltMusic(); +} + +void sdlplayer_halt_fx() +{ + if(!sound_closed) + Mix_HaltChannel(-1); +} + +void sdlplayer_resume_music() +{ + if(!sound_closed) + Mix_ResumeMusic(); +} + +void sdlplayer_resume_fx() +{ + if(!sound_closed) + Mix_Resume(-1); +} + +void sdlplayer_close() +{ + sound_closed = TRUE; + Mix_HaltMusic(); + Mix_HaltChannel(-1); + Mix_CloseAudio(); +} + +void sdlplayer_reopen() +{ + Mix_OpenAudio(44100,MIX_DEFAULT_FORMAT,2,AUDIO_BUFFERS); + sound_closed = FALSE; + //Mix_ResumeMusic(); + //Mix_Resume(-1); + +} + +#endif // USE_SDLMIXER diff --git a/src/gcompris/soundutil.c b/src/gcompris/soundutil.c index 38dd1cb..5041c97 100644 --- a/src/gcompris/soundutil.c +++ b/src/gcompris/soundutil.c @@ -54,6 +54,21 @@ gc_sound_policy_get() return sound_policy; } +void +gc_sound_close() +{ + gc_sound_bg_close(); + gc_sound_fx_close(); +} + + +void +gc_sound_reopen() +{ + gc_sound_bg_reopen(); + gc_sound_fx_reopen(); +} + GSList * gc_sound_get_music_list() { diff --git a/src/gcompris/soundutil_sdl.c b/src/gcompris/soundutil_sdl.c new file mode 100644 index 0000000..9f55249 --- /dev/null +++ b/src/gcompris/soundutil_sdl.c @@ -0,0 +1,405 @@ +/* gcompris - soundutil.c + * + * Copyright (C) 2002 Pascal Georges + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#ifdef USE_SDLMIXER + +#include "string.h" + +#ifdef __APPLE__ +# include <sys/types.h> +#endif +#include "gcompris.h" +#include "soundutil_sdl.h" +#include <signal.h> +#include <glib.h> + +static int sound_policy; +static gboolean music_paused = FALSE; +static gboolean sound_closed = FALSE; + +/* mutex */ +GMutex *lock = NULL; +GMutex *lock_music = NULL; +GMutex *lock_fx = NULL; +GCond *cond = NULL; + +/* Singleton */ +static guint sound_init = 0; + +/* Forward function declarations */ +GThread *thread_scheduler_fx, *thread_scheduler_music; + +static void *thread_play_ogg (gchar *file); + +static gpointer scheduler_fx (gpointer user_data); +static gpointer scheduler_music (gpointer user_data); + +/* sound control */ +GObject *gc_sound_controller = NULL; +void gc_sound_callback_sdl(GcomprisSound *ctl, + gchar *file, gpointer user_data); + +/* ===================================================================== + * + * =====================================================================*/ +void +gc_sound_init() +{ + + /* Check to run the init once only */ + if(sound_init == 1) + { + if(sound_closed == TRUE) + gc_sound_reopen(); + + return; + } + sound_init = 1; + + gc_sound_controller = g_object_new (GCOMPRIS_SOUND_TYPE, NULL); + + g_signal_connect( gc_sound_controller, + "sound-played", + (GCallback) gc_sound_callback_sdl, + NULL); + + g_assert( gc_sound_controller != NULL ); + + /* Initialize the thread system */ + if (!g_thread_supported ()) g_thread_init (NULL); + + lock = g_mutex_new (); + lock_music = g_mutex_new (); + lock_fx = g_mutex_new (); + cond = g_cond_new (); + + sound_policy = PLAY_AFTER_CURRENT; + + if(sdlplayer_init()!=0) { + /* Sound init failed. Desactivate the sound */ + gc_prop_get()->music = 0; + gc_prop_get()->fx = 0; + return; + } + + thread_scheduler_fx = g_thread_create((GThreadFunc)scheduler_fx, NULL, FALSE, NULL); + if (thread_scheduler_fx == NULL) + perror("create failed for fx scheduler"); + + thread_scheduler_music = g_thread_create((GThreadFunc)scheduler_music, NULL, FALSE, NULL); + if (thread_scheduler_music == NULL) + perror("create failed for music scheduler"); + +} + +void +gc_sound_bg_close() +{ + if ( !sound_closed ) + { + sound_closed = TRUE; + if ( music_paused ) { + music_paused = FALSE; + gc_sound_bg_resume(); + } + g_mutex_lock(lock_fx); + sdlplayer_halt_music(); + sdlplayer_halt_fx(); + g_mutex_lock(lock_music); + sdlplayer_close(); + } +} + +void +gc_sound_fx_close() +{ +} + +void +gc_sound_fx_reopen() +{ + if (gc_prop_get()->fx || gc_prop_get()->music) { + if (sound_closed) + { + sdlplayer_reopen(); + g_mutex_unlock(lock_fx); + g_mutex_unlock(lock_music); + sound_closed = FALSE; + music_paused = FALSE; + } + } +} + +void +gc_sound_bg_reopen() +{ +} + +void +gc_sound_bg_pause() +{ + sdlplayer_pause_music(); + music_paused = TRUE; +} + +void +gc_sound_bg_resume() +{ + sdlplayer_resume_music(); + music_paused = FALSE; +} + +void +gc_sound_fx_pause() +{ +} + +void +gc_sound_fx_resume() +{ +} + +/* ===================================================================== + * Thread scheduler background : + * - launches a single thread for playing and play any file found + * in the gcompris music directory + ======================================================================*/ +static gpointer +scheduler_music (gpointer user_data) +{ + GcomprisProperties *properties = gc_prop_get(); + gint i; + gchar *str; + gchar *music_dir; + GSList *musiclist = NULL; + GDir *dir; + const gchar *one_dirent; + + /* Sleep to let gcompris intialisation and intro music to complete */ + g_usleep(25000000); + + /* Load the Music directory file names */ + music_dir = g_strconcat(properties->package_data_dir, "/music/background", NULL); + + dir = g_dir_open(music_dir, 0, NULL); + + if (!dir) { + g_warning ("Couldn't open music dir: %s", music_dir); + g_free(music_dir); + return NULL; + } + + /* Fill up the music list */ + while((one_dirent = g_dir_read_name(dir)) != NULL) + { + if (g_str_has_suffix(one_dirent, ".ogg")) + { + str = g_strdup_printf("%s/%s", music_dir, one_dirent); + musiclist = g_slist_insert (musiclist, str, RAND(0, g_slist_length(musiclist))); + } + } + g_dir_close(dir); + + /* No music no play */ + if(g_slist_length(musiclist)==0) + { + g_free(music_dir); + return NULL; + } + + /* Now loop over all our music files */ + while (TRUE) + { + for(i=0; i<g_slist_length(musiclist); i++) + { + /* Music can be disabled at any time */ + while(!gc_prop_get()->music || music_paused || sound_closed) + g_usleep(1000000); + + /* WARNING Displaying stuff in a thread seems to make gcompris unstable */ + /* display_ogg_file_credits((char *)g_list_nth_data(musiclist, i)); */ + // if(decode_ogg_file((char *)g_list_nth_data(musiclist, i))!=0) + g_mutex_lock(lock_music); + if(sdlplayer_music((char *)g_slist_nth_data(musiclist, i), 128)!=0){ + g_warning("sdlplayer_music failed, try again in 5 seconds"); + g_usleep(5000000); + } + g_mutex_unlock(lock_music); + + } + } + + /* Never happen */ + g_slist_free(musiclist); + g_warning( "The background thread music is stopped now. "\ + "The files in %s are not ogg vorbis OR the sound output failed", + music_dir); + g_free(music_dir); + return NULL; +} + +/* ===================================================================== + * Thread scheduler : + * - launches a single thread for playing a file + * - joins the previous thread at its end + * - then launches another thread if some sounds are pending + * - the thread never ends + ======================================================================*/ +static gpointer +scheduler_fx (gpointer user_data) +{ + char *sound = NULL; + + while (TRUE) + { + if ( ( sound = get_next_sound_to_play( ) ) != NULL ) + { + thread_play_ogg(sound); + g_free(sound); + } + else + { + g_mutex_lock (lock); + g_cond_wait (cond, lock); + g_mutex_unlock (lock); + } + } + return NULL; +} + + +/* ===================================================================== + * Thread function for playing a single file + ======================================================================*/ +static void* +thread_play_ogg (gchar *file) +{ + gchar *absolute_file; + + g_warning(" Thread_play_ogg %s", file); + + absolute_file = gc_file_find_absolute(file); + + if (!absolute_file) + return NULL; + + g_warning(" Calling gcompris internal sdlplayer_file (%s)", absolute_file); + g_mutex_lock(lock_fx); + sdlplayer_fx(absolute_file, 128); + g_mutex_unlock(lock_fx); + g_signal_emit (gc_sound_controller, + GCOMPRIS_SOUND_GET_CLASS (gc_sound_controller)->sound_played_signal_id, + 0 /* details */, + g_strdup(file)); + g_warning(" sdlplayer_fx(%s) ended.", absolute_file); + + g_free(absolute_file); + + return NULL; +} + +void +fx_play() +{ + // Tell the scheduler to check for new sounds to play + g_warning("Tell the scheduler to check for new sounds to play\n"); + g_cond_signal (cond); +} + +void gc_sound_callback_sdl(GcomprisSound *ctl, + gchar *file, gpointer user_data) +{ + gc_sound_callback(file); +} + +/*************************************/ +/* GObject control sound */ +struct _GcomprisSoundPrivate +{ +}; + +/* "gcompris-marshal.h" */ + +#include <glib-object.h> + +/* VOID:POINTER (gcompris-marshal.list:3) */ +#define gnome_canvas_marshal_VOID__POINTER g_cclosure_marshal_VOID__POINTER + +static void +gc_sound_instance_init (GTypeInstance *instance, + gpointer g_class) +{ + GcomprisSound *self = (GcomprisSound *)instance; + self->private = g_new (GcomprisSoundPrivate, 1); +} + +static void +default_sound_played_signal_handler (GcomprisSound *obj, gchar *file, gpointer user_data) +{ + /* Here, we trigger the real file write. */ + g_warning ("sound_played: %s\n", file); +} + +static void +gc_sound_class_init (gpointer g_class, + gpointer g_class_data) +{ + GcomprisSoundClass *klass = GCOMPRIS_SOUND_CLASS (g_class); + + klass->sound_played = default_sound_played_signal_handler; + + klass->sound_played_signal_id = + g_signal_new ("sound-played", + G_TYPE_FROM_CLASS (g_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + G_STRUCT_OFFSET (GcomprisSoundClass, sound_played), + NULL /* accumulator */, + NULL /* accu_data */, + gnome_canvas_marshal_VOID__POINTER, + G_TYPE_NONE /* return_type */, + 1 /* n_params */, + G_TYPE_POINTER /* param_types */); + +} + +GType gc_sound_get_type (void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (GcomprisSoundClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + gc_sound_class_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (GcomprisSound), + 0, /* n_preallocs */ + gc_sound_instance_init /* instance_init */ + }; + type = g_type_register_static (G_TYPE_OBJECT, + "GcomprisSoundType", + &info, 0); + } + return type; +} + +#endif + diff --git a/src/gcompris/soundutil_sdl.h b/src/gcompris/soundutil_sdl.h new file mode 100644 index 0000000..9f0286a --- /dev/null +++ b/src/gcompris/soundutil_sdl.h @@ -0,0 +1,99 @@ +/* gcompris - gameutil.h + * + * Copyright (C) 2000 Bruno Coudoin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 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; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#ifdef USE_SDLMIXER + +#ifndef SOUNDUTIL_SDL_H +#define SOUNDUTIL_SDL_H + +#include <stdio.h> +#include "gcompris.h" + +#define MAX_QUEUE_LENGTH 5 +#define MAX_SOUND_FILES 20 + +int decode_ogg_file(char *infile); +void display_ao_devices(); + +/* + * SDL PLAYER + */ +int sdlplayer_init(); +void sdlplayer_close(); +void sdlplayer_reopen(); + +int sdlplayer_music(char *filename, int volume); +void sdlplayer_halt_music(); +void sdlplayer_pause_music(); +void sdlplayer_resume_music(); + +void sdlplayer_halt_fx(); +void sdlplayer_resume_fx(); +int sdlplayer_fx(char *filename, int volume); + +gchar *gc_sound_alphabet(gchar *chars); + + +/*************************************************************/ +/* GObject to control sound. code get from maman-file.h */ +/*************************************************************/ +/* + * Potentially, include other headers on which this header depends. + */ +#include <glib-object.h> + +#define GCOMPRIS_SOUND_TYPE (gc_sound_get_type ()) +#define GCOMPRIS_SOUND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCOMPRIS_SOUND_TYPE, GcomprisSound)) +#define GCOMPRIS_SOUND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCOMPRIS_SOUND_TYPE, GcomprisSoundClass)) +#define GCOMPRIS_SOUND_IS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCOMPRIS_SOUND_TYPE)) +#define GCOMPRIS_SOUND_IS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCOMPRIS_SOUND_TYPE)) +#define GCOMPRIS_SOUND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCOMPRIS_SOUND_TYPE, GcomprisSoundClass)) + +typedef struct _GcomprisSound GcomprisSound; +typedef struct _GcomprisSoundClass GcomprisSoundClass; +typedef struct _GcomprisSoundPrivate GcomprisSoundPrivate; + +struct _GcomprisSound { + GObject parent; + /* instance members */ + GcomprisSoundPrivate *private; +}; + +struct _GcomprisSoundClass { + GObjectClass parent; + + guint sound_played_signal_id; + void (*sound_played) (GcomprisSound *self, gchar *file, gpointer user_data); +}; + +/* used by MAMAN_TYPE_FILE */ +GType gc_sound_get_type (void); + +/* API. */ + +/* empty for now */ + + +/* Declaration of GCompris Sound Controller */ +extern GObject *gc_sound_controller; + +#endif + +#endif // |