From: Prince Kumar Dubey <prince.dubey@samsung.com>
authorPrince Kumar Dubey <prince.dubey@samsung.com>
Fri, 4 Nov 2011 12:18:13 +0000 (12:18 +0000)
committerraster <raster@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Fri, 4 Nov 2011 12:18:13 +0000 (12:18 +0000)
From: Govindaraju S M <govi.sm@samsung.com>
Subject: edje multisense patch for sound sample, tone and haptic play

... This is the beginning of sound (and haptic) support in Edje - it
works, but only at certain basic sample playback levels. more will come.

git-svn-id: http://svn.enlightenment.org/svn/e/trunk/edje@64731 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

32 files changed:
AUTHORS
configure.ac
data/include/edje.inc
doc/examples.dox
src/Makefile.am
src/bin/Makefile.am
src/bin/edje_cc.c
src/bin/edje_cc.h
src/bin/edje_cc_handlers.c
src/bin/edje_cc_out.c
src/bin/edje_decc.c
src/bin/edje_multisense_convert.c [new file with mode: 0644]
src/bin/edje_multisense_convert.h [new file with mode: 0644]
src/examples/Makefile.am
src/examples/multisense.edc [new file with mode: 0644]
src/lib/Edje.h
src/lib/Makefile.am
src/lib/edje_data.c
src/lib/edje_embryo.c
src/lib/edje_load.c
src/lib/edje_main.c
src/lib/edje_module.c
src/lib/edje_multisense.c [new file with mode: 0644]
src/lib/edje_private.h
src/lib/edje_program.c
src/modules/Makefile.am [new file with mode: 0644]
src/modules/alsa_snd_player/Makefile.am [new file with mode: 0644]
src/modules/alsa_snd_player/alsa_snd_player.c [new file with mode: 0644]
src/modules/eet_snd_reader/Makefile.am [new file with mode: 0644]
src/modules/eet_snd_reader/eet_snd_reader.c [new file with mode: 0644]
src/modules/multisense_factory/Makefile.am [new file with mode: 0644]
src/modules/multisense_factory/multisense_factory.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
index 9712dab..56c5483 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -18,3 +18,5 @@ Shilpa Singh <shilpa.singh@samsung.com> <shilpasingh.o@gmail.com>
 Mike Blumenkrantz <mike@zentific.com
 Jaehwan Kim <jae.hwan.kim@samsung.com>
 billiob (Boris Faure) <billiob@gmail.com>
+Govindaraju SM <govi.sm@samsung.com> <govism@gmail.com>
+Prince Kumar Dubey <prince.dubey@samsung.com> <prince.dubey@gmail.com>
index b6dcd6a..1aedd92 100644 (file)
@@ -290,6 +290,157 @@ PKG_CHECK_MODULES([ECORE_IMF],
    ],
    [have_ecore_imf="no"])
 
+# Enable Multisense use
+want_multisense="no"
+AC_ARG_ENABLE([multisense],
+   [AC_HELP_STRING(
+       [--enable-multisense],
+       [multisense provides sound. tone and haptic effects support, [[default=disabled]]]
+    )],
+    [want_multisense=$enableval]
+)
+AM_CONDITIONAL([ENABLE_MULTISENSE], [test "x${want_multisense}" = "xyes"])
+
+if test "x${want_multisense}" = "xyes" ; then
+   AC_DEFINE([ENABLE_MULTISENSE], [1], [Use Multisense])
+fi
+
+##sndfile library
+have_sndfile="no"
+want_sndfile="auto"
+AC_ARG_ENABLE([sndfile],
+   [AC_HELP_STRING([--disable-sndfile], [disable sndfile support. @<:@default=detect@:>@])],
+   [want_sndfile=$enableval], [])
+
+if test "x${want_multisense}" = "xyes" -a  "x$want_sndfile" != "xno"; then
+
+          PKG_CHECK_MODULES([SNDFILE],
+             [sndfile >= 1.0.22],
+             [
+              AC_DEFINE(HAVE_LIBSNDFILE, 1, [sndfile support for Edje])
+              have_sndfile="yes"
+              requirement_edje="sndfile >= 1.0.22 ${requirement_edje}"
+              ],
+             [have_sndfile="no"]
+          )
+       
+       if test "x$want_sndfile" = "xyes" -a "x$have_sndfile" = "xno"; then
+           AC_MSG_ERROR([sndfile support requested, but not found by pkg-config.])
+       fi
+fi
+AM_CONDITIONAL([HAVE_LIBSNDFILE], [test "x${have_sndfile}" = "xyes"])
+
+##libremix library
+have_libremix="no"
+want_libremix="auto"
+AC_ARG_ENABLE([remix],
+   [AC_HELP_STRING([--disable-remix], [disable remix support. @<:@default=detect@:>@])],
+   [want_libremix=$enableval], [])
+
+if test "x${want_multisense}" = "xyes" -a "x$want_libremix" != "xno"; then
+   PKG_CHECK_MODULES([REMIX],
+      [remix >= 0.2.3],
+      [
+       AC_DEFINE(HAVE_LIBREMIX, 1, [remix support for Edje])
+       have_libremix="yes"
+       requirement_edje="remix >= 0.2.3 ${requirement_edje}"
+       AC_DEFINE(__REMIX_PLUGIN__, 1, "Set to REMIX Plugin type")
+       REMIX_PLUGIN_DIR="${libdir}/remix"
+       AC_SUBST(REMIX_PLUGIN_DIR)
+       if test "x${prefix}" = "xNONE"; then
+         REMIX_PLUGIN_DIR="${ac_default_prefix}/lib/remix"
+       else
+         REMIX_PLUGIN_DIR="${prefix}/lib/remix"
+       fi
+       AC_DEFINE_UNQUOTED(REMIX_PLUGIN_DIR, "$REMIX_PLUGIN_DIR", [Set the remix plugin directory])
+       ],
+      [have_libremix="no"]
+   )
+
+       if test "x$want_libremix" = "xyes" -a "x$have_libremix" = "xno"; then
+           AC_MSG_ERROR([remix support requested, but not found by pkg-config.])
+       fi
+fi
+AM_CONDITIONAL([HAVE_LIBREMIX], [test "x${have_libremix}" = "xyes"])
+
+##vorbis/ogg library
+have_vorbis="no"
+want_vorbis="auto"
+AC_ARG_ENABLE([vorbisenc],
+   [AC_HELP_STRING([--disable-vorbis], [disable ogg-vorbis support. @<:@default=detect@:>@])],
+   [want_vorbis=$enableval], [])
+
+if test "x${want_multisense}" = "xyes" -a "x$want_vorbis" != "xno"; then
+   PKG_CHECK_MODULES([VORBISENC],
+      [
+       ogg >= 1.1.4
+       vorbis >= 1.2.3
+       vorbisenc >= 1.2.3
+      ],
+      [
+       AC_DEFINE(HAVE_VORBIS, 1, [vorbis support for Edje])
+       have_vorbis="yes"
+       requirement_edje="ogg >= 1.1.4 vorbis >= 1.2.3 vorbisenc >= 1.2.3 ${requirement_edje}"
+      ],
+      [have_vorbis="no"]
+   )
+
+       if test "x$want_vorbis" = "xyes" -a "x$have_vorbis" = "xno"; then
+           AC_MSG_ERROR([vorbisenc support requested, but not found by pkg-config.])
+       fi
+fi
+
+##alsa library
+have_alsa_lib="no"
+want_alsa_lib="auto"
+AC_ARG_ENABLE([flac],
+   [AC_HELP_STRING([--disable-alsa], [disable alsa support. @<:@default=detect@:>@])],
+   [want_alsa_lib=$enableval], [])
+
+if test "x${want_multisense}" = "xyes" -a "x$want_alsa_lib" != "xno"; then
+   PKG_CHECK_MODULES([ALSA],
+      [
+       alsa >= 1.0.21a
+      ],
+      [
+       AC_DEFINE(HAVE_LIBALSA, 1, [ALSA support for Edje])
+       have_alsa_lib="yes"
+       requirement_edje="alsa >= 1.0.21a ${requirement_edje}"
+      ],
+      [have_alsa_lib="no"]
+   )
+
+       if test "x$want_alsa_lib" = "xyes" -a "x$have_alsa_lib" = "xno"; then
+           AC_MSG_ERROR([alsa support requested, but not found by pkg-config.])
+       fi
+fi     
+AM_CONDITIONAL([HAVE_LIBALSA], [test "x${have_alsa_lib}" = "xyes"])
+
+
+##flac library
+have_flac_lib="no"
+want_flac_lib="auto"
+AC_ARG_ENABLE([flac],
+   [AC_HELP_STRING([--disable-flac], [disable flac support. @<:@default=detect@:>@])],
+   [want_flac_lib=$enableval], [])
+
+if test "x${want_multisense}" = "xyes" -a "x$want_flac_lib" != "xno"; then
+   PKG_CHECK_MODULES([FLAC],
+      [
+       flac >= 1.2.1
+      ],
+      [
+       AC_DEFINE(HAVE_LIBFLAC, 1, [flac support for Edje])
+       have_flac_lib="yes"
+       requirement_edje="flac >= 1.2.1 ${requirement_edje}"
+      ],
+      [have_flac_lib="no"]
+   )
+       if test "x$want_flac_lib" = "xyes" -a "x$have_flac_lib" = "xno"; then
+           AC_MSG_ERROR([flac support requested, but not found by pkg-config.])
+       fi
+fi
+
 # Dependencies for the binaries
 
 if test "x$have_edje_cc" = "xyes"; then
@@ -432,6 +583,10 @@ src/Makefile
 src/lib/Makefile
 src/bin/Makefile
 src/bin/epp/Makefile
+src/modules/Makefile
+src/modules/alsa_snd_player/Makefile
+src/modules/eet_snd_reader/Makefile
+src/modules/multisense_factory/Makefile
 src/tests/Makefile
 utils/Makefile
 src/examples/Makefile
@@ -452,6 +607,16 @@ echo "Configuration Options Summary:"
 echo
 echo "  Amalgamation.........: ${do_amalgamation}"
 echo "  Ecore IMF............: $have_ecore_imf"
+echo "  Multisense...........: $want_multisense"
+
+if test "x${want_multisense}" = "xyes" ; then
+echo "  LibRemix.............: $have_libremix"
+echo "  Libsndfile...........: $have_sndfile"
+echo "  Ogg/Vorbis...........: $have_vorbis"
+echo "  LibFLAC..............: $have_flac_lib"
+echo "  LibALSA..............: $have_alsa_lib"
+fi
+
 echo "  EDJE_PROGRAM_CACHE...: $want_edje_program_cache"
 echo "  EDJE_CALC_CACHE......: $want_edje_calc_cache"
 echo "  Fixed point..........: $want_fixed_point"
index 45394cb..dfa5416 100644 (file)
@@ -213,3 +213,7 @@ enum State_Param
 
 native set_state_val(part_id, State_Param:p, ...);
 native get_state_val(part_id, State_Param:p, ...);
+
+/* Multisense */
+native       play_sample      (sample_name[], Float:speed);
+native       play_tone        (tone_name[], Float:duration);
index be3df77..846c4c0 100644 (file)
@@ -14,6 +14,7 @@
  * @li @ref tutorial_edje_drag
  * @li @ref tutorial_edje_perspective
  * @li @ref tutorial_edje_animations
+ * @li @ref tutorial_edje_multisense
  */
 
 /**
  * @include edje-animations.c
  * @include animations.edc
  */
+
+ /**
+ * @page tutorial_edje_multisense Multisense example
+ * @dontinclude edje-multisense.c
+ *
+ * This is a simple example in which a rect is created and sound and tone
+ * are played on mouse down event.
+ *
+ * Focusing on the creation of sample and tone. It should be noted that
+ * creation of sample sound is from any supported (sndfile lib) audio file,
+ * tone from of specific audible frequency range are controlled by the theme:
+ *
+ * The full source code follows:
+ * @include edje-multisense.c
+ * @include sound.edc
+ */
index 69930d5..d97f1db 100644 (file)
@@ -1,4 +1,4 @@
 ## Process this file with automake to produce Makefile.in
 
-SUBDIRS = lib bin tests examples
+SUBDIRS = lib bin modules tests examples
 MAINTAINERCLEANFILES = Makefile.in
index cce746c..a936d5a 100644 (file)
@@ -16,7 +16,8 @@ edje_cc_out.c \
 edje_cc_parse.c \
 edje_cc_mem.c \
 edje_cc_handlers.c \
-edje_cc_sources.c
+edje_cc_sources.c \
+edje_multisense_convert.c
 
 edje_cc_CPPFLAGS = \
 -I$(top_srcdir)/src/bin \
@@ -25,8 +26,8 @@ edje_cc_CPPFLAGS = \
 -DPACKAGE_LIB_DIR=\"$(libdir)\" \
 -DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
 -DEPP_DIR=\"$(libdir)/$(PACKAGE)/utils\" \
-@EDJE_CFLAGS@ @EDJE_CC_CFLAGS@ @EVIL_CFLAGS@
-edje_cc_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_CC_LIBS@ @EVIL_LIBS@ -lm
+@EDJE_CFLAGS@ @EDJE_CC_CFLAGS@ @EVIL_CFLAGS@ @SNDFILE_CFLAGS@
+edje_cc_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_CC_LIBS@ @EVIL_LIBS@ @VORBISENC_LIBS@ @FLAC_LIBS@ @SNDFILE_LIBS@ -lm
 edje_cc_LDFLAGS = @lt_enable_auto_import@
 
 
@@ -40,7 +41,7 @@ edje_decc_CPPFLAGS = \
 -I$(top_srcdir)/src/bin \
 -I$(top_srcdir)/src/lib \
 @EDJE_CFLAGS@ @EDJE_DECC_CFLAGS@ @EVIL_CFLAGS@
-edje_decc_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_DECC_LIBS@
+edje_decc_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_DECC_LIBS@ @VORBISENC_LIBS@ @FLAC_LIBS@ @SNDFILE_LIBS@
 edje_decc_LDFLAGS = @lt_enable_auto_import@
 
 edje_player_SOURCES = edje_player.c
@@ -48,7 +49,7 @@ edje_player_CPPFLAGS = \
 -I$(top_srcdir)/src/bin \
 -I$(top_srcdir)/src/lib \
 @EDJE_PLAYER_CFLAGS@ @EVIL_CFLAGS@
-edje_player_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_PLAYER_LIBS@ @EVIL_LIBS@
+edje_player_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_PLAYER_LIBS@ @EVIL_LIBS@ @VORBISENC_LIBS@ @FLAC_LIBS@ @SNDFILE_LIBS@
 edje_player_LDFLAGS = @lt_enable_auto_import@
 
 edje_inspector_SOURCES = edje_inspector.c
@@ -56,7 +57,7 @@ edje_inspector_CPPFLAGS = \
 -I$(top_srcdir)/src/bin \
 -I$(top_srcdir)/src/lib \
 @EDJE_INSPECTOR_CFLAGS@
-edje_inspector_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_INSPECTOR_LIBS@
+edje_inspector_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_INSPECTOR_LIBS@ @VORBISENC_LIBS@ @FLAC_LIBS@
 edje_inspector_LDFLAGS = @lt_enable_auto_import@
 
 edje_external_inspector_SOURCES = edje_external_inspector.c
@@ -64,9 +65,8 @@ edje_external_inspector_CPPFLAGS = \
 -I$(top_srcdir)/src/bin \
 -I$(top_srcdir)/src/lib \
 @EDJE_EXTERNAL_INSPECTOR_CFLAGS@
-edje_external_inspector_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_EXTERNAL_INSPECTOR_LIBS@
+edje_external_inspector_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_EXTERNAL_INSPECTOR_LIBS@ @VORBISENC_LIBS@ @FLAC_LIBS@ @SNDFILE_LIBS@
 edje_external_inspector_LDFLAGS = @lt_enable_auto_import@
 
-
-EXTRA_DIST = @EDJE_RECC_PRG@ edje_cc.h edje_convert.h edje_convert.c edje_convert_main.c edje_data_convert.c
+EXTRA_DIST = @EDJE_RECC_PRG@ edje_cc.h edje_convert.h edje_convert.c edje_multisense_convert.h edje_data_convert.c
 EXTRA_SCRIPTS = edje_recc
index f7c3bfd..adcbbb6 100644 (file)
@@ -12,7 +12,7 @@ int _edje_cc_log_dom = -1;
 static void main_help(void);
 
 Eina_Prefix  *pfx = NULL;
-
+Eina_List *snd_dirs = NULL;
 Eina_List *img_dirs = NULL;
 Eina_List *fnt_dirs = NULL;
 Eina_List *defines = NULL;
@@ -40,6 +40,7 @@ main_help(void)
       "\n"
       "-id image/directory      Add a directory to look in for relative path images\n"
       "-fd font/directory       Add a directory to look in for relative path fonts\n"
+      "-sd sound/directory      Add a directory to look in for relative path sounds samples\n"
       "-td temp/directory       Directory to store temporary files\n"
       "-v                       Verbose output\n"
       "-no-lossy                Do NOT allow images to be lossy\n"
@@ -113,6 +114,11 @@ main(int argc, char **argv)
             i++;
             fnt_dirs = eina_list_append(fnt_dirs, argv[i]);
          }
+        else if ((!strcmp(argv[i], "-sd") || !strcmp(argv[i], "--sound_dir")) && (i < (argc - 1)))
+          {
+             i++;
+             snd_dirs = eina_list_append(snd_dirs, argv[i]);
+          }
        else if ((!strcmp(argv[i], "-td") || !strcmp(argv[i], "--tmp_dir")) && (i < (argc - 1)))
          {
             i++;
index 743d771..bcd31a1 100644 (file)
@@ -197,6 +197,7 @@ void    error_and_abort(Eet_File *ef, const char *fmt, ...);
 extern Eina_List             *ext_dirs;
 extern Eina_List             *img_dirs;
 extern Eina_List             *fnt_dirs;
+extern Eina_List             *snd_dirs;
 extern char                  *file_in;
 extern char                  *tmp_dir;
 extern char                  *file_out;
index 0351987..6bc070a 100644 (file)
@@ -261,6 +261,9 @@ static void st_collections_group_programs_program_after(void);
 static void st_collections_group_programs_program_api(void);
 
 static void ob_collections_group_programs_program_script(void);
+static void st_collections_group_sound_sample_name(void);
+static void st_collections_group_sound_sample_source(void);
+static void st_collections_group_sound_tone(void);
 
 /*****/
 
@@ -299,6 +302,13 @@ New_Statement_Handler statement_handlers[] =
      {"collections.color_classes.color_class.color", st_color_class_color}, /* dup */
      {"collections.color_classes.color_class.color2", st_color_class_color2}, /* dup */
      {"collections.color_classes.color_class.color3", st_color_class_color3}, /* dup */
+
+     {"collections.sounds.sample.name", st_collections_group_sound_sample_name},
+     {"collections.sounds.sample.source", st_collections_group_sound_sample_source},
+     {"collections.group.sounds.sample.name", st_collections_group_sound_sample_name}, /* dup */
+     {"collections.group.sounds.sample.source", st_collections_group_sound_sample_source}, /* dup */
+     {"collections.sounds.tone", st_collections_group_sound_tone},
+     {"collections.group.sounds.tone", st_collections_group_sound_tone}, /* dup */
      {"collections.group.name", st_collections_group_name},
      {"collections.group.inherit", st_collections_group_inherit},
      {"collections.group.script_only", st_collections_group_script_only},
@@ -663,6 +673,10 @@ New_Object_Handler object_handlers[] =
      {"collections.styles.style", ob_styles_style}, /* dup */
      {"collections.color_classes", NULL}, /* dup */
      {"collections.color_classes.color_class", ob_color_class}, /* dup */
+     {"collections.sounds", NULL},
+     {"collections.group.sounds", NULL}, /* dup */
+     {"collections.sounds.sample", NULL},
+     {"collections.group.sounds.sample", NULL}, /* dup */
      {"collections.group", ob_collections_group},
      {"collections.group.data", NULL},
      {"collections.group.script", ob_collections_group_script},
@@ -1825,12 +1839,13 @@ st_styles_style_tag(void)
             ..
             group { }
             group { }
+            sounds { }
             ..
         }
     @description
         The "collections" block is used to list the groups that compose the
         theme. Additional "collections" blocks do not prevent overriding group
-        names.
+        names. The "sounds" block comprises of all sound definitions.
     @endblock
 */
 static void
@@ -1841,6 +1856,219 @@ ob_collections(void)
 }
 
 /**
+    @page edcref
+    @block
+        sounds
+    @context
+        sounds {
+           sample {
+              name: "sound_file1" COMP;
+              source: "sound_file1.wav";
+           }
+           sample {
+              name: "sound_file2" LOSSY 0.4;
+              source: "sound_file2.wav";
+           }
+           tone: "tone-1"  2300;
+        }
+
+    @description
+        The "sounds" block contains a list of one or more sound sample and tones items.
+    @endblock
+    @block
+        sample
+    @context
+       sample {
+          name: "sound_file1" RAW;
+          source: "sound_file1.wav";
+       }
+       sample {
+          name: "sound_file2" LOSSY 0.5;
+          source: "sound_file2.wav";
+       }
+       sample {
+          name: "sound_file3" COMP;
+          source: "sound_file3.wav";
+       }
+       sample {
+          name: "sound_file4" AS-IS;
+          source: "sound_file1.wav";
+       }
+    @description
+        The sample block defines the sound sample.
+    @endblock
+    @property
+        name
+    @parameters
+        [sample name] [compression type] [if lossy, then quality]
+    @effect
+        Used to include each sound file. The full path to the directory holding
+        the sounds can be defined later with edje_cc's "-sd" option.
+        @li RAW: Uncompressed.
+        @li COMP: Lossless compression.
+        @li LOSSY [-0.1  - 1.0]: Lossy comression with quality from 0 to 1.0.
+        @li AS_IS: Check for re-encoding, no compression/encoding, just write the file information as it is.
+    @endproperty
+    @since 1.1.0
+ */
+static void
+st_collections_group_sound_sample_name(void)
+{
+   Edje_Sound_Sample *sample;
+   const char *tmp;
+   unsigned int i;
+   
+   if (!edje_file->sound_dir)
+     edje_file->sound_dir = mem_alloc(SZ(Edje_Sound_Directory));
+   
+   tmp = parse_str(0);
+   
+   for (i = 0; i < edje_file->sound_dir->samples_count; i++)
+     {
+        if (!strcmp(edje_file->sound_dir->samples[i].name, tmp))
+          {
+             free((char *)tmp);
+             return;
+          }
+     }
+   
+   edje_file->sound_dir->samples_count++;
+   edje_file->sound_dir->samples = 
+     realloc(edje_file->sound_dir->samples,
+             sizeof(Edje_Sound_Sample) * 
+             edje_file->sound_dir->samples_count);
+
+   if (!edje_file->sound_dir->samples)
+     {
+        ERR("%s: Error. No enough memory.", progname);
+        exit(-1);
+     }
+   
+   sample =
+     edje_file->sound_dir->samples +
+     edje_file->sound_dir->samples_count - 1;
+   memset(sample, 0, sizeof (Edje_Sound_Sample));
+   
+   sample->name = tmp;
+   sample->id = edje_file->sound_dir->samples_count - 1;
+   sample->compression = parse_enum(1,
+                                    "RAW", EDJE_SOUND_SOURCE_TYPE_INLINE_RAW,
+                                    "COMP", EDJE_SOUND_SOURCE_TYPE_INLINE_COMP,
+                                    "LOSSY", EDJE_SOUND_SOURCE_TYPE_INLINE_LOSSY,
+                                    "AS_IS", EDJE_SOUND_SOURCE_TYPE_INLINE_AS_IS,
+                                    NULL);
+   
+   if (sample->compression == EDJE_SOUND_SOURCE_TYPE_INLINE_LOSSY)
+     {
+        sample->quality = parse_float_range(2, 45.0, 1000.0);
+        check_arg_count(3);
+     }
+   else
+     check_arg_count(2);
+
+}
+
+/**
+    @page edcref
+    @property
+        source
+    @parameters
+        [sound file name]
+    @effect
+        The Sound source file name (Source can be mono/stereo WAV file.
+        Only files with 44.1 KHz sample rate supported now)
+    @endproperty
+    @since 1.1.0
+ */
+static void
+st_collections_group_sound_sample_source(void)
+{
+   Edje_Sound_Sample *sample;
+
+   if (!edje_file->sound_dir->samples)
+     {
+        ERR("%s: Error. Invalid sound sample source definition.", progname);
+        exit(-1);
+     }
+   
+   sample = 
+     edje_file->sound_dir->samples +
+     edje_file->sound_dir->samples_count - 1;
+   
+   if (!sample)
+     {
+        ERR("%s: Error. Invalid sound sample source definition.", progname);
+        exit(-1);
+     }
+   sample->snd_src = parse_str(0);
+   check_arg_count(1);
+}
+
+/**
+    @page edcref
+    @property
+        tone
+    @parameters
+        [tone name] [frequency]
+    @effect
+        sound of specific frequency
+    @endproperty
+    @since 1.1.0
+ */
+static void
+st_collections_group_sound_tone(void)
+{
+   Edje_Sound_Tone *tone;
+   const char *tmp;
+   unsigned int i;
+   int value;
+
+   check_arg_count(2);
+   
+   if (!edje_file->sound_dir)
+     edje_file->sound_dir = mem_alloc(SZ(Edje_Sound_Directory));
+   
+   tmp = parse_str(0);
+   /* Audible range 20 to 20KHz */
+   value = parse_int_range(1, 20, 20000);
+   
+   /* Check for Tone duplication */
+   for (i = 0; i < edje_file->sound_dir->tones_count; i++)
+     {
+        if (!strcmp(edje_file->sound_dir->tones[i].name, tmp))
+          {
+             ERR("%s: Error. Tone name: %s already exist.", progname, tmp);
+             free((char *)tmp);
+             exit(-1);
+          }
+        if (edje_file->sound_dir->tones[i].value == value)
+          {
+             ERR("%s: Error. Tone name %s with same frequency %d exist.",
+                 progname, edje_file->sound_dir->tones[i].name, value);
+             exit(-1);
+          }
+     }
+   edje_file->sound_dir->tones_count++;
+   edje_file->sound_dir->tones = 
+     realloc(edje_file->sound_dir->tones,
+             sizeof (Edje_Sound_Tone) * 
+             edje_file->sound_dir->tones_count);
+   
+   if (!edje_file->sound_dir->tones)
+     {
+        ERR("%s: Error. No enough memory.", progname);
+        exit(-1);
+     }
+   
+   tone = edje_file->sound_dir->tones + edje_file->sound_dir->tones_count - 1;
+   memset(tone, 0, sizeof (Edje_Sound_Tone));
+   
+   tone->name = tmp;
+   tone->value = value;
+   tone->id = edje_file->sound_dir->tones_count - 1;
+}
+
+/**
    @edcsection{group,Group sub blocks}
  */
 
@@ -1874,7 +2102,7 @@ ob_collections_group(void)
 {
    Edje_Part_Collection *pc;
    Code *cd;
-
+   
    if (current_de && !current_de->entry)
      {
        ERR("%p: Error. A collection without a name was detected, that's not allowed.", progname);
@@ -7005,7 +7233,7 @@ st_collections_group_programs_program_in(void)
     @effect
         Action to be performed by the program. Valid actions are: STATE_SET,
         ACTION_STOP, SIGNAL_EMIT, DRAG_VAL_SET, DRAG_VAL_STEP, DRAG_VAL_PAGE,
-        FOCUS_SET, PARAM_COPY, PARAM_SET
+        FOCUS_SET, PARAM_COPY, PARAM_SET, PLAY_SAMPLE, PLAY_TONE
         Only one action can be specified per program. Examples:\n
            action: STATE_SET "statename" 0.5;\n
            action: ACTION_STOP;\n
@@ -7016,7 +7244,9 @@ st_collections_group_programs_program_in(void)
            action: FOCUS_SET;\n
            action: FOCUS_OBJECT;\n
            action: PARAM_COPY "src_part" "src_param" "dst_part" "dst_param";\n
-          action: PARAM_SET "part" "param" "value";\n
+           action: PARAM_SET "part" "param" "value";\n
+           action: PLAY_SAMPLE "sample name";\n
+           action: PLAY_TONE "tone name" duration in seconds ( Range 0.1 to 10.0 );\n
     @endproperty
 */
 static void
@@ -7024,22 +7254,25 @@ st_collections_group_programs_program_action(void)
 {
    Edje_Part_Collection *pc;
    Edje_Program *ep;
-
+   int i;
+   
    pc = eina_list_data_get(eina_list_last(edje_collections));
    ep = current_program;
    ep->action = parse_enum(0,
-                          "STATE_SET", EDJE_ACTION_TYPE_STATE_SET,
-                          "ACTION_STOP", EDJE_ACTION_TYPE_ACTION_STOP,
-                          "SIGNAL_EMIT", EDJE_ACTION_TYPE_SIGNAL_EMIT,
-                          "DRAG_VAL_SET", EDJE_ACTION_TYPE_DRAG_VAL_SET,
-                          "DRAG_VAL_STEP", EDJE_ACTION_TYPE_DRAG_VAL_STEP,
-                          "DRAG_VAL_PAGE", EDJE_ACTION_TYPE_DRAG_VAL_PAGE,
-                          "SCRIPT", EDJE_ACTION_TYPE_SCRIPT,
-                          "FOCUS_SET", EDJE_ACTION_TYPE_FOCUS_SET,
-                          "FOCUS_OBJECT", EDJE_ACTION_TYPE_FOCUS_OBJECT,
-                          "PARAM_COPY", EDJE_ACTION_TYPE_PARAM_COPY,
-                          "PARAM_SET", EDJE_ACTION_TYPE_PARAM_SET,
-                          NULL);
+                           "STATE_SET", EDJE_ACTION_TYPE_STATE_SET,
+                           "ACTION_STOP", EDJE_ACTION_TYPE_ACTION_STOP,
+                           "SIGNAL_EMIT", EDJE_ACTION_TYPE_SIGNAL_EMIT,
+                           "DRAG_VAL_SET", EDJE_ACTION_TYPE_DRAG_VAL_SET,
+                           "DRAG_VAL_STEP", EDJE_ACTION_TYPE_DRAG_VAL_STEP,
+                           "DRAG_VAL_PAGE", EDJE_ACTION_TYPE_DRAG_VAL_PAGE,
+                           "SCRIPT", EDJE_ACTION_TYPE_SCRIPT,
+                           "FOCUS_SET", EDJE_ACTION_TYPE_FOCUS_SET,
+                           "FOCUS_OBJECT", EDJE_ACTION_TYPE_FOCUS_OBJECT,
+                           "PARAM_COPY", EDJE_ACTION_TYPE_PARAM_COPY,
+                           "PARAM_SET", EDJE_ACTION_TYPE_PARAM_SET,
+                           "PLAY_SAMPLE", EDJE_ACTION_TYPE_SOUND_SAMPLE,
+                           "PLAY_TONE", EDJE_ACTION_TYPE_SOUND_TONE,
+                           NULL);
    if (ep->action == EDJE_ACTION_TYPE_STATE_SET)
      {
        ep->state = parse_str(1);
@@ -7050,6 +7283,38 @@ st_collections_group_programs_program_action(void)
        ep->state = parse_str(1);
        ep->state2 = parse_str(2);
      }
+   else if (ep->action == EDJE_ACTION_TYPE_SOUND_SAMPLE)
+     {
+        ep->sample_name = parse_str(1);
+        for (i = 0; i < (int)edje_file->sound_dir->samples_count; i++)
+          {
+             if (!strcmp(edje_file->sound_dir->samples[i].name, ep->sample_name))
+               break;
+             if (i == (int)(edje_file->sound_dir->samples_count - 1))
+               {
+                  ERR("%s: Error. No Sample name %s exist.", progname,
+                      ep->sample_name);
+                  exit(-1);
+               }
+          }
+        ep->speed = parse_float_range(2, 0.0, 10.0);
+     }
+   else if (ep->action == EDJE_ACTION_TYPE_SOUND_TONE)
+     {
+        ep->tone_name = parse_str(1);
+        for (i = 0; i < (int)edje_file->sound_dir->tones_count; i++)
+          {
+             if (!strcmp(edje_file->sound_dir->tones[i].name, ep->tone_name))
+               break;
+             if (i == (int)(edje_file->sound_dir->tones_count - 1))
+               {
+                  ERR("%s: Error. No Tone name %s exist.", progname,
+                      ep->tone_name);
+                  exit(-1);
+               }
+          }
+        ep->duration = parse_float_range(2, 0.1, 10.0);
+     }
    else if (ep->action == EDJE_ACTION_TYPE_DRAG_VAL_SET)
      {
        ep->value = parse_float(1);
@@ -7068,30 +7333,30 @@ st_collections_group_programs_program_action(void)
    else if (ep->action == EDJE_ACTION_TYPE_PARAM_COPY)
      {
        char *src_part, *dst_part;
-
+        
        src_part = parse_str(1);
        ep->state = parse_str(2);
        dst_part = parse_str(3);
        ep->state2 = parse_str(4);
-
+        
        data_queue_part_lookup(pc, src_part, &(ep->param.src));
        data_queue_part_lookup(pc, dst_part, &(ep->param.dst));
-
+        
        free(src_part);
        free(dst_part);
      }
    else if (ep->action == EDJE_ACTION_TYPE_PARAM_SET)
      {
        char *part;
-
+        
        part = parse_str(1);
        ep->state = parse_str(2);
        ep->state2 = parse_str(3);
-
+        
        data_queue_part_lookup(pc, part, &(ep->param.dst));
        free(part);
      }
-
+   
    switch (ep->action)
      {
       case EDJE_ACTION_TYPE_ACTION_STOP:
@@ -7106,11 +7371,17 @@ st_collections_group_programs_program_action(void)
        check_arg_count(1);
        break;
       case EDJE_ACTION_TYPE_PARAM_COPY:
-        check_arg_count(5);
-        break;
+        check_arg_count(5);
+        break;
       case EDJE_ACTION_TYPE_PARAM_SET:
-        check_arg_count(4);
-        break;
+        check_arg_count(4);
+        break;
+      case EDJE_ACTION_TYPE_SOUND_SAMPLE:
+        check_arg_count(3);
+        break;
+      case EDJE_ACTION_TYPE_SOUND_TONE:
+        check_arg_count(3);
+        break;
       default:
        check_arg_count(3);
      }
index a1aa168..1d4195e 100644 (file)
@@ -28,6 +28,7 @@ void *alloca (size_t);
 
 #include "edje_cc.h"
 #include "edje_convert.h"
+#include "edje_multisense_convert.h"
 
 #include <lua.h>
 #include <lauxlib.h>
@@ -650,6 +651,114 @@ data_write_images(Eet_File *ef, int *image_num, int *input_bytes, int *input_raw
    return total_bytes;
 }
 
+static int
+data_write_sounds(Eet_File * ef, int *sound_num, int *input_bytes, int *input_raw_bytes)
+{
+   int bytes = 0;
+   int total_bytes = 0;
+   
+   if ((edje_file) && (edje_file->sound_dir))
+     {
+        Eina_List *ll;
+        Edje_Sound_Sample *sample;
+#ifdef HAVE_LIBSNDFILE
+        Edje_Sound_Encode *enc_info;
+#endif
+        char *dir_path = NULL;
+        char snd_path[PATH_MAX];
+        char sndid_str[15];
+        void *fdata;
+        FILE *fp = NULL;
+        struct stat st;
+        int size = 0;
+        int i;
+
+        for (i = 0; i < (int)edje_file->sound_dir->samples_count; i++)
+          {
+             sample = &edje_file->sound_dir->samples[i];
+             memset(&st, 0, sizeof(struct stat));
+             
+             // Search the Sound file in all the -sd ( sound directory )
+             EINA_LIST_FOREACH(snd_dirs, ll, dir_path)
+               {
+                  snprintf((char *)snd_path, sizeof(snd_path), "%s/%s", dir_path,
+                           sample->snd_src);
+                  stat(snd_path, &st);
+                  if (st.st_size) break;
+               }
+             if (!st.st_size)
+               {
+                  snprintf((char *)snd_path, sizeof(snd_path), "%s",
+                           sample->snd_src);
+                  stat(snd_path, &st);
+               }
+             size = st.st_size;
+             if (!size)
+               {
+                  ERR("%s: Error. Unable to load sound source file : %s",
+                      progname, sample->snd_src);
+                  exit(-1);
+               }
+#ifdef HAVE_LIBSNDFILE
+             enc_info = _edje_multisense_encode(snd_path, sample, sample->quality);
+             
+             stat(enc_info->file, &st);
+             size = st.st_size;
+             fp = fopen(enc_info->file, "rb");
+#else
+             fp = fopen(snd_path, "rb");
+#endif
+             if (!fp)
+               {
+                  ERR("%s: Error: Unable to load sound data of: %s",
+                      progname, sample->name);
+                  exit(-1);
+               }
+             
+             snprintf(sndid_str, sizeof(sndid_str), "edje/sounds/%i", sample->id);
+             fdata = malloc(size);
+             if (!fdata)
+               {
+                  ERR("%s: Error. %s:%i while allocating memory to load file \"%s\"",
+                      progname, file_in, line, snd_path);
+                  exit(-1);
+               }
+             if (fread(fdata, size, 1, fp))
+               bytes = eet_write(ef, sndid_str, fdata, size, EINA_FALSE);
+             free(fdata);
+             fclose(fp);
+             
+#ifdef HAVE_LIBSNDFILE
+             //If encoded temporary file, delete it.
+             if (enc_info->encoded) unlink(enc_info->file);
+#endif
+             *sound_num += 1;
+             total_bytes += bytes;
+             *input_bytes += size;
+             *input_raw_bytes += size;
+
+             if (verbose)
+               {
+#ifdef HAVE_LIBSNDFILE
+                  printf ("%s: Wrote %9i bytes (%4iKb) for \"%s\" %s sound entry"
+                          "\"%s\" \n", progname, bytes, (bytes + 512) / 1024,
+                          sndid_str, enc_info->comp_type, sample->name);
+#else
+                  printf ("%s: Wrote %9i bytes (%4iKb) for \"%s\" %s sound entry"
+                          "\"%s\" \n", progname, bytes, (bytes + 512) / 1024,
+                          sndid_str, "RAW PCM", sample->name);
+#endif
+               }
+#ifdef HAVE_LIBSNDFILE
+             if ((enc_info->file) && (!enc_info->encoded)) eina_stringshare_del(enc_info->file);
+             if (enc_info) free(enc_info);
+             enc_info = NULL;
+#endif
+          }
+     }
+   return total_bytes;
+}
+
 static void
 check_groups(Eet_File *ef)
 {
@@ -1058,6 +1167,7 @@ data_write(void)
    int fmap_bytes = 0;
    int input_raw_bytes = 0;
    int image_num = 0;
+   int sound_num = 0;
    int font_num = 0;
    int collection_num = 0;
 
@@ -1083,6 +1193,8 @@ data_write(void)
                                   &input_raw_bytes);
    total_bytes += data_write_images(ef, &image_num, &input_bytes,
                                    &input_raw_bytes);
+   total_bytes += data_write_sounds(ef, &sound_num, &input_bytes,
+                &input_raw_bytes);
 
    total_bytes += data_write_groups(ef, &collection_num);
    data_write_scripts(ef);
@@ -1106,6 +1218,7 @@ data_write(void)
        printf("Summary:\n"
               "  Wrote %i collections\n"
               "  Wrote %i images\n"
+          "  Wrote %i sounds\n"
               "  Wrote %i fonts\n"
               "  Wrote %i bytes (%iKb) of original source data\n"
               "  Wrote %i bytes (%iKb) of original source font map\n"
@@ -1120,6 +1233,7 @@ data_write(void)
               ,
               collection_num,
               image_num,
+          sound_num,
               font_num,
               src_bytes, (src_bytes + 512) / 1024,
               fmap_bytes, (fmap_bytes + 512) / 1024,
index 00c9215..2c32c19 100644 (file)
@@ -370,6 +370,51 @@ output(void)
        chmod(out, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP);
 
      }
+
+   if (edje_file->sound_dir)
+     {
+        Edje_Sound_Sample *sample;
+        void *sound_data;
+        char out[PATH_MAX];
+        char out1[PATH_MAX];
+        char *pp;
+        int sound_data_size;
+        FILE *f;
+        int i;
+
+        for (i = 0; i < (int)edje_file->sound_dir->samples_count; i++)
+          {
+             sample = &edje_file->sound_dir->samples[i];
+             if ((!sample) || (!sample->name)) continue;
+             snprintf(out, sizeof(out), "edje/sounds/%i", sample->id);
+             sound_data = (void *)eet_read_direct(tef, out, &sound_data_size);
+             if (sound_data)
+               {
+                  snprintf(out1, sizeof(out1), "%s/%s", outdir, sample->name);
+                  pp = strdup(out1);
+                  p = strrchr(pp, '/');
+                  *p = 0;
+                  if (strstr(pp, "../"))
+                    {
+                       ERR("Potential security violation. attempt to write in parent dir.");
+                       exit(-1);
+                    }
+                  ecore_file_mkpath(pp);
+                  free(pp);
+                  if (strstr(out, "../"))
+                    {
+                       ERR("Potential security violation. attempt to write in parent dir.");
+                       exit(-1);
+                    }
+                  f = fopen(out1, "wb");
+                  if (fwrite(sound_data, sound_data_size, 1, f) != 1)
+                    ERR("Could not write sound: %s", strerror(errno));
+                  fclose(f);
+                  free(sound_data);
+              }
+          }
+
+     }
    eet_close(tef);
 }
 
diff --git a/src/bin/edje_multisense_convert.c b/src/bin/edje_multisense_convert.c
new file mode 100644 (file)
index 0000000..cf74be2
--- /dev/null
@@ -0,0 +1,329 @@
+#include "edje_multisense_convert.h"
+
+#ifdef HAVE_LIBSNDFILE
+# define READBUF 1024
+# ifdef HAVE_VORBIS
+#  include <vorbis/vorbisenc.h>
+# endif
+
+# ifdef HAVE_LIBFLAC
+#  include <FLAC/metadata.h>
+#  include <FLAC/stream_encoder.h>
+# endif
+
+Edje_Sound_Encode *
+_edje_multisense_encode(const char *filename, Edje_Sound_Sample *sample, double quality)
+{
+   SF_INFO sfinfo;
+   SNDFILE* sfile;
+   Edje_Sound_Encode *enc_info;
+   
+   enc_info = calloc(1, sizeof(Edje_Sound_Encode));
+   if (!enc_info)
+     {
+        ERR("Error. while allocating memory to load file ");
+        exit(-1);
+     }
+   memset (&sfinfo, 0, sizeof (SF_INFO));
+   
+   enc_info->encoded = EINA_FALSE;
+   enc_info->comp_type = "RAW PCM";
+   
+   // Open wav file using sndfile
+   sfile = sf_open (filename, SFM_READ, &sfinfo);
+   if (!sfile)
+     {
+        ERR("Error. Unable to open audio file : %s", filename);
+        exit(-1);
+     }
+
+   if (!sf_format_check(&sfinfo))
+     {
+        ERR("Error. Unknown file, not a valid audio file");
+        exit(-1);
+     }
+
+   if (sample->compression == EDJE_SOUND_SOURCE_TYPE_INLINE_COMP)
+     {
+        sf_close(sfile);
+#ifdef HAVE_LIBFLAC
+        //encode provided wav file to flac
+        enc_info->file = _edje_multisense_encode_to_flac((char *)filename, sfinfo);
+        if (enc_info->file)
+          {
+             enc_info->comp_type = "FLAC";
+             enc_info->encoded = EINA_TRUE;
+          }
+#else
+        WRN("WARNING: Unable to encode sound %s to FLAC compression",
+            sample->name);
+#endif
+     }
+   else if (sample->compression == EDJE_SOUND_SOURCE_TYPE_INLINE_LOSSY)
+     {
+        sf_close(sfile);
+#ifdef HAVE_VORBIS
+        //encode provided wav file to ogg-vorbis
+        enc_info->file = _edje_multisense_encode_to_ogg_vorbis((char *)filename,
+                                                               quality, sfinfo);
+        if (enc_info->file)
+          {
+             enc_info->comp_type = "OGG-VORBIS";
+             enc_info->encoded = EINA_TRUE;
+          }
+#else
+        WRN("WARNING: Unable to encode sound %s to Ogg-Vorbis",
+            sample->name);
+#endif
+     }
+   else
+     eina_stringshare_replace(&enc_info->file, filename);
+   return enc_info;
+}
+
+#ifdef HAVE_LIBFLAC
+const char*
+_edje_multisense_encode_to_flac(char *snd_path, SF_INFO sfinfo)
+{
+   unsigned total_samples = 0; /* can use a 32-bit number due to WAVE size limitations */
+   FLAC__bool ok = 1;
+   FLAC__StreamEncoder *encoder = 0;
+   FLAC__StreamEncoderInitStatus init_status;
+   FLAC__StreamMetadata *metadata[2];
+   FLAC__StreamMetadata_VorbisComment_Entry entry;
+   SNDFILE *sfile;
+   sf_count_t size;
+   char *tmp;
+
+   sfile = sf_open(snd_path, SFM_READ, &sfinfo);
+   if (!sfile) return NULL;
+   if (!sf_format_check(&sfinfo))
+     {
+        sf_close(sfile);
+        return NULL;
+     }
+   size = sf_seek(sfile, 0, SEEK_END);
+   sf_seek(sfile, 0, SEEK_SET);
+   tmp = malloc(strlen(snd_path) + 1 + 5);
+   if (!tmp)
+     {
+        sf_close(sfile);
+        return NULL;
+     }
+   strcpy(tmp, snd_path);
+   snd_path = tmp;
+   strcat(snd_path, ".flac");
+
+   total_samples = size;
+
+   /* allocate the encoder */
+   if ((encoder = FLAC__stream_encoder_new()) == NULL)
+     {
+        ERR("ERROR: Creating FLAC encoder\n");
+        free(snd_path);
+        sf_close(sfile);
+        return NULL;
+     }
+
+   /* Verify it's own encoded output. This will slow the encoding process. */
+   ok &= FLAC__stream_encoder_set_verify(encoder, 1);
+
+   //Levels range from 0 (fastest, least compression) to 8 (slowest, most compression).
+   //A value larger than 8 will be treated as 8.
+   //5 is used for good compression and moderate compression/decompression speed.
+   ok &= FLAC__stream_encoder_set_compression_level(encoder, 5);
+   ok &= FLAC__stream_encoder_set_channels(encoder, sfinfo.channels);
+   ok &= FLAC__stream_encoder_set_bits_per_sample(encoder, 16);
+   ok &= FLAC__stream_encoder_set_sample_rate(encoder, sfinfo.samplerate);
+   ok &= FLAC__stream_encoder_set_total_samples_estimate(encoder, total_samples);
+
+   /* now add some metadata; we'll add some tags and a padding block */
+   if (ok)
+     {
+        if ((metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL
+            || (metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL
+            || !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "Encoder", "flac")
+            || !FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, 0))
+          {
+             ERR("ERROR: out of memory error or tag error\n");
+             ok = 0;
+          }
+        metadata[1]->length = 16; /* set the padding length */
+        ok = FLAC__stream_encoder_set_metadata(encoder, metadata, 2);
+     }
+
+   /* initialize encoder */
+   if (ok)
+     {
+        init_status = FLAC__stream_encoder_init_file(encoder, snd_path, NULL,
+                                                     (void *)(total_samples));
+        if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
+          {
+             ERR("ERROR: unable to initialize FLAC encoder: %s\n",
+                 FLAC__StreamEncoderInitStatusString[init_status]);
+             ok = 0;
+          }
+     }
+   
+   /* read blocks of samples from WAVE file and feed to encoder */
+   while (ok)
+     {
+        FLAC__int32 readbuffer[READBUF * 2];
+        sf_count_t count;
+        int i;
+        
+        count = sf_readf_int(sfile, readbuffer, READBUF);
+        if (count <= 0) break;
+        for (i = 0; i < (count * sfinfo.channels); i++)
+          readbuffer[i] = readbuffer[i] >> 16;
+        ok = FLAC__stream_encoder_process_interleaved(encoder, readbuffer,
+                                                      count);
+     }
+
+   FLAC__stream_encoder_finish(encoder);
+   /* now that encoding is finished, the metadata can be freed */
+   FLAC__metadata_object_delete(metadata[0]);
+   FLAC__metadata_object_delete(metadata[1]);
+
+   FLAC__stream_encoder_delete(encoder);
+   sf_close(sfile);
+   return (snd_path);
+}
+#endif
+
+#ifdef HAVE_VORBIS
+const char *
+_edje_multisense_encode_to_ogg_vorbis(char *snd_path, double quality, SF_INFO sfinfo)
+{
+   ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */
+   ogg_page og; /* one Ogg bitstream page.  Vorbis packets are inside */
+   ogg_packet op; /* one raw packet of data for decode */
+   vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */
+   vorbis_comment vc; /* struct that stores all the user comments */
+   vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
+   vorbis_block vb; /* local working space for packet->PCM decode */
+   int eos = 0, ret;
+   char *tmp;
+   SNDFILE *sfile;
+   FILE *fout;
+
+   sfile = sf_open(snd_path, SFM_READ, &sfinfo);
+   if (!sfile) return NULL;
+   if (!sf_format_check(&sfinfo))
+     {
+        sf_close(sfile);
+        return NULL;
+     }
+   tmp = malloc(strlen(snd_path) + 1 + 4);
+   if (!tmp)
+     {
+        sf_close(sfile);
+        return NULL;
+     }
+   strcpy(tmp, snd_path);
+   snd_path = tmp;
+   strcat(snd_path, ".ogg");
+   fout = fopen(snd_path, "wb");
+   if (!fout)
+     {
+        free(snd_path);
+        sf_close(sfile);
+        return NULL;
+     }
+
+   /********** Encode setup ************/
+   vorbis_info_init(&vi);
+   ret = vorbis_encode_init(&vi, sfinfo.channels, sfinfo.samplerate, 
+                            -1, (long)(quality * 1000), -1);
+   if (ret == OV_EFAULT) printf("OV_EFAULT\n");
+   if (ret == OV_EINVAL) printf("OV_EINVAL\n");
+   if (ret == OV_EIMPL) printf("OV_EIMPL\n");
+
+   if (ret)
+     {
+        fclose(fout);
+        free(snd_path);
+        sf_close(sfile);
+        return NULL;
+     }
+
+   /* add a comment */
+   vorbis_comment_init(&vc);
+   vorbis_comment_add_tag(&vc, "", "");
+
+   /* set up the analysis state and auxiliary encoding storage */
+   vorbis_analysis_init(&vd, &vi);
+   vorbis_block_init(&vd, &vb);
+
+   srand(time(NULL));
+   ogg_stream_init(&os, rand());
+
+   ogg_packet header;
+   ogg_packet header_comm;
+   ogg_packet header_code;
+
+   vorbis_analysis_headerout(&vd, &vc, &header, &header_comm, &header_code);
+   ogg_stream_packetin(&os, &header); /* automatically placed in its own page */
+   ogg_stream_packetin(&os, &header_comm);
+   ogg_stream_packetin(&os, &header_code);
+
+   while (!eos)
+     {
+        int result = ogg_stream_flush(&os, &og);
+        if (!result) break;
+        fwrite(og.header, 1, og.header_len, fout);
+        fwrite(og.body, 1, og.body_len, fout);
+     }
+
+   while (!eos)
+     {
+        int i, ch;
+        float readbuffer[READBUF * 2];
+        sf_count_t count;
+        
+        count = sf_readf_float(sfile, readbuffer, READBUF);
+
+        if (!count)
+          vorbis_analysis_wrote(&vd, 0);
+        else
+          {
+             float **buffer = vorbis_analysis_buffer(&vd, count);
+             
+             /* uninterleave samples */
+             for (i = 0; i < count; i++)
+               {
+                  for (ch = 0; ch < sfinfo.channels; ch++)
+                    buffer[ch][i]= readbuffer[(i * sfinfo.channels) + ch];
+               }
+             vorbis_analysis_wrote(&vd, i);
+          }
+        while (vorbis_analysis_blockout(&vd, &vb) == 1)
+          {
+             vorbis_analysis(&vb, NULL);
+             vorbis_bitrate_addblock(&vb);
+
+             while (vorbis_bitrate_flushpacket(&vd, &op))
+               {
+                  ogg_stream_packetin(&os, &op);
+                  while (!eos)
+                    {
+                       int result = ogg_stream_pageout(&os, &og);
+                       if (!result) break;
+                       fwrite(og.header, 1, og.header_len, fout);
+                       fwrite(og.body, 1, og.body_len, fout);
+                       if (ogg_page_eos(&og)) eos = 1;
+                    }
+               }
+          }
+     }
+   ogg_stream_clear(&os);
+   vorbis_block_clear(&vb);
+   vorbis_dsp_clear(&vd);
+   vorbis_comment_clear(&vc);
+   vorbis_info_clear(&vi);
+   sf_close(sfile);
+   fclose (fout);
+   return snd_path;
+}
+#endif
+#endif
diff --git a/src/bin/edje_multisense_convert.h b/src/bin/edje_multisense_convert.h
new file mode 100644 (file)
index 0000000..05ee2f7
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef EDJE_SND_CONVERT_H__
+# define EDJE_SND_CONVERT_H__
+#include "edje_private.h"
+
+#ifdef HAVE_LIBSNDFILE
+#include <sndfile.h>
+
+#define SF_CONTAINER(x)    ((x) & SF_FORMAT_TYPEMASK)
+#define SF_CODEC(x)        ((x) & SF_FORMAT_SUBMASK)
+
+typedef struct _Edje_Sound_Encode  Edje_Sound_Encode;
+
+struct _Edje_Sound_Encode /*Encoding information*/
+{
+   const char *file; /* the encode sound file path */
+   Eina_Bool encoded; /* True if encoding is successful else False */
+   char *comp_type; /* either LOSSLESS (FLAC) or LOSSY (Ogg/Vorbis) Compression */
+};
+
+Edje_Sound_Encode *_edje_multisense_encode(const char* filename, Edje_Sound_Sample *sample, double quality);
+const char *_edje_multisense_encode_to_flac(char *snd_path, SF_INFO sfinfo);
+const char *_edje_multisense_encode_to_ogg_vorbis(char *snd_path, double quality, SF_INFO sfinfo);
+
+#endif
+#endif
index fc13c5b..5868c1e 100644 (file)
@@ -1,7 +1,10 @@
 MAINTAINERCLEANFILES = Makefile.in
 
 pkglibdir = $(datadir)/$(PACKAGE)/examples
-
+if ENABLE_MULTISENSE
+MULTISENSE_EDC_FILE = multisense.edc
+SND_DIR = -sd $(srcdir)
+endif
 #put here all EDCs one needs to the examples
 EDCS = basic.edc \
        swallow.edc \
@@ -12,7 +15,8 @@ EDCS = basic.edc \
        signals-messages.edc \
        color-class.edc \
        perspective.edc \
-       animations.edc
+       animations.edc \
+       $(MULTISENSE_EDC_FILE)
 
 filesdir = $(datadir)/$(PACKAGE)/examples
 files_DATA =
@@ -49,7 +53,7 @@ pkglib_PROGRAMS += \
 LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_LIBS@
 
 .edc.edj:
-       $(edje_cc) -v -id $(srcdir) $< $(builddir)/$(@F)
+       $(edje_cc) -v -id $(srcdir) $(SND_DIR) $< $(builddir)/$(@F)
 
 EDJS = $(EDCS:%.edc=%.edj)
 
diff --git a/src/examples/multisense.edc b/src/examples/multisense.edc
new file mode 100644 (file)
index 0000000..330896b
--- /dev/null
@@ -0,0 +1,135 @@
+collections {
+   sounds {
+      sample {
+         name: "sound_name1" RAW;
+//         source: "sample.wav";
+//         source: "sample-flac10k.wav";
+         source: "sample-flac10k-mono.wav";
+      }
+      sample {
+         name: "sound_name2" COMP;
+         source: "sample.wav";
+      }
+/*      
+      sample {
+         name: "sound_name3" LOSSY 0.5;
+         source: "sample.wav";
+      }
+      sample {
+         name: "sound_name4" AS_IS;
+         source: "sample.wav";
+      }
+ */
+      sample {
+//         name: "sound_name5" AS_IS;
+//         name: "sound_name5" COMP;
+         name: "sound_name5" RAW;
+//         source: "sample-ogg.wav";
+//         source: "sample-ogg10k.wav";
+         source: "sample-flac10k.wav";
+//         source: "sample-flac10k-mono.wav";
+      }
+      sample {
+         name: "sound_name6" AS_IS;
+//         name: "sound_name6" LOSSY 45.0;
+         source: "sample-flac44k-mono.wav";
+//         source: "sample.ogg";
+      }
+      tone: "tone-name" 2600;
+   }
+   group {
+      name: "example_group";
+      parts {
+         part {
+            name: "sample_bg";
+            type: RECT;
+            mouse_events: 1;
+            description {
+               state: "default" 0.0;
+               min: 300 150;
+               max: 300 150;
+               color: 200 200 200 100;
+               align: 0.5 0.0;
+               rel1 {
+                  relative: 0.0 0.0;
+               }
+            }
+         }
+         part {
+            name: "sample_text";
+            type: TEXT;
+            mouse_events: 1;
+            repeat_events: 1;
+            description {
+               state: "default" 0.0;
+               rel1.to: "sample_bg";
+               rel2.to: "sample_bg";
+               text {
+                  font: "Sans";
+                  size: 20;
+                  text: "Play Sound Sample";
+               }
+            }
+         }
+         part {
+            name: "tone_bg";
+            type: RECT;
+             mouse_events: 1;
+            description {
+               state: "default" 0.0;
+               min: 300 150;
+               max: 300 150;
+               align: 0.5 0.0;
+               color: 180 180 180 100;
+               rel1 {
+                  relative: 0.0 1.0;
+                  to: "sample_bg";
+               }
+            }
+         }
+         part {
+            name: "tone_text";
+            type: TEXT;
+             mouse_events: 1;
+             repeat_events : 1;
+            description {
+               state: "default" 0.0;
+               rel1.to: "tone_bg";
+               rel2.to: "tone_bg";
+               text {
+                  font: "Sans";
+                  size: 20;
+                  text: "Play Tone";
+               }
+            }
+         }
+         programs {
+            program {
+               name: "click_sample1";
+               signal: "mouse,down,1";
+               source: "sample_bg";
+               action: PLAY_SAMPLE "sound_name1" 1.0;
+            }
+            program {
+               name: "click_sample2";
+               signal: "mouse,down,2";
+               source: "sample_bg";
+               action: PLAY_SAMPLE "sound_name5" 1.0;
+            }
+            program {
+               name: "click_sample3";
+               signal: "mouse,down,3";
+               source: "sample_bg";
+               action: PLAY_SAMPLE "sound_name6" 1.0;
+            }
+            program {
+               name: "click_tone";
+               signal: "mouse,down,1";
+               source: "tone_bg";
+               action: PLAY_TONE "tone-name" 0.1;
+            }
+         }
+      }
+   }
+}
+
index ba6706d..1c93873 100644 (file)
@@ -602,20 +602,22 @@ typedef enum _Edje_Text_Effect
 
 typedef enum _Edje_Action_Type
 {
-   EDJE_ACTION_TYPE_NONE          = 0,
-   EDJE_ACTION_TYPE_STATE_SET     = 1,
-   EDJE_ACTION_TYPE_ACTION_STOP   = 2,
-   EDJE_ACTION_TYPE_SIGNAL_EMIT   = 3,
-   EDJE_ACTION_TYPE_DRAG_VAL_SET  = 4,
-   EDJE_ACTION_TYPE_DRAG_VAL_STEP = 5,
-   EDJE_ACTION_TYPE_DRAG_VAL_PAGE = 6,
-   EDJE_ACTION_TYPE_SCRIPT        = 7,
-   EDJE_ACTION_TYPE_FOCUS_SET     = 8,
-   EDJE_ACTION_TYPE_RESERVED00    = 9,
-   EDJE_ACTION_TYPE_FOCUS_OBJECT  = 10,
-   EDJE_ACTION_TYPE_PARAM_COPY    = 11,
-   EDJE_ACTION_TYPE_PARAM_SET     = 12,
-   EDJE_ACTION_TYPE_LAST          = 13
+   EDJE_ACTION_TYPE_NONE                = 0,
+   EDJE_ACTION_TYPE_STATE_SET           = 1,
+   EDJE_ACTION_TYPE_ACTION_STOP         = 2,
+   EDJE_ACTION_TYPE_SIGNAL_EMIT         = 3,
+   EDJE_ACTION_TYPE_DRAG_VAL_SET        = 4,
+   EDJE_ACTION_TYPE_DRAG_VAL_STEP       = 5,
+   EDJE_ACTION_TYPE_DRAG_VAL_PAGE       = 6,
+   EDJE_ACTION_TYPE_SCRIPT              = 7,
+   EDJE_ACTION_TYPE_FOCUS_SET           = 8,
+   EDJE_ACTION_TYPE_RESERVED00          = 9,
+   EDJE_ACTION_TYPE_FOCUS_OBJECT        = 10,
+   EDJE_ACTION_TYPE_PARAM_COPY          = 11,
+   EDJE_ACTION_TYPE_PARAM_SET           = 12,
+   EDJE_ACTION_TYPE_SOUND_SAMPLE        = 13,
+   EDJE_ACTION_TYPE_SOUND_TONE          = 14,
+   EDJE_ACTION_TYPE_LAST                = 15
 } Edje_Action_Type;
 
 typedef enum _Edje_Tween_Mode
@@ -3798,7 +3800,7 @@ EAPI const Edje_External_Param_Info *edje_external_param_info_get   (const char
  */
    EAPI const Edje_External_Type       *edje_external_type_get         (const char *type_name);
 
-   EAPI Eina_Bool               edje_module_load                (const char *module);
+   EAPI Eina_Module            *edje_module_load                (const char *module);
    EAPI const Eina_List        *edje_available_modules_get      (void);
 
    /* perspective info for maps inside edje objects */
index cd9674f..884d676 100644 (file)
@@ -12,7 +12,9 @@ AM_CPPFLAGS = \
 @EVIL_CFLAGS@ \
 @EDJE_CFLAGS@ \
 @ECORE_IMF_CFLAGS@ \
-@EFL_EDJE_BUILD@
+@EFL_EDJE_BUILD@ \
+@REMIX_CFLAGS@ \
+@SNDFILE_CFLAGS@ 
 
 lib_LTLIBRARIES = libedje.la
 
@@ -39,6 +41,7 @@ edje_match.c \
 edje_message_queue.c \
 edje_misc.c \
 edje_module.c \
+edje_multisense.c \
 edje_program.c \
 edje_script_only.c \
 edje_smart.c \
@@ -127,7 +130,7 @@ else
 libedje_la_SOURCES = $(base_sources)
 endif
 
-libedje_la_LIBADD = @EDJE_LIBS@ @ECORE_IMF_LIBS@ @EVIL_LIBS@ -lm
+libedje_la_LIBADD = @EDJE_LIBS@ @ECORE_IMF_LIBS@ @EVIL_LIBS@ @REMIX_LIBS@ @SNDFILE_LIBS@ -lm
 libedje_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@
 
 EXTRA_DIST = edje_private.h edje_container.h edje_convert.h
index a9e6197..6b7b395 100644 (file)
@@ -16,6 +16,9 @@ Eet_Data_Descriptor *_edje_edd_edje_image_directory_set = NULL;
 Eet_Data_Descriptor *_edje_edd_edje_image_directory_set_entry = NULL;
 Eet_Data_Descriptor *_edje_edd_edje_limit = NULL;
 Eet_Data_Descriptor *_edje_edd_edje_limit_pointer = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_sound_sample = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_sound_tone = NULL;
+Eet_Data_Descriptor *_edje_edd_edje_sound_directory = NULL;
 Eet_Data_Descriptor *_edje_edd_edje_program = NULL;
 Eet_Data_Descriptor *_edje_edd_edje_program_pointer = NULL;
 Eet_Data_Descriptor *_edje_edd_edje_program_target = NULL;
@@ -169,6 +172,9 @@ _edje_edd_shutdown(void)
    FREED(_edje_edd_edje_image_directory_entry);
    FREED(_edje_edd_edje_limit);
    FREED(_edje_edd_edje_limit_pointer);
+   FREED(_edje_edd_edje_sound_sample);
+   FREED(_edje_edd_edje_sound_tone);
+   FREED(_edje_edd_edje_sound_directory);
    FREED(_edje_edd_edje_program);
    FREED(_edje_edd_edje_program_pointer);
    FREED(_edje_edd_edje_program_target);
@@ -284,6 +290,29 @@ _edje_edd_init(void)
    EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(_edje_edd_edje_image_directory, Edje_Image_Directory, "entries", entries, _edje_edd_edje_image_directory_entry);
    EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(_edje_edd_edje_image_directory, Edje_Image_Directory, "sets", sets, _edje_edd_edje_image_directory_set);
 
+   /* Sound */
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Sound_Sample);
+   _edje_edd_edje_sound_sample =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_sample, Edje_Sound_Sample, "name", name, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_sample, Edje_Sound_Sample, "snd_src", snd_src, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_sample, Edje_Sound_Sample, "compression", compression, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_sample, Edje_Sound_Sample, "mode", mode, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_sample, Edje_Sound_Sample, "quality", quality, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_sample, Edje_Sound_Sample, "id", id, EET_T_INT);
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Sound_Tone);
+   _edje_edd_edje_sound_tone =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_tone, Edje_Sound_Tone, "name", name, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_tone, Edje_Sound_Tone, "value", value, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_tone, Edje_Sound_Tone, "id", id, EET_T_INT);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Sound_Directory);
+   _edje_edd_edje_sound_directory =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(_edje_edd_edje_sound_directory, Edje_Sound_Directory, "samples", samples, _edje_edd_edje_sound_sample);
+   EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(_edje_edd_edje_sound_directory, Edje_Sound_Directory, "tones", tones, _edje_edd_edje_sound_tone);
+
    /* collection directory */
    EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Part_Collection_Directory_Entry);
    _edje_edd_edje_part_collection_directory_entry =
@@ -341,6 +370,7 @@ _edje_edd_init(void)
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_file, Edje_File, "feature_ver", feature_ver, EET_T_INT);
    EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_file, Edje_File, "external_dir", external_dir, _edje_edd_edje_external_directory);
    EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_file, Edje_File, "image_dir", image_dir, _edje_edd_edje_image_directory);
+   EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_file, Edje_File, "sound_dir", sound_dir, _edje_edd_edje_sound_directory);
    EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_file, Edje_File, "styles", styles, _edje_edd_edje_style);
    EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_file, Edje_File, "color_classes", color_classes, _edje_edd_edje_color_class);
    EET_DATA_DESCRIPTOR_ADD_HASH(_edje_edd_edje_file, Edje_File, "data", data, _edje_edd_edje_string);
@@ -376,6 +406,11 @@ _edje_edd_init(void)
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "in.from", in.from, EET_T_DOUBLE);
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "in.range", in.range, EET_T_DOUBLE);
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "action", action, EET_T_INT);
+
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "sample_name", sample_name, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "tone_name", tone_name, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program ,"duration", duration, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program ,"speed", speed, EET_T_DOUBLE);
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "state", state, EET_T_STRING);
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "state2", state2, EET_T_STRING);
    EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "value", value, EET_T_DOUBLE);
index 7575cca..378a1fb 100644 (file)
@@ -72,6 +72,8 @@
  * set_state(part_id, state[], Float:state_val)
  * get_state(part_id, dst[], maxlen, &Float:val)
  * set_tween_state(part_id, Float:tween, state1[], Float:state1_val, state2[], Float:state2_val)
+ * play_sample(sample_name, speed)
+ * play_tone(tone_name, duration)
  * run_program(program_id)
  * Direction:get_drag_dir(part_id)
  * get_drag(part_id, &Float:dx, &Float:&dy)
@@ -824,6 +826,38 @@ _edje_embryo_fn_get_part_id(Embryo_Program *ep, Embryo_Cell *params)
    return -1;
 }
 
+static Embryo_Cell
+_edje_embryo_fn_play_sample(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   char *sample_name = NULL;
+   float speed = 1.0;
+
+   CHKPARAM(1);
+   ed = embryo_program_data_get(ep);
+   GETSTR(sample_name, params[1]);
+   if ((!sample_name)) return 0;
+   speed = EMBRYO_CELL_TO_FLOAT(params[2]);
+   _edje_multisense_internal_sound_sample_play(ed, sample_name, (double)speed);
+   return 0;
+}
+
+static Embryo_Cell
+_edje_embryo_fn_play_tone(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   char *tone_name = NULL;
+   float duration = 0.1;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+   GETSTR(tone_name, params[1]);
+   if ((!tone_name)) return 0;
+   duration = EMBRYO_CELL_TO_FLOAT(params[2]);
+   _edje_multisense_internal_sound_tone_play(ed, tone_name, (double) duration);
+   return 0;
+}
+
 /* set_state(part_id, state[], Float:state_val) */
 static Embryo_Cell
 _edje_embryo_fn_set_state(Embryo_Program *ep, Embryo_Cell *params)
@@ -3006,7 +3040,8 @@ _edje_embryo_script_init(Edje_Part_Collection *edc)
    embryo_program_native_call_add(ep, "stop_programs_on", _edje_embryo_fn_stop_programs_on);
    embryo_program_native_call_add(ep, "set_min_size", _edje_embryo_fn_set_min_size);
    embryo_program_native_call_add(ep, "set_max_size", _edje_embryo_fn_set_max_size);
-
+   embryo_program_native_call_add(ep, "play_sample", _edje_embryo_fn_play_sample);
+   embryo_program_native_call_add(ep, "play_tone", _edje_embryo_fn_play_tone);
    embryo_program_native_call_add(ep, "send_message", _edje_embryo_fn_send_message);
    embryo_program_native_call_add(ep, "get_geometry", _edje_embryo_fn_get_geometry);
    embryo_program_native_call_add(ep, "custom_state", _edje_embryo_fn_custom_state);
index e539168..a5cdad5 100644 (file)
@@ -1094,6 +1094,25 @@ _edje_file_free(Edje_File *edf)
        free(edf->image_dir->sets);
        free(edf->image_dir);
      }
+   if (edf->sound_dir)
+     {
+        unsigned int i;
+
+        if (edf->free_strings)
+          {
+             for (i = 0; i < edf->sound_dir->samples_count; ++i)
+               {
+                  eina_stringshare_del(edf->sound_dir->samples[i].name);
+                  eina_stringshare_del(edf->sound_dir->samples[i].snd_src);
+               }
+
+             for (i = 0; i < edf->sound_dir->tones_count; ++i)
+               eina_stringshare_del(edf->sound_dir->tones[i].name);
+          }
+        free(edf->sound_dir->samples);
+        free(edf->sound_dir->tones);
+        free(edf->sound_dir);
+     }
 
    if (edf->external_dir)
      {
@@ -1130,6 +1149,8 @@ _edje_program_free(Edje_Program *pr, Eina_Bool free_strings)
        if (pr->filter.state) eina_stringshare_del(pr->filter.state);
        if (pr->state) eina_stringshare_del(pr->state);
        if (pr->state2) eina_stringshare_del(pr->state2);
+   if (pr->sample_name) eina_stringshare_del(pr->sample_name);
+   if (pr->tone_name) eina_stringshare_del(pr->tone_name);
      }
    EINA_LIST_FREE(pr->targets, prt)
      free(prt);
index 5cc7b98..cf443c7 100644 (file)
@@ -61,6 +61,7 @@ edje_init(void)
    _edje_external_init();
    _edje_module_init();
    _edje_message_init();
+   _edje_multisense_init();
 
    _edje_real_part_mp = eina_mempool_add("chained_mempool",
                                         "Edje_Real_Part", NULL,
@@ -123,6 +124,7 @@ _edje_shutdown_core(void)
    _edje_real_part_state_mp = NULL;
    _edje_real_part_mp = NULL;
 
+   _edje_multisense_shutdown();
    _edje_message_shutdown();
    _edje_module_shutdown();
    _edje_external_shutdown();
index 0d29b36..e84cb97 100644 (file)
@@ -14,41 +14,40 @@ Eina_List *_modules_found = NULL;
 # define EDJE_MODULE_NAME "module.so"
 #endif
 
-EAPI Eina_Bool
+EAPI Eina_Module *
 edje_module_load(const char *module)
 {
    const char *path;
    Eina_List *l;
+   Eina_Module *em = NULL;
 
-   EINA_SAFETY_ON_NULL_RETURN_VAL(module, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(module, NULL);
 
-   if (eina_hash_find(_registered_modules, module))
-     return EINA_TRUE;
+   em =  (Eina_Module *)eina_hash_find(_registered_modules, module);
+   if (em) return em;
 
    EINA_LIST_FOREACH(_modules_paths, l, path)
      {
-       Eina_Module *em;
-       char tmp[PATH_MAX];
+        char tmp[PATH_MAX];
 
-       snprintf(tmp, sizeof (tmp), "%s/%s/%s/" EDJE_MODULE_NAME, path, module, MODULE_ARCH
+        snprintf(tmp, sizeof (tmp), "%s/%s/%s/" EDJE_MODULE_NAME, path, module, MODULE_ARCH
 #ifdef EDJE_EXTRA_MODULE_NAME
                  , module
 #endif
                 );
-       em = eina_module_new(tmp);
-       if (!em) continue ;
-
-       if (!eina_module_load(em))
-         {
-            eina_module_free(em);
-            continue ;
-         }
-
-       return !!eina_hash_add(_registered_modules, module, em);
+        em = eina_module_new(tmp);
+        if (!em) continue;
+
+        if (!eina_module_load(em))
+          {
+             eina_module_free(em);
+             continue;
+          }
+        if (eina_hash_add(_registered_modules, module, em))
+          return em;
      }
 
-   ERR("Could not find the module %s", module);
-   return EINA_FALSE;
+   return NULL;
 }
 
 void
diff --git a/src/lib/edje_multisense.c b/src/lib/edje_multisense.c
new file mode 100644 (file)
index 0000000..3f0044a
--- /dev/null
@@ -0,0 +1,382 @@
+#include "config.h"
+#include <string.h>
+#include <fcntl.h>
+#include <Eina.h>
+#include <Edje.h>
+#include "edje_private.h"
+
+typedef struct _Multisense_Data
+{
+   Edje_Multisense_Env *msenv;
+#ifdef HAVE_LIBREMIX
+   RemixDeck *deck;
+   RemixTrack *track;
+   RemixLayer *snd_layer, *player_layer;
+   RemixBase *player;
+   RemixBase *player_snd;
+   int remaining;
+   int offset;
+   Eina_List *snd_src_list;
+
+   MULTISENSE_SOUND_PLAYER_GET_FUNC multisense_sound_player_get;
+#endif
+}Multisense_Data;
+
+#define BUF_LEN 64
+#define SND_PROCESS_LENGTH 2048
+
+static Ecore_Thread *player_thread = NULL;
+static Eina_Bool pipe_initialized = EINA_FALSE;
+static int command_pipe[2];
+
+typedef enum _Edje_Sound_Action_Type
+{
+   EDJE_PLAY_SAMPLE = 0,
+   EDJE_PLAY_TONE,
+   /*
+   EDJE_PLAY_PATTERN,
+   EDJE_PLAY_INSTRUMENT,
+   EDJE_PLAY_SONG,
+   */
+   EDJE_SOUND_LAST
+} Edje_Sound_Action_Type;
+
+typedef struct _Edje_Sample_Action Edje_Sample_Action;
+typedef struct _Edje_Tone_Action Edje_Tone_Action;
+typedef struct _Edje_Multisense_Sound_Action Edje_Multisense_Sound_Action;
+
+struct _Edje_Sample_Action
+{
+   char sample_name[BUF_LEN];
+   double speed;
+};
+
+struct _Edje_Tone_Action
+{
+   char tone_name[BUF_LEN];
+   double duration;
+};
+
+struct _Edje_Multisense_Sound_Action
+{
+   Edje *ed;
+   Edje_Sound_Action_Type action;
+   union {
+      Edje_Sample_Action sample;
+      Edje_Tone_Action tone;
+   } type;
+};
+
+static Multisense_Data *
+init_multisense_environment(void)
+{
+   Multisense_Data *msdata;
+   char ms_factory[BUF_LEN];
+   char *ms_factory_env;
+   Eina_Module *m = NULL;
+   MULTISENSE_FACTORY_INIT_FUNC multisense_factory_init;
+
+   msdata = calloc(1, sizeof(Multisense_Data));
+   if (!msdata) goto err;
+
+   msdata->msenv = calloc(1, sizeof(Edje_Multisense_Env));
+   if (!msdata->msenv) goto err;
+
+   ms_factory_env = getenv("MULTISENSE_FACTORY");
+   if (ms_factory_env)
+     strncpy(ms_factory, ms_factory_env, BUF_LEN);
+   else
+     strcpy(ms_factory, "multisense_factory");
+   
+   m = edje_module_load(ms_factory);
+   if (!m) goto err;
+   
+#ifdef HAVE_LIBREMIX
+   msdata->msenv->remixenv = remix_init();
+#endif
+
+   multisense_factory_init = 
+     eina_module_symbol_get(m, "multisense_factory_init");
+   if (multisense_factory_init) multisense_factory_init(msdata->msenv);
+
+#ifdef HAVE_LIBREMIX
+   msdata->multisense_sound_player_get = 
+     eina_module_symbol_get(m, "multisense_sound_player_get");
+   if (!msdata->multisense_sound_player_get) goto err;
+
+   msdata->deck = remix_deck_new(msdata->msenv->remixenv);
+   msdata->track = remix_track_new(msdata->msenv->remixenv, msdata->deck);
+   msdata->snd_layer = remix_layer_new_ontop(msdata->msenv->remixenv,
+                                             msdata->track,
+                                             REMIX_TIME_SAMPLES);
+   msdata->player_layer = remix_layer_new_ontop(msdata->msenv->remixenv,
+                                                msdata->track,
+                                                REMIX_TIME_SAMPLES);
+   msdata->player = msdata->multisense_sound_player_get(msdata->msenv);
+   if (!msdata->player) goto err;
+   msdata->player_snd = remix_sound_new(msdata->msenv->remixenv,
+                                        msdata->player, msdata->player_layer,
+                                        REMIX_SAMPLES(0),
+                                        REMIX_SAMPLES(REMIX_COUNT_INFINITE));
+#endif
+   return msdata;
+
+err:
+   if (msdata)
+     {
+#ifdef HAVE_LIBREMIX
+        if (msdata->deck) remix_destroy(msdata->msenv->remixenv, msdata->deck);
+        if (msdata->msenv->remixenv) remix_purge(msdata->msenv->remixenv);
+#endif
+        if (msdata->msenv) free(msdata->msenv);
+        free(msdata);
+     }
+   return NULL;
+}
+
+#ifdef HAVE_LIBREMIX
+static RemixBase *
+eet_sound_reader_get(Edje_Multisense_Env *msenv, const char *path, const char *sound_id, const double speed)
+{
+   RemixPlugin *sf_plugin = NULL;
+   RemixBase * eet_snd_reader = NULL;
+   int sf_path_key = 0;
+   int sf_sound_id_key = 0;
+   int sf_speed_key = 0;
+   CDSet *sf_parms = NULL;
+   RemixEnv *env = msenv->remixenv;
+
+   if (sf_plugin == NULL)
+     {
+        sf_plugin = remix_find_plugin(env, "eet_sndfile_reader");
+        if (sf_plugin == NULL)
+          {
+             ERR ("Multisense EET Sound reader plugin NULL\n");
+             return NULL;
+          }
+        
+        sf_path_key = remix_get_init_parameter_key(env, sf_plugin, "path");
+        sf_sound_id_key = remix_get_init_parameter_key(env, sf_plugin, "sound_id");
+        sf_speed_key = remix_get_init_parameter_key(env, sf_plugin, "speed");
+     }
+   sf_parms = cd_set_replace(env, sf_parms, sf_path_key, CD_STRING(path));
+   sf_parms = cd_set_replace(env, sf_parms, sf_sound_id_key, CD_STRING(sound_id));
+   sf_parms = cd_set_replace(env, sf_parms, sf_speed_key, CD_DOUBLE(speed));
+   eet_snd_reader = remix_new(env, sf_plugin, sf_parms);
+   
+   return eet_snd_reader;
+}
+
+
+static RemixBase *
+edje_remix_sample_create(Multisense_Data *msdata, Edje*ed, Edje_Sample_Action *action)
+{
+   RemixBase *remix_snd = NULL;
+   Edje_Sound_Sample *sample;
+   int i;
+   char snd_id_str[16];
+
+   if ((!ed) || (!ed->file) || (!ed->file->sound_dir))
+     return NULL;
+
+   for (i = 0; i < (int)ed->file->sound_dir->samples_count; i++)
+     {
+        sample = &ed->file->sound_dir->samples[i];
+        if (!strcmp(sample->name, action->sample_name))
+          {
+             snprintf(snd_id_str, sizeof(snd_id_str), "edje/sounds/%i", sample->id);
+             remix_snd = eet_sound_reader_get(msdata->msenv, ed->file->path,
+                                              snd_id_str, action->speed);
+             break;
+          }
+     }
+   return remix_snd;
+}
+
+static RemixBase *
+edje_remix_tone_create(Multisense_Data *msdata, Edje*ed, Edje_Tone_Action *action)
+{
+   Edje_Sound_Tone *tone;
+   RemixSquareTone *square;
+   unsigned int i;
+
+   if ((!ed) || (!ed->file) || (!ed->file->sound_dir))
+     return NULL;
+   
+   for (i = 0; i < ed->file->sound_dir->tones_count; i++)
+     {
+        tone = &ed->file->sound_dir->tones[i];
+        if (!strcmp(tone->name, action->tone_name))
+          {
+             square = remix_squaretone_new (msdata->msenv->remixenv, tone->value);
+             break;
+          }
+     }
+   return square;
+}
+
+static void
+sound_command_handler(Multisense_Data *msdata)
+{
+   RemixCount length;
+   Edje_Multisense_Sound_Action command;
+   RemixBase *base = NULL;
+   RemixBase *sound;
+   
+   if (read(command_pipe[0], &command, sizeof(command)) <= 0) return;
+   switch (command.action)
+     {
+      case EDJE_PLAY_SAMPLE:
+        base = edje_remix_sample_create(msdata, command.ed,
+                                        &command.type.sample);
+        length = remix_length(msdata->msenv->remixenv, base);
+        break;
+      case EDJE_PLAY_TONE:
+        base = edje_remix_tone_create(msdata, command.ed, &command.type.tone);
+        length = (command.type.tone.duration *
+                              remix_get_samplerate(msdata->msenv->remixenv));
+        break;
+      default:
+        ERR("Invalid Sound Play Command\n");
+        break;
+     }
+   if (base)
+     {
+        sound = remix_sound_new(msdata->msenv->remixenv, base, msdata->snd_layer,
+                                REMIX_SAMPLES(msdata->offset),
+                                REMIX_SAMPLES(length));
+        if (msdata->remaining < length) msdata->remaining = length;
+        msdata->snd_src_list = eina_list_append(msdata->snd_src_list, sound);
+        msdata->snd_src_list = eina_list_append(msdata->snd_src_list, base);
+     }
+}
+#endif
+
+static void
+_player_job(void *data __UNUSED__, Ecore_Thread *th)
+{
+   fd_set wait_fds;
+#ifdef HAVE_LIBREMIX
+   RemixBase *sound;
+   RemixCount process_len;
+#endif
+   Multisense_Data *msdata = init_multisense_environment();
+   if (!msdata) return;
+
+   fcntl(command_pipe[0], F_SETFL, O_NONBLOCK);
+   FD_ZERO(&wait_fds);
+   FD_SET(command_pipe[0], &wait_fds);
+
+#ifdef HAVE_LIBREMIX
+   while (!ecore_thread_check(th))
+     {
+        if (!msdata->remaining)
+          {
+             //Cleanup already played sound sources
+             EINA_LIST_FREE(msdata->snd_src_list, sound)
+               {
+                  remix_destroy(msdata->msenv->remixenv, sound);
+               }
+             //wait for new sound
+             select(command_pipe[0] + 1, &wait_fds, NULL, NULL, 0);
+          }
+        //read sound command , if any
+        sound_command_handler(msdata);
+        process_len = MIN(msdata->remaining, SND_PROCESS_LENGTH);
+        remix_process(msdata->msenv->remixenv, msdata->deck, process_len,
+                      RemixNone, RemixNone);
+        msdata->offset += process_len;
+        msdata->remaining -= process_len;
+     }
+
+   //Cleanup last played sound sources
+   EINA_LIST_FREE(msdata->snd_src_list, sound)
+     {
+        remix_destroy(msdata->msenv->remixenv, sound);
+     }
+
+   //cleanup Remix stuffs
+   remix_destroy(msdata->msenv->remixenv, msdata->player);
+   remix_destroy(msdata->msenv->remixenv, msdata->deck);
+   remix_purge(msdata->msenv->remixenv);
+#endif
+
+   free(msdata->msenv);
+   free(msdata);
+   close(command_pipe[0]);
+   close(command_pipe[1]);
+}
+
+static void
+_player_cancel(void *data __UNUSED__, Ecore_Thread *th __UNUSED__)
+{
+   player_thread = NULL;
+}
+
+static void
+_player_end(void *data __UNUSED__, Ecore_Thread *th __UNUSED__)
+{
+   player_thread = NULL;
+}
+
+Eina_Bool
+_edje_multisense_internal_sound_sample_play(Edje *ed, const char *sample_name, const double speed)
+{
+   ssize_t size = 0;
+#ifdef ENABLE_MULTISENSE
+   Edje_Multisense_Sound_Action command;
+   
+   if ((!pipe_initialized) && (!player_thread)) return EINA_FALSE;
+
+   command.action = EDJE_PLAY_SAMPLE;
+   command.ed = ed;
+   strncpy(command.type.sample.sample_name, sample_name, BUF_LEN);
+   command.type.sample.speed = speed;
+   size = write(command_pipe[1], &command, sizeof(command));
+#endif
+   return (size == sizeof(Edje_Multisense_Sound_Action));
+}
+
+Eina_Bool
+_edje_multisense_internal_sound_tone_play(Edje *ed, const char *tone_name, const double duration)
+{
+   ssize_t size = 0;
+#ifdef ENABLE_MULTISENSE
+   Edje_Multisense_Sound_Action command;
+   
+   if ((!pipe_initialized) && (!player_thread)) return EINA_FALSE;
+   command.action = EDJE_PLAY_TONE;
+   command.ed = ed;
+   strncpy(command.type.tone.tone_name, tone_name, BUF_LEN);
+   command.type.tone.duration = duration;
+   size = write(command_pipe[1], &command, sizeof(command));
+#endif
+   return (size == sizeof(Edje_Multisense_Sound_Action));
+
+}
+
+/* Initialize the modules in main thread. to avoid dlopen issue in the Threads */
+void
+_edje_multisense_init(void)
+{
+#ifdef ENABLE_MULTISENSE
+   if (!pipe_initialized && (pipe(command_pipe) != -1))
+     pipe_initialized = EINA_TRUE;
+   
+   if (!player_thread)
+     player_thread = ecore_thread_run(_player_job, _player_end, _player_cancel, NULL);
+#endif
+}
+
+void
+_edje_multisense_shutdown(void)
+{
+#ifdef ENABLE_MULTISENSE
+   if (pipe_initialized)
+     {
+        close(command_pipe[1]);
+        close(command_pipe[0]);
+     }
+   if (player_thread) ecore_thread_cancel(player_thread);
+#endif
+}
index ead0382..0d58900 100644 (file)
@@ -268,6 +268,9 @@ typedef struct _Edje_Image_Directory_Entry           Edje_Image_Directory_Entry;
 typedef struct _Edje_Image_Directory_Set             Edje_Image_Directory_Set;
 typedef struct _Edje_Image_Directory_Set_Entry       Edje_Image_Directory_Set_Entry;
 typedef struct _Edje_Limit                           Edje_Limit;
+typedef struct _Edje_Sound_Sample                    Edje_Sound_Sample;
+typedef struct _Edje_Sound_Tone                      Edje_Sound_Tone;
+typedef struct _Edje_Sound_Directory                 Edje_Sound_Directory;
 typedef struct _Edje_Program                         Edje_Program;
 typedef struct _Edje_Program_Target                  Edje_Program_Target;
 typedef struct _Edje_Program_After                   Edje_Program_After;
@@ -328,6 +331,12 @@ typedef struct _Edje_Text_Insert_Filter_Callback Edje_Text_Insert_Filter_Callbac
 #define EDJE_IMAGE_SOURCE_TYPE_EXTERNAL       3
 #define EDJE_IMAGE_SOURCE_TYPE_LAST           4
 
+#define EDJE_SOUND_SOURCE_TYPE_NONE           0
+#define EDJE_SOUND_SOURCE_TYPE_INLINE_RAW     1
+#define EDJE_SOUND_SOURCE_TYPE_INLINE_COMP    2
+#define EDJE_SOUND_SOURCE_TYPE_INLINE_LOSSY   3
+#define EDJE_SOUND_SOURCE_TYPE_INLINE_AS_IS   4
+
 #define EDJE_VAR_NONE   0
 #define EDJE_VAR_INT    1
 #define EDJE_VAR_FLOAT  2
@@ -410,6 +419,7 @@ struct _Edje_File
 
    Edje_External_Directory        *external_dir;
    Edje_Image_Directory           *image_dir;
+   Edje_Sound_Directory           *sound_dir;
    Eina_List                      *styles;
    Eina_List                      *color_classes;
 
@@ -517,6 +527,33 @@ struct _Edje_Image_Directory_Set_Entry
    } size;
 };
 
+struct _Edje_Sound_Sample /*Sound Sample*/
+{
+   const char *name; /* the nominal name of the sound */
+   const char *snd_src;  /* Sound source Wav file */
+   int   compression;  /* Compression - RAW, LOSSLESS COMP ,  LOSSY ) */
+   int   mode; /* alternate source mode. 0 = none */
+   double quality;
+   int   id; /* the id no. of the sound */
+};
+
+struct _Edje_Sound_Tone /*Sound Sample*/
+{
+   const char *name; /* the nominal name of the sound - if any */
+   int   value; /* alternate source mode. 0 = none */
+   int   id; /* the id no. of the sound */
+};
+
+struct _Edje_Sound_Directory
+{
+
+   Edje_Sound_Sample *samples;  /* an array of Edje_Sound_Sample entries */
+   unsigned int samples_count;
+
+   Edje_Sound_Tone *tones;  /* an array of Edje_Sound_Tone entries */
+   unsigned int tones_count;
+};
+
 /*----------*/
 
 struct _Edje_Program /* a conditional program to be run */
@@ -526,6 +563,10 @@ struct _Edje_Program /* a conditional program to be run */
 
    const char *signal; /* if signal emission name matches the glob here... */
    const char *source; /* if part that emitted this (name) matches this glob */
+   const char *sample_name;
+   const char *tone_name;
+   double duration;
+   double speed;
 
    struct {
       const char *part;
@@ -1921,4 +1962,28 @@ void _edje_object_orientation_inform(Evas_Object *obj);
 void _edje_lib_ref(void);
 void _edje_lib_unref(void);
 
+void _edje_multisense_init(void);
+void _edje_multisense_shutdown(void);
+Eina_Bool _edje_multisense_internal_sound_sample_play(Edje *ed, const char *sample_name, const double speed);
+Eina_Bool _edje_multisense_internal_sound_tone_play(Edje *ed, const char *tone_name, const double duration);
+
+#ifdef HAVE_LIBREMIX
+#include <remix/remix.h>
+#endif
+#include <Eina.h>
+
+typedef struct _Edje_Multisense_Env  Edje_Multisense_Env;
+
+struct _Edje_Multisense_Env
+{
+#ifdef HAVE_LIBREMIX
+   RemixEnv *remixenv;
+#endif
+};
+
+typedef Eina_Bool (*MULTISENSE_FACTORY_INIT_FUNC) (Edje_Multisense_Env *);
+#ifdef HAVE_LIBREMIX
+typedef RemixBase* (*MULTISENSE_SOUND_PLAYER_GET_FUNC) (Edje_Multisense_Env *);
+#endif
+
 #endif
index 48ff6ef..a0394d3 100644 (file)
@@ -769,6 +769,16 @@ _edje_program_run(Edje *ed, Edje_Program *pr, Eina_Bool force, const char *ssig,
               }
          }
         break;
+     case EDJE_ACTION_TYPE_SOUND_SAMPLE:
+        if (_edje_block_break(ed))
+          goto break_prog;
+        _edje_multisense_internal_sound_sample_play(ed, pr->sample_name, pr->speed);
+        break;
+     case EDJE_ACTION_TYPE_SOUND_TONE:
+        if (_edje_block_break(ed))
+          goto break_prog;
+        _edje_multisense_internal_sound_tone_play(ed, pr->tone_name, pr->duration);
+        break;
      case EDJE_ACTION_TYPE_PARAM_COPY:
           {
              Edje_Real_Part *src_part, *dst_part;
diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am
new file mode 100644 (file)
index 0000000..937a690
--- /dev/null
@@ -0,0 +1,10 @@
+if ENABLE_MULTISENSE\r
+FACTORY_MODULE =  multisense_factory\r
+if HAVE_LIBREMIX\r
+SND_READER_MODULE = eet_snd_reader\r
+if HAVE_LIBALSA\r
+ALSA_MODULE =  alsa_snd_player\r
+endif\r
+endif\r
+endif\r
+SUBDIRS = $(FACTORY_MODULE) $(SND_READER_MODULE) $(ALSA_MODULE)\r
diff --git a/src/modules/alsa_snd_player/Makefile.am b/src/modules/alsa_snd_player/Makefile.am
new file mode 100644 (file)
index 0000000..de015f8
--- /dev/null
@@ -0,0 +1,20 @@
+## Process this file with automake to produce Makefile.in
+
+MAINTAINERCLEANFILES = Makefile.in
+
+pkglibdir = $(REMIX_PLUGIN_DIR)
+
+AM_CPPFLAGS = \
+-I. \
+-DPACKAGE_LIB_DIR=\"$(libdir)/remix\" \
+-DPACKAGE_DATA_DIR=\"$(datadir)/remix\" \
+@EDJE_CFLAGS@ \
+@REMIX_CFLAGS@ \
+@ALSA_CFLAGS@
+
+pkgdir = $(REMIX_PLUGIN_DIR)
+pkg_LTLIBRARIES = libalsa_snd_player.la
+
+libalsa_snd_player_la_SOURCES = alsa_snd_player.c
+libalsa_snd_player_la_LDFLAGS =  -no-undefined @lt_enable_auto_import@ -module -avoid-version @EDJE_LIBS@ @REMIX_LIBS@ @ALSA_LIBS@
+libalsa_snd_player_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/src/modules/alsa_snd_player/alsa_snd_player.c b/src/modules/alsa_snd_player/alsa_snd_player.c
new file mode 100644 (file)
index 0000000..c9e4deb
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Remix ALSA Player: ALSA audio output
+ *
+ * Govindaraju SM <govi.sm@samsung.com>, October 2011
+ * Prince Kumar Dubey <prince.dubey@samsung.com>, October 2011
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <remix/remix.h>
+#include <alsa/asoundlib.h>
+#include <Eina.h>
+
+#define ALSA_PLAYER_BUFFERLEN 2048
+
+typedef struct _AlsaPlayerData AlsaPlayerData;
+typedef short PLAYER_PCM;
+
+struct _AlsaPlayerData
+{
+   RemixPCM databuffer[ALSA_PLAYER_BUFFERLEN];
+   snd_pcm_t *alsa_dev;
+   unsigned int stereo;
+   unsigned channels;
+   unsigned int frequency;
+};
+
+/* Optimisation dependencies: none */
+static RemixBase *alsa_player_optimise(RemixEnv *env, RemixBase *base);
+
+static snd_pcm_t *
+alsa_open(int channels, unsigned samplerate)
+{
+   const char *device = "default";
+   snd_pcm_t *alsa_dev = NULL;
+   snd_pcm_hw_params_t *hw_params;
+   snd_pcm_uframes_t alsa_buffer_frames;
+   snd_pcm_uframes_t alsa_period_size;
+   int err;
+   
+   alsa_buffer_frames = ALSA_PLAYER_BUFFERLEN;
+   alsa_period_size = ALSA_PLAYER_BUFFERLEN / 4;
+   
+   if ((err = snd_pcm_open (&alsa_dev, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
+     {
+        goto catch_error;
+     }
+   
+   if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0)
+     {
+        goto catch_error;
+     }
+   
+   if ((err = snd_pcm_hw_params_any(alsa_dev, hw_params)) < 0)
+     {
+        printf ("cannot initialize hardware parameter structure (%s)\n", snd_strerror (err));
+        goto catch_error;
+     }
+
+   if ((err = snd_pcm_hw_params_set_access(alsa_dev, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
+     {
+         printf ("cannot set access type (%s)\n", snd_strerror (err));
+         goto catch_error;
+     }
+
+   if ((err = snd_pcm_hw_params_set_format(alsa_dev, hw_params, SND_PCM_FORMAT_FLOAT)) < 0)
+     {
+        // FIXME: handle if float format not possible
+        printf ("cannot set sample format (%s)\n", snd_strerror (err));
+        goto catch_error;
+     }
+   
+   if ((err = snd_pcm_hw_params_set_rate_near(alsa_dev, hw_params, &samplerate, 0)) < 0)
+     {
+        // FIXME: get actual sample rate and tell remix
+        printf ("cannot set sample rate (%s)\n", snd_strerror (err));
+        goto catch_error;
+     }
+   
+   if ((err = snd_pcm_hw_params_set_channels(alsa_dev, hw_params, channels)) < 0)
+     {
+        printf ("cannot set channel count (%s)\n", snd_strerror (err));
+        goto catch_error;
+     }
+
+   if ((err = snd_pcm_hw_params_set_buffer_size_near(alsa_dev, hw_params, &alsa_buffer_frames)) < 0)
+     {
+        fprintf (stderr, "cannot set buffer size (%s)\n", snd_strerror (err));
+        goto catch_error;
+     }
+
+   if ((err = snd_pcm_hw_params_set_period_size_near(alsa_dev, hw_params, &alsa_period_size, 0)) < 0)
+     {
+        fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err));
+        goto catch_error;
+     }
+
+   if ((err = snd_pcm_hw_params(alsa_dev, hw_params)) < 0)
+     {
+        printf ("cannot set parameters (%s)\n", snd_strerror (err));
+        goto catch_error;
+     }
+
+   snd_pcm_hw_params_free(hw_params);
+   if ((err = snd_pcm_prepare(alsa_dev)) < 0)
+     {
+        printf ("cannot prepare audio interface for use (%s)\n", snd_strerror(err));
+        goto catch_error;
+     }
+
+   catch_error:
+   if ((err < 0) && (alsa_dev != NULL))
+     {
+        snd_pcm_close (alsa_dev);
+        return NULL;
+     }
+   return alsa_dev;
+}
+
+static RemixBase *
+alsa_player_reset_device(RemixEnv *env, RemixBase *base)
+{
+   AlsaPlayerData *player_data = remix_base_get_instance_data(env, base);
+
+   if (player_data->alsa_dev)
+     {
+        snd_pcm_drain(player_data->alsa_dev);
+        snd_pcm_close(player_data->alsa_dev);
+     }
+   player_data->alsa_dev = alsa_open(player_data->channels, player_data->frequency);
+   if (!player_data->alsa_dev)
+     {
+        remix_set_error(env, REMIX_ERROR_SYSTEM);
+        return RemixNone;
+     }
+   return base;
+}
+
+static RemixBase *
+alsa_player_init(RemixEnv *env, RemixBase *base, CDSet *parameters __UNUSED__)
+{
+   CDSet *channels;
+   AlsaPlayerData *player_data = calloc(1, sizeof(AlsaPlayerData));
+
+   if (!player_data)
+     {
+        remix_set_error(env, REMIX_ERROR_SYSTEM);
+        return RemixNone;
+     }
+   
+   remix_base_set_instance_data(env, base, player_data);
+   channels = remix_get_channels(env);
+
+   player_data->channels = cd_set_size(env, channels);
+   if (player_data->channels == 1)
+     player_data->stereo = 0;
+   else if (player_data->channels == 2)
+     player_data->stereo = 1;
+   
+   player_data->frequency = remix_get_samplerate(env);
+   alsa_player_reset_device(env, base);
+   base = alsa_player_optimise(env, base);
+   return base;
+}
+
+static RemixBase *
+alsa_player_clone(RemixEnv *env, RemixBase *base __UNUSED__)
+{
+   RemixBase *new_player = remix_base_new (env);
+   alsa_player_init(env, new_player, NULL);
+   return new_player;
+}
+
+static int
+alsa_player_destroy(RemixEnv *env, RemixBase *base)
+{
+   AlsaPlayerData *player_data = remix_base_get_instance_data(env, base);
+   
+   if (player_data->alsa_dev)
+     {
+        snd_pcm_drain(player_data->alsa_dev);
+        snd_pcm_close(player_data->alsa_dev);
+     }
+   free(player_data);
+   return 0;
+}
+
+static int
+alsa_player_ready(RemixEnv *env, RemixBase *base)
+{
+   AlsaPlayerData *player_data = remix_base_get_instance_data(env, base);
+   RemixCount nr_channels;
+   CDSet *channels;
+   int samplerate;
+
+   channels = remix_get_channels (env);
+   samplerate = (int)remix_get_samplerate(env);
+   nr_channels = cd_set_size(env, channels);
+   return ((samplerate == (int)player_data->frequency) &&
+           (((nr_channels == 1) && (player_data->stereo == 0)) ||
+               ((nr_channels > 1) && (player_data->stereo == 1))));
+}
+
+static RemixBase *
+alsa_player_prepare(RemixEnv *env, RemixBase *base)
+{
+   alsa_player_reset_device(env, base);
+   return base;
+}
+
+static RemixCount
+alsa_player_playbuffer(RemixEnv *env __UNUSED__, AlsaPlayerData *player, RemixPCM *data, RemixCount count)
+{
+   return snd_pcm_writei(player->alsa_dev, data, count);
+}
+
+static RemixCount
+alsa_player_chunk(RemixEnv *env, RemixChunk *chunk, RemixCount offset, RemixCount count, int channelname __UNUSED__, void *data)
+{
+   AlsaPlayerData *player = data;
+   RemixCount remaining = count, written = 0, n, playcount;
+   RemixPCM *d;
+   
+   while (remaining > 0)
+     {
+        playcount = MIN(remaining, ALSA_PLAYER_BUFFERLEN);
+
+        d = &chunk->data[offset];
+        n = alsa_player_playbuffer(env, player, d, playcount);
+
+        if (n == -1) return -1;
+        else n /= sizeof (PLAYER_PCM);
+        
+        offset += n;
+        written += n;
+        remaining -= n;
+     }
+   return written;
+}
+
+static RemixCount
+alsa_player_process(RemixEnv *env, RemixBase *base, RemixCount count, RemixStream *input, RemixStream *output __UNUSED__)
+{
+   AlsaPlayerData *player_data = remix_base_get_instance_data(env, base);
+   RemixCount nr_channels = remix_stream_nr_channels(env, input);
+   RemixCount remaining = count, processed = 0, n, nn;
+   
+   if ((nr_channels == 1) && (player_data->stereo == 0))
+     { /*MONO*/
+        return remix_stream_chunkfuncify(env, input, count,
+                                         alsa_player_chunk, player_data);
+     }
+   else if ((nr_channels == 2) && (player_data->stereo == 1))
+     { /*STEREO*/
+        while (processed < count)
+          {
+             n = MIN(remaining, ALSA_PLAYER_BUFFERLEN);
+             n = remix_stream_interleave_2(env, input, 
+                                           REMIX_CHANNEL_LEFT,
+                                           REMIX_CHANNEL_RIGHT,
+                                           player_data->databuffer, n);
+             nn = alsa_player_playbuffer(env, player_data,
+                                         player_data->databuffer, n);
+             processed += n;
+             remaining -= n;
+          }
+        return processed;
+     }
+   printf ("[alsa_player_process] unsupported stream/output channel\n");
+   printf ("combination %ld / %d\n", nr_channels, player_data->stereo ? 2 : 1);
+   return -1;
+}
+
+static RemixCount
+alsa_player_length(RemixEnv *env __UNUSED__, RemixBase *base __UNUSED__)
+{
+   return REMIX_COUNT_INFINITE;
+}
+
+static RemixCount
+alsa_player_seek(RemixEnv *env __UNUSED__, RemixBase *base __UNUSED__, RemixCount count __UNUSED__)
+{
+   return count;
+}
+
+static int
+alsa_player_flush (RemixEnv *env, RemixBase *base)
+{
+   alsa_player_reset_device(env, base);
+   return 0;
+}
+
+static struct _RemixMethods _alsa_player_methods =
+{
+   alsa_player_clone,
+   alsa_player_destroy,
+   alsa_player_ready,
+   alsa_player_prepare,
+   alsa_player_process,
+   alsa_player_length,
+   alsa_player_seek,
+   alsa_player_flush,
+};
+
+static RemixBase *
+alsa_player_optimise(RemixEnv *env, RemixBase *base)
+{
+   remix_base_set_methods(env, base, &_alsa_player_methods);
+   return base;
+}
+
+static struct _RemixMetaText alsa_player_metatext =
+{
+   "alsa_snd_player",
+   "ALSA sound player for Remix",
+   "Output the audio stream into ALSA Driver",
+   "Copyright (C) 2011, Samsung Electronics Co., Ltd.",
+   "http://www.samsung.com",
+   REMIX_ONE_AUTHOR("Govindaraju SM", "prince.dubey@samsung.com"),
+};
+
+static struct _RemixPlugin alsa_player_plugin =
+{
+   &alsa_player_metatext,
+   REMIX_FLAGS_NONE,
+   CD_EMPTY_SET, /* init scheme */
+   alsa_player_init,
+   CD_EMPTY_SET, /* process scheme */
+   NULL, /* suggests */
+   NULL, /* plugin data */
+   NULL  /* destroy */
+};
+
+EAPI CDList *
+remix_load(RemixEnv *env)
+{
+   CDList *plugins = cd_list_new(env);
+   plugins = cd_list_prepend(env, plugins, CD_POINTER(&alsa_player_plugin));
+   return plugins;
+}
diff --git a/src/modules/eet_snd_reader/Makefile.am b/src/modules/eet_snd_reader/Makefile.am
new file mode 100644 (file)
index 0000000..c154dc2
--- /dev/null
@@ -0,0 +1,17 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+pkglibdir = $(REMIX_PLUGIN_DIR)
+
+AM_CPPFLAGS = \
+-I. \
+-DPACKAGE_LIB_DIR=\"$(libdir)/remix\" \
+-DPACKAGE_DATA_DIR=\"$(datadir)/remix\" \
+@EDJE_CFLAGS@ \
+@REMIX_CFLAGS@
+
+pkgdir = $(REMIX_PLUGIN_DIR)
+pkg_LTLIBRARIES =  libeet_sndfile_reader.la
+
+libeet_sndfile_reader_la_SOURCES = eet_snd_reader.c
+libeet_sndfile_reader_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version @EDJE_LIBS@ @REMIX_LIBS@
+libeet_sndfile_reader_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/src/modules/eet_snd_reader/eet_snd_reader.c b/src/modules/eet_snd_reader/eet_snd_reader.c
new file mode 100644 (file)
index 0000000..3df4912
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * RemixSnd_eetfile: a libsnd EET Virtual file handler
+ *
+ * Govindaraju SM <govi.sm@samsung.com>, August 2011
+ * Prince Kumar Dubey <prince.dubey@samsung.com>, August 2011
+ */
+
+#include "config.h"
+#include <math.h>
+#include <sndfile.h>
+#include <remix/remix.h>
+#include <Eet.h>
+
+#define PATH_KEY     1
+#define SOUND_ID_KEY 2
+#define SPEED_KEY    3
+#define BLOCK_FRAMES 8192
+
+static RemixBase *remix_eet_sndfile_optimise(RemixEnv *env, RemixBase *sndfile);
+
+typedef struct _VIO_DATA VIO_DATA;
+typedef struct _SndInstanceData SndInstanceData;
+
+struct _VIO_DATA
+{
+   sf_count_t  offset, length;
+   const char *data;
+};
+
+struct _SndInstanceData
+{
+   /* plugin parameters */
+   char       *path;
+   char       *sound_id;
+   double      speed;
+
+   /* Edj & Sndfile Reader */
+   Eet_File   *efp;
+   SNDFILE    *pcm_fp;
+   SF_INFO    *snd_info;
+   VIO_DATA   *vio_data;
+
+   /* PCM buffers */
+   RemixPCM   *readbuf;
+   RemixPCM   *inbuf;
+   RemixPCM   *outbuf;
+
+   /* Resample stuffs */
+   RemixPCM    prevreadbuf[2];
+   int         enable_resample;
+   double      rs_ratio;
+   RemixCount  resample_len;
+   RemixCount  in_avail;
+   RemixCount  out_generated;
+   RemixCount  required_resamples;
+};
+
+static sf_count_t
+eet_snd_file_get_length(void *user_data)
+{
+   VIO_DATA *vf = user_data;
+   return vf->length;
+}
+
+static sf_count_t
+eet_snd_file_seek(sf_count_t offset, int whence, void *user_data)
+{
+   VIO_DATA *vf = user_data;
+   
+   switch (whence)
+     {
+      case SEEK_SET:
+        vf->offset = offset;
+        break;
+      case SEEK_CUR:
+        vf->offset += offset;
+        break;
+      case SEEK_END:
+        vf->offset = vf->length + offset;
+        break;
+      default:
+        break;
+     }
+   return vf->offset;
+}
+
+static sf_count_t
+eet_snd_file_read(void *ptr, sf_count_t count, void *user_data)
+{
+   VIO_DATA *vf = user_data;
+
+   if ((vf->offset + count) > vf->length)
+     count = vf->length - vf->offset;
+   memcpy(ptr, vf->data + vf->offset, count);
+   vf->offset += count;
+   return count;
+}
+
+static sf_count_t
+eet_snd_file_tell(void *user_data)
+{
+   VIO_DATA *vf = user_data;
+   return vf->offset;
+}
+
+static int
+remix_init_resampler_data(RemixEnv *env, RemixBase *base)
+{
+   SndInstanceData *si = remix_base_get_instance_data(env, base);
+
+   si->rs_ratio = remix_get_samplerate(env) / si->snd_info->samplerate;
+   si->rs_ratio /= si->speed;
+   si->resample_len = (si->snd_info->frames * si->rs_ratio);
+
+   si->outbuf = malloc(sizeof(RemixPCM) * BLOCK_FRAMES * 2);
+   if (!si->outbuf) return 0;
+   if ((si->rs_ratio == 1.0)/* && (si->snd_info->channels == 2)*/)
+     {
+        si->enable_resample = 0;
+        return 1;
+     }
+   else
+     si->enable_resample = 1;
+
+   si->in_avail = 0;
+   si->out_generated = 0;
+   si->inbuf = malloc(sizeof(RemixPCM) * BLOCK_FRAMES *
+                      si->snd_info->channels);
+   if (!si->inbuf) return 0;
+   return 1;
+}
+
+static RemixBase *
+remix_eet_sndfile_create(RemixEnv *env, RemixBase *sndfile, const char *path, const char *sound_id, const double speed)
+{
+   SF_VIRTUAL_IO *eet_vio;
+   SndInstanceData *si;
+   const void *sound_data;
+   int sound_size;
+
+   if ((!path) || (!sound_id)) return NULL;
+
+   si = calloc(1, sizeof(SndInstanceData));
+   if (!si) goto err;
+   remix_base_set_instance_data(env, sndfile, si);
+
+   si->path = strdup(path);
+   si->sound_id = strdup(sound_id);
+   si->speed = speed;
+
+   si->efp = eet_open(path, EET_FILE_MODE_READ);
+   if (!si->efp) goto err;
+
+   // xxx: eet_read_direct does not work on Threads, using eet_read.
+   sound_data = eet_read(si->efp, sound_id, &(sound_size));
+   eet_close(si->efp);
+   si->efp = NULL;
+   if (sound_data == NULL) goto err;
+
+   eet_vio = calloc(1, sizeof(SF_VIRTUAL_IO));
+   if (!eet_vio) goto err;
+
+   /* Set up func pointers to read snd file directly from EET. */
+   eet_vio->get_filelen = eet_snd_file_get_length;
+   eet_vio->seek = eet_snd_file_seek;
+   eet_vio->read = eet_snd_file_read;
+   eet_vio->tell = eet_snd_file_tell;
+
+   si->vio_data = calloc(1, sizeof(VIO_DATA));
+   if (!si->vio_data) goto err;
+   si->vio_data->offset = 0;
+   si->vio_data->length = sound_size;
+   si->vio_data->data = sound_data;
+
+   si->snd_info = calloc(1, sizeof(SF_INFO));
+   if (!si->snd_info) goto err;
+
+   si->pcm_fp = sf_open_virtual(eet_vio, SFM_READ, si->snd_info, si->vio_data);
+   if (!si->pcm_fp) goto err;
+   free(eet_vio);
+   eet_vio = NULL;
+
+   if (!remix_init_resampler_data(env, sndfile)) goto err;
+   si->out_generated = 0;
+
+   return sndfile;
+
+err:
+   if (eet_vio) free(eet_vio);
+   remix_set_error(env, REMIX_ERROR_SYSTEM);
+   remix_destroy(env, (RemixBase *)sndfile);
+   return RemixNone;
+}
+
+static RemixBase *
+remix_eet_sndfile_reader_init(RemixEnv *env, RemixBase *base, CDSet *parameters)
+{
+   char *file_path, *sound_id;
+   double speed;
+
+   file_path = (cd_set_find(env, parameters, PATH_KEY)).s_string;
+   sound_id = (cd_set_find(env, parameters, SOUND_ID_KEY)).s_string;
+   speed = (cd_set_find(env, parameters, SPEED_KEY)).s_double;
+
+   if (!remix_eet_sndfile_create(env, base, file_path, sound_id, speed))
+     return RemixNone;
+   remix_eet_sndfile_optimise (env, base);
+   return base;
+}
+
+static RemixBase *
+remix_eet_sndfile_clone(RemixEnv *env, RemixBase *base)
+{
+   SndInstanceData *si = remix_base_get_instance_data(env, base);
+   RemixBase *new_sndfile = remix_base_new(env);
+
+   remix_eet_sndfile_create(env, new_sndfile, si->path, si->sound_id, si->speed);
+   remix_eet_sndfile_optimise(env, new_sndfile);
+   return new_sndfile;
+}
+
+static int
+remix_eet_sndfile_destroy(RemixEnv *env, RemixBase *base)
+{
+   SndInstanceData *si = remix_base_get_instance_data(env, base);
+   if (si)
+     {
+        sf_close (si->pcm_fp);
+        eet_close(si->efp);
+        if (si->path) free(si->path);
+        if (si->sound_id) free(si->sound_id);
+        if (si->snd_info) free(si->snd_info);
+        if (si->efp) eet_close(si->efp);
+        if (si->inbuf) free(si->inbuf);
+        if (si->outbuf) free(si->outbuf);
+        if (si->vio_data) free(si->vio_data);
+        free(si);
+      }
+   if (base) free (base);
+   return 0;
+}
+
+static int
+remix_pcm_resample(SndInstanceData *si)
+{
+   RemixPCM *src, *dst, *srcbase;
+   int i = 0, in_samples, pos, total, chnum, reqsamp, avail;
+   int interp = 1;
+   
+   dst = si->outbuf + (si->out_generated * 2);
+   in_samples = (double)si->required_resamples / si->rs_ratio;
+   chnum = si->snd_info->channels;
+   reqsamp = si->required_resamples;
+   avail = si->in_avail;
+   srcbase = si->readbuf;
+   if ((interp) && (si->rs_ratio >= 1.0))
+     {
+        // linear interpolation of resampling for lower quality samples
+        // so they don't get high requency aliasing effects
+        for (i = 0; i < reqsamp; i++)
+          {
+             float fpos, fpos1;
+             RemixPCM psam[2];
+             
+             fpos = (float)(i * in_samples) / (float)reqsamp;
+             pos = fpos;
+             if (pos >= avail) break;
+             fpos -= pos;
+             fpos1 = 1.0 - fpos;
+             src = srcbase + (pos * chnum);
+             if (chnum == 2)
+               {
+                  if (i == 0)
+                    {
+                       psam[0] = si->prevreadbuf[0];
+                       psam[1] = si->prevreadbuf[1];
+                    }
+                  else
+                    {
+                       psam[0] = src[0 - 2];
+                       psam[1] = src[1 - 2];
+                    }
+                  *dst++ = (src[0] * fpos) + (psam[0] * fpos1);
+                  *dst++ = (src[1] * fpos) + (psam[1] * fpos1);
+               }
+             else
+               {
+                  if (i == 0)
+                    psam[0] = si->prevreadbuf[0];
+                  else
+                    psam[0] = src[0 - 1];
+                  *dst++ = (src[0] * fpos) + (psam[0] * fpos1);
+               }
+          }
+     }
+   else
+     {
+        // simple sample-picking/nearest. faster and simpler
+        for (i = 0; i < reqsamp; i++)
+          {
+             pos = (i * in_samples) / reqsamp;
+             if (pos >= avail) break;
+             src = srcbase + (pos * chnum);
+             if (chnum == 2)
+               {
+                  *dst++ = src[0];
+                  *dst++ = src[1];
+               }
+             else
+               *dst++ = src[0];
+          }
+     }
+   si->out_generated += i;
+   total = (i * in_samples) / reqsamp;
+   si->readbuf += total * chnum;
+   si->in_avail -= total;
+   return total;
+}
+
+/* An RemixChunkFunc for creating sndfile */
+static RemixCount
+remix_eet_sndfile_read_update(RemixEnv *env, RemixBase *sndfile, RemixCount count)
+{
+   SndInstanceData *si = remix_base_get_instance_data(env, sndfile);
+   
+   si->out_generated = 0;
+   if (si->enable_resample)
+     {
+        RemixCount gen = 0;
+
+        while (gen < count)
+          {
+             if (si->in_avail <= 0)
+               {
+                  si->in_avail = sf_readf_float(si->pcm_fp, si->inbuf, BLOCK_FRAMES);
+                  si->readbuf = si->inbuf;
+               }
+             si->required_resamples = (count - gen);
+             remix_pcm_resample(si);
+             if (si->snd_info->channels == 2)
+               {
+                  si->prevreadbuf[0] = si->readbuf[-2];
+                  si->prevreadbuf[1] = si->readbuf[-1];
+               }
+             else
+               {
+                  si->prevreadbuf[0] = si->readbuf[-1];
+               }
+             gen += si->out_generated;
+          }
+        si->out_generated = gen;
+     }
+   else
+     {
+        si->out_generated = sf_readf_float(si->pcm_fp, si->outbuf, count);
+     }
+   return si->out_generated;
+}
+
+static RemixCount
+remix_eet_sndfile_read_into_chunk(RemixEnv *env, RemixChunk *chunk, RemixCount offset, RemixCount count, int channelname, void *data)
+{
+   RemixBase *sndfile = data;
+   SndInstanceData *si = remix_base_get_instance_data(env, sndfile);
+   RemixPCM *d, *p;
+   RemixCount remaining = count, written = 0, n, i;
+
+   d = &chunk->data[offset];
+   n = MIN(remaining, BLOCK_FRAMES);
+   // Need parameter support to advance the data reading
+   if (channelname == 0)
+     remix_eet_sndfile_read_update(env, sndfile, n);
+   n = MIN(si->out_generated, remaining);
+   p = si->outbuf;
+   if (si->snd_info->channels > 1) p += channelname;
+   for (i = 0; i < n; i++)
+     {
+        *d++ = *p;
+        p += si->snd_info->channels;
+     }
+   if (n == 0) n = _remix_pcm_set(d, 0.0, remaining);
+   remaining -= n;
+   written += n;
+   return written;
+}
+
+static RemixCount
+remix_eet_sndfile_reader_process(RemixEnv *env, RemixBase *base, RemixCount count, RemixStream *input __UNUSED__, RemixStream *output)
+{
+   return remix_stream_chunkfuncify(env, output, count, 
+                                    remix_eet_sndfile_read_into_chunk,
+                                    base);
+}
+
+static RemixCount
+remix_eet_sndfile_length(RemixEnv *env, RemixBase *base)
+{
+   SndInstanceData *si = remix_base_get_instance_data(env, base);
+   return si->resample_len;
+}
+
+static RemixCount
+remix_eet_sndfile_seek(RemixEnv *env, RemixBase *base, RemixCount offset)
+{
+   SndInstanceData *si = remix_base_get_instance_data(env, base);
+   return sf_seek(si->pcm_fp, offset, SEEK_SET);
+}
+
+static struct _RemixMethods _remix_eet_sndfile_reader_methods =
+{
+   remix_eet_sndfile_clone,
+   remix_eet_sndfile_destroy,
+   NULL, /* ready */
+   NULL, /* prepare */
+   remix_eet_sndfile_reader_process,
+   remix_eet_sndfile_length,
+   remix_eet_sndfile_seek,
+   NULL, /* flush */
+};
+
+static RemixBase *
+remix_eet_sndfile_optimise(RemixEnv *env, RemixBase *sndfile)
+{
+   remix_base_set_methods(env, sndfile, &_remix_eet_sndfile_reader_methods);
+   return sndfile;
+}
+
+static struct _RemixParameterScheme path_scheme =
+{
+   "path",
+   "Path to sound file",
+   REMIX_TYPE_STRING,
+   REMIX_CONSTRAINT_TYPE_NONE,
+   {NULL},
+   REMIX_HINT_FILENAME,
+};
+
+static struct _RemixParameterScheme sound_id_scheme =
+{
+   "sound_id",
+   "Sound Id (Key) inside EET",
+   REMIX_TYPE_STRING,
+   REMIX_CONSTRAINT_TYPE_NONE,
+   {NULL},
+   REMIX_HINT_DEFAULT,
+};
+
+static struct _RemixParameterScheme speed_scheme =
+{
+   "speed",
+   "Sound Play Speed",
+   REMIX_TYPE_FLOAT,
+   REMIX_CONSTRAINT_TYPE_NONE,
+   {NULL},
+   REMIX_HINT_DEFAULT,
+};
+
+static struct _RemixMetaText eet_sndfile_reader_metatext =
+{
+   "eet_sndfile_reader",
+   "File:: Sound file Reader from EET",
+   "Reads PCM audio files from EET bundle using libsndfile",
+   "Copyright (C) 2011, Samsung Electronics Co., Ltd.",
+   "http://www.samsung.com",
+   REMIX_ONE_AUTHOR ("govi.sm@samsung.com", "prince.dubey@samsung.com"),
+};
+
+static struct _RemixPlugin eet_sndfile_reader_plugin =
+{
+   &eet_sndfile_reader_metatext,
+   REMIX_FLAGS_NONE,
+   CD_EMPTY_SET, /* init scheme */
+   remix_eet_sndfile_reader_init,
+   CD_EMPTY_SET, /* process scheme */
+   NULL, /* suggests */
+   NULL, /* plugin data */
+   NULL  /* destroy */
+};
+
+EAPI CDList *
+remix_load(RemixEnv *env)
+{
+   CDList *plugins = cd_list_new(env);
+   
+   eet_sndfile_reader_plugin.init_scheme =
+     cd_set_insert(env, eet_sndfile_reader_plugin.init_scheme, PATH_KEY,
+                   CD_POINTER(&path_scheme));
+   eet_sndfile_reader_plugin.init_scheme =
+     cd_set_insert(env, eet_sndfile_reader_plugin.init_scheme, SOUND_ID_KEY,
+                   CD_POINTER(&sound_id_scheme));
+   eet_sndfile_reader_plugin.init_scheme =
+     cd_set_insert(env, eet_sndfile_reader_plugin.init_scheme, SPEED_KEY,
+                   CD_POINTER(&speed_scheme));
+   
+   plugins = cd_list_prepend(env, plugins,
+                             CD_POINTER(&eet_sndfile_reader_plugin));
+   return plugins;
+}
diff --git a/src/modules/multisense_factory/Makefile.am b/src/modules/multisense_factory/Makefile.am
new file mode 100644 (file)
index 0000000..768c8ce
--- /dev/null
@@ -0,0 +1,21 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+pkglibdir = $(datadir)/$(PACKAGE)/modules/multisense_factory
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir)/src/lib \
+-I$(top_srcdir)/src/lib/include \
+-DPACKAGE_BIN_DIR=\"$(bindir)\" \
+-DPACKAGE_LIB_DIR=\"$(libdir)\" \
+-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
+-DPACKAGE_EXAMPLES_DIR=\"$(datadir)/$(PACKAGE)/multisense_factory\" \
+@EDJE_CFLAGS@ \
+@REMIX_CFLAGS@
+
+pkgdir = $(libdir)/edje/modules/multisense_factory/$(MODULE_ARCH)
+pkg_LTLIBRARIES = module.la
+
+module_la_SOURCES = multisense_factory.c
+module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version $(top_builddir)/src/lib/libedje.la @EDJE_LIBS@ @REMIX_LIBS@
+module_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/src/modules/multisense_factory/multisense_factory.c b/src/modules/multisense_factory/multisense_factory.c
new file mode 100644 (file)
index 0000000..e22623d
--- /dev/null
@@ -0,0 +1,33 @@
+#include "config.h"\r
+#include <edje_private.h>\r
+\r
+#define DEFAULT_SAMPLERATE 44100\r
+\r
+#ifdef HAVE_LIBREMIX\r
+EAPI RemixBase *\r
+multisense_sound_player_get(Edje_Multisense_Env *msenv)\r
+{\r
+   RemixEnv *env = msenv->remixenv;\r
+   RemixPlugin *player_plugin;\r
+   RemixBase *player;\r
+   \r
+   player_plugin = remix_find_plugin(env, "alsa_snd_player");\r
+   if (!player_plugin)\r
+     {\r
+        printf("ALSA player_plugin init fail\n");\r
+        return remix_monitor_new(env);\r
+     }\r
+   player =  remix_new(env, player_plugin, NULL);\r
+   return player;\r
+}\r
+#endif\r
+\r
+EAPI Eina_Bool\r
+multisense_factory_init(Edje_Multisense_Env *env)\r
+{\r
+#ifdef HAVE_LIBREMIX\r
+   remix_set_samplerate(env->remixenv, DEFAULT_SAMPLERATE);\r
+   remix_set_channels(env->remixenv, REMIX_STEREO);\r
+#endif\r
+   return EINA_TRUE;\r
+}\r