diff options
author | Yves Combe <ycombe@src.gnome.org> | 2006-11-29 22:36:20 (GMT) |
---|---|---|
committer | Yves Combe <ycombe@src.gnome.org> | 2006-11-29 22:36:20 (GMT) |
commit | ca72d79e5237bdecab78bcc20225242488ea1e8f (patch) | |
tree | e7ced9d2c038cb56788eabb8a9079aba43a2e887 | |
parent | 33cfc959568035ec0cfd0088821cc99ad8ef64a9 (diff) |
Rewrite gc_sound without gob (in C).
-rw-r--r-- | ChangeLog | 70 | ||||
-rw-r--r-- | src/gc_sound/ChangeLog | 69 | ||||
-rw-r--r-- | src/gc_sound/aclocal.m4 | 54 | ||||
-rw-r--r-- | src/gc_sound/configure.in | 6 | ||||
-rw-r--r-- | src/gc_sound/src/Makefile.am | 47 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-channel.c | 290 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-channel.gob | 321 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-channel.h | 104 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-item.c | 421 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-item.gob | 310 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-item.h | 104 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-marshallers.c | 56 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-marshallers.h | 21 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-mixer-SDL.c | 456 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-mixer-SDL.h | 110 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-mixer-private.h | 52 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-mixer.c | 125 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-mixer.gob | 156 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound-mixer.h | 97 | ||||
-rw-r--r-- | src/gc_sound/src/gc-sound.h | 1 | ||||
-rw-r--r-- | src/gc_sound/src/marshallers.list | 3 | ||||
-rw-r--r-- | src/gc_sound/src/test_gc_sound.c | 78 |
22 files changed, 2126 insertions, 825 deletions
@@ -1,3 +1,73 @@ +2006-11-29 Yves Combe <yves@ycombe.net> + + Rewrite gc_sound without gob (in C). + Architecture change: + - GCSoundMixer is an interface. GCSoundMixerSDL just implement it. + That to allow change libsdl dependencie to gstreamer when needed. + - GCSoundChannel and GCSoundItem just uses GCSoundMixer interface to run. + + TODO: + - object_ref is not correct. + - python binding. + - add a record capability in interface (for now SDL_mixer can not do it). + - future way. add a gstreamer implementation of interface. + + * aclocal.m4: + * configure.in: + * src/gc_sound/src/Makefile.am: + * src/gc_sound/src/gc-sound-channel.c: (gc_sound_channel_play_item), + (gc_sound_channel_get_root), (gc_sound_channel_pause), + (gc_sound_channel_resume), (gc_sound_channel_halt), + (gc_sound_channel_get_policy), (gc_sound_channel_set_policy), + (gc_sound_channel_play), (gc_sound_channel_init), + (gc_sound_channel_get_property), (gc_sound_channel_set_property), + (gc_sound_channel_signal_chunk_end), (gc_sound_channel_signal_run), + (gc_sound_channel_class_init): + * src/gc_sound/src/gc-sound-channel.gob: + * src/gc_sound/src/gc-sound-channel.h: + * src/gc_sound/src/gc-sound-item.c: (gc_sound_item_run_next), + (gc_sound_item_set_loop), (gc_sound_item_get_policy), + (gc_sound_item_set_policy), (gc_sound_item_child_start), + (gc_sound_item_child_end), (gc_sound_item_append_child), + (gc_sound_item_play), (gc_sound_item_set_filename), + (gc_sound_item_get_filename), (gc_sound_item_signal_real_play), + (gc_sound_item_signal_play_end), (gc_sound_item_signal_play_start), + (gc_sound_item_signal_chunk_end), + (gc_sound_item_signal_chunk_start), (gc_sound_item_init), + (gc_sound_item_get_property), (gc_sound_item_set_property), + (gc_sound_item_class_init): + * src/gc_sound/src/gc-sound-item.gob: + * src/gc_sound/src/gc-sound-item.h: + * src/gc_sound/src/gc-sound-marshallers.c: + * src/gc_sound/src/gc-sound-marshallers.h: + * src/gc_sound/src/gc-sound-mixer-SDL.c: (gc_sound_mixer_SDL_new), + (gc_sound_mixer_SDL_open_audio), (gc_sound_mixer_SDL_close_audio), + (gc_sound_mixer_SDL_new_channel), (gc_sound_mixer_SDL_pause), + (gc_sound_mixer_SDL_resume), (gc_sound_mixer_SDL_halt), + (gc_sound_mixer_SDL_pause_channel), + (gc_sound_mixer_SDL_resume_channel), + (gc_sound_mixer_SDL_halt_channel), (gc_sound_mixer_SDL_play_item), + (channel_finished_cb), (gc_sound_mixer_SDL_channel_finished), + (gc_sound_mixer_SDL_init), (gc_sound_mixer_SDL_finalize), + (gc_sound_mixer_SDL_get_property), + (gc_sound_mixer_SDL_set_property), (gc_sound_mixer_SDL_class_init), + (gc_init_sound_mixer): + * src/gc_sound/src/gc-sound-mixer-SDL.h: + * src/gc_sound/src/gc-sound-mixer-private.h: + * src/gc_sound/src/gc-sound-mixer.c: (gc_sound_mixer_open_audio), + (gc_sound_mixer_close_audio), (gc_sound_mixer_new_channel), + (gc_sound_mixer_pause), (gc_sound_mixer_resume), + (gc_sound_mixer_halt), (gc_sound_mixer_pause_channel), + (gc_sound_mixer_resume_channel), (gc_sound_mixer_halt_channel), + (gc_sound_mixer_play_item), (gc_sound_mixer_get_type), + (_gc_sound_mixer_install_property), (gc_sound_mixer_iface_init): + * src/gc_sound/src/gc-sound-mixer.gob: + * src/gc_sound/src/gc-sound-mixer.h: + * src/gc_sound/src/gc-sound.h: + * src/gc_sound/src/marshallers.list: + * src/gc_sound/src/test_gc_sound.c: (main): + + 2006-11-16 Yves Combe <yves@ycombe.net> Added sound policy (play only if iddle, after current, or interrupt and play). diff --git a/src/gc_sound/ChangeLog b/src/gc_sound/ChangeLog index 87a4b27..72e5c10 100644 --- a/src/gc_sound/ChangeLog +++ b/src/gc_sound/ChangeLog @@ -1,3 +1,72 @@ +2006-11-29 Yves Combe <yves@ycombe.net> + + Rewrite gc_sound without gob (in C). + Architecture change: + - GCSoundMixer is an interface. GCSoundMixerSDL just implement it. + That to allow change libsdl dependencie to gstreamer when needed. + - GCSoundChannel and GCSoundItem just uses GCSoundMixer interface to run. + + TODO: + - object_ref is not correct. + - python binding. + - add a record capability in interface (for now SDL_mixer can not do it). + - future way. add a gstreamer implementation of interface. + + * aclocal.m4: + * configure.in: + * src/Makefile.am: + * src/gc-sound-channel.c: (gc_sound_channel_play_item), + (gc_sound_channel_get_root), (gc_sound_channel_pause), + (gc_sound_channel_resume), (gc_sound_channel_halt), + (gc_sound_channel_get_policy), (gc_sound_channel_set_policy), + (gc_sound_channel_play), (gc_sound_channel_init), + (gc_sound_channel_get_property), (gc_sound_channel_set_property), + (gc_sound_channel_signal_chunk_end), (gc_sound_channel_signal_run), + (gc_sound_channel_class_init): + * src/gc-sound-channel.gob: + * src/gc-sound-channel.h: + * src/gc-sound-item.c: (gc_sound_item_run_next), + (gc_sound_item_set_loop), (gc_sound_item_get_policy), + (gc_sound_item_set_policy), (gc_sound_item_child_start), + (gc_sound_item_child_end), (gc_sound_item_append_child), + (gc_sound_item_play), (gc_sound_item_set_filename), + (gc_sound_item_get_filename), (gc_sound_item_signal_real_play), + (gc_sound_item_signal_play_end), (gc_sound_item_signal_play_start), + (gc_sound_item_signal_chunk_end), + (gc_sound_item_signal_chunk_start), (gc_sound_item_init), + (gc_sound_item_get_property), (gc_sound_item_set_property), + (gc_sound_item_class_init): + * src/gc-sound-item.gob: + * src/gc-sound-item.h: + * src/gc-sound-marshallers.c: + * src/gc-sound-marshallers.h: + * src/gc-sound-mixer-SDL.c: (gc_sound_mixer_SDL_new), + (gc_sound_mixer_SDL_open_audio), (gc_sound_mixer_SDL_close_audio), + (gc_sound_mixer_SDL_new_channel), (gc_sound_mixer_SDL_pause), + (gc_sound_mixer_SDL_resume), (gc_sound_mixer_SDL_halt), + (gc_sound_mixer_SDL_pause_channel), + (gc_sound_mixer_SDL_resume_channel), + (gc_sound_mixer_SDL_halt_channel), (gc_sound_mixer_SDL_play_item), + (channel_finished_cb), (gc_sound_mixer_SDL_channel_finished), + (gc_sound_mixer_SDL_init), (gc_sound_mixer_SDL_finalize), + (gc_sound_mixer_SDL_get_property), + (gc_sound_mixer_SDL_set_property), (gc_sound_mixer_SDL_class_init), + (gc_init_sound_mixer): + * src/gc-sound-mixer-SDL.h: + * src/gc-sound-mixer-private.h: + * src/gc-sound-mixer.c: (gc_sound_mixer_open_audio), + (gc_sound_mixer_close_audio), (gc_sound_mixer_new_channel), + (gc_sound_mixer_pause), (gc_sound_mixer_resume), + (gc_sound_mixer_halt), (gc_sound_mixer_pause_channel), + (gc_sound_mixer_resume_channel), (gc_sound_mixer_halt_channel), + (gc_sound_mixer_play_item), (gc_sound_mixer_get_type), + (_gc_sound_mixer_install_property), (gc_sound_mixer_iface_init): + * src/gc-sound-mixer.gob: + * src/gc-sound-mixer.h: + * src/gc-sound.h: + * src/marshallers.list: + * src/test_gc_sound.c: (main): + 2006-11-16 Yves Combe <yves@ycombe.net> Added sound policy (play only if iddle, after current, or interrupt and play). diff --git a/src/gc_sound/aclocal.m4 b/src/gc_sound/aclocal.m4 index 936c7ca..75137d0 100644 --- a/src/gc_sound/aclocal.m4 +++ b/src/gc_sound/aclocal.m4 @@ -70,6 +70,60 @@ AC_DEFUN([GOB2_CHECK],[ GOB2_HOOK($1,[],[AC_MSG_WARN([Cannot find GOB-2, check http://www.5z.com/jirka/gob.html])]) ]) +dnl -*- mode: autoconf -*- + +# serial 1 + +dnl Usage: +dnl GTK_DOC_CHECK([minimum-gtk-doc-version]) +AC_DEFUN([GTK_DOC_CHECK], +[ + AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first + AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first + dnl for overriding the documentation installation directory + AC_ARG_WITH(html-dir, + AC_HELP_STRING([--with-html-dir=PATH], [path to installed docs]),, + [with_html_dir='${datadir}/gtk-doc/html']) + HTML_DIR="$with_html_dir" + AC_SUBST(HTML_DIR) + + dnl enable/disable documentation building + AC_ARG_ENABLE(gtk-doc, + AC_HELP_STRING([--enable-gtk-doc], + [use gtk-doc to build documentation [default=no]]),, + enable_gtk_doc=no) + + have_gtk_doc=no + if test x$enable_gtk_doc = xyes; then + if test -z "$PKG_CONFIG"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + if test "$PKG_CONFIG" != "no" && $PKG_CONFIG --exists gtk-doc; then + have_gtk_doc=yes + fi + + dnl do we want to do a version check? +ifelse([$1],[],, + [gtk_doc_min_version=$1 + if test "$have_gtk_doc" = yes; then + AC_MSG_CHECKING([gtk-doc version >= $gtk_doc_min_version]) + if $PKG_CONFIG --atleast-version $gtk_doc_min_version gtk-doc; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + have_gtk_doc=no + fi + fi +]) + if test "$have_gtk_doc" != yes; then + enable_gtk_doc=no + fi + fi + + AM_CONDITIONAL(ENABLE_GTK_DOC, test x$enable_gtk_doc = xyes) + AM_CONDITIONAL(GTK_DOC_USE_LIBTOOL, test -n "$LIBTOOL") +]) + # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # serial 48 Debian 1.5.22-4 AC_PROG_LIBTOOL diff --git a/src/gc_sound/configure.in b/src/gc_sound/configure.in index be5d5f9..3d3b878 100644 --- a/src/gc_sound/configure.in +++ b/src/gc_sound/configure.in @@ -14,8 +14,14 @@ AC_PROG_LIBTOOL AC_PROG_CC AC_PROG_INSTALL +GTK_DOC_CHECK GOB2_CHECK([2.0.0]) +AC_MSG_CHECKING([for glib-genmarshal]) +GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0` +AC_SUBST(GLIB_GENMARSHAL) +AC_MSG_RESULT($GLIB_GENMARSHAL) + PKG_CHECK_MODULES(GC_SOUND,[ glib-2.0 >= 2.10.0 gobject-2.0 >= 2.8.0 diff --git a/src/gc_sound/src/Makefile.am b/src/gc_sound/src/Makefile.am index 39c1d2e..9999865 100644 --- a/src/gc_sound/src/Makefile.am +++ b/src/gc_sound/src/Makefile.am @@ -12,19 +12,24 @@ libgcsoundincludedir = $(includedir)/gcompris/gcsound libgcsoundinclude_HEADERS = \ gc-sound.h \ gc-sound-mixer.h \ + gc-sound-mixer-SDL.h \ gc-sound-channel.h \ + gc-sound-marshallers.h \ gc-sound-item.h -libgcsound_PRIVATE = \ - gc-sound.h \ - gc-sound-mixer-private.h \ - gc-sound-channel-private.h \ - gc-sound-item-private.h +libgcsound_PRIVATE = +# \ +# gc-sound.h \ +# gc-sound-mixer-private.h \ +# gc-sound-channel-private.h \ +# gc-sound-item-private.h libgcsound_2_la_SOURCES = \ $(libgcsoundinclude_HEADERS) \ $(libgcsound_PRIVATE) \ gc-sound-mixer.c \ + gc-sound-mixer-SDL.c \ + gc-sound-marshallers.c \ gc-sound-channel.c \ gc-sound-item.c @@ -43,7 +48,31 @@ gc-sound-item.c: gc-sound-channel.c gc-sound-mixer.c: gc-sound-channel.c -%.c %.h %-private.h: %.gob - gob2 $< -clean-local: - rm -f gc-sound-*.h gc-sound-*.c +gc-sound-marshallers.h: $(srcdir)/marshallers.list $(srcdir)/Makefile + @( $(GLIB_GENMARSHAL) --header --prefix=gc_sound_marshal $< ) > xgen-cmh \ + && (cmp -s xgen-cmh $@ || (echo "Creating $@..."; cp xgen-cmh $@) ) \ + && rm -f xgen-cmh + +gc-sound-marshallers.c: $(srcdir)/marshallers.list $(srcdir)/Makefile + @( echo "#include <gc-sound-marshallers.h>"; \ + $(GLIB_GENMARSHAL) --body --prefix=gc_sound_marshal $< ) > xgen-cmc \ + && (cmp -s xgen-cmc $@ || (echo "Creating $@..."; cp xgen-cmc $@) ) \ + && rm -f xgen-cmc + +# gc-sound-enumerations.h: $(static_headers) Makefile gc-sound-enumerations.h.in +# @( cd $(srcdir) && $(GLIB_MKENUMS) --template gc-sound-enumerations.h.in \ +# $(gc_sound_HEADERS) ) > xgen-gtbh \ +# && (cmp -s xgen-gtbh $@ || (echo "Creating $@..."; cp xgen-gtbh $@) ) \ +# && rm -f xgen-gtbh + +# gc-sound-enumerations.c: $(static_headers) Makefile gc-sound-enumerations.c.in +# @( cd $(srcdir) && $(GLIB_MKENUMS) --template gc-sound-enumerations.c.in \ +# $(gc_sound_HEADERS) ) >> xgen-gtbc \ +# && (cmp -s xgen-gtbc $@ || (echo "Creating $@..."; cp xgen-gtbc $@) ) \ +# && rm -f xgen-gtbc + +# gc-sound-enumerations.c.in \ +# gc-sound-enumerations.h.in \ +EXTRA_DIST=\ + marshallers.list \ + $(NULL) diff --git a/src/gc_sound/src/gc-sound-channel.c b/src/gc_sound/src/gc-sound-channel.c new file mode 100644 index 0000000..15592a8 --- /dev/null +++ b/src/gc_sound/src/gc-sound-channel.c @@ -0,0 +1,290 @@ +/* gcompris - gc-sound-channel.c + * + * Copyright (C) 2006 Yves Combe + * + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <gc-sound-channel.h> +#include <gc-sound-marshallers.h> + +/* signals */ +enum { + RUN, /* internal: launch recursive playing of playlist */ + CHUNK_END, + PLAY_START, /* Start real playing of item */ + PLAY_END, /* end playing */ + PAUSED, /* channel paused */ + RESUMED, /* channel resumed */ + HALTED, /* channel halted */ + DESTROY, + + N_SIGNALS +}; + +guint gc_sound_channel_signals[N_SIGNALS] = {0}; + +gboolean gc_sound_channel_play_item (GCSoundChannel * self, GCSoundItem *item) +{ + g_warning("gc_sound_channel_play_item %s %s", self->nick, item->nick); + + self->running_sample = item; + self->stopped = FALSE; + + return gc_sound_mixer_play_item (self->mixer, self, item); +} + +GCSoundItem * gc_sound_channel_get_root (GCSoundChannel * self) +{ + return self->root; +} + +gboolean gc_sound_channel_pause (GCSoundChannel * self) +{ + return gc_sound_mixer_pause_channel( self->mixer, self); +} + +gboolean gc_sound_channel_resume (GCSoundChannel * self) +{ + return gc_sound_mixer_resume_channel( self->mixer, self); +} + +gboolean gc_sound_channel_halt (GCSoundChannel * self) +{ + return gc_sound_mixer_halt_channel( self->mixer, self); +} + +GCSoundPolicy gc_sound_channel_get_policy (GCSoundChannel * self) +{ + return self->policy; +} +gboolean gc_sound_channel_set_policy (GCSoundChannel * self, + GCSoundPolicy policy) +{ + self->policy = policy; + return TRUE; +} + +gboolean gc_sound_channel_play (GCSoundChannel *self, + GCSoundItem *item) +{ + GCSoundPolicy policy; + + /* item policy if it's set */ + if (gc_sound_item_get_policy(item) == GC_SOUND_POLICY_NONE) + policy = self->policy; + else + policy = gc_sound_item_get_policy(item); + + //g_warning ("play_item %s with policy %d", item->nick, policy); + + switch (policy) { + case GC_SOUND_PLAY_ONLY_IF_IDLE: + if (self->running_sample || g_list_length (self->playlist)>0) + return; + self->playlist = g_list_append (self->playlist, item); + // TODO send a signal to run !!! + g_signal_emit(self, gc_sound_channel_signals[RUN], 0); + break; + + case GC_SOUND_INTERRUPT_AND_PLAY: + g_list_free (self->playlist); + self->playlist = NULL; + self->playlist = g_list_append (self->playlist, item); + if (self->running_sample){ + self->stopped = TRUE; + //g_warning("halting channel %d %d", self->_priv->channel, g_list_length(self->_priv->play_list)); + // send a signal to halt. + gc_sound_channel_halt(self); + } + // TODO send a signal to run !!! + g_signal_emit(self, gc_sound_channel_signals[RUN], 0); + break; + + default: + self->playlist = g_list_append (self->playlist, item); + if (!self->running_sample) + // TODO send a signal to run !!! + g_signal_emit(self, gc_sound_channel_signals[RUN], 0); + break; + } + +} + +/* GType stuff */ +enum { + PROP_0, + PROP_MIXER +}; + + +/* GType */ +G_DEFINE_TYPE(GCSoundChannel, gc_sound_channel, G_TYPE_OBJECT); + +static void +gc_sound_channel_init(GCSoundChannel* self) +{ + // initialisation des variables. + //g_warning("gc_sound_channel_init"); + + self->volume = 1.0; + self->policy = GC_SOUND_PLAY_AFTER_CURRENT; + + self->stopped = FALSE; + + self->mixer = NULL; + self->root = GC_SOUND_ITEM(g_object_new(GC_TYPE_SOUND_ITEM, "channel", self, NULL)); + + self->playlist = NULL; + + //this one is the item with the file + self->running_sample = NULL; + // this one is the group playing + self->running_root = NULL; + + //debug. will be removed. + gchar *nick; + +} + +static void +gc_sound_channel_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec) +{ + GCSoundChannel *self = GC_SOUND_CHANNEL(object); + switch(prop_id) { + case PROP_MIXER: + g_value_set_object(value, self->mixer); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gc_sound_channel_set_property(GObject* object, guint prop_id, GValue const* value, GParamSpec* pspec) +{ + GCSoundChannel *self = GC_SOUND_CHANNEL(object); + + switch(prop_id) { + case PROP_MIXER: + self->mixer = g_value_get_object(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } + +} + +static void +gc_sound_channel_signal_chunk_end (GCSoundChannel *self) +{ + GCSoundItem *chunk = self->running_sample; + + self->running_sample = NULL; + + g_return_if_fail(GC_IS_SOUND_ITEM(chunk)); + + g_warning ("%s received chunk_end self->stopped %s", self->nick, self->stopped ? "TRUE" : "FALSE"); + + g_signal_emit_by_name (chunk, "chunk_end", 0, self->stopped); +} + +static void +gc_sound_channel_signal_run (GCSoundChannel *self) +{ + GList *item_root; + gboolean ret; + + g_warning("Channel %s received run !", self->nick); + + while (g_list_length(self->playlist)>0) + { + self->running_root = g_list_first (self->playlist); + self->playlist = g_list_remove_link (self->playlist, self->running_root); + + ret = gc_sound_item_run_next (GC_SOUND_ITEM(self->running_root->data), FALSE); + if (ret) + return ; + } +} + +static void +gc_sound_channel_class_init(GCSoundChannelClass* self_class) +{ + // c'est ici qu'il faut passer les properties et les signals. + // g_warning("gc_sound_channel_class_init"); + + GObjectClass* go_class; + + /* GObjectClass */ + go_class = G_OBJECT_CLASS(self_class); + + go_class->get_property = gc_sound_channel_get_property; + go_class->set_property = gc_sound_channel_set_property; + + g_object_class_install_property(go_class, + PROP_MIXER, + g_param_spec_object ("mixer", + "GCompris mixer", + "The mixer where this channel stand", + GC_TYPE_SOUND_MIXER, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + +/* signals */ +/* enum { */ +/* RUN, /\* internal: launch recursive playing of playlist *\/ */ + +/* PLAY_START, /\* Start real playing of item *\/ */ +/* PLAY_END, /\* end playing *\/ */ +/* PAUSED, /\* channel paused *\/ */ +/* RESUMED, /\* channel resumed *\/ */ +/* HALTED, /\* channel halted *\/ */ +/* DESTROY, */ + +/* N_SIGNALS */ +/* }; */ + + self_class->run = gc_sound_channel_signal_run; + self_class->chunk_end = gc_sound_channel_signal_chunk_end; + + gc_sound_channel_signals[RUN] = + g_signal_new("run", /* name */ + GC_TYPE_SOUND_CHANNEL, /* itype */ + (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION), /* flags */ + G_STRUCT_OFFSET (GCSoundChannelClass, run), /* offset function */ + NULL, /* accumulator */ + NULL, /* accu data */ + gc_sound_marshal_VOID__VOID, /* marshal */ + G_TYPE_NONE, /* return value */ + 0 /* n_params */ + ); + + gc_sound_channel_signals[CHUNK_END] = + g_signal_new("chunk_end", /* name */ + GC_TYPE_SOUND_CHANNEL, /* itype */ + (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION), /* flags */ + G_STRUCT_OFFSET (GCSoundChannelClass, chunk_end), /* offset function */ + NULL, /* accumulator */ + NULL, /* accu data */ + gc_sound_marshal_VOID__BOOLEAN, /* marshal */ + G_TYPE_NONE, /* return value */ + 1, /* n_params */ + G_TYPE_BOOLEAN + ); + +} diff --git a/src/gc_sound/src/gc-sound-channel.gob b/src/gc_sound/src/gc-sound-channel.gob deleted file mode 100644 index 37bfc08..0000000 --- a/src/gc_sound/src/gc-sound-channel.gob +++ /dev/null @@ -1,321 +0,0 @@ -%alltop{/* gcompris - gc-sound-channel.gob - * - * Copyright (C) 2006 Yves Combe - * - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -%} - -requires 2.0.0 - -%{ -#include <gc-sound-channel.h> -#include <SDL.h> -#include <SDL_thread.h> -#include <SDL_mixer.h> -#include <SDL_audio.h> -#include <libintl.h> - -#define _(String) gettext (String) -#define gettext_noop(String) String - -#ifndef N_ -#define N_(String) gettext_noop (String) -#endif - -#include "gc-sound-channel-private.h" -#include "gc-sound-item-private.h" -%} - -%h{ -#include <gc-sound.h> -%} - - -%{ -static GHashTable *channels_table = NULL; -%} - -enum GC_SOUND { - POLICY_NONE, - PLAY_ONLY_IF_IDLE, - PLAY_AFTER_CURRENT, - INTERRUPT_AND_PLAY -} GC:Sound:Policy; - -class GC:Sound:Channel from G:Object { - public gchar *nick = {NULL}; - - /* channel is the mixer channel number we use */ - private int channel - destroy { - g_hash_table_remove(channels_table, GINT_TO_POINTER(channel)); - - if (g_hash_table_size (channels_table) == 0) { - g_hash_table_destroy(channels_table); - channels_table = NULL; - } - }; - - private gboolean initialised = {FALSE}; - - private Mix_Chunk *sample; - private GC:Sound:Item *playing_item = { NULL }; - private G:List *playing_root = { NULL }; - private G:List *play_list = { NULL }; - - /* the default volume for the channel */ - private int volume = { MIX_MAX_VOLUME }; - property INT volume - ( nick= _("Channel volume"), - blurb= _("Default volume of the channel"), - export, - link); - - /* The default policy for the channel */ - private GCSoundPolicy policy = {GC_SOUND_PLAY_AFTER_CURRENT}; - property ENUM policy - ( nick = _("Channel policy"), - blurb = _("Default policy for this channel"), - enum_type = GC:Sound:Policy, - export, link); - - /* the mixer we are attached on */ - /* The mixer initalise SDL and audio */ - private GC:Sound:Mixer *mixer = { NULL } - destroywith g_object_unref ; - - property OBJECT mixer - (nick = _("GCompris Sound Mixer"), - blurb = _("GCompris Sound Mixer where this sound channel is"), - object_type=GC:Sound:Mixer, - flags = CONSTRUCT_ONLY, - export) - set { self->_priv->mixer = GC_SOUND_MIXER(g_value_get_object -(VAL)); - self->_priv->channel = self->_priv->mixer->channels++ ; - Mix_AllocateChannels(self->_priv->mixer->channels ); - - g_warning("Channel #%d initialised", self->_priv->channel); - Mix_HaltChannel(self->_priv->channel); - - g_hash_table_insert(channels_table, &(self->_priv->channel), self); - - self->_priv->rootItem = GC_SOUND_ITEM(g_object_new(gc_sound_item_get_type(), "channel", self, NULL)); - - g_object_ref(self->_priv->rootItem); - - } - get { g_value_set_object (VAL, G_OBJECT(self->_priv->channel)); } - ; - - private GC:Sound:Item *rootItem = { NULL } - destroywith g_object_unref; - - property OBJECT rootItem - (nick = _("GCompris Sound Item root"), - blurb = _("GCompris Sound Item root"), - object_type=GC:Sound:Item, - export, link) - ; - - private gboolean stopped = { FALSE }; - - init (self) { - //g_warning("gc channel instance init"); - if (!channels_table) - channels_table = g_hash_table_new (g_int_hash, g_int_equal); - - Mix_ChannelFinished(self_channel_finished); - } - - class_init (class) { - //g_warning("gc channel class init"); - } - - public GC:Sound:Item * - new_item (self) - { - return GC_SOUND_ITEM(g_object_new(gc_sound_item_get_type(), "parent", self->_priv->rootItem, NULL)); - } - - private void channel_finished (int channel) - { - /* check we are on the right channel */ - /* this a too simple callback */ - /* get self */ - GCSoundChannel *self; - - //g_warning ("Channel finished %d", channel); - - self = GC_SOUND_CHANNEL(g_hash_table_lookup(channels_table, &channel)); - - if (!self) { - g_warning ("Cannot get GCSoundChannel from hash !!!!!"); - return; - } - self_play_finished (self, self->_priv->playing_item); - } - - private void real_play ( GC:Sound:Item *item, gpointer data) - { - //g_warning ("Real play %s", item->nick); - GCSoundChannel *self = GC_SOUND_CHANNEL(data); - - gchar * filename = gc_sound_item_get_filename(item); - - if (Mix_Playing(self->_priv->channel)){ - g_warning("Channel busy ? no play!"); - return; - } - - if (filename == NULL){ - g_warning("No filename ? no play!"); - return; - } - - self->_priv->sample=Mix_LoadWAV_RW(SDL_RWFromFile(filename, "rb"), 1); - if (!self->_priv->sample) { - g_warning("Sample music %s cannot be load", filename); - return; - } - - if ((item->volume == -1) || (item->volume > self->_priv->volume)) - Mix_VolumeChunk(self->_priv->sample, self->_priv->volume); - else - Mix_VolumeChunk(self->_priv->sample, item->volume); - - if (Mix_PlayChannel(self->_priv->channel, self->_priv->sample, 0)==-1) { - g_warning("Channel cannot play music %s", filename); - return; - } - - g_warning("Playing %s on channel #%d", filename, self->_priv->channel); - - - self->_priv->playing_item = item; - } - - - signal first NONE (POINTER) - void play_finished (self, GC:Sound:Item *item (check null type)) - { - //g_warning ("Channel finish item %s", item->nick); - Mix_FreeChunk(self->_priv->sample); - self->_priv->sample = NULL; - - gc_sound_item_play_next(item, self->_priv->stopped); - } - - /* connected to do_play signal of item */ - protected void do_play (GC:Sound:Item *item, gpointer data) - { - GCSoundChannel *self = GC_SOUND_CHANNEL(data); - GCSoundPolicy policy; - - /* item policy if it's set */ - if (gc_sound_item_get_policy(item) == GC_SOUND_POLICY_NONE) - policy = self->_priv->policy; - else - policy = gc_sound_item_get_policy(item); - - //g_warning ("play_item %s with policy %d", item->nick, policy); - - switch (policy) { - case GC_SOUND_PLAY_ONLY_IF_IDLE: - if (self->_priv->sample || g_list_length (self->_priv->play_list)>0) - return; - break; - - case GC_SOUND_INTERRUPT_AND_PLAY: - g_list_free (self->_priv->play_list); - self->_priv->play_list = NULL; - self->_priv->play_list = g_list_append (self->_priv->play_list, item); - if (self->_priv->sample){ - self->_priv->stopped = TRUE; - //g_warning("halting channel %d %d", self->_priv->channel, g_list_length(self->_priv->play_list)); - self_halt(self); - } - self_run(self); - break; - - default: - self->_priv->play_list = g_list_append (self->_priv->play_list, item); - if (!self->_priv->sample) - self_run(self); - break; - } - } - - protected void play_first_item(self) - { - gboolean ret; - - while (g_list_length(self->_priv->play_list)>0) - { - self->_priv->playing_root = g_list_first (self->_priv->play_list); - self->_priv->play_list = g_list_remove_link (self->_priv->play_list, self->_priv->playing_root); - - ret = gc_sound_item_play_next (GC_SOUND_ITEM(self->_priv->playing_root->data), FALSE); - if (ret) - return ; - } - } - - private void item_play_finished (GC:Sound:Item *item, gboolean stopped, gpointer data) - { - //g_warning("channel item_play_finished %s %s", item->nick, stopped ? "STOPPED":"normal"); - - /* if item our our root item playing */ - if (item == GC_SOUND_ITEM(GC_SOUND_CHANNEL(data)->_priv->playing_root->data)) - { - GC_SOUND_CHANNEL(data)->_priv->playing_root = NULL; - /* do not call run if we are stopping */ - if (GC_SOUND_CHANNEL(data)->_priv->stopped) - GC_SOUND_CHANNEL(data)->_priv->stopped = FALSE; - else - self_run(GC_SOUND_CHANNEL(data)); - } - } - - public void connect_me (self, GC:Sound:Item *item ) - { - gc_sound_item_connect__play_finished(item, self_item_play_finished, self); - gc_sound_item_connect__do_play(item, self_do_play, self); - gc_sound_item_connect__real_play(item, self_real_play, self); - - } - - private signal first NONE (NONE) - void run (self) - { - //g_warning("channel run"); - self_play_first_item(self); - } - - public signal first NONE (NONE) - void halt (self) - { - //g_warning("halting channel %d", self->_priv->channel); - Mix_HaltChannel(self->_priv->channel); - } - - private signal first NONE (POINTER) - void halt_and_play (self, GC:Sound:Item *item ) - { - } - -} diff --git a/src/gc_sound/src/gc-sound-channel.h b/src/gc_sound/src/gc-sound-channel.h new file mode 100644 index 0000000..ca1769e --- /dev/null +++ b/src/gc_sound/src/gc-sound-channel.h @@ -0,0 +1,104 @@ +/* gcompris - gc-sound-channel.h + * + * Copyright (C) 2006 Yves Combe + * + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __GC_SOUND_CHANNEL_H__ +#define __GC_SOUND_CHANNEL_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS + +typedef struct _GCSoundChannel GCSoundChannel; +typedef struct _GCSoundChannelClass GCSoundChannelClass; + +typedef enum { + GC_SOUND_POLICY_NONE, + GC_SOUND_PLAY_ONLY_IF_IDLE, + GC_SOUND_PLAY_AFTER_CURRENT, + GC_SOUND_INTERRUPT_AND_PLAY +} GCSoundPolicy; + +G_END_DECLS + +#include <glib-object.h> +#include <gc-sound-mixer.h> +#include <gc-sound-item.h> + +G_BEGIN_DECLS + +#define GC_TYPE_SOUND_CHANNEL (gc_sound_channel_get_type()) +#define GC_SOUND_CHANNEL(i) (G_TYPE_CHECK_INSTANCE_CAST((i), GC_TYPE_SOUND_CHANNEL, GCSoundChannel)) +#define GC_SOUND_CHANNEL_CLASS(c) (G_TYPE_CHECK_CLASS_CAST((c), GC_TYPE_SOUND_CHANNEL, GCSoundChannelClass)) +#define GC_IS_SOUND_CHANNEL(i) (G_TYPE_CHECK_INSTANCE_TYPE((i), GC_TYPE_SOUND_CHANNEL)) +#define GC_IS_SOUND_CHANNEL_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE((c), GC_TYPE_SOUND_CHANNEL)) +#define GC_SOUND_CHANNEL_GET_CLASS(i) (G_TYPE_INSTANCE_GET_CLASS((i), GC_TYPE_SOUND_CHANNEL, GCSoundChannelClass)) + +GType gc_sound_channel_get_type(void); + +struct _GCSoundChannel { + GObject __parent__; + + gdouble volume; + GCSoundPolicy policy; + //gint policy; + + gboolean stopped; + + GCSoundMixer* mixer; + GCSoundItem* root; + + GList* playlist; + //this one is the item with the file + GCSoundItem* running_sample; + // this one is the group playing + GList* running_root; + + gint channel_number; + + //debug. will be removed. + gchar *nick; +}; + +struct _GCSoundChannelClass { + GObjectClass __parentClass__; + + /* signal handlers */ + void (* run) (GCSoundChannel * self); + void (* chunk_end) (GCSoundChannel * self); +}; + +GCSoundItem * gc_sound_channel_get_root (GCSoundChannel * self); + +gboolean gc_sound_channel_pause (GCSoundChannel * self); +gboolean gc_sound_channel_resume (GCSoundChannel * self); +gboolean gc_sound_channel_halt (GCSoundChannel * self); + +gboolean gc_sound_channel_play (GCSoundChannel * channel, + GCSoundItem *item); + +gboolean gc_sound_channel_play_item (GCSoundChannel * self, + GCSoundItem *item); + +GCSoundPolicy gc_sound_channel_get_policy (GCSoundChannel * self); +gboolean gc_sound_channel_set_policy (GCSoundChannel * self, + GCSoundPolicy policy); + +G_END_DECLS + +#endif diff --git a/src/gc_sound/src/gc-sound-item.c b/src/gc_sound/src/gc-sound-item.c new file mode 100644 index 0000000..9820be5 --- /dev/null +++ b/src/gc_sound/src/gc-sound-item.c @@ -0,0 +1,421 @@ +/* gcompris - gc-sound-item.c + * + * Copyright (C) 2006 Yves Combe + * + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <gc-sound-item.h> +#include <gc-sound-marshallers.h> + + +/* signals */ +enum { + REAL_PLAY, /* internal: real launch play*/ + + PLAY_START, /* Start real playing of item */ + PLAY_END, /* end playing */ + CHUNK_START, /* Start real playing of item */ + CHUNK_END, /* Start real playing of item */ + PAUSED, /* channel paused */ + RESUMED, /* channel resumed */ + HALTED, /* channel halted */ + DESTROY, + + N_SIGNALS +}; + +guint gc_sound_item_signals[N_SIGNALS] = {0}; + +// internal use +gboolean gc_sound_item_run_next (GCSoundItem *self, + gboolean stopped) +{ + gboolean ret; + + g_warning("run_next %s %d", self->nick, stopped); + + /* if we are stopped, we don't continue */ + if (stopped) { + g_signal_emit(self, gc_sound_item_signals[PLAY_END], 0, stopped); + return TRUE; + } + + /* If we are muted, we have nothing to do */ + if (self->mute) + return FALSE; + + /* mark if we are in play tree */ + self->has_played = TRUE; + + if (g_list_length(self->children) == 0) + return FALSE; + + if (self->playing == NULL) + self->playing = g_list_first(self->children); + else + self->playing = g_list_next (self->playing ); + + if ((self->playing == NULL) && (self->loop)) { + g_warning ("looping on %s", self->nick); + self->playing = g_list_first (self->children ); + } + + while (self->playing) { + if ( GC_SOUND_ITEM(self->playing->data) == self){ + if (!self->started) + g_signal_emit(self, gc_sound_item_signals[PLAY_START], 0); + g_signal_emit(self, gc_sound_item_signals[REAL_PLAY], 0); + return TRUE; + } + else { + ret= gc_sound_item_run_next ( GC_SOUND_ITEM(self->playing->data), FALSE); + if (ret) + return ret; + } + self->playing = g_list_next (self->playing ); + } + + /* if we have play, it's finished */ + if (self->started) { + g_signal_emit(self, gc_sound_item_signals[PLAY_END], 0, FALSE); + } + + return FALSE; +} + +void gc_sound_item_set_loop(GCSoundItem *self, gboolean loop) +{ + self->loop = loop; +} + +GCSoundPolicy gc_sound_item_get_policy (GCSoundItem * self) +{ + return self->policy; +} +gboolean gc_sound_item_set_policy (GCSoundItem * self, + GCSoundPolicy policy) +{ + self->policy = policy; + return TRUE; +} + +void gc_sound_item_child_start( GCSoundItem *child, gpointer data) +{ + GCSoundItem *self = GC_SOUND_ITEM(data); + + g_return_if_fail(GC_IS_SOUND_ITEM(self)); + + if (self->has_played){ + self->started = TRUE; + g_signal_emit( self, gc_sound_item_signals[PLAY_START], 0); + } + +} + +void gc_sound_item_child_end( GCSoundItem *child, gboolean stopped, gpointer data) +{ + GCSoundItem *self = GC_SOUND_ITEM(data); + + if (self->has_played) + gc_sound_item_run_next(self, stopped); +} + +GCSoundItem * gc_sound_item_append_child (GCSoundItem *self) +{ + GCSoundItem *child; + + child = GC_SOUND_ITEM(g_object_new(gc_sound_item_get_type(), "parent", self, "channel", self->channel, NULL)); + + /* Child is added to our lists */ + self->children = g_list_append (self->children, child); + + /* we get a ref */ + g_object_ref (G_OBJECT(child)); + + g_signal_connect( child, "play-end", (GCallback) gc_sound_item_child_end, self); + g_signal_connect( child, "play-start", (GCallback) gc_sound_item_child_start, self); + return child; +} + +gboolean gc_sound_item_play (GCSoundItem *self) +{ + return gc_sound_channel_play (self->channel, self); +} + +void gc_sound_item_set_filename (GCSoundItem *self, gchar *filename) +{ + if (filename) { + self->filename = filename; + + if ( (!self->children) || (self != self->children->data)) + self->children = g_list_prepend( self->children, self); + } else { + self->filename = NULL; + if ( (self->children) && (self == self->children->data)) + self->children = g_list_remove ( self->children, self); + } +} + +gchar * gc_sound_item_get_filename (GCSoundItem *self) +{ + return self->filename; +} + +static void +gc_sound_item_signal_real_play (GCSoundItem *self) +{ + g_warning("item %s received real_play", self->nick); + + g_signal_emit(self, gc_sound_item_signals[CHUNK_START], 0); + gc_sound_channel_play_item (self->channel, self); +} + +static void +gc_sound_item_signal_play_end (GCSoundItem *self, gboolean stopped) +{ + g_warning("item %s received play_end", self->nick); + + if (self->has_played || stopped) { + self->started = FALSE; + self->has_played = FALSE; + } + +} + +static void +gc_sound_item_signal_play_start (GCSoundItem *self) +{ + g_warning("item %s received play_start", self->nick); + + self->started = TRUE; +} + +static void +gc_sound_item_signal_chunk_end (GCSoundItem *self, gboolean stopped) +{ + g_warning("item %s received chunk_end", self->nick); + + /* + We receive this signal from channel when play of chunk if finished. + We have to continue play in our group. + */ + + gc_sound_item_run_next (self, stopped); +} + +static void +gc_sound_item_signal_chunk_start (GCSoundItem *self) +{ + g_warning("item %s received chunk_start", self->nick); + + self->started = TRUE; +} + +/* GType stuff */ +enum { + PROP_0, + PROP_CHANNEL, + PROP_PARENT, + PROP_FILENAME +}; + +/* GType */ +G_DEFINE_TYPE(GCSoundItem, gc_sound_item, G_TYPE_OBJECT); + +static void +gc_sound_item_init(GCSoundItem* self) +{ + // initialisation des variables. + g_warning("gc_sound_item_init"); + + self->volume = -1.0; + self->mute = FALSE; + + self->policy = GC_SOUND_PLAY_AFTER_CURRENT; + self->loop = FALSE; + + self->filename = NULL; + + self->channel = NULL; + self->parent = NULL; + self->children = NULL; + + //debug. will be removed + gchar * nick; + + //internal use + // TRUE if we are in running play tree. + self->has_played = FALSE; + + // our group already started + self->started = FALSE; + + // child we are playing + self->playing = NULL; + +} + +static void +gc_sound_item_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec) +{ + GCSoundItem *self = GC_SOUND_ITEM(object); + switch(prop_id) { + case PROP_CHANNEL: + g_value_set_object(value, self->channel); + break; + case PROP_PARENT: + g_value_set_object(value, self->parent); + break; + case PROP_FILENAME: + g_value_set_string(value, self->filename); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gc_sound_item_set_property(GObject* object, guint prop_id, GValue const* value, GParamSpec* pspec) +{ + GCSoundItem *self = GC_SOUND_ITEM(object); + + switch(prop_id) { + case PROP_CHANNEL: + self->channel = g_value_get_object(value); + break; + case PROP_PARENT: + self->parent = g_value_get_object(value); + break; + case PROP_FILENAME: + gc_sound_item_set_filename( self, (gchar *)g_value_get_string(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } + +} + +static void +gc_sound_item_class_init(GCSoundItemClass* self_class) +{ + // c'est ici qu'il faut passer les properties et les signals. + g_warning("gc_sound_item_class_init"); + + GObjectClass* go_class; + + /* GObjectClass */ + go_class = G_OBJECT_CLASS(self_class); + + go_class->get_property = gc_sound_item_get_property; + go_class->set_property = gc_sound_item_set_property; + + g_object_class_install_property(go_class, + PROP_CHANNEL, + g_param_spec_object ("channel", + "GCompris channel", + "The channel where this channel stand", + GC_TYPE_SOUND_CHANNEL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_install_property(go_class, + PROP_PARENT, + g_param_spec_object ("parent", + "GCompris parent", + "The parent where this channel stand", + GC_TYPE_SOUND_ITEM, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + +/* signals */ +/* enum { */ +/* RUN, /\* internal: launch recursive playing of playlist *\/ */ + +/* PLAY_START, /\* Start real playing of item *\/ */ +/* PLAY_END, /\* end playing *\/ */ +/* PAUSED, /\* channel paused *\/ */ +/* RESUMED, /\* channel resumed *\/ */ +/* HALTED, /\* channel halted *\/ */ +/* DESTROY, */ + +/* N_SIGNALS */ +/* }; */ + + self_class->real_play = gc_sound_item_signal_real_play; + self_class->play_start = gc_sound_item_signal_play_start; + self_class->play_end = gc_sound_item_signal_play_end; + self_class->chunk_start = gc_sound_item_signal_chunk_start; + self_class->chunk_end = gc_sound_item_signal_chunk_end; + + gc_sound_item_signals[REAL_PLAY] = + g_signal_new("real_play", /* name */ + GC_TYPE_SOUND_ITEM, /* itype */ + (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION), /* flags */ + G_STRUCT_OFFSET (GCSoundItemClass, real_play), /* offset function */ + NULL, /* accumulator */ + NULL, /* accu data */ + gc_sound_marshal_VOID__VOID, /* marshal */ + G_TYPE_NONE, /* return value */ + 0 /* n_params */ + ); + gc_sound_item_signals[PLAY_START] = + g_signal_new("play_start", /* name */ + GC_TYPE_SOUND_ITEM, /* itype */ + (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION), /* flags */ + G_STRUCT_OFFSET (GCSoundItemClass, play_start), /* offset function */ + NULL, /* accumulator */ + NULL, /* accu data */ + gc_sound_marshal_VOID__VOID, /* marshal */ + G_TYPE_NONE, /* return value */ + 0 /* n_params */ + ); + gc_sound_item_signals[PLAY_END] = + g_signal_new("play_end", /* name */ + GC_TYPE_SOUND_ITEM, /* itype */ + (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION), /* flags */ + G_STRUCT_OFFSET (GCSoundItemClass, play_end), /* offset function */ + NULL, /* accumulator */ + NULL, /* accu data */ + gc_sound_marshal_VOID__BOOLEAN, /* marshal */ + G_TYPE_NONE, /* return value */ + 1 /* n_params */, + G_TYPE_BOOLEAN + ); + gc_sound_item_signals[CHUNK_START] = + g_signal_new("chunk_start", /* name */ + GC_TYPE_SOUND_ITEM, /* itype */ + (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION), /* flags */ + G_STRUCT_OFFSET (GCSoundItemClass, chunk_start), /* offset function */ + NULL, /* accumulator */ + NULL, /* accu data */ + gc_sound_marshal_VOID__VOID, /* marshal */ + G_TYPE_NONE, /* return value */ + 0 /* n_params */ + ); + gc_sound_item_signals[CHUNK_END] = + g_signal_new("chunk_end", /* name */ + GC_TYPE_SOUND_ITEM, /* itype */ + (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION), /* flags */ + G_STRUCT_OFFSET (GCSoundItemClass, chunk_end), /* offset function */ + NULL, /* accumulator */ + NULL, /* accu data */ + gc_sound_marshal_VOID__BOOLEAN, /* marshal */ + G_TYPE_NONE, /* return value */ + 1, /* n_params */ + G_TYPE_BOOLEAN + ); + +} diff --git a/src/gc_sound/src/gc-sound-item.gob b/src/gc_sound/src/gc-sound-item.gob deleted file mode 100644 index 6f8fa1d..0000000 --- a/src/gc_sound/src/gc-sound-item.gob +++ /dev/null @@ -1,310 +0,0 @@ -%alltop{/* gcompris - gc-sound-item.gob - * - * Copyright (C) 2006 Yves Combe - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -%} - -requires 2.0.0 - -%h{ -#ifndef __TYPEDEF_GC_SOUND_CHANNEL__ -#define __TYPEDEF_GC_SOUND_CHANNEL__ -typedef struct _GCSoundChannel GCSoundChannel; -#endif -%} - -%{ -#include <gc-sound-item.h> -#include <SDL.h> -#include <SDL_thread.h> -#include <SDL_mixer.h> -#include <SDL_audio.h> -#include <libintl.h> - -#define _(String) gettext (String) -#define gettext_noop(String) String - -#ifndef N_ -#define N_(String) gettext_noop (String) -#endif - - -#include "gc-sound-item-private.h" - -%} - -%privateheader{ - /* because of GCSoundPolicy */ - #include "gc-sound-channel.h" -%} -class GC:Sound:Item from G:Object { - /* debug */ - public gchar *nick = {NULL}; - - /*************************/ - /* muted or not ? */ - public gboolean mute = { FALSE }; - - property BOOLEAN mute - ( nick=_("Mute"), - blurb=_("Do not play me"), - export, link ); - - /*************************/ - /* loop or not ? */ - public gboolean loop = { FALSE }; - - property BOOLEAN loop - ( nick=_("Loop"), - blurb=_("Play loop"), - export, link ); - - /*************************/ - /* channel where we play */ - private GC:Sound:Channel *channel = { NULL } - destroywith g_object_unref ; - - property OBJECT channel - ( nick=_("Channel playing for us"), - blurb=_("Numero of channel"), - object_type=GC:Sound:Channel, - export ) - set { self->_priv->channel = GC_SOUND_CHANNEL(g_value_get_object -(VAL)); - gc_sound_channel_connect_me( self->_priv->channel, self); - } - get { g_value_set_object (VAL, G_OBJECT(self->_priv->channel)); }; - - /*******************************************************/ - /* Parent is another item. We receive channel from it. */ - private GC:Sound:Item *parent = { NULL } - destroywith g_object_unref ; - - property OBJECT parent - ( nick=_("Channel playing for us"), - blurb=_("Numero of channel"), - object_type=GC:Sound:Item, - export) - set { self->_priv->parent = GC_SOUND_ITEM(g_value_get_object -(VAL)); - } - get { g_value_set_object (VAL, G_OBJECT(self->_priv->parent)); } - ; - - /********************************************/ - /* filename is the name of file we play */ - /* may be NULL, in case we are only a group */ - private gchar *filename = { NULL } - destroywith g_free; - property STRING filename - ( nick=_("Filename of sound"), - blurb=_("sound file to play"), - export ) - set { - if (self->_priv->filename==NULL) - g_free(self->_priv->filename); - - self->_priv->filename = g_strdup(g_value_get_string(VAL)); - self->_priv->PlayList = g_list_remove ( self->_priv->PlayList, self); - - if (self->_priv->filename) - self->_priv->PlayList = g_list_insert ( self->_priv->PlayList, self, 0); - - } - get { g_value_set_string(VAL, g_strdup(self->_priv->filename));}; - - /*******************************************/ - /* Volume for the sound */ - public int volume = { -1 }; - - /****************************************/ - /* mark if item or one child is playing */ - private gboolean started = { FALSE }; - - /*****************************/ - /* mark if is playing or not */ - private gboolean has_played = { FALSE }; - - /* playing part of the child */ - private G:List *playing = { NULL }; - - /* childs */ - private G:List *SoundItems = { NULL } - destroy { - GList *list; - - for (list = SoundItems; list != NULL; list = list->next) - g_object_unref(G_OBJECT(list->data)); - - g_list_free (SoundItems); - }; - - /* The default policy for the channel */ - private GC:Sound:Policy policy = {GC_SOUND_POLICY_NONE}; - property ENUM policy - ( nick = _("Channel policy"), - blurb = _("Default policy for this channel"), - enum_type = GC:Sound:Policy, - export, link); - - - /* PlayList */ - private GList *PlayList = { NULL } - destroy { - g_list_free (PlayList); - }; - - - /* Objects methods */ - init (self) { - //g_warning("Item sound instance init"); - /* do nothing. We set up channel when property is set */ - } - - class_init (class) { - //g_warning("item sound class init"); - - } - - public GC:Sound:Item * - new (self) - { - GCSoundItem *child; - - child = GC_SOUND_ITEM(g_object_new(gc_sound_item_get_type(), "parent", self, "channel", self->_priv->channel, NULL)); - - /* Child is added to our lists */ - self->_priv->SoundItems = g_list_append (self->_priv->SoundItems, child); - self->_priv->PlayList = g_list_append (self->_priv->PlayList, child); - - /* we get a ref */ - g_object_ref (G_OBJECT(child)); - - /* we need to know if start play or end on it, to send the same signal (group start/end) */ - self_connect__play_finished ( child, self_child_play_finished, self); - self_connect__play_started ( child, self_child_play_started, self); - - return child; - } - - public void - play (self) - { - /* Change that with policy */ - self->_priv->has_played = TRUE; - - /* we will be added in play list channel */ - self_do_play (self); - } - - signal first NONE (NONE) - void do_play (self) - { - //g_warning ("item %s received do_play signal", self->nick); - } - - signal first NONE (NONE) - void real_play (self) - { - //g_warning ("item %s received do_play signal", self->nick); - } - - - /* play */ - signal first NONE (BOOLEAN) - void play_finished (self, gboolean stopped) - { - //g_warning("item : play_finished %s", self->nick); - if ((!self->_priv->has_played) || (!self->_priv->playing) || stopped) { - self->_priv->started = FALSE; - self->_priv->has_played = FALSE; - } - } - - signal last NONE (NONE) - void play_started (self) - { - self->_priv->started = TRUE; - } - - private void child_play_finished (GC:Sound:Item *item, gboolean stopped, gpointer data) - { - if ( GC_SOUND_ITEM(data)->_priv->has_played ) - self_play_next(GC_SOUND_ITEM(data), stopped); - } - - private void child_play_started (GC:Sound:Item *item, gpointer data) - { - if (! GC_SOUND_ITEM(data)->_priv->started) - self_play_started(GC_SOUND_ITEM(data)); - } - - protected gboolean play_next (self, gboolean stopped) - { - gboolean ret; - - //g_warning("play_next %s %d", self->nick, stopped); - - if (stopped) { - gc_sound_item_play_finished(self, TRUE); - return TRUE; - } - - if (self->mute) - return FALSE; - - /* mark if we are in play tree */ - self->_priv->has_played = TRUE; - - if (g_list_length(self->_priv->PlayList) == 0) - return FALSE; - - if (self->_priv->playing == NULL) - self->_priv->playing = g_list_first(self->_priv->PlayList); - else - self->_priv->playing = g_list_next (self->_priv->playing ); - - if ((self->_priv->playing == NULL) && (self->loop)) { - //g_warning ("looping on %s", self->nick); - self->_priv->playing = g_list_first (self->_priv->PlayList ); - } - - while (self->_priv->playing) { - if ( GC_SOUND_ITEM(self->_priv->playing->data) == self){ - if (!self->_priv->started) - self_play_started(self); - self_real_play(self); - return TRUE; - } - else { - ret= self_play_next ( GC_SOUND_ITEM(self->_priv->playing->data), FALSE); - if (ret) - return ret; - } - self->_priv->playing = g_list_next (self->_priv->playing ); - } - - /* if we have play, it's finished */ - if (self->_priv->started) { - self_play_finished(self, FALSE); - } - - return FALSE; - } - - -} diff --git a/src/gc_sound/src/gc-sound-item.h b/src/gc_sound/src/gc-sound-item.h new file mode 100644 index 0000000..534252e --- /dev/null +++ b/src/gc_sound/src/gc-sound-item.h @@ -0,0 +1,104 @@ +/* gcompris - gc-sound-item.h + * + * Copyright (C) 2006 Yves Combe + * + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __GC_SOUND_ITEM_H__ +#define __GC_SOUND_ITEM_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS + + +typedef struct _GCSoundItem GCSoundItem; +typedef struct _GCSoundItemClass GCSoundItemClass; + + +G_END_DECLS +#include <gc-sound-channel.h> +G_BEGIN_DECLS + + +#define GC_TYPE_SOUND_ITEM (gc_sound_item_get_type()) +#define GC_SOUND_ITEM(i) (G_TYPE_CHECK_INSTANCE_CAST((i), GC_TYPE_SOUND_ITEM, GCSoundItem)) +#define GC_SOUND_ITEM_CLASS(c) (G_TYPE_CHECK_CLASS_CAST((c), GC_TYPE_SOUND_ITEM, GCSoundItemClass)) +#define GC_IS_SOUND_ITEM(i) (G_TYPE_CHECK_INSTANCE_TYPE((i), GC_TYPE_SOUND_ITEM)) +#define GC_IS_SOUND_ITEM_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE((c), GC_TYPE_SOUND_ITEM)) +#define GC_SOUND_ITEM_GET_CLASS(i) (G_TYPE_INSTANCE_GET_CLASS((i), GC_TYPE_SOUND_ITEM, GCSoundItemClass)) + +GType gc_sound_item_get_type(void); + +struct _GCSoundItem { + GObject __parent__; + + gdouble volume; + gboolean mute; + + GCSoundPolicy policy; + //gint policy; + gboolean loop; + + gchar* filename; + + GCSoundChannel* channel; + GCSoundItem* parent; + GList* children; + + //debug. will be removed + gchar * nick; + + //internal use + // TRUE if we are in running play tree. + gboolean has_played; + + // our group already started + gboolean started; + + // child we are playing + GList *playing; +}; + +struct _GCSoundItemClass { + GObjectClass __parentClass__; + + /* signal handlers */ + void (* real_play) (GCSoundItem * self); + void (* play_start) (GCSoundItem * self); + void (* play_end) (GCSoundItem * self, gboolean stopped); + void (* chunk_start) (GCSoundItem * self); + void (* chunk_end) (GCSoundItem * self, gboolean stopped); + +}; + +// internal use +gboolean gc_sound_item_run_next (GCSoundItem *self, + gboolean stopped); + +GCSoundItem * gc_sound_item_append_child (GCSoundItem *self); + +gboolean gc_sound_item_play (GCSoundItem *self); + +void gc_sound_item_set_filename (GCSoundItem *self, gchar *filename); + +gchar * gc_sound_item_get_filename (GCSoundItem *self); + +void gc_sound_item_set_loop(GCSoundItem *self, gboolean loop); + +G_END_DECLS + +#endif diff --git a/src/gc_sound/src/gc-sound-marshallers.c b/src/gc_sound/src/gc-sound-marshallers.c new file mode 100644 index 0000000..6666255 --- /dev/null +++ b/src/gc_sound/src/gc-sound-marshallers.c @@ -0,0 +1,56 @@ +#include <gc-sound-marshallers.h> + +#include <glib-object.h> + + +#ifdef G_ENABLE_DEBUG +#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) +#define g_marshal_value_peek_char(v) g_value_get_char (v) +#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) +#define g_marshal_value_peek_int(v) g_value_get_int (v) +#define g_marshal_value_peek_uint(v) g_value_get_uint (v) +#define g_marshal_value_peek_long(v) g_value_get_long (v) +#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) +#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) +#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) +#define g_marshal_value_peek_enum(v) g_value_get_enum (v) +#define g_marshal_value_peek_flags(v) g_value_get_flags (v) +#define g_marshal_value_peek_float(v) g_value_get_float (v) +#define g_marshal_value_peek_double(v) g_value_get_double (v) +#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) +#define g_marshal_value_peek_param(v) g_value_get_param (v) +#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) +#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) +#define g_marshal_value_peek_object(v) g_value_get_object (v) +#else /* !G_ENABLE_DEBUG */ +/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. + * Do not access GValues directly in your code. Instead, use the + * g_value_get_*() functions + */ +#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int +#define g_marshal_value_peek_char(v) (v)->data[0].v_int +#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint +#define g_marshal_value_peek_int(v) (v)->data[0].v_int +#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint +#define g_marshal_value_peek_long(v) (v)->data[0].v_long +#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 +#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 +#define g_marshal_value_peek_enum(v) (v)->data[0].v_long +#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_float(v) (v)->data[0].v_float +#define g_marshal_value_peek_double(v) (v)->data[0].v_double +#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer +#endif /* !G_ENABLE_DEBUG */ + + +/* VOID:VOID (marshallers.list:1) */ + +/* VOID:BOOLEAN (marshallers.list:2) */ + +/* VOID:OBJECT (marshallers.list:3) */ + diff --git a/src/gc_sound/src/gc-sound-marshallers.h b/src/gc_sound/src/gc-sound-marshallers.h new file mode 100644 index 0000000..17bf6c5 --- /dev/null +++ b/src/gc_sound/src/gc-sound-marshallers.h @@ -0,0 +1,21 @@ + +#ifndef __gc_sound_marshal_MARSHAL_H__ +#define __gc_sound_marshal_MARSHAL_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS + +/* VOID:VOID (marshallers.list:1) */ +#define gc_sound_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID + +/* VOID:BOOLEAN (marshallers.list:2) */ +#define gc_sound_marshal_VOID__BOOLEAN g_cclosure_marshal_VOID__BOOLEAN + +/* VOID:OBJECT (marshallers.list:3) */ +#define gc_sound_marshal_VOID__OBJECT g_cclosure_marshal_VOID__OBJECT + +G_END_DECLS + +#endif /* __gc_sound_marshal_MARSHAL_H__ */ + diff --git a/src/gc_sound/src/gc-sound-mixer-SDL.c b/src/gc_sound/src/gc-sound-mixer-SDL.c new file mode 100644 index 0000000..d389301 --- /dev/null +++ b/src/gc_sound/src/gc-sound-mixer-SDL.c @@ -0,0 +1,456 @@ +/* gcompris - gc-sound-mixer-SDL.c + * + * Copyright (C) 2006 Yves Combe + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <gc-sound-mixer-SDL.h> +#include <gc-sound-marshallers.h> + +#include <SDL.h> +#include <SDL_thread.h> +#include <SDL_mixer.h> +#include <SDL_audio.h> + +/* signals */ +enum { + CHANNEL_FINISHED, /* internal: real launch play*/ + + PAUSED, + RESUMED, + HALTED, + DESTROY, + + N_SIGNALS +}; + +guint gc_sound_mixer_SDL_signals[N_SIGNALS] = {0}; + +static GCSoundMixerSDL *running_mixer = NULL; + +GCSoundMixer *gc_sound_mixer_SDL_new(void) +{ + return GC_SOUND_MIXER(g_object_new(GC_TYPE_SOUND_MIXER_SDL, NULL)); +} + +gboolean +gc_sound_mixer_SDL_open_audio (GCSoundMixer* mixer) +{ + int audio_rate,audio_channels; + Uint16 audio_format; + int audio_buffers=2048; + int bits = 0; + GCSoundMixerSDL* self; + + g_return_val_if_fail(GC_IS_SOUND_MIXER_SDL(mixer), FALSE); + + self = GC_SOUND_MIXER_SDL(mixer); + + if (self->audio_opened){ + g_warning("Audio already opened !"); + return FALSE; + } + + // initialize sdl mixer, open up the audio device + if(Mix_OpenAudio(44100,MIX_DEFAULT_FORMAT,2,audio_buffers)<0){ + g_warning("GCSoundMixer can not open audio dev"); + return FALSE; + } + + self->audio_opened = FALSE; + + // print out some info on the audio device and stream + Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels); + bits=audio_format&0xFF; + Mix_AllocateChannels(g_hash_table_size(self->channels_from_pointer)); + g_warning("Opened audio at %d Hz %d bit %s, %d bytes audio buffer number of channels %d", + audio_rate, + bits, + audio_channels>1?"stereo":"mono", + audio_buffers, + g_hash_table_size(self->channels_from_pointer)); + return TRUE; +} + +gboolean +gc_sound_mixer_SDL_close_audio (GCSoundMixer * mixer) +{ + GCSoundMixerSDL* self; + + g_return_val_if_fail(GC_IS_SOUND_MIXER_SDL(mixer), FALSE); + + self = GC_SOUND_MIXER_SDL(mixer); + + if (!self->audio_opened) + { + g_warning ("Audio is not opened !"); + return FALSE; + } + Mix_CloseAudio(); + g_warning("Closing audio"); + self->audio_opened = FALSE; + return TRUE; +} + +static GCSoundChannel *gc_sound_mixer_SDL_new_channel (GCSoundMixer * mixer) + { + GCSoundMixerSDL* self; + + g_return_val_if_fail(GC_IS_SOUND_MIXER_SDL(mixer), FALSE); + + self = GC_SOUND_MIXER_SDL(mixer); + + g_warning ("gc_sound_mixer_SDL_new_channel"); + + GCSoundChannel *channel = GC_SOUND_CHANNEL(g_object_new(GC_TYPE_SOUND_CHANNEL, + "mixer", self, NULL)); + + g_assert (channel != 0); + + channel->channel_number = g_hash_table_size(self->channels_from_pointer); + + g_warning ("inserting channel %d into tables", channel->channel_number); + g_hash_table_insert (self->channels_from_pointer, + channel, + GINT_TO_POINTER(channel->channel_number)); + + g_hash_table_insert (self->channels_to_pointer, + &(channel->channel_number), + channel); + + Mix_AllocateChannels(channel->channel_number + 1); + + g_warning ("Numbers of channels allocated %d", Mix_AllocateChannels(-1)); + + return channel; + } + + +gboolean gc_sound_mixer_SDL_pause (GCSoundMixer * mixer) + { + GCSoundMixerSDL* self; + + g_return_val_if_fail(GC_IS_SOUND_MIXER_SDL(mixer), FALSE); + + self = GC_SOUND_MIXER_SDL(mixer); + + if (self->paused){ + g_warning ("gc_sound_mixer_SDL_pause : Already paused !"); + return FALSE; + } + + Mix_Pause(-1); + self->paused = TRUE; + } + +gboolean +gc_sound_mixer_SDL_resume (GCSoundMixer * mixer) + { + GCSoundMixerSDL* self; + + g_return_val_if_fail(GC_IS_SOUND_MIXER_SDL(mixer), FALSE); + + self = GC_SOUND_MIXER_SDL(mixer); + + if (!self->paused){ + g_warning ("gc_sound_mixer_SDL_resume : Not paused !"); + return FALSE; + } + Mix_Resume(-1); + self->paused = FALSE; + } + +gboolean +gc_sound_mixer_SDL_halt (GCSoundMixer * mixer) + { + GCSoundMixerSDL* self; + + g_return_val_if_fail(GC_IS_SOUND_MIXER_SDL(mixer), FALSE); + + self = GC_SOUND_MIXER_SDL(mixer); + + Mix_HaltChannel(-1); + } + +gboolean +gc_sound_mixer_SDL_pause_channel (GCSoundMixer * mixer, GCSoundChannel * channel) + { + GCSoundMixerSDL* self; + + g_return_val_if_fail(GC_IS_SOUND_MIXER_SDL(mixer), FALSE); + g_return_val_if_fail(GC_IS_SOUND_CHANNEL(channel), FALSE); + + self = GC_SOUND_MIXER_SDL(mixer); + int channel_number = (int) g_hash_table_lookup (self->channels_from_pointer, + channel); + + Mix_Pause (channel_number); + } + +gboolean +gc_sound_mixer_SDL_resume_channel (GCSoundMixer * mixer, GCSoundChannel * channel) + { + GCSoundMixerSDL* self; + + g_return_val_if_fail(GC_IS_SOUND_MIXER_SDL(mixer), FALSE); + g_return_val_if_fail(GC_IS_SOUND_CHANNEL(channel), FALSE); + + self = GC_SOUND_MIXER_SDL(mixer); + + int channel_number = (int) g_hash_table_lookup (self->channels_from_pointer, + channel); + + Mix_Resume (channel_number); + return TRUE; + } + + +gboolean +gc_sound_mixer_SDL_halt_channel (GCSoundMixer * mixer, GCSoundChannel * channel) + { + GCSoundMixerSDL* self; + + g_return_val_if_fail(GC_IS_SOUND_MIXER_SDL(mixer), FALSE); + g_return_val_if_fail(GC_IS_SOUND_CHANNEL(channel), FALSE); + + self = GC_SOUND_MIXER_SDL(mixer); + + int channel_number = (int) g_hash_table_lookup (self->channels_from_pointer, + channel); + + Mix_HaltChannel (channel_number); + + return TRUE; + } + + +gboolean +gc_sound_mixer_SDL_play_item (GCSoundMixer * mixer, GCSoundChannel * channel, GCSoundItem *item ) + { + Mix_Chunk *sample; + + GCSoundMixerSDL* self; + + g_return_val_if_fail(GC_IS_SOUND_MIXER_SDL(mixer), FALSE); + g_return_val_if_fail(GC_IS_SOUND_CHANNEL(channel), FALSE); + + self = GC_SOUND_MIXER_SDL(mixer); + + int channel_number = (int) g_hash_table_lookup (self->channels_from_pointer, + channel); + + if (Mix_Playing(channel_number)){ + g_warning("Channel busy ? no play!"); + return FALSE; + } + + if (item->filename == NULL){ + g_warning("No filename ? no play!"); + return FALSE; + } + + sample = Mix_LoadWAV_RW(SDL_RWFromFile(item->filename, "rb"), 1); + if (!sample) { + g_warning("Sample music %s cannot be load", item->filename); + return FALSE; + } + + if ((item->volume == -1.0) || (item->volume > channel->volume)) + Mix_VolumeChunk(sample, (int ) channel->volume * MIX_MAX_VOLUME); + else + Mix_VolumeChunk(sample, (int) item->volume * MIX_MAX_VOLUME); + + if (Mix_PlayChannel(channel_number, sample, 0)==-1) { + g_warning("Channel cannot play music %s", item->filename); + Mix_FreeChunk (sample); + return FALSE; + } + + g_hash_table_insert( self->samples, channel, sample); + + g_warning("Playing %s on channel #%d", item->filename, channel_number); + + return TRUE; + } + +void channel_finished_cb (int channel_number) + { + GCSoundMixerSDL* self = running_mixer; + + g_warning("Channel number %d size %d", + channel_number, + g_hash_table_size(self->channels_to_pointer)); + + int cn = channel_number; + + GCSoundChannel *channel = GC_SOUND_CHANNEL(g_hash_table_lookup (self->channels_to_pointer, + &cn)); + + g_return_if_fail(channel != NULL); + g_return_if_fail(GC_IS_SOUND_MIXER_SDL(self)); + g_return_if_fail(GC_IS_SOUND_CHANNEL(channel)); + + g_signal_emit(self, gc_sound_mixer_SDL_signals[CHANNEL_FINISHED], 0, channel, NULL); + + } + + +static +void gc_sound_mixer_SDL_channel_finished (GCSoundMixerSDL* self, + GCSoundChannel* channel) +{ + Mix_Chunk *sample; + + sample = g_hash_table_lookup (self->samples, channel); + Mix_FreeChunk (sample); + + g_signal_emit_by_name (channel, "chunk_end", 0, channel->stopped); +} + +static void +gc_sound_mixer_SDL_init (GCSoundMixerSDL* self) + { + /* SDL_mixer limitation */ + if (running_mixer != NULL) + g_error("Sorry, i can't allocate more than one mixer !!!"); + running_mixer = self; + + self->channels_from_pointer = g_hash_table_new (g_direct_hash, + g_direct_equal); + self->channels_to_pointer = g_hash_table_new (g_int_hash, + g_int_equal); + self->samples = g_hash_table_new (g_direct_hash, + g_direct_equal); + self->paused = FALSE; + + if(SDL_Init(SDL_INIT_AUDIO)<0){ + g_warning("SDL_init failed"); + } + Mix_ChannelFinished(channel_finished_cb); + + self->audio_opened = FALSE; + + if (!gc_sound_mixer_SDL_open_audio (GC_SOUND_MIXER(self))) { + g_warning("gc_sound_mixer_SDL_init: cannot open audio !"); + } + + + + } + +enum { + PROP_0, + PROP_DEVICE, +}; + + +static void +gc_sound_mixer_SDL_finalize (GObject* object) + { + GCSoundMixerSDL * self = GC_SOUND_MIXER_SDL(object); + + running_mixer = NULL; + + g_hash_table_destroy (self->channels_from_pointer); + g_hash_table_destroy (self->channels_to_pointer); + g_hash_table_destroy (self->samples); + + if (self->audio_opened) + Mix_CloseAudio(); + + SDL_Quit(); + } + + +static void +gc_sound_mixer_SDL_get_property() {} + +static void +gc_sound_mixer_SDL_set_property() {} + +static void +gc_sound_mixer_SDL_class_init (GCSoundMixerSDLClass* self_class) + { + g_warning("gc_sound_mixer_SDL_class_init"); + + GObjectClass* go_class; + + /* GObjectClass */ + go_class = G_OBJECT_CLASS(self_class); + go_class->finalize = gc_sound_mixer_SDL_finalize; + go_class->get_property = gc_sound_mixer_SDL_get_property; + go_class->set_property = gc_sound_mixer_SDL_set_property; + + _gc_sound_mixer_install_property( go_class, PROP_DEVICE); + +/* signals */ +/* enum { */ +/* CHANNEL_FINISHED, /\* internal: real launch play*\/ */ + +/* PAUSED, */ +/* RESUMED, */ +/* HALTED, */ +/* DESTROY, */ + +/* N_SIGNALS */ +/* }; */ + + + self_class->channel_finished = gc_sound_mixer_SDL_channel_finished; + + gc_sound_mixer_SDL_signals[CHANNEL_FINISHED] = + g_signal_new("channel_finished", /* name */ + GC_TYPE_SOUND_MIXER_SDL, /* itype */ + (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION), /* flags */ + G_STRUCT_OFFSET (GCSoundMixerSDLClass, channel_finished), /* offset function */ + NULL, /* accumulator */ + NULL, /* accu data */ + gc_sound_marshal_VOID__OBJECT, /* marshal */ + G_TYPE_NONE, /* return value */ + 1, /* n_params */ + GC_TYPE_SOUND_CHANNEL + ); + + + + } + +static void gc_init_sound_mixer (GCSoundMixerIface* iface); + +G_DEFINE_TYPE_WITH_CODE(GCSoundMixerSDL, gc_sound_mixer_SDL, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(GC_TYPE_SOUND_MIXER, gc_init_sound_mixer)); + + void gc_init_sound_mixer (GCSoundMixerIface* iface) +{ + g_warning("Sound Mixer is initalized from SDL! "); + + /* vtable */ + iface->open_audio = gc_sound_mixer_SDL_open_audio; + iface->close_audio = gc_sound_mixer_SDL_close_audio; + + iface->new_channel = gc_sound_mixer_SDL_new_channel; + + iface->pause = gc_sound_mixer_SDL_pause; + iface->resume = gc_sound_mixer_SDL_resume; + iface->halt = gc_sound_mixer_SDL_halt; + + iface->pause_channel = gc_sound_mixer_SDL_pause_channel; + iface->resume_channel = gc_sound_mixer_SDL_resume_channel; + iface->halt_channel = gc_sound_mixer_SDL_halt_channel; + + iface->play_item = gc_sound_mixer_SDL_play_item; + +} diff --git a/src/gc_sound/src/gc-sound-mixer-SDL.h b/src/gc_sound/src/gc-sound-mixer-SDL.h new file mode 100644 index 0000000..59190bb --- /dev/null +++ b/src/gc_sound/src/gc-sound-mixer-SDL.h @@ -0,0 +1,110 @@ +/* gcompris - gc-sound-mixer-SDL.h + * + * Copyright (C) 2006 Yves Combe + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __GC_SOUND_MIXER_SDL_H__ +#define __GC_SOUND_MIXER_SDL_H__ + +#include <gc-sound-mixer.h> +#include <gc-sound-channel.h> +#include <gc-sound-item.h> + +G_BEGIN_DECLS + +typedef struct _GCSoundMixerSDL GCSoundMixerSDL; +typedef struct _GCSoundMixerSDLClass GCSoundMixerSDLClass; + +#define GC_TYPE_SOUND_MIXER_SDL (gc_sound_mixer_SDL_get_type()) +#define GC_SOUND_MIXER_SDL(i) (G_TYPE_CHECK_INSTANCE_CAST((i), GC_TYPE_SOUND_MIXER_SDL, GCSoundMixerSDL)) +#define GC_SOUND_MIXER_SDL_CLASS(c) (G_TYPE_CHECK_CLASS_CAST((c), GC_TYPE_SOUND_MIXER_SDL, GCSoundMixerSDLClass)) +#define GC_IS_SOUND_MIXER_SDL(i) (G_TYPE_CHECK_INSTANCE_TYPE((i), GC_TYPE_SOUND_MIXER_SDL)) +#define GC_IS_SOUND_MIXER_SDL_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE((c), GC_TYPE_SOUND_MIXER_SDL)) +#define GC_SOUND_MIXER_SDL_GET_CLASS(i) (G_TYPE_INSTANCE_GET_CLASS((i), GC_TYPE_SOUND_MIXER_SDL, GCSoundMixerSDLClass)) + +GType gc_sound_mixer_SDL_get_type(void); + +GCSoundMixer * gc_sound_mixer_SDL_new(void); + +/* +gboolean gc_sound_mixer_SDL_open_audio (GCSoundMixerSDL * self); +gboolean gc_sound_mixer_SDL_close_audio (GCSoundMixerSDL * self); + +GCSoundChannel * gc_sound_mixer_SDL_new_channel (GCSoundMixer * self); + +gboolean gc_sound_mixer_SDL_pause (GCSoundMixerSDL * self); +gboolean gc_sound_mixer_SDL_resume (GCSoundMixerSDL * self); +gboolean gc_sound_mixer_SDL_halt (GCSoundMixerSDL * self); + +gboolean gc_sound_mixer_SDL_pause_channel (GCSoundMixerSDL * self, GCSoundChannel * channel); +gboolean gc_sound_mixer_SDL_resume_channel (GCSoundMixerSDL * self, GCSoundChannel * channel); +gboolean gc_sound_mixer_SDL_halt_channel (GCSoundMixerSDL * self, GCSoundChannel * channel); + +gboolean gc_sound_mixer_SDL_play_item (GCSoundMixerSDL * self, GCSoundChannel * channel, GCSoundItem *item); +*/ + +struct _GCSoundMixerSDL { + GObject __parent__; + + /* Is audio initiallised correctly */ + gboolean audio_opened; + gboolean paused; + + /* List of channels */ + GHashTable *channels_from_pointer; + GHashTable *channels_to_pointer; + GHashTable *samples; + + gboolean stopped; + + // debug only. will be removed. + gchar* nick; +}; + +struct _GCSoundMixerSDLClass { + GInitiallyUnownedClass base_class; + + /* vtable */ + gboolean (* open_audio) (GCSoundMixerSDL * self); + gboolean (* close_audio) (GCSoundMixerSDL * self); + + GCSoundChannel * (* new_channel) (GCSoundMixer * self); + + gboolean (* pause) (GCSoundMixerSDL * self); + gboolean (* resume) (GCSoundMixerSDL * self); + gboolean (* halt) (GCSoundMixerSDL * self); + + gboolean (* pause_channel) (GCSoundMixerSDL * self, + GCSoundChannel * channel); + + gboolean (* resume_channel) (GCSoundMixerSDL * self, + GCSoundChannel * channel); + + gboolean (* halt_channel) (GCSoundMixerSDL * self, + GCSoundChannel * channel); + + gboolean (* play_item) (GCSoundMixerSDL * self, + GCSoundChannel * channel, + GCSoundItem * item); + + void (* channel_finished) (GCSoundMixerSDL * self, + GCSoundChannel * channel); +}; + +G_END_DECLS + +#endif diff --git a/src/gc_sound/src/gc-sound-mixer-private.h b/src/gc_sound/src/gc-sound-mixer-private.h new file mode 100644 index 0000000..41ad6b6 --- /dev/null +++ b/src/gc_sound/src/gc-sound-mixer-private.h @@ -0,0 +1,52 @@ +/* Generated by GOB (v2.0.14) (do not edit directly) */ + + +/* gcompris - gc-sound-mixer.gob + * + * Copyright (C) 2006 Yves Combe + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#line 1 "gc-sound-mixer-SDL.gob" +#line 25 "gc-sound-mixer-private.h" +#ifndef __GC_SOUND_MIXER_PRIVATE_H__ +#define __GC_SOUND_MIXER_PRIVATE_H__ + +#include "gc-sound-mixer.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +struct _GCSoundMixerPrivate { +#line 52 "gc-sound-mixer-SDL.gob" + int audio_buffers; +#line 53 "gc-sound-mixer-SDL.gob" + int bits; +#line 55 "gc-sound-mixer-SDL.gob" + GList * channels_list; +#line 65 "gc-sound-mixer-SDL.gob" + gboolean audio_device; +#line 108 "gc-sound-mixer-SDL.gob" + gboolean sdl_ok; +#line 46 "gc-sound-mixer-private.h" +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/src/gc_sound/src/gc-sound-mixer.c b/src/gc_sound/src/gc-sound-mixer.c new file mode 100644 index 0000000..703e2e9 --- /dev/null +++ b/src/gc_sound/src/gc-sound-mixer.c @@ -0,0 +1,125 @@ +/* gcompris - gc-sound-mixer.c + * + * Copyright (C) 2006 Yves Combe + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <gc-sound-mixer.h> +#include <gc-sound-mixer-SDL.h> + +gboolean +gc_sound_mixer_open_audio (GCSoundMixer * self) +{ + return GC_SOUND_MIXER_GET_CLASS(self)->open_audio (self); +} + +gboolean +gc_sound_mixer_close_audio (GCSoundMixer * self) +{ + return GC_SOUND_MIXER_GET_CLASS(self)->close_audio (self); +} + +GCSoundChannel * +gc_sound_mixer_new_channel (GCSoundMixer * self) +{ + g_return_val_if_fail (GC_IS_SOUND_MIXER_SDL (self), (GCSoundChannel * )NULL); + g_assert (GC_SOUND_MIXER_GET_CLASS(self)->new_channel != 0); + + return GC_SOUND_MIXER_GET_CLASS(self)->new_channel (self); +} + + +gboolean +gc_sound_mixer_pause (GCSoundMixer * self) +{ + return GC_SOUND_MIXER_GET_CLASS(self)->pause (self); +} + + +gboolean +gc_sound_mixer_resume (GCSoundMixer * self) +{ + return GC_SOUND_MIXER_GET_CLASS(self)->resume (self); +} + +gboolean +gc_sound_mixer_halt (GCSoundMixer * self) +{ + return GC_SOUND_MIXER_GET_CLASS(self)->halt (self); +} + +gboolean +gc_sound_mixer_pause_channel (GCSoundMixer * self, GCSoundChannel * channel) +{ + return GC_SOUND_MIXER_GET_CLASS(self)->pause_channel (self, channel); +} + +gboolean +gc_sound_mixer_resume_channel (GCSoundMixer * self, GCSoundChannel * channel) +{ + return GC_SOUND_MIXER_GET_CLASS(self)->resume_channel (self, channel); +} + +gboolean +gc_sound_mixer_halt_channel (GCSoundMixer * self, GCSoundChannel * channel) +{ + return GC_SOUND_MIXER_GET_CLASS(self)->halt_channel (self, channel); +} + +gboolean +gc_sound_mixer_play_item (GCSoundMixer * self, GCSoundChannel * channel, GCSoundItem *item) +{ + return GC_SOUND_MIXER_GET_CLASS(self)->play_item (self, channel, item); +} + + +/* GType stuff */ +static void gc_sound_mixer_iface_init(gpointer iface); + +GType +gc_sound_mixer_get_type (void) +{ + static GType type = 0; + if (type == 0) { + static const GTypeInfo info = { + sizeof (GCSoundMixerIface), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) gc_sound_mixer_iface_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL /* instance_init */ + }; + type = g_type_register_static (G_TYPE_INTERFACE, "GCSoundMixer", &info, 0); + g_type_interface_add_prerequisite(type, G_TYPE_OBJECT); + } + return type; +} + +void _gc_sound_mixer_install_property(GObjectClass* go_class, gboolean device_id){ + g_object_class_override_property(go_class, device_id, "device"); +} + +static void +gc_sound_mixer_iface_init(gpointer iface) { + g_object_interface_install_property(iface, + g_param_spec_boolean ("device", + "device", + "Device", + FALSE, + G_PARAM_READABLE)); +} diff --git a/src/gc_sound/src/gc-sound-mixer.gob b/src/gc_sound/src/gc-sound-mixer.gob deleted file mode 100644 index 3fca60f..0000000 --- a/src/gc_sound/src/gc-sound-mixer.gob +++ /dev/null @@ -1,156 +0,0 @@ -%alltop{/* gcompris - gc-sound-mixer.gob - * - * Copyright (C) 2006 Yves Combe - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -%} - -requires 2.0.0 - -%{ -#include "gc-sound-mixer.h" -#include "gc-sound-channel.h" -#include "SDL.h" -#include "SDL_thread.h" -#include "SDL_mixer.h" -#include "SDL_audio.h" -#include "libintl.h" - -#define _(String) gettext (String) -#define gettext_noop(String) String - -#ifndef N_ -#define N_(String) gettext_noop (String) -#endif - -#include "gc-sound-mixer-private.h" -%} - -%h{ -#ifndef __TYPEDEF_GC_SOUND_CHANNEL__ -#define __TYPEDEF_GC_SOUND_CHANNEL__ -typedef struct _GCSoundChannel GCSoundChannel; -#endif -%} -class GC:Sound:Mixer from G:Object { - public gchar *nick = {NULL}; - protected int channels = { 0 }; - - private int audio_buffers=2048; - private int bits = 0; - - private G:List *channels_list = { NULL } - destroy { - GList *chan; - for (chan = channels_list; chan != NULL; chan = g_list_next (chan)) { - g_object_unref (chan); - } - - g_list_free (channels_list); - }; - - private gboolean audio_device = { FALSE} - destroy { - self_set_audio_device(self, FALSE); - if (self->_priv->sdl_ok) - SDL_Quit(); - }; - - property BOOLEAN audio_device - ( nick = _("Audio device opened"), - blurb = _("Open and close the audio device"), - export ) - set { - int audio_rate,audio_channels; - Uint16 audio_format; - - gboolean val = g_value_get_boolean (VAL); - if ( val != self->_priv->audio_device) { - if (val) { - // initialize sdl mixer, open up the audio device - if(Mix_OpenAudio(44100,MIX_DEFAULT_FORMAT,2,self->_priv->audio_buffers)<0){ - g_warning("GCSoundMixer can not open audio dev"); - return; - } - - // print out some info on the audio device and stream - Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels); - self->_priv->bits=audio_format&0xFF; - Mix_AllocateChannels(self->channels ); - g_warning("Opened audio at %d Hz %d bit %s, %d bytes audio buffer\n Number of channels %d", audio_rate, - self->_priv->bits, audio_channels>1?"stereo":"mono", self->_priv->audio_buffers, self->channels); - - Mix_AllocateChannels(self->channels ); - } else { - Mix_CloseAudio(); - g_warning("Closing audio"); - } - - self->_priv->audio_device = val; - } - } - get { g_value_set_boolean (VAL, self->_priv->audio_device); }; - - - private gboolean sdl_ok = { FALSE }; - - init (self) { - //g_warning("gc mixer init"); - - // initialize SDL for audio - if(SDL_Init(SDL_INIT_AUDIO)<0){ - g_warning("SDL_init failed"); - self->_priv->sdl_ok = FALSE; - } else - self->_priv->sdl_ok = TRUE; - - self_set_audio_device(self, TRUE); -} - - class_init (class) { - //g_warning("gc mixer class init"); - - } - - public GC:Sound:Mixer * - new (void) - { - return (GCSoundMixer *)GET_NEW; - } - - public void close_audio(self) - { - self_set_audio_device( self, FALSE); - } - public void open_audio(self) - { - self_set_audio_device( self, TRUE); - } - - public GC:Sound:Channel * - new_channel(self) - { - GCSoundChannel *new_channel; - - new_channel = GC_SOUND_CHANNEL(g_object_new(gc_sound_channel_get_type(), "mixer", self, NULL)); - g_object_ref (new_channel); - - self->_priv->channels_list = g_list_append(self->_priv->channels_list, new_channel); - - return new_channel; - } - -} diff --git a/src/gc_sound/src/gc-sound-mixer.h b/src/gc_sound/src/gc-sound-mixer.h new file mode 100644 index 0000000..8bb8a9e --- /dev/null +++ b/src/gc_sound/src/gc-sound-mixer.h @@ -0,0 +1,97 @@ +/* gcompris - gc-sound-mixer.h + * + * Copyright (C) 2006 Yves Combe + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __GC_SOUND_MIXER_H__ +#define __GC_SOUND_MIXER_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS + +/* + * Main interface structure + */ +typedef struct _GCSoundMixer GCSoundMixer; +typedef struct _GCSoundMixerIface GCSoundMixerIface; + +G_END_DECLS + +#include <gc-sound-channel.h> +#include <gc-sound-item.h> + +G_BEGIN_DECLS + +/* + * Type checking and casting macros + */ +#define GC_TYPE_SOUND_MIXER (gc_sound_mixer_get_type()) +#define GC_SOUND_MIXER(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), GC_TYPE_SOUND_MIXER, GCSoundMixer) +#define GC_IS_SOUND_MIXER(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj), GC_TYPE_SOUND_MIXER) +#define GC_SOUND_MIXER_GET_CLASS(obj) G_TYPE_INSTANCE_GET_INTERFACE((obj), GC_TYPE_SOUND_MIXER, GCSoundMixerIface) + +GType gc_sound_mixer_get_type(void); + +void _gc_sound_mixer_install_property (GObjectClass* go_class, + gboolean device_id); + +gboolean gc_sound_mixer_open_audio (GCSoundMixer * self); +gboolean gc_sound_mixer_close_audio (GCSoundMixer * self); + +GCSoundChannel * gc_sound_mixer_new_channel (GCSoundMixer * self); + +gboolean gc_sound_mixer_pause (GCSoundMixer * self); +gboolean gc_sound_mixer_resume (GCSoundMixer * self); +gboolean gc_sound_mixer_halt (GCSoundMixer * self); + +gboolean gc_sound_mixer_pause_channel (GCSoundMixer * self, GCSoundChannel * channel); +gboolean gc_sound_mixer_resume_channel (GCSoundMixer * self, GCSoundChannel * channel); +gboolean gc_sound_mixer_halt_channel (GCSoundMixer * self, GCSoundChannel * channel); + +gboolean gc_sound_mixer_play_item (GCSoundMixer * self, GCSoundChannel * channel, GCSoundItem *item); + +struct _GCSoundMixerIface { + GTypeInterface base_iface; + + /* vtable */ + gboolean (* open_audio) (GCSoundMixer * self); + gboolean (* close_audio) (GCSoundMixer * self); + + GCSoundChannel * (* new_channel) (GCSoundMixer * self); + + gboolean (* pause) (GCSoundMixer * self); + gboolean (* resume) (GCSoundMixer * self); + gboolean (* halt) (GCSoundMixer * self); + + gboolean (* pause_channel) (GCSoundMixer * self, + GCSoundChannel * channel); + + gboolean (* resume_channel) (GCSoundMixer * self, + GCSoundChannel * channel); + + gboolean (* halt_channel) (GCSoundMixer * self, + GCSoundChannel * channel); + + gboolean (* play_item) (GCSoundMixer * self, + GCSoundChannel * channel, + GCSoundItem *item); +}; + +G_END_DECLS + +#endif diff --git a/src/gc_sound/src/gc-sound.h b/src/gc_sound/src/gc-sound.h index f87863f..228b193 100644 --- a/src/gc_sound/src/gc-sound.h +++ b/src/gc_sound/src/gc-sound.h @@ -21,5 +21,6 @@ */ #include <gc-sound-mixer.h> +#include <gc-sound-mixer-SDL.h> #include <gc-sound-channel.h> #include <gc-sound-item.h> diff --git a/src/gc_sound/src/marshallers.list b/src/gc_sound/src/marshallers.list new file mode 100644 index 0000000..2fbec7d --- /dev/null +++ b/src/gc_sound/src/marshallers.list @@ -0,0 +1,3 @@ +VOID:VOID +VOID:BOOLEAN +VOID:OBJECT diff --git a/src/gc_sound/src/test_gc_sound.c b/src/gc_sound/src/test_gc_sound.c index 8ae03cc..6ae45d0 100644 --- a/src/gc_sound/src/test_gc_sound.c +++ b/src/gc_sound/src/test_gc_sound.c @@ -16,12 +16,12 @@ main (int argc, char *argv) { GCSoundMixer *gcmix; GCSoundChannel* gcchan1, *gcchan2; - GCSoundItem *item1, *item2, *item3, *root1, *root2, *item1_1, *item1_2; - g_type_init (); + GCSoundItem *item1, *item2, *item3, *root1, *root2, *item1_1, *item1_2; + g_type_init (); /* Sound mixer opens SDL and audio device */ - gcmix = gc_sound_mixer_new(); - gcmix->nick = "gcmix"; + gcmix = gc_sound_mixer_SDL_new(); + GC_SOUND_MIXER_SDL(gcmix)->nick = "gcmix"; /* We open two chans to play simultaneously */ gcchan1 = gc_sound_mixer_new_channel(gcmix); @@ -29,20 +29,34 @@ main (int argc, char *argv) gcchan1->nick = "gcchan1"; gcchan2->nick = "gcchan2"; + //g_warning ("nick of mixer %s %s", GC_SOUND_MIXER_SDL(gcchan1->mixer)->nick, + // GC_SOUND_MIXER_SDL(gcchan2->mixer)->nick); + GCSoundMixer *gcmix2; + + g_object_get(G_OBJECT(gcchan2), "mixer", &gcmix2, NULL); + + g_warning ("g_object_get return mixer %s", GC_SOUND_MIXER_SDL(gcmix2)->nick); /* Each chan has a root item, where we group the sounds to play in that channel*/ - root1 = GC_SOUND_ITEM(gc_sound_channel_get_rootItem(gcchan1)); - root2 = GC_SOUND_ITEM(gc_sound_channel_get_rootItem(gcchan2)); + root1 = GC_SOUND_ITEM(gc_sound_channel_get_root(gcchan1)); + root2 = GC_SOUND_ITEM(gc_sound_channel_get_root(gcchan2)); root1->nick="root1"; root2->nick="root2"; /* create new item for our sounds */ - item1 = gc_sound_item_new (root1); - item2 = gc_sound_item_new (root2); - item3 = gc_sound_item_new (root2); - item1_1 = gc_sound_item_new (item1); + item1 = gc_sound_item_append_child (root1); + item2 = gc_sound_item_append_child (root2); + item3 = gc_sound_item_append_child (root2); + item1_1 = gc_sound_item_append_child (item1); + + item1_2 = gc_sound_item_append_child (item1); + + GCSoundChannel *gcc2; + g_object_get(G_OBJECT(item2), "channel", &gcc2, NULL); + + g_warning ("g_object_get return channel %s", GC_SOUND_CHANNEL(gcc2)->nick); + - item1_2 = gc_sound_item_new (item1); item1->nick = "item1"; item2->nick = "item2"; item3->nick = "item3"; @@ -64,31 +78,37 @@ main (int argc, char *argv) gc_sound_item_set_policy(item3, GC_SOUND_INTERRUPT_AND_PLAY); // callback connection - gc_sound_item_connect__play_finished(item2, finish, NULL); - gc_sound_item_connect__play_finished(item3, finish, NULL); - gc_sound_item_connect__play_started(item1_1, start, NULL); - gc_sound_item_connect__play_started(item1_2, start, NULL); + //gc_sound_item_connect__play_finished(item2, finish, NULL); + //gc_sound_item_connect__play_finished(item3, finish, NULL); + //gc_sound_item_connect__play_started(item1_1, start, NULL); + //gc_sound_item_connect__play_started(item1_2, start, NULL); + g_signal_connect( item2, "play_end", finish, NULL); + g_signal_connect( item2, "play_end", finish, NULL); + g_signal_connect( item1_1, "play_start", start, NULL); + g_signal_connect( item1_2, "play_start", start, NULL); + - // test mute - //gc_sound_item_set_mute(item1_1, TRUE); +/* // test mute */ +/* //gc_sound_item_set_mute(item1_1, TRUE); */ - gc_sound_item_set_loop(item1, TRUE); + gc_sound_item_set_loop(item1, TRUE); - //play - gc_sound_item_play(item2); - g_usleep(1000000); + //play + gc_sound_item_play(item2); + g_usleep(1000000); - /* will loop with the two sounds of group */ - gc_sound_item_play(item1); + /* will loop with the two sounds of group */ + gc_sound_item_play(item1); - g_usleep(8000000); + g_usleep(8000000); - //stopping loop after next - gc_sound_item_set_loop(item1, FALSE); - g_usleep(3000000); + //stopping loop after next + g_warning("stopping loop on item1"); + gc_sound_item_set_loop(item1, FALSE); + g_usleep(3000000); - //this will sop item2 because of policy - gc_sound_item_play(item3); + //this will stop item2 because of policy + gc_sound_item_play(item3); /* infinite loop */ g_main_loop_run(g_main_loop_new (NULL, FALSE)); |