diff --git a/legacy/edje/AUTHORS b/legacy/edje/AUTHORS index 9712dabaf6..56c5483185 100644 --- a/legacy/edje/AUTHORS +++ b/legacy/edje/AUTHORS @@ -18,3 +18,5 @@ Shilpa Singh Mike Blumenkrantz billiob (Boris Faure) +Govindaraju SM +Prince Kumar Dubey diff --git a/legacy/edje/configure.ac b/legacy/edje/configure.ac index b6dcd6abbd..1aedd92b06 100644 --- a/legacy/edje/configure.ac +++ b/legacy/edje/configure.ac @@ -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" diff --git a/legacy/edje/data/include/edje.inc b/legacy/edje/data/include/edje.inc index 45394cb258..dfa5416069 100644 --- a/legacy/edje/data/include/edje.inc +++ b/legacy/edje/data/include/edje.inc @@ -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); diff --git a/legacy/edje/doc/examples.dox b/legacy/edje/doc/examples.dox index be3df77163..846c4c0b98 100644 --- a/legacy/edje/doc/examples.dox +++ b/legacy/edje/doc/examples.dox @@ -14,6 +14,7 @@ * @li @ref tutorial_edje_drag * @li @ref tutorial_edje_perspective * @li @ref tutorial_edje_animations + * @li @ref tutorial_edje_multisense */ /** @@ -826,3 +827,20 @@ * @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 + */ + diff --git a/legacy/edje/src/Makefile.am b/legacy/edje/src/Makefile.am index 69930d5720..d97f1db1d4 100644 --- a/legacy/edje/src/Makefile.am +++ b/legacy/edje/src/Makefile.am @@ -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 diff --git a/legacy/edje/src/bin/Makefile.am b/legacy/edje/src/bin/Makefile.am index cce746c315..a936d5a82c 100644 --- a/legacy/edje/src/bin/Makefile.am +++ b/legacy/edje/src/bin/Makefile.am @@ -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 diff --git a/legacy/edje/src/bin/edje_cc.c b/legacy/edje/src/bin/edje_cc.c index f7c3bfd53f..adcbbb64b9 100644 --- a/legacy/edje/src/bin/edje_cc.c +++ b/legacy/edje/src/bin/edje_cc.c @@ -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++; diff --git a/legacy/edje/src/bin/edje_cc.h b/legacy/edje/src/bin/edje_cc.h index 743d7717be..bcd31a133e 100644 --- a/legacy/edje/src/bin/edje_cc.h +++ b/legacy/edje/src/bin/edje_cc.h @@ -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; diff --git a/legacy/edje/src/bin/edje_cc_handlers.c b/legacy/edje/src/bin/edje_cc_handlers.c index 0351987114..6bc070abb8 100644 --- a/legacy/edje/src/bin/edje_cc_handlers.c +++ b/legacy/edje/src/bin/edje_cc_handlers.c @@ -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 @@ -1840,6 +1855,219 @@ ob_collections(void) edje_file->collection = eina_hash_string_small_new(NULL); } +/** + @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); } diff --git a/legacy/edje/src/bin/edje_cc_out.c b/legacy/edje/src/bin/edje_cc_out.c index a1aa168ef8..1d4195e30d 100644 --- a/legacy/edje/src/bin/edje_cc_out.c +++ b/legacy/edje/src/bin/edje_cc_out.c @@ -28,6 +28,7 @@ void *alloca (size_t); #include "edje_cc.h" #include "edje_convert.h" +#include "edje_multisense_convert.h" #include #include @@ -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, diff --git a/legacy/edje/src/bin/edje_decc.c b/legacy/edje/src/bin/edje_decc.c index 00c9215fef..2c32c19a43 100644 --- a/legacy/edje/src/bin/edje_decc.c +++ b/legacy/edje/src/bin/edje_decc.c @@ -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/legacy/edje/src/bin/edje_multisense_convert.c b/legacy/edje/src/bin/edje_multisense_convert.c new file mode 100644 index 0000000000..cf74be2e3d --- /dev/null +++ b/legacy/edje/src/bin/edje_multisense_convert.c @@ -0,0 +1,329 @@ +#include "edje_multisense_convert.h" + +#ifdef HAVE_LIBSNDFILE +# define READBUF 1024 +# ifdef HAVE_VORBIS +# include +# endif + +# ifdef HAVE_LIBFLAC +# include +# include +# 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/legacy/edje/src/bin/edje_multisense_convert.h b/legacy/edje/src/bin/edje_multisense_convert.h new file mode 100644 index 0000000000..05ee2f72f2 --- /dev/null +++ b/legacy/edje/src/bin/edje_multisense_convert.h @@ -0,0 +1,25 @@ +#ifndef EDJE_SND_CONVERT_H__ +# define EDJE_SND_CONVERT_H__ +#include "edje_private.h" + +#ifdef HAVE_LIBSNDFILE +#include + +#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 diff --git a/legacy/edje/src/examples/Makefile.am b/legacy/edje/src/examples/Makefile.am index fc13c5ba22..5868c1e317 100644 --- a/legacy/edje/src/examples/Makefile.am +++ b/legacy/edje/src/examples/Makefile.am @@ -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/legacy/edje/src/examples/multisense.edc b/legacy/edje/src/examples/multisense.edc new file mode 100644 index 0000000000..330896be07 --- /dev/null +++ b/legacy/edje/src/examples/multisense.edc @@ -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; + } + } + } + } +} + diff --git a/legacy/edje/src/lib/Edje.h b/legacy/edje/src/lib/Edje.h index ba6706d839..1c93873da3 100644 --- a/legacy/edje/src/lib/Edje.h +++ b/legacy/edje/src/lib/Edje.h @@ -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 */ diff --git a/legacy/edje/src/lib/Makefile.am b/legacy/edje/src/lib/Makefile.am index cd9674f1b9..884d67683e 100644 --- a/legacy/edje/src/lib/Makefile.am +++ b/legacy/edje/src/lib/Makefile.am @@ -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 diff --git a/legacy/edje/src/lib/edje_data.c b/legacy/edje/src/lib/edje_data.c index a9e61970c7..6b7b3955cb 100644 --- a/legacy/edje/src/lib/edje_data.c +++ b/legacy/edje/src/lib/edje_data.c @@ -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); diff --git a/legacy/edje/src/lib/edje_embryo.c b/legacy/edje/src/lib/edje_embryo.c index 7575ccaec7..378a1fbfe8 100644 --- a/legacy/edje/src/lib/edje_embryo.c +++ b/legacy/edje/src/lib/edje_embryo.c @@ -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); diff --git a/legacy/edje/src/lib/edje_load.c b/legacy/edje/src/lib/edje_load.c index e53916812e..a5cdad5059 100644 --- a/legacy/edje/src/lib/edje_load.c +++ b/legacy/edje/src/lib/edje_load.c @@ -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); diff --git a/legacy/edje/src/lib/edje_main.c b/legacy/edje/src/lib/edje_main.c index 5cc7b98254..cf443c75a1 100644 --- a/legacy/edje/src/lib/edje_main.c +++ b/legacy/edje/src/lib/edje_main.c @@ -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(); diff --git a/legacy/edje/src/lib/edje_module.c b/legacy/edje/src/lib/edje_module.c index 0d29b3684a..e84cb9742d 100644 --- a/legacy/edje/src/lib/edje_module.c +++ b/legacy/edje/src/lib/edje_module.c @@ -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 ; + 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); + 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/legacy/edje/src/lib/edje_multisense.c b/legacy/edje/src/lib/edje_multisense.c new file mode 100644 index 0000000000..3f0044a895 --- /dev/null +++ b/legacy/edje/src/lib/edje_multisense.c @@ -0,0 +1,382 @@ +#include "config.h" +#include +#include +#include +#include +#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 +} diff --git a/legacy/edje/src/lib/edje_private.h b/legacy/edje/src/lib/edje_private.h index ead0382dfd..0d58900b38 100644 --- a/legacy/edje/src/lib/edje_private.h +++ b/legacy/edje/src/lib/edje_private.h @@ -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 +#endif +#include + +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 diff --git a/legacy/edje/src/lib/edje_program.c b/legacy/edje/src/lib/edje_program.c index 48ff6efea0..a0394d35fc 100644 --- a/legacy/edje/src/lib/edje_program.c +++ b/legacy/edje/src/lib/edje_program.c @@ -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/legacy/edje/src/modules/Makefile.am b/legacy/edje/src/modules/Makefile.am new file mode 100644 index 0000000000..937a6900b4 --- /dev/null +++ b/legacy/edje/src/modules/Makefile.am @@ -0,0 +1,10 @@ +if ENABLE_MULTISENSE +FACTORY_MODULE = multisense_factory +if HAVE_LIBREMIX +SND_READER_MODULE = eet_snd_reader +if HAVE_LIBALSA +ALSA_MODULE = alsa_snd_player +endif +endif +endif +SUBDIRS = $(FACTORY_MODULE) $(SND_READER_MODULE) $(ALSA_MODULE) diff --git a/legacy/edje/src/modules/alsa_snd_player/Makefile.am b/legacy/edje/src/modules/alsa_snd_player/Makefile.am new file mode 100644 index 0000000000..de015f8302 --- /dev/null +++ b/legacy/edje/src/modules/alsa_snd_player/Makefile.am @@ -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/legacy/edje/src/modules/alsa_snd_player/alsa_snd_player.c b/legacy/edje/src/modules/alsa_snd_player/alsa_snd_player.c new file mode 100644 index 0000000000..c9e4deb29c --- /dev/null +++ b/legacy/edje/src/modules/alsa_snd_player/alsa_snd_player.c @@ -0,0 +1,340 @@ +/* + * Remix ALSA Player: ALSA audio output + * + * Govindaraju SM , October 2011 + * Prince Kumar Dubey , October 2011 + */ + +#include "config.h" +#include +#include +#include +#include + +#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/legacy/edje/src/modules/eet_snd_reader/Makefile.am b/legacy/edje/src/modules/eet_snd_reader/Makefile.am new file mode 100644 index 0000000000..c154dc2348 --- /dev/null +++ b/legacy/edje/src/modules/eet_snd_reader/Makefile.am @@ -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/legacy/edje/src/modules/eet_snd_reader/eet_snd_reader.c b/legacy/edje/src/modules/eet_snd_reader/eet_snd_reader.c new file mode 100644 index 0000000000..3df4912988 --- /dev/null +++ b/legacy/edje/src/modules/eet_snd_reader/eet_snd_reader.c @@ -0,0 +1,498 @@ +/* + * RemixSnd_eetfile: a libsnd EET Virtual file handler + * + * Govindaraju SM , August 2011 + * Prince Kumar Dubey , August 2011 + */ + +#include "config.h" +#include +#include +#include +#include + +#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/legacy/edje/src/modules/multisense_factory/Makefile.am b/legacy/edje/src/modules/multisense_factory/Makefile.am new file mode 100644 index 0000000000..768c8ce1c4 --- /dev/null +++ b/legacy/edje/src/modules/multisense_factory/Makefile.am @@ -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/legacy/edje/src/modules/multisense_factory/multisense_factory.c b/legacy/edje/src/modules/multisense_factory/multisense_factory.c new file mode 100644 index 0000000000..e22623d8e0 --- /dev/null +++ b/legacy/edje/src/modules/multisense_factory/multisense_factory.c @@ -0,0 +1,33 @@ +#include "config.h" +#include + +#define DEFAULT_SAMPLERATE 44100 + +#ifdef HAVE_LIBREMIX +EAPI RemixBase * +multisense_sound_player_get(Edje_Multisense_Env *msenv) +{ + RemixEnv *env = msenv->remixenv; + RemixPlugin *player_plugin; + RemixBase *player; + + player_plugin = remix_find_plugin(env, "alsa_snd_player"); + if (!player_plugin) + { + printf("ALSA player_plugin init fail\n"); + return remix_monitor_new(env); + } + player = remix_new(env, player_plugin, NULL); + return player; +} +#endif + +EAPI Eina_Bool +multisense_factory_init(Edje_Multisense_Env *env) +{ +#ifdef HAVE_LIBREMIX + remix_set_samplerate(env->remixenv, DEFAULT_SAMPLERATE); + remix_set_channels(env->remixenv, REMIX_STEREO); +#endif + return EINA_TRUE; +}