From: Prince Kumar Dubey <prince.dubey@samsung.com>

From: Govindaraju S M <govi.sm@samsung.com>
Subject: edje multisense patch for sound sample, tone and haptic play

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



SVN revision: 64731
This commit is contained in:
Prince Kumar Dubey 2011-11-04 12:18:13 +00:00 committed by Carsten Haitzler
parent eaa1a494be
commit 3cc8139906
32 changed files with 2689 additions and 77 deletions

View File

@ -18,3 +18,5 @@ Shilpa Singh <shilpa.singh@samsung.com> <shilpasingh.o@gmail.com>
Mike Blumenkrantz <mike@zentific.com
Jaehwan Kim <jae.hwan.kim@samsung.com>
billiob (Boris Faure) <billiob@gmail.com>
Govindaraju SM <govi.sm@samsung.com> <govism@gmail.com>
Prince Kumar Dubey <prince.dubey@samsung.com> <prince.dubey@gmail.com>

View File

@ -290,6 +290,157 @@ PKG_CHECK_MODULES([ECORE_IMF],
],
[have_ecore_imf="no"])
# Enable Multisense use
want_multisense="no"
AC_ARG_ENABLE([multisense],
[AC_HELP_STRING(
[--enable-multisense],
[multisense provides sound. tone and haptic effects support, [[default=disabled]]]
)],
[want_multisense=$enableval]
)
AM_CONDITIONAL([ENABLE_MULTISENSE], [test "x${want_multisense}" = "xyes"])
if test "x${want_multisense}" = "xyes" ; then
AC_DEFINE([ENABLE_MULTISENSE], [1], [Use Multisense])
fi
##sndfile library
have_sndfile="no"
want_sndfile="auto"
AC_ARG_ENABLE([sndfile],
[AC_HELP_STRING([--disable-sndfile], [disable sndfile support. @<:@default=detect@:>@])],
[want_sndfile=$enableval], [])
if test "x${want_multisense}" = "xyes" -a "x$want_sndfile" != "xno"; then
PKG_CHECK_MODULES([SNDFILE],
[sndfile >= 1.0.22],
[
AC_DEFINE(HAVE_LIBSNDFILE, 1, [sndfile support for Edje])
have_sndfile="yes"
requirement_edje="sndfile >= 1.0.22 ${requirement_edje}"
],
[have_sndfile="no"]
)
if test "x$want_sndfile" = "xyes" -a "x$have_sndfile" = "xno"; then
AC_MSG_ERROR([sndfile support requested, but not found by pkg-config.])
fi
fi
AM_CONDITIONAL([HAVE_LIBSNDFILE], [test "x${have_sndfile}" = "xyes"])
##libremix library
have_libremix="no"
want_libremix="auto"
AC_ARG_ENABLE([remix],
[AC_HELP_STRING([--disable-remix], [disable remix support. @<:@default=detect@:>@])],
[want_libremix=$enableval], [])
if test "x${want_multisense}" = "xyes" -a "x$want_libremix" != "xno"; then
PKG_CHECK_MODULES([REMIX],
[remix >= 0.2.3],
[
AC_DEFINE(HAVE_LIBREMIX, 1, [remix support for Edje])
have_libremix="yes"
requirement_edje="remix >= 0.2.3 ${requirement_edje}"
AC_DEFINE(__REMIX_PLUGIN__, 1, "Set to REMIX Plugin type")
REMIX_PLUGIN_DIR="${libdir}/remix"
AC_SUBST(REMIX_PLUGIN_DIR)
if test "x${prefix}" = "xNONE"; then
REMIX_PLUGIN_DIR="${ac_default_prefix}/lib/remix"
else
REMIX_PLUGIN_DIR="${prefix}/lib/remix"
fi
AC_DEFINE_UNQUOTED(REMIX_PLUGIN_DIR, "$REMIX_PLUGIN_DIR", [Set the remix plugin directory])
],
[have_libremix="no"]
)
if test "x$want_libremix" = "xyes" -a "x$have_libremix" = "xno"; then
AC_MSG_ERROR([remix support requested, but not found by pkg-config.])
fi
fi
AM_CONDITIONAL([HAVE_LIBREMIX], [test "x${have_libremix}" = "xyes"])
##vorbis/ogg library
have_vorbis="no"
want_vorbis="auto"
AC_ARG_ENABLE([vorbisenc],
[AC_HELP_STRING([--disable-vorbis], [disable ogg-vorbis support. @<:@default=detect@:>@])],
[want_vorbis=$enableval], [])
if test "x${want_multisense}" = "xyes" -a "x$want_vorbis" != "xno"; then
PKG_CHECK_MODULES([VORBISENC],
[
ogg >= 1.1.4
vorbis >= 1.2.3
vorbisenc >= 1.2.3
],
[
AC_DEFINE(HAVE_VORBIS, 1, [vorbis support for Edje])
have_vorbis="yes"
requirement_edje="ogg >= 1.1.4 vorbis >= 1.2.3 vorbisenc >= 1.2.3 ${requirement_edje}"
],
[have_vorbis="no"]
)
if test "x$want_vorbis" = "xyes" -a "x$have_vorbis" = "xno"; then
AC_MSG_ERROR([vorbisenc support requested, but not found by pkg-config.])
fi
fi
##alsa library
have_alsa_lib="no"
want_alsa_lib="auto"
AC_ARG_ENABLE([flac],
[AC_HELP_STRING([--disable-alsa], [disable alsa support. @<:@default=detect@:>@])],
[want_alsa_lib=$enableval], [])
if test "x${want_multisense}" = "xyes" -a "x$want_alsa_lib" != "xno"; then
PKG_CHECK_MODULES([ALSA],
[
alsa >= 1.0.21a
],
[
AC_DEFINE(HAVE_LIBALSA, 1, [ALSA support for Edje])
have_alsa_lib="yes"
requirement_edje="alsa >= 1.0.21a ${requirement_edje}"
],
[have_alsa_lib="no"]
)
if test "x$want_alsa_lib" = "xyes" -a "x$have_alsa_lib" = "xno"; then
AC_MSG_ERROR([alsa support requested, but not found by pkg-config.])
fi
fi
AM_CONDITIONAL([HAVE_LIBALSA], [test "x${have_alsa_lib}" = "xyes"])
##flac library
have_flac_lib="no"
want_flac_lib="auto"
AC_ARG_ENABLE([flac],
[AC_HELP_STRING([--disable-flac], [disable flac support. @<:@default=detect@:>@])],
[want_flac_lib=$enableval], [])
if test "x${want_multisense}" = "xyes" -a "x$want_flac_lib" != "xno"; then
PKG_CHECK_MODULES([FLAC],
[
flac >= 1.2.1
],
[
AC_DEFINE(HAVE_LIBFLAC, 1, [flac support for Edje])
have_flac_lib="yes"
requirement_edje="flac >= 1.2.1 ${requirement_edje}"
],
[have_flac_lib="no"]
)
if test "x$want_flac_lib" = "xyes" -a "x$have_flac_lib" = "xno"; then
AC_MSG_ERROR([flac support requested, but not found by pkg-config.])
fi
fi
# Dependencies for the binaries
if test "x$have_edje_cc" = "xyes"; then
@ -432,6 +583,10 @@ src/Makefile
src/lib/Makefile
src/bin/Makefile
src/bin/epp/Makefile
src/modules/Makefile
src/modules/alsa_snd_player/Makefile
src/modules/eet_snd_reader/Makefile
src/modules/multisense_factory/Makefile
src/tests/Makefile
utils/Makefile
src/examples/Makefile
@ -452,6 +607,16 @@ echo "Configuration Options Summary:"
echo
echo " Amalgamation.........: ${do_amalgamation}"
echo " Ecore IMF............: $have_ecore_imf"
echo " Multisense...........: $want_multisense"
if test "x${want_multisense}" = "xyes" ; then
echo " LibRemix.............: $have_libremix"
echo " Libsndfile...........: $have_sndfile"
echo " Ogg/Vorbis...........: $have_vorbis"
echo " LibFLAC..............: $have_flac_lib"
echo " LibALSA..............: $have_alsa_lib"
fi
echo " EDJE_PROGRAM_CACHE...: $want_edje_program_cache"
echo " EDJE_CALC_CACHE......: $want_edje_calc_cache"
echo " Fixed point..........: $want_fixed_point"

View File

@ -213,3 +213,7 @@ enum State_Param
native set_state_val(part_id, State_Param:p, ...);
native get_state_val(part_id, State_Param:p, ...);
/* Multisense */
native play_sample (sample_name[], Float:speed);
native play_tone (tone_name[], Float:duration);

View File

@ -14,6 +14,7 @@
* @li @ref tutorial_edje_drag
* @li @ref tutorial_edje_perspective
* @li @ref tutorial_edje_animations
* @li @ref tutorial_edje_multisense
*/
/**
@ -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
*/

View File

@ -1,4 +1,4 @@
## Process this file with automake to produce Makefile.in
SUBDIRS = lib bin tests examples
SUBDIRS = lib bin modules tests examples
MAINTAINERCLEANFILES = Makefile.in

View File

@ -16,7 +16,8 @@ edje_cc_out.c \
edje_cc_parse.c \
edje_cc_mem.c \
edje_cc_handlers.c \
edje_cc_sources.c
edje_cc_sources.c \
edje_multisense_convert.c
edje_cc_CPPFLAGS = \
-I$(top_srcdir)/src/bin \
@ -25,8 +26,8 @@ edje_cc_CPPFLAGS = \
-DPACKAGE_LIB_DIR=\"$(libdir)\" \
-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
-DEPP_DIR=\"$(libdir)/$(PACKAGE)/utils\" \
@EDJE_CFLAGS@ @EDJE_CC_CFLAGS@ @EVIL_CFLAGS@
edje_cc_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_CC_LIBS@ @EVIL_LIBS@ -lm
@EDJE_CFLAGS@ @EDJE_CC_CFLAGS@ @EVIL_CFLAGS@ @SNDFILE_CFLAGS@
edje_cc_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_CC_LIBS@ @EVIL_LIBS@ @VORBISENC_LIBS@ @FLAC_LIBS@ @SNDFILE_LIBS@ -lm
edje_cc_LDFLAGS = @lt_enable_auto_import@
@ -40,7 +41,7 @@ edje_decc_CPPFLAGS = \
-I$(top_srcdir)/src/bin \
-I$(top_srcdir)/src/lib \
@EDJE_CFLAGS@ @EDJE_DECC_CFLAGS@ @EVIL_CFLAGS@
edje_decc_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_DECC_LIBS@
edje_decc_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_DECC_LIBS@ @VORBISENC_LIBS@ @FLAC_LIBS@ @SNDFILE_LIBS@
edje_decc_LDFLAGS = @lt_enable_auto_import@
edje_player_SOURCES = edje_player.c
@ -48,7 +49,7 @@ edje_player_CPPFLAGS = \
-I$(top_srcdir)/src/bin \
-I$(top_srcdir)/src/lib \
@EDJE_PLAYER_CFLAGS@ @EVIL_CFLAGS@
edje_player_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_PLAYER_LIBS@ @EVIL_LIBS@
edje_player_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_PLAYER_LIBS@ @EVIL_LIBS@ @VORBISENC_LIBS@ @FLAC_LIBS@ @SNDFILE_LIBS@
edje_player_LDFLAGS = @lt_enable_auto_import@
edje_inspector_SOURCES = edje_inspector.c
@ -56,7 +57,7 @@ edje_inspector_CPPFLAGS = \
-I$(top_srcdir)/src/bin \
-I$(top_srcdir)/src/lib \
@EDJE_INSPECTOR_CFLAGS@
edje_inspector_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_INSPECTOR_LIBS@
edje_inspector_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_INSPECTOR_LIBS@ @VORBISENC_LIBS@ @FLAC_LIBS@
edje_inspector_LDFLAGS = @lt_enable_auto_import@
edje_external_inspector_SOURCES = edje_external_inspector.c
@ -64,9 +65,8 @@ edje_external_inspector_CPPFLAGS = \
-I$(top_srcdir)/src/bin \
-I$(top_srcdir)/src/lib \
@EDJE_EXTERNAL_INSPECTOR_CFLAGS@
edje_external_inspector_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_EXTERNAL_INSPECTOR_LIBS@
edje_external_inspector_LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_EXTERNAL_INSPECTOR_LIBS@ @VORBISENC_LIBS@ @FLAC_LIBS@ @SNDFILE_LIBS@
edje_external_inspector_LDFLAGS = @lt_enable_auto_import@
EXTRA_DIST = @EDJE_RECC_PRG@ edje_cc.h edje_convert.h edje_convert.c edje_convert_main.c edje_data_convert.c
EXTRA_DIST = @EDJE_RECC_PRG@ edje_cc.h edje_convert.h edje_convert.c edje_multisense_convert.h edje_data_convert.c
EXTRA_SCRIPTS = edje_recc

View File

@ -12,7 +12,7 @@ int _edje_cc_log_dom = -1;
static void main_help(void);
Eina_Prefix *pfx = NULL;
Eina_List *snd_dirs = NULL;
Eina_List *img_dirs = NULL;
Eina_List *fnt_dirs = NULL;
Eina_List *defines = NULL;
@ -40,6 +40,7 @@ main_help(void)
"\n"
"-id image/directory Add a directory to look in for relative path images\n"
"-fd font/directory Add a directory to look in for relative path fonts\n"
"-sd sound/directory Add a directory to look in for relative path sounds samples\n"
"-td temp/directory Directory to store temporary files\n"
"-v Verbose output\n"
"-no-lossy Do NOT allow images to be lossy\n"
@ -113,6 +114,11 @@ main(int argc, char **argv)
i++;
fnt_dirs = eina_list_append(fnt_dirs, argv[i]);
}
else if ((!strcmp(argv[i], "-sd") || !strcmp(argv[i], "--sound_dir")) && (i < (argc - 1)))
{
i++;
snd_dirs = eina_list_append(snd_dirs, argv[i]);
}
else if ((!strcmp(argv[i], "-td") || !strcmp(argv[i], "--tmp_dir")) && (i < (argc - 1)))
{
i++;

View File

@ -197,6 +197,7 @@ void error_and_abort(Eet_File *ef, const char *fmt, ...);
extern Eina_List *ext_dirs;
extern Eina_List *img_dirs;
extern Eina_List *fnt_dirs;
extern Eina_List *snd_dirs;
extern char *file_in;
extern char *tmp_dir;
extern char *file_out;

View File

@ -261,6 +261,9 @@ static void st_collections_group_programs_program_after(void);
static void st_collections_group_programs_program_api(void);
static void ob_collections_group_programs_program_script(void);
static void st_collections_group_sound_sample_name(void);
static void st_collections_group_sound_sample_source(void);
static void st_collections_group_sound_tone(void);
/*****/
@ -299,6 +302,13 @@ New_Statement_Handler statement_handlers[] =
{"collections.color_classes.color_class.color", st_color_class_color}, /* dup */
{"collections.color_classes.color_class.color2", st_color_class_color2}, /* dup */
{"collections.color_classes.color_class.color3", st_color_class_color3}, /* dup */
{"collections.sounds.sample.name", st_collections_group_sound_sample_name},
{"collections.sounds.sample.source", st_collections_group_sound_sample_source},
{"collections.group.sounds.sample.name", st_collections_group_sound_sample_name}, /* dup */
{"collections.group.sounds.sample.source", st_collections_group_sound_sample_source}, /* dup */
{"collections.sounds.tone", st_collections_group_sound_tone},
{"collections.group.sounds.tone", st_collections_group_sound_tone}, /* dup */
{"collections.group.name", st_collections_group_name},
{"collections.group.inherit", st_collections_group_inherit},
{"collections.group.script_only", st_collections_group_script_only},
@ -663,6 +673,10 @@ New_Object_Handler object_handlers[] =
{"collections.styles.style", ob_styles_style}, /* dup */
{"collections.color_classes", NULL}, /* dup */
{"collections.color_classes.color_class", ob_color_class}, /* dup */
{"collections.sounds", NULL},
{"collections.group.sounds", NULL}, /* dup */
{"collections.sounds.sample", NULL},
{"collections.group.sounds.sample", NULL}, /* dup */
{"collections.group", ob_collections_group},
{"collections.group.data", NULL},
{"collections.group.script", ob_collections_group_script},
@ -1825,12 +1839,13 @@ st_styles_style_tag(void)
..
group { }
group { }
sounds { }
..
}
@description
The "collections" block is used to list the groups that compose the
theme. Additional "collections" blocks do not prevent overriding group
names.
names. The "sounds" block comprises of all sound definitions.
@endblock
*/
static void
@ -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}
*/
@ -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
@ -7017,6 +7245,8 @@ st_collections_group_programs_program_in(void)
action: FOCUS_OBJECT;\n
action: PARAM_COPY "src_part" "src_param" "dst_part" "dst_param";\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,6 +7254,7 @@ 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;
@ -7039,6 +7270,8 @@ st_collections_group_programs_program_action(void)
"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)
{
@ -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);
@ -7111,6 +7376,12 @@ st_collections_group_programs_program_action(void)
case EDJE_ACTION_TYPE_PARAM_SET:
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);
}

View File

@ -28,6 +28,7 @@ void *alloca (size_t);
#include "edje_cc.h"
#include "edje_convert.h"
#include "edje_multisense_convert.h"
#include <lua.h>
#include <lauxlib.h>
@ -650,6 +651,114 @@ data_write_images(Eet_File *ef, int *image_num, int *input_bytes, int *input_raw
return total_bytes;
}
static int
data_write_sounds(Eet_File * ef, int *sound_num, int *input_bytes, int *input_raw_bytes)
{
int bytes = 0;
int total_bytes = 0;
if ((edje_file) && (edje_file->sound_dir))
{
Eina_List *ll;
Edje_Sound_Sample *sample;
#ifdef HAVE_LIBSNDFILE
Edje_Sound_Encode *enc_info;
#endif
char *dir_path = NULL;
char snd_path[PATH_MAX];
char sndid_str[15];
void *fdata;
FILE *fp = NULL;
struct stat st;
int size = 0;
int i;
for (i = 0; i < (int)edje_file->sound_dir->samples_count; i++)
{
sample = &edje_file->sound_dir->samples[i];
memset(&st, 0, sizeof(struct stat));
// Search the Sound file in all the -sd ( sound directory )
EINA_LIST_FOREACH(snd_dirs, ll, dir_path)
{
snprintf((char *)snd_path, sizeof(snd_path), "%s/%s", dir_path,
sample->snd_src);
stat(snd_path, &st);
if (st.st_size) break;
}
if (!st.st_size)
{
snprintf((char *)snd_path, sizeof(snd_path), "%s",
sample->snd_src);
stat(snd_path, &st);
}
size = st.st_size;
if (!size)
{
ERR("%s: Error. Unable to load sound source file : %s",
progname, sample->snd_src);
exit(-1);
}
#ifdef HAVE_LIBSNDFILE
enc_info = _edje_multisense_encode(snd_path, sample, sample->quality);
stat(enc_info->file, &st);
size = st.st_size;
fp = fopen(enc_info->file, "rb");
#else
fp = fopen(snd_path, "rb");
#endif
if (!fp)
{
ERR("%s: Error: Unable to load sound data of: %s",
progname, sample->name);
exit(-1);
}
snprintf(sndid_str, sizeof(sndid_str), "edje/sounds/%i", sample->id);
fdata = malloc(size);
if (!fdata)
{
ERR("%s: Error. %s:%i while allocating memory to load file \"%s\"",
progname, file_in, line, snd_path);
exit(-1);
}
if (fread(fdata, size, 1, fp))
bytes = eet_write(ef, sndid_str, fdata, size, EINA_FALSE);
free(fdata);
fclose(fp);
#ifdef HAVE_LIBSNDFILE
//If encoded temporary file, delete it.
if (enc_info->encoded) unlink(enc_info->file);
#endif
*sound_num += 1;
total_bytes += bytes;
*input_bytes += size;
*input_raw_bytes += size;
if (verbose)
{
#ifdef HAVE_LIBSNDFILE
printf ("%s: Wrote %9i bytes (%4iKb) for \"%s\" %s sound entry"
"\"%s\" \n", progname, bytes, (bytes + 512) / 1024,
sndid_str, enc_info->comp_type, sample->name);
#else
printf ("%s: Wrote %9i bytes (%4iKb) for \"%s\" %s sound entry"
"\"%s\" \n", progname, bytes, (bytes + 512) / 1024,
sndid_str, "RAW PCM", sample->name);
#endif
}
#ifdef HAVE_LIBSNDFILE
if ((enc_info->file) && (!enc_info->encoded)) eina_stringshare_del(enc_info->file);
if (enc_info) free(enc_info);
enc_info = NULL;
#endif
}
}
return total_bytes;
}
static void
check_groups(Eet_File *ef)
{
@ -1058,6 +1167,7 @@ data_write(void)
int fmap_bytes = 0;
int input_raw_bytes = 0;
int image_num = 0;
int sound_num = 0;
int font_num = 0;
int collection_num = 0;
@ -1083,6 +1193,8 @@ data_write(void)
&input_raw_bytes);
total_bytes += data_write_images(ef, &image_num, &input_bytes,
&input_raw_bytes);
total_bytes += data_write_sounds(ef, &sound_num, &input_bytes,
&input_raw_bytes);
total_bytes += data_write_groups(ef, &collection_num);
data_write_scripts(ef);
@ -1106,6 +1218,7 @@ data_write(void)
printf("Summary:\n"
" Wrote %i collections\n"
" Wrote %i images\n"
" Wrote %i sounds\n"
" Wrote %i fonts\n"
" Wrote %i bytes (%iKb) of original source data\n"
" Wrote %i bytes (%iKb) of original source font map\n"
@ -1120,6 +1233,7 @@ data_write(void)
,
collection_num,
image_num,
sound_num,
font_num,
src_bytes, (src_bytes + 512) / 1024,
fmap_bytes, (fmap_bytes + 512) / 1024,

View File

@ -370,6 +370,51 @@ output(void)
chmod(out, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP);
}
if (edje_file->sound_dir)
{
Edje_Sound_Sample *sample;
void *sound_data;
char out[PATH_MAX];
char out1[PATH_MAX];
char *pp;
int sound_data_size;
FILE *f;
int i;
for (i = 0; i < (int)edje_file->sound_dir->samples_count; i++)
{
sample = &edje_file->sound_dir->samples[i];
if ((!sample) || (!sample->name)) continue;
snprintf(out, sizeof(out), "edje/sounds/%i", sample->id);
sound_data = (void *)eet_read_direct(tef, out, &sound_data_size);
if (sound_data)
{
snprintf(out1, sizeof(out1), "%s/%s", outdir, sample->name);
pp = strdup(out1);
p = strrchr(pp, '/');
*p = 0;
if (strstr(pp, "../"))
{
ERR("Potential security violation. attempt to write in parent dir.");
exit(-1);
}
ecore_file_mkpath(pp);
free(pp);
if (strstr(out, "../"))
{
ERR("Potential security violation. attempt to write in parent dir.");
exit(-1);
}
f = fopen(out1, "wb");
if (fwrite(sound_data, sound_data_size, 1, f) != 1)
ERR("Could not write sound: %s", strerror(errno));
fclose(f);
free(sound_data);
}
}
}
eet_close(tef);
}

View File

@ -0,0 +1,329 @@
#include "edje_multisense_convert.h"
#ifdef HAVE_LIBSNDFILE
# define READBUF 1024
# ifdef HAVE_VORBIS
# include <vorbis/vorbisenc.h>
# endif
# ifdef HAVE_LIBFLAC
# include <FLAC/metadata.h>
# include <FLAC/stream_encoder.h>
# endif
Edje_Sound_Encode *
_edje_multisense_encode(const char *filename, Edje_Sound_Sample *sample, double quality)
{
SF_INFO sfinfo;
SNDFILE* sfile;
Edje_Sound_Encode *enc_info;
enc_info = calloc(1, sizeof(Edje_Sound_Encode));
if (!enc_info)
{
ERR("Error. while allocating memory to load file ");
exit(-1);
}
memset (&sfinfo, 0, sizeof (SF_INFO));
enc_info->encoded = EINA_FALSE;
enc_info->comp_type = "RAW PCM";
// Open wav file using sndfile
sfile = sf_open (filename, SFM_READ, &sfinfo);
if (!sfile)
{
ERR("Error. Unable to open audio file : %s", filename);
exit(-1);
}
if (!sf_format_check(&sfinfo))
{
ERR("Error. Unknown file, not a valid audio file");
exit(-1);
}
if (sample->compression == EDJE_SOUND_SOURCE_TYPE_INLINE_COMP)
{
sf_close(sfile);
#ifdef HAVE_LIBFLAC
//encode provided wav file to flac
enc_info->file = _edje_multisense_encode_to_flac((char *)filename, sfinfo);
if (enc_info->file)
{
enc_info->comp_type = "FLAC";
enc_info->encoded = EINA_TRUE;
}
#else
WRN("WARNING: Unable to encode sound %s to FLAC compression",
sample->name);
#endif
}
else if (sample->compression == EDJE_SOUND_SOURCE_TYPE_INLINE_LOSSY)
{
sf_close(sfile);
#ifdef HAVE_VORBIS
//encode provided wav file to ogg-vorbis
enc_info->file = _edje_multisense_encode_to_ogg_vorbis((char *)filename,
quality, sfinfo);
if (enc_info->file)
{
enc_info->comp_type = "OGG-VORBIS";
enc_info->encoded = EINA_TRUE;
}
#else
WRN("WARNING: Unable to encode sound %s to Ogg-Vorbis",
sample->name);
#endif
}
else
eina_stringshare_replace(&enc_info->file, filename);
return enc_info;
}
#ifdef HAVE_LIBFLAC
const char*
_edje_multisense_encode_to_flac(char *snd_path, SF_INFO sfinfo)
{
unsigned total_samples = 0; /* can use a 32-bit number due to WAVE size limitations */
FLAC__bool ok = 1;
FLAC__StreamEncoder *encoder = 0;
FLAC__StreamEncoderInitStatus init_status;
FLAC__StreamMetadata *metadata[2];
FLAC__StreamMetadata_VorbisComment_Entry entry;
SNDFILE *sfile;
sf_count_t size;
char *tmp;
sfile = sf_open(snd_path, SFM_READ, &sfinfo);
if (!sfile) return NULL;
if (!sf_format_check(&sfinfo))
{
sf_close(sfile);
return NULL;
}
size = sf_seek(sfile, 0, SEEK_END);
sf_seek(sfile, 0, SEEK_SET);
tmp = malloc(strlen(snd_path) + 1 + 5);
if (!tmp)
{
sf_close(sfile);
return NULL;
}
strcpy(tmp, snd_path);
snd_path = tmp;
strcat(snd_path, ".flac");
total_samples = size;
/* allocate the encoder */
if ((encoder = FLAC__stream_encoder_new()) == NULL)
{
ERR("ERROR: Creating FLAC encoder\n");
free(snd_path);
sf_close(sfile);
return NULL;
}
/* Verify it's own encoded output. This will slow the encoding process. */
ok &= FLAC__stream_encoder_set_verify(encoder, 1);
//Levels range from 0 (fastest, least compression) to 8 (slowest, most compression).
//A value larger than 8 will be treated as 8.
//5 is used for good compression and moderate compression/decompression speed.
ok &= FLAC__stream_encoder_set_compression_level(encoder, 5);
ok &= FLAC__stream_encoder_set_channels(encoder, sfinfo.channels);
ok &= FLAC__stream_encoder_set_bits_per_sample(encoder, 16);
ok &= FLAC__stream_encoder_set_sample_rate(encoder, sfinfo.samplerate);
ok &= FLAC__stream_encoder_set_total_samples_estimate(encoder, total_samples);
/* now add some metadata; we'll add some tags and a padding block */
if (ok)
{
if ((metadata[0] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL
|| (metadata[1] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)) == NULL
|| !FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, "Encoder", "flac")
|| !FLAC__metadata_object_vorbiscomment_append_comment(metadata[0], entry, 0))
{
ERR("ERROR: out of memory error or tag error\n");
ok = 0;
}
metadata[1]->length = 16; /* set the padding length */
ok = FLAC__stream_encoder_set_metadata(encoder, metadata, 2);
}
/* initialize encoder */
if (ok)
{
init_status = FLAC__stream_encoder_init_file(encoder, snd_path, NULL,
(void *)(total_samples));
if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
{
ERR("ERROR: unable to initialize FLAC encoder: %s\n",
FLAC__StreamEncoderInitStatusString[init_status]);
ok = 0;
}
}
/* read blocks of samples from WAVE file and feed to encoder */
while (ok)
{
FLAC__int32 readbuffer[READBUF * 2];
sf_count_t count;
int i;
count = sf_readf_int(sfile, readbuffer, READBUF);
if (count <= 0) break;
for (i = 0; i < (count * sfinfo.channels); i++)
readbuffer[i] = readbuffer[i] >> 16;
ok = FLAC__stream_encoder_process_interleaved(encoder, readbuffer,
count);
}
FLAC__stream_encoder_finish(encoder);
/* now that encoding is finished, the metadata can be freed */
FLAC__metadata_object_delete(metadata[0]);
FLAC__metadata_object_delete(metadata[1]);
FLAC__stream_encoder_delete(encoder);
sf_close(sfile);
return (snd_path);
}
#endif
#ifdef HAVE_VORBIS
const char *
_edje_multisense_encode_to_ogg_vorbis(char *snd_path, double quality, SF_INFO sfinfo)
{
ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */
ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
ogg_packet op; /* one raw packet of data for decode */
vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */
vorbis_comment vc; /* struct that stores all the user comments */
vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
vorbis_block vb; /* local working space for packet->PCM decode */
int eos = 0, ret;
char *tmp;
SNDFILE *sfile;
FILE *fout;
sfile = sf_open(snd_path, SFM_READ, &sfinfo);
if (!sfile) return NULL;
if (!sf_format_check(&sfinfo))
{
sf_close(sfile);
return NULL;
}
tmp = malloc(strlen(snd_path) + 1 + 4);
if (!tmp)
{
sf_close(sfile);
return NULL;
}
strcpy(tmp, snd_path);
snd_path = tmp;
strcat(snd_path, ".ogg");
fout = fopen(snd_path, "wb");
if (!fout)
{
free(snd_path);
sf_close(sfile);
return NULL;
}
/********** Encode setup ************/
vorbis_info_init(&vi);
ret = vorbis_encode_init(&vi, sfinfo.channels, sfinfo.samplerate,
-1, (long)(quality * 1000), -1);
if (ret == OV_EFAULT) printf("OV_EFAULT\n");
if (ret == OV_EINVAL) printf("OV_EINVAL\n");
if (ret == OV_EIMPL) printf("OV_EIMPL\n");
if (ret)
{
fclose(fout);
free(snd_path);
sf_close(sfile);
return NULL;
}
/* add a comment */
vorbis_comment_init(&vc);
vorbis_comment_add_tag(&vc, "", "");
/* set up the analysis state and auxiliary encoding storage */
vorbis_analysis_init(&vd, &vi);
vorbis_block_init(&vd, &vb);
srand(time(NULL));
ogg_stream_init(&os, rand());
ogg_packet header;
ogg_packet header_comm;
ogg_packet header_code;
vorbis_analysis_headerout(&vd, &vc, &header, &header_comm, &header_code);
ogg_stream_packetin(&os, &header); /* automatically placed in its own page */
ogg_stream_packetin(&os, &header_comm);
ogg_stream_packetin(&os, &header_code);
while (!eos)
{
int result = ogg_stream_flush(&os, &og);
if (!result) break;
fwrite(og.header, 1, og.header_len, fout);
fwrite(og.body, 1, og.body_len, fout);
}
while (!eos)
{
int i, ch;
float readbuffer[READBUF * 2];
sf_count_t count;
count = sf_readf_float(sfile, readbuffer, READBUF);
if (!count)
vorbis_analysis_wrote(&vd, 0);
else
{
float **buffer = vorbis_analysis_buffer(&vd, count);
/* uninterleave samples */
for (i = 0; i < count; i++)
{
for (ch = 0; ch < sfinfo.channels; ch++)
buffer[ch][i]= readbuffer[(i * sfinfo.channels) + ch];
}
vorbis_analysis_wrote(&vd, i);
}
while (vorbis_analysis_blockout(&vd, &vb) == 1)
{
vorbis_analysis(&vb, NULL);
vorbis_bitrate_addblock(&vb);
while (vorbis_bitrate_flushpacket(&vd, &op))
{
ogg_stream_packetin(&os, &op);
while (!eos)
{
int result = ogg_stream_pageout(&os, &og);
if (!result) break;
fwrite(og.header, 1, og.header_len, fout);
fwrite(og.body, 1, og.body_len, fout);
if (ogg_page_eos(&og)) eos = 1;
}
}
}
}
ogg_stream_clear(&os);
vorbis_block_clear(&vb);
vorbis_dsp_clear(&vd);
vorbis_comment_clear(&vc);
vorbis_info_clear(&vi);
sf_close(sfile);
fclose (fout);
return snd_path;
}
#endif
#endif

View File

@ -0,0 +1,25 @@
#ifndef EDJE_SND_CONVERT_H__
# define EDJE_SND_CONVERT_H__
#include "edje_private.h"
#ifdef HAVE_LIBSNDFILE
#include <sndfile.h>
#define SF_CONTAINER(x) ((x) & SF_FORMAT_TYPEMASK)
#define SF_CODEC(x) ((x) & SF_FORMAT_SUBMASK)
typedef struct _Edje_Sound_Encode Edje_Sound_Encode;
struct _Edje_Sound_Encode /*Encoding information*/
{
const char *file; /* the encode sound file path */
Eina_Bool encoded; /* True if encoding is successful else False */
char *comp_type; /* either LOSSLESS (FLAC) or LOSSY (Ogg/Vorbis) Compression */
};
Edje_Sound_Encode *_edje_multisense_encode(const char* filename, Edje_Sound_Sample *sample, double quality);
const char *_edje_multisense_encode_to_flac(char *snd_path, SF_INFO sfinfo);
const char *_edje_multisense_encode_to_ogg_vorbis(char *snd_path, double quality, SF_INFO sfinfo);
#endif
#endif

View File

@ -1,7 +1,10 @@
MAINTAINERCLEANFILES = Makefile.in
pkglibdir = $(datadir)/$(PACKAGE)/examples
if ENABLE_MULTISENSE
MULTISENSE_EDC_FILE = multisense.edc
SND_DIR = -sd $(srcdir)
endif
#put here all EDCs one needs to the examples
EDCS = basic.edc \
swallow.edc \
@ -12,7 +15,8 @@ EDCS = basic.edc \
signals-messages.edc \
color-class.edc \
perspective.edc \
animations.edc
animations.edc \
$(MULTISENSE_EDC_FILE)
filesdir = $(datadir)/$(PACKAGE)/examples
files_DATA =
@ -49,7 +53,7 @@ pkglib_PROGRAMS += \
LDADD = $(top_builddir)/src/lib/libedje.la @EDJE_LIBS@
.edc.edj:
$(edje_cc) -v -id $(srcdir) $< $(builddir)/$(@F)
$(edje_cc) -v -id $(srcdir) $(SND_DIR) $< $(builddir)/$(@F)
EDJS = $(EDCS:%.edc=%.edj)

View File

@ -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;
}
}
}
}
}

View File

@ -615,7 +615,9 @@ typedef enum _Edje_Action_Type
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_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 */

View File

@ -12,7 +12,9 @@ AM_CPPFLAGS = \
@EVIL_CFLAGS@ \
@EDJE_CFLAGS@ \
@ECORE_IMF_CFLAGS@ \
@EFL_EDJE_BUILD@
@EFL_EDJE_BUILD@ \
@REMIX_CFLAGS@ \
@SNDFILE_CFLAGS@
lib_LTLIBRARIES = libedje.la
@ -39,6 +41,7 @@ edje_match.c \
edje_message_queue.c \
edje_misc.c \
edje_module.c \
edje_multisense.c \
edje_program.c \
edje_script_only.c \
edje_smart.c \
@ -127,7 +130,7 @@ else
libedje_la_SOURCES = $(base_sources)
endif
libedje_la_LIBADD = @EDJE_LIBS@ @ECORE_IMF_LIBS@ @EVIL_LIBS@ -lm
libedje_la_LIBADD = @EDJE_LIBS@ @ECORE_IMF_LIBS@ @EVIL_LIBS@ @REMIX_LIBS@ @SNDFILE_LIBS@ -lm
libedje_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@
EXTRA_DIST = edje_private.h edje_container.h edje_convert.h

View File

@ -16,6 +16,9 @@ Eet_Data_Descriptor *_edje_edd_edje_image_directory_set = NULL;
Eet_Data_Descriptor *_edje_edd_edje_image_directory_set_entry = NULL;
Eet_Data_Descriptor *_edje_edd_edje_limit = NULL;
Eet_Data_Descriptor *_edje_edd_edje_limit_pointer = NULL;
Eet_Data_Descriptor *_edje_edd_edje_sound_sample = NULL;
Eet_Data_Descriptor *_edje_edd_edje_sound_tone = NULL;
Eet_Data_Descriptor *_edje_edd_edje_sound_directory = NULL;
Eet_Data_Descriptor *_edje_edd_edje_program = NULL;
Eet_Data_Descriptor *_edje_edd_edje_program_pointer = NULL;
Eet_Data_Descriptor *_edje_edd_edje_program_target = NULL;
@ -169,6 +172,9 @@ _edje_edd_shutdown(void)
FREED(_edje_edd_edje_image_directory_entry);
FREED(_edje_edd_edje_limit);
FREED(_edje_edd_edje_limit_pointer);
FREED(_edje_edd_edje_sound_sample);
FREED(_edje_edd_edje_sound_tone);
FREED(_edje_edd_edje_sound_directory);
FREED(_edje_edd_edje_program);
FREED(_edje_edd_edje_program_pointer);
FREED(_edje_edd_edje_program_target);
@ -284,6 +290,29 @@ _edje_edd_init(void)
EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(_edje_edd_edje_image_directory, Edje_Image_Directory, "entries", entries, _edje_edd_edje_image_directory_entry);
EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(_edje_edd_edje_image_directory, Edje_Image_Directory, "sets", sets, _edje_edd_edje_image_directory_set);
/* Sound */
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Sound_Sample);
_edje_edd_edje_sound_sample =
eet_data_descriptor_file_new(&eddc);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_sample, Edje_Sound_Sample, "name", name, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_sample, Edje_Sound_Sample, "snd_src", snd_src, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_sample, Edje_Sound_Sample, "compression", compression, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_sample, Edje_Sound_Sample, "mode", mode, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_sample, Edje_Sound_Sample, "quality", quality, EET_T_DOUBLE);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_sample, Edje_Sound_Sample, "id", id, EET_T_INT);
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Sound_Tone);
_edje_edd_edje_sound_tone =
eet_data_descriptor_file_new(&eddc);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_tone, Edje_Sound_Tone, "name", name, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_tone, Edje_Sound_Tone, "value", value, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_sound_tone, Edje_Sound_Tone, "id", id, EET_T_INT);
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Sound_Directory);
_edje_edd_edje_sound_directory =
eet_data_descriptor_file_new(&eddc);
EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(_edje_edd_edje_sound_directory, Edje_Sound_Directory, "samples", samples, _edje_edd_edje_sound_sample);
EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(_edje_edd_edje_sound_directory, Edje_Sound_Directory, "tones", tones, _edje_edd_edje_sound_tone);
/* collection directory */
EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Part_Collection_Directory_Entry);
_edje_edd_edje_part_collection_directory_entry =
@ -341,6 +370,7 @@ _edje_edd_init(void)
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_file, Edje_File, "feature_ver", feature_ver, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_file, Edje_File, "external_dir", external_dir, _edje_edd_edje_external_directory);
EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_file, Edje_File, "image_dir", image_dir, _edje_edd_edje_image_directory);
EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_file, Edje_File, "sound_dir", sound_dir, _edje_edd_edje_sound_directory);
EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_file, Edje_File, "styles", styles, _edje_edd_edje_style);
EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_file, Edje_File, "color_classes", color_classes, _edje_edd_edje_color_class);
EET_DATA_DESCRIPTOR_ADD_HASH(_edje_edd_edje_file, Edje_File, "data", data, _edje_edd_edje_string);
@ -376,6 +406,11 @@ _edje_edd_init(void)
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "in.from", in.from, EET_T_DOUBLE);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "in.range", in.range, EET_T_DOUBLE);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "action", action, EET_T_INT);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "sample_name", sample_name, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "tone_name", tone_name, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program ,"duration", duration, EET_T_DOUBLE);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program ,"speed", speed, EET_T_DOUBLE);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "state", state, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "state2", state2, EET_T_STRING);
EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "value", value, EET_T_DOUBLE);

View File

@ -72,6 +72,8 @@
* set_state(part_id, state[], Float:state_val)
* get_state(part_id, dst[], maxlen, &Float:val)
* set_tween_state(part_id, Float:tween, state1[], Float:state1_val, state2[], Float:state2_val)
* play_sample(sample_name, speed)
* play_tone(tone_name, duration)
* run_program(program_id)
* Direction:get_drag_dir(part_id)
* get_drag(part_id, &Float:dx, &Float:&dy)
@ -824,6 +826,38 @@ _edje_embryo_fn_get_part_id(Embryo_Program *ep, Embryo_Cell *params)
return -1;
}
static Embryo_Cell
_edje_embryo_fn_play_sample(Embryo_Program *ep, Embryo_Cell *params)
{
Edje *ed;
char *sample_name = NULL;
float speed = 1.0;
CHKPARAM(1);
ed = embryo_program_data_get(ep);
GETSTR(sample_name, params[1]);
if ((!sample_name)) return 0;
speed = EMBRYO_CELL_TO_FLOAT(params[2]);
_edje_multisense_internal_sound_sample_play(ed, sample_name, (double)speed);
return 0;
}
static Embryo_Cell
_edje_embryo_fn_play_tone(Embryo_Program *ep, Embryo_Cell *params)
{
Edje *ed;
char *tone_name = NULL;
float duration = 0.1;
CHKPARAM(2);
ed = embryo_program_data_get(ep);
GETSTR(tone_name, params[1]);
if ((!tone_name)) return 0;
duration = EMBRYO_CELL_TO_FLOAT(params[2]);
_edje_multisense_internal_sound_tone_play(ed, tone_name, (double) duration);
return 0;
}
/* set_state(part_id, state[], Float:state_val) */
static Embryo_Cell
_edje_embryo_fn_set_state(Embryo_Program *ep, Embryo_Cell *params)
@ -3006,7 +3040,8 @@ _edje_embryo_script_init(Edje_Part_Collection *edc)
embryo_program_native_call_add(ep, "stop_programs_on", _edje_embryo_fn_stop_programs_on);
embryo_program_native_call_add(ep, "set_min_size", _edje_embryo_fn_set_min_size);
embryo_program_native_call_add(ep, "set_max_size", _edje_embryo_fn_set_max_size);
embryo_program_native_call_add(ep, "play_sample", _edje_embryo_fn_play_sample);
embryo_program_native_call_add(ep, "play_tone", _edje_embryo_fn_play_tone);
embryo_program_native_call_add(ep, "send_message", _edje_embryo_fn_send_message);
embryo_program_native_call_add(ep, "get_geometry", _edje_embryo_fn_get_geometry);
embryo_program_native_call_add(ep, "custom_state", _edje_embryo_fn_custom_state);

View File

@ -1094,6 +1094,25 @@ _edje_file_free(Edje_File *edf)
free(edf->image_dir->sets);
free(edf->image_dir);
}
if (edf->sound_dir)
{
unsigned int i;
if (edf->free_strings)
{
for (i = 0; i < edf->sound_dir->samples_count; ++i)
{
eina_stringshare_del(edf->sound_dir->samples[i].name);
eina_stringshare_del(edf->sound_dir->samples[i].snd_src);
}
for (i = 0; i < edf->sound_dir->tones_count; ++i)
eina_stringshare_del(edf->sound_dir->tones[i].name);
}
free(edf->sound_dir->samples);
free(edf->sound_dir->tones);
free(edf->sound_dir);
}
if (edf->external_dir)
{
@ -1130,6 +1149,8 @@ _edje_program_free(Edje_Program *pr, Eina_Bool free_strings)
if (pr->filter.state) eina_stringshare_del(pr->filter.state);
if (pr->state) eina_stringshare_del(pr->state);
if (pr->state2) eina_stringshare_del(pr->state2);
if (pr->sample_name) eina_stringshare_del(pr->sample_name);
if (pr->tone_name) eina_stringshare_del(pr->tone_name);
}
EINA_LIST_FREE(pr->targets, prt)
free(prt);

View File

@ -61,6 +61,7 @@ edje_init(void)
_edje_external_init();
_edje_module_init();
_edje_message_init();
_edje_multisense_init();
_edje_real_part_mp = eina_mempool_add("chained_mempool",
"Edje_Real_Part", NULL,
@ -123,6 +124,7 @@ _edje_shutdown_core(void)
_edje_real_part_state_mp = NULL;
_edje_real_part_mp = NULL;
_edje_multisense_shutdown();
_edje_message_shutdown();
_edje_module_shutdown();
_edje_external_shutdown();

View File

@ -14,20 +14,20 @@ 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];
snprintf(tmp, sizeof (tmp), "%s/%s/%s/" EDJE_MODULE_NAME, path, module, MODULE_ARCH
@ -43,12 +43,11 @@ edje_module_load(const char *module)
eina_module_free(em);
continue;
}
return !!eina_hash_add(_registered_modules, module, em);
if (eina_hash_add(_registered_modules, module, em))
return em;
}
ERR("Could not find the module %s", module);
return EINA_FALSE;
return NULL;
}
void

View File

@ -0,0 +1,382 @@
#include "config.h"
#include <string.h>
#include <fcntl.h>
#include <Eina.h>
#include <Edje.h>
#include "edje_private.h"
typedef struct _Multisense_Data
{
Edje_Multisense_Env *msenv;
#ifdef HAVE_LIBREMIX
RemixDeck *deck;
RemixTrack *track;
RemixLayer *snd_layer, *player_layer;
RemixBase *player;
RemixBase *player_snd;
int remaining;
int offset;
Eina_List *snd_src_list;
MULTISENSE_SOUND_PLAYER_GET_FUNC multisense_sound_player_get;
#endif
}Multisense_Data;
#define BUF_LEN 64
#define SND_PROCESS_LENGTH 2048
static Ecore_Thread *player_thread = NULL;
static Eina_Bool pipe_initialized = EINA_FALSE;
static int command_pipe[2];
typedef enum _Edje_Sound_Action_Type
{
EDJE_PLAY_SAMPLE = 0,
EDJE_PLAY_TONE,
/*
EDJE_PLAY_PATTERN,
EDJE_PLAY_INSTRUMENT,
EDJE_PLAY_SONG,
*/
EDJE_SOUND_LAST
} Edje_Sound_Action_Type;
typedef struct _Edje_Sample_Action Edje_Sample_Action;
typedef struct _Edje_Tone_Action Edje_Tone_Action;
typedef struct _Edje_Multisense_Sound_Action Edje_Multisense_Sound_Action;
struct _Edje_Sample_Action
{
char sample_name[BUF_LEN];
double speed;
};
struct _Edje_Tone_Action
{
char tone_name[BUF_LEN];
double duration;
};
struct _Edje_Multisense_Sound_Action
{
Edje *ed;
Edje_Sound_Action_Type action;
union {
Edje_Sample_Action sample;
Edje_Tone_Action tone;
} type;
};
static Multisense_Data *
init_multisense_environment(void)
{
Multisense_Data *msdata;
char ms_factory[BUF_LEN];
char *ms_factory_env;
Eina_Module *m = NULL;
MULTISENSE_FACTORY_INIT_FUNC multisense_factory_init;
msdata = calloc(1, sizeof(Multisense_Data));
if (!msdata) goto err;
msdata->msenv = calloc(1, sizeof(Edje_Multisense_Env));
if (!msdata->msenv) goto err;
ms_factory_env = getenv("MULTISENSE_FACTORY");
if (ms_factory_env)
strncpy(ms_factory, ms_factory_env, BUF_LEN);
else
strcpy(ms_factory, "multisense_factory");
m = edje_module_load(ms_factory);
if (!m) goto err;
#ifdef HAVE_LIBREMIX
msdata->msenv->remixenv = remix_init();
#endif
multisense_factory_init =
eina_module_symbol_get(m, "multisense_factory_init");
if (multisense_factory_init) multisense_factory_init(msdata->msenv);
#ifdef HAVE_LIBREMIX
msdata->multisense_sound_player_get =
eina_module_symbol_get(m, "multisense_sound_player_get");
if (!msdata->multisense_sound_player_get) goto err;
msdata->deck = remix_deck_new(msdata->msenv->remixenv);
msdata->track = remix_track_new(msdata->msenv->remixenv, msdata->deck);
msdata->snd_layer = remix_layer_new_ontop(msdata->msenv->remixenv,
msdata->track,
REMIX_TIME_SAMPLES);
msdata->player_layer = remix_layer_new_ontop(msdata->msenv->remixenv,
msdata->track,
REMIX_TIME_SAMPLES);
msdata->player = msdata->multisense_sound_player_get(msdata->msenv);
if (!msdata->player) goto err;
msdata->player_snd = remix_sound_new(msdata->msenv->remixenv,
msdata->player, msdata->player_layer,
REMIX_SAMPLES(0),
REMIX_SAMPLES(REMIX_COUNT_INFINITE));
#endif
return msdata;
err:
if (msdata)
{
#ifdef HAVE_LIBREMIX
if (msdata->deck) remix_destroy(msdata->msenv->remixenv, msdata->deck);
if (msdata->msenv->remixenv) remix_purge(msdata->msenv->remixenv);
#endif
if (msdata->msenv) free(msdata->msenv);
free(msdata);
}
return NULL;
}
#ifdef HAVE_LIBREMIX
static RemixBase *
eet_sound_reader_get(Edje_Multisense_Env *msenv, const char *path, const char *sound_id, const double speed)
{
RemixPlugin *sf_plugin = NULL;
RemixBase * eet_snd_reader = NULL;
int sf_path_key = 0;
int sf_sound_id_key = 0;
int sf_speed_key = 0;
CDSet *sf_parms = NULL;
RemixEnv *env = msenv->remixenv;
if (sf_plugin == NULL)
{
sf_plugin = remix_find_plugin(env, "eet_sndfile_reader");
if (sf_plugin == NULL)
{
ERR ("Multisense EET Sound reader plugin NULL\n");
return NULL;
}
sf_path_key = remix_get_init_parameter_key(env, sf_plugin, "path");
sf_sound_id_key = remix_get_init_parameter_key(env, sf_plugin, "sound_id");
sf_speed_key = remix_get_init_parameter_key(env, sf_plugin, "speed");
}
sf_parms = cd_set_replace(env, sf_parms, sf_path_key, CD_STRING(path));
sf_parms = cd_set_replace(env, sf_parms, sf_sound_id_key, CD_STRING(sound_id));
sf_parms = cd_set_replace(env, sf_parms, sf_speed_key, CD_DOUBLE(speed));
eet_snd_reader = remix_new(env, sf_plugin, sf_parms);
return eet_snd_reader;
}
static RemixBase *
edje_remix_sample_create(Multisense_Data *msdata, Edje*ed, Edje_Sample_Action *action)
{
RemixBase *remix_snd = NULL;
Edje_Sound_Sample *sample;
int i;
char snd_id_str[16];
if ((!ed) || (!ed->file) || (!ed->file->sound_dir))
return NULL;
for (i = 0; i < (int)ed->file->sound_dir->samples_count; i++)
{
sample = &ed->file->sound_dir->samples[i];
if (!strcmp(sample->name, action->sample_name))
{
snprintf(snd_id_str, sizeof(snd_id_str), "edje/sounds/%i", sample->id);
remix_snd = eet_sound_reader_get(msdata->msenv, ed->file->path,
snd_id_str, action->speed);
break;
}
}
return remix_snd;
}
static RemixBase *
edje_remix_tone_create(Multisense_Data *msdata, Edje*ed, Edje_Tone_Action *action)
{
Edje_Sound_Tone *tone;
RemixSquareTone *square;
unsigned int i;
if ((!ed) || (!ed->file) || (!ed->file->sound_dir))
return NULL;
for (i = 0; i < ed->file->sound_dir->tones_count; i++)
{
tone = &ed->file->sound_dir->tones[i];
if (!strcmp(tone->name, action->tone_name))
{
square = remix_squaretone_new (msdata->msenv->remixenv, tone->value);
break;
}
}
return square;
}
static void
sound_command_handler(Multisense_Data *msdata)
{
RemixCount length;
Edje_Multisense_Sound_Action command;
RemixBase *base = NULL;
RemixBase *sound;
if (read(command_pipe[0], &command, sizeof(command)) <= 0) return;
switch (command.action)
{
case EDJE_PLAY_SAMPLE:
base = edje_remix_sample_create(msdata, command.ed,
&command.type.sample);
length = remix_length(msdata->msenv->remixenv, base);
break;
case EDJE_PLAY_TONE:
base = edje_remix_tone_create(msdata, command.ed, &command.type.tone);
length = (command.type.tone.duration *
remix_get_samplerate(msdata->msenv->remixenv));
break;
default:
ERR("Invalid Sound Play Command\n");
break;
}
if (base)
{
sound = remix_sound_new(msdata->msenv->remixenv, base, msdata->snd_layer,
REMIX_SAMPLES(msdata->offset),
REMIX_SAMPLES(length));
if (msdata->remaining < length) msdata->remaining = length;
msdata->snd_src_list = eina_list_append(msdata->snd_src_list, sound);
msdata->snd_src_list = eina_list_append(msdata->snd_src_list, base);
}
}
#endif
static void
_player_job(void *data __UNUSED__, Ecore_Thread *th)
{
fd_set wait_fds;
#ifdef HAVE_LIBREMIX
RemixBase *sound;
RemixCount process_len;
#endif
Multisense_Data *msdata = init_multisense_environment();
if (!msdata) return;
fcntl(command_pipe[0], F_SETFL, O_NONBLOCK);
FD_ZERO(&wait_fds);
FD_SET(command_pipe[0], &wait_fds);
#ifdef HAVE_LIBREMIX
while (!ecore_thread_check(th))
{
if (!msdata->remaining)
{
//Cleanup already played sound sources
EINA_LIST_FREE(msdata->snd_src_list, sound)
{
remix_destroy(msdata->msenv->remixenv, sound);
}
//wait for new sound
select(command_pipe[0] + 1, &wait_fds, NULL, NULL, 0);
}
//read sound command , if any
sound_command_handler(msdata);
process_len = MIN(msdata->remaining, SND_PROCESS_LENGTH);
remix_process(msdata->msenv->remixenv, msdata->deck, process_len,
RemixNone, RemixNone);
msdata->offset += process_len;
msdata->remaining -= process_len;
}
//Cleanup last played sound sources
EINA_LIST_FREE(msdata->snd_src_list, sound)
{
remix_destroy(msdata->msenv->remixenv, sound);
}
//cleanup Remix stuffs
remix_destroy(msdata->msenv->remixenv, msdata->player);
remix_destroy(msdata->msenv->remixenv, msdata->deck);
remix_purge(msdata->msenv->remixenv);
#endif
free(msdata->msenv);
free(msdata);
close(command_pipe[0]);
close(command_pipe[1]);
}
static void
_player_cancel(void *data __UNUSED__, Ecore_Thread *th __UNUSED__)
{
player_thread = NULL;
}
static void
_player_end(void *data __UNUSED__, Ecore_Thread *th __UNUSED__)
{
player_thread = NULL;
}
Eina_Bool
_edje_multisense_internal_sound_sample_play(Edje *ed, const char *sample_name, const double speed)
{
ssize_t size = 0;
#ifdef ENABLE_MULTISENSE
Edje_Multisense_Sound_Action command;
if ((!pipe_initialized) && (!player_thread)) return EINA_FALSE;
command.action = EDJE_PLAY_SAMPLE;
command.ed = ed;
strncpy(command.type.sample.sample_name, sample_name, BUF_LEN);
command.type.sample.speed = speed;
size = write(command_pipe[1], &command, sizeof(command));
#endif
return (size == sizeof(Edje_Multisense_Sound_Action));
}
Eina_Bool
_edje_multisense_internal_sound_tone_play(Edje *ed, const char *tone_name, const double duration)
{
ssize_t size = 0;
#ifdef ENABLE_MULTISENSE
Edje_Multisense_Sound_Action command;
if ((!pipe_initialized) && (!player_thread)) return EINA_FALSE;
command.action = EDJE_PLAY_TONE;
command.ed = ed;
strncpy(command.type.tone.tone_name, tone_name, BUF_LEN);
command.type.tone.duration = duration;
size = write(command_pipe[1], &command, sizeof(command));
#endif
return (size == sizeof(Edje_Multisense_Sound_Action));
}
/* Initialize the modules in main thread. to avoid dlopen issue in the Threads */
void
_edje_multisense_init(void)
{
#ifdef ENABLE_MULTISENSE
if (!pipe_initialized && (pipe(command_pipe) != -1))
pipe_initialized = EINA_TRUE;
if (!player_thread)
player_thread = ecore_thread_run(_player_job, _player_end, _player_cancel, NULL);
#endif
}
void
_edje_multisense_shutdown(void)
{
#ifdef ENABLE_MULTISENSE
if (pipe_initialized)
{
close(command_pipe[1]);
close(command_pipe[0]);
}
if (player_thread) ecore_thread_cancel(player_thread);
#endif
}

View File

@ -268,6 +268,9 @@ typedef struct _Edje_Image_Directory_Entry Edje_Image_Directory_Entry;
typedef struct _Edje_Image_Directory_Set Edje_Image_Directory_Set;
typedef struct _Edje_Image_Directory_Set_Entry Edje_Image_Directory_Set_Entry;
typedef struct _Edje_Limit Edje_Limit;
typedef struct _Edje_Sound_Sample Edje_Sound_Sample;
typedef struct _Edje_Sound_Tone Edje_Sound_Tone;
typedef struct _Edje_Sound_Directory Edje_Sound_Directory;
typedef struct _Edje_Program Edje_Program;
typedef struct _Edje_Program_Target Edje_Program_Target;
typedef struct _Edje_Program_After Edje_Program_After;
@ -328,6 +331,12 @@ typedef struct _Edje_Text_Insert_Filter_Callback Edje_Text_Insert_Filter_Callbac
#define EDJE_IMAGE_SOURCE_TYPE_EXTERNAL 3
#define EDJE_IMAGE_SOURCE_TYPE_LAST 4
#define EDJE_SOUND_SOURCE_TYPE_NONE 0
#define EDJE_SOUND_SOURCE_TYPE_INLINE_RAW 1
#define EDJE_SOUND_SOURCE_TYPE_INLINE_COMP 2
#define EDJE_SOUND_SOURCE_TYPE_INLINE_LOSSY 3
#define EDJE_SOUND_SOURCE_TYPE_INLINE_AS_IS 4
#define EDJE_VAR_NONE 0
#define EDJE_VAR_INT 1
#define EDJE_VAR_FLOAT 2
@ -410,6 +419,7 @@ struct _Edje_File
Edje_External_Directory *external_dir;
Edje_Image_Directory *image_dir;
Edje_Sound_Directory *sound_dir;
Eina_List *styles;
Eina_List *color_classes;
@ -517,6 +527,33 @@ struct _Edje_Image_Directory_Set_Entry
} size;
};
struct _Edje_Sound_Sample /*Sound Sample*/
{
const char *name; /* the nominal name of the sound */
const char *snd_src; /* Sound source Wav file */
int compression; /* Compression - RAW, LOSSLESS COMP , LOSSY ) */
int mode; /* alternate source mode. 0 = none */
double quality;
int id; /* the id no. of the sound */
};
struct _Edje_Sound_Tone /*Sound Sample*/
{
const char *name; /* the nominal name of the sound - if any */
int value; /* alternate source mode. 0 = none */
int id; /* the id no. of the sound */
};
struct _Edje_Sound_Directory
{
Edje_Sound_Sample *samples; /* an array of Edje_Sound_Sample entries */
unsigned int samples_count;
Edje_Sound_Tone *tones; /* an array of Edje_Sound_Tone entries */
unsigned int tones_count;
};
/*----------*/
struct _Edje_Program /* a conditional program to be run */
@ -526,6 +563,10 @@ struct _Edje_Program /* a conditional program to be run */
const char *signal; /* if signal emission name matches the glob here... */
const char *source; /* if part that emitted this (name) matches this glob */
const char *sample_name;
const char *tone_name;
double duration;
double speed;
struct {
const char *part;
@ -1921,4 +1962,28 @@ void _edje_object_orientation_inform(Evas_Object *obj);
void _edje_lib_ref(void);
void _edje_lib_unref(void);
void _edje_multisense_init(void);
void _edje_multisense_shutdown(void);
Eina_Bool _edje_multisense_internal_sound_sample_play(Edje *ed, const char *sample_name, const double speed);
Eina_Bool _edje_multisense_internal_sound_tone_play(Edje *ed, const char *tone_name, const double duration);
#ifdef HAVE_LIBREMIX
#include <remix/remix.h>
#endif
#include <Eina.h>
typedef struct _Edje_Multisense_Env Edje_Multisense_Env;
struct _Edje_Multisense_Env
{
#ifdef HAVE_LIBREMIX
RemixEnv *remixenv;
#endif
};
typedef Eina_Bool (*MULTISENSE_FACTORY_INIT_FUNC) (Edje_Multisense_Env *);
#ifdef HAVE_LIBREMIX
typedef RemixBase* (*MULTISENSE_SOUND_PLAYER_GET_FUNC) (Edje_Multisense_Env *);
#endif
#endif

View File

@ -769,6 +769,16 @@ _edje_program_run(Edje *ed, Edje_Program *pr, Eina_Bool force, const char *ssig,
}
}
break;
case EDJE_ACTION_TYPE_SOUND_SAMPLE:
if (_edje_block_break(ed))
goto break_prog;
_edje_multisense_internal_sound_sample_play(ed, pr->sample_name, pr->speed);
break;
case EDJE_ACTION_TYPE_SOUND_TONE:
if (_edje_block_break(ed))
goto break_prog;
_edje_multisense_internal_sound_tone_play(ed, pr->tone_name, pr->duration);
break;
case EDJE_ACTION_TYPE_PARAM_COPY:
{
Edje_Real_Part *src_part, *dst_part;

View File

@ -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)

View File

@ -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

View File

@ -0,0 +1,340 @@
/*
* Remix ALSA Player: ALSA audio output
*
* Govindaraju SM <govi.sm@samsung.com>, October 2011
* Prince Kumar Dubey <prince.dubey@samsung.com>, October 2011
*/
#include "config.h"
#include <stdio.h>
#include <remix/remix.h>
#include <alsa/asoundlib.h>
#include <Eina.h>
#define ALSA_PLAYER_BUFFERLEN 2048
typedef struct _AlsaPlayerData AlsaPlayerData;
typedef short PLAYER_PCM;
struct _AlsaPlayerData
{
RemixPCM databuffer[ALSA_PLAYER_BUFFERLEN];
snd_pcm_t *alsa_dev;
unsigned int stereo;
unsigned channels;
unsigned int frequency;
};
/* Optimisation dependencies: none */
static RemixBase *alsa_player_optimise(RemixEnv *env, RemixBase *base);
static snd_pcm_t *
alsa_open(int channels, unsigned samplerate)
{
const char *device = "default";
snd_pcm_t *alsa_dev = NULL;
snd_pcm_hw_params_t *hw_params;
snd_pcm_uframes_t alsa_buffer_frames;
snd_pcm_uframes_t alsa_period_size;
int err;
alsa_buffer_frames = ALSA_PLAYER_BUFFERLEN;
alsa_period_size = ALSA_PLAYER_BUFFERLEN / 4;
if ((err = snd_pcm_open (&alsa_dev, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
{
goto catch_error;
}
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0)
{
goto catch_error;
}
if ((err = snd_pcm_hw_params_any(alsa_dev, hw_params)) < 0)
{
printf ("cannot initialize hardware parameter structure (%s)\n", snd_strerror (err));
goto catch_error;
}
if ((err = snd_pcm_hw_params_set_access(alsa_dev, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
printf ("cannot set access type (%s)\n", snd_strerror (err));
goto catch_error;
}
if ((err = snd_pcm_hw_params_set_format(alsa_dev, hw_params, SND_PCM_FORMAT_FLOAT)) < 0)
{
// FIXME: handle if float format not possible
printf ("cannot set sample format (%s)\n", snd_strerror (err));
goto catch_error;
}
if ((err = snd_pcm_hw_params_set_rate_near(alsa_dev, hw_params, &samplerate, 0)) < 0)
{
// FIXME: get actual sample rate and tell remix
printf ("cannot set sample rate (%s)\n", snd_strerror (err));
goto catch_error;
}
if ((err = snd_pcm_hw_params_set_channels(alsa_dev, hw_params, channels)) < 0)
{
printf ("cannot set channel count (%s)\n", snd_strerror (err));
goto catch_error;
}
if ((err = snd_pcm_hw_params_set_buffer_size_near(alsa_dev, hw_params, &alsa_buffer_frames)) < 0)
{
fprintf (stderr, "cannot set buffer size (%s)\n", snd_strerror (err));
goto catch_error;
}
if ((err = snd_pcm_hw_params_set_period_size_near(alsa_dev, hw_params, &alsa_period_size, 0)) < 0)
{
fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err));
goto catch_error;
}
if ((err = snd_pcm_hw_params(alsa_dev, hw_params)) < 0)
{
printf ("cannot set parameters (%s)\n", snd_strerror (err));
goto catch_error;
}
snd_pcm_hw_params_free(hw_params);
if ((err = snd_pcm_prepare(alsa_dev)) < 0)
{
printf ("cannot prepare audio interface for use (%s)\n", snd_strerror(err));
goto catch_error;
}
catch_error:
if ((err < 0) && (alsa_dev != NULL))
{
snd_pcm_close (alsa_dev);
return NULL;
}
return alsa_dev;
}
static RemixBase *
alsa_player_reset_device(RemixEnv *env, RemixBase *base)
{
AlsaPlayerData *player_data = remix_base_get_instance_data(env, base);
if (player_data->alsa_dev)
{
snd_pcm_drain(player_data->alsa_dev);
snd_pcm_close(player_data->alsa_dev);
}
player_data->alsa_dev = alsa_open(player_data->channels, player_data->frequency);
if (!player_data->alsa_dev)
{
remix_set_error(env, REMIX_ERROR_SYSTEM);
return RemixNone;
}
return base;
}
static RemixBase *
alsa_player_init(RemixEnv *env, RemixBase *base, CDSet *parameters __UNUSED__)
{
CDSet *channels;
AlsaPlayerData *player_data = calloc(1, sizeof(AlsaPlayerData));
if (!player_data)
{
remix_set_error(env, REMIX_ERROR_SYSTEM);
return RemixNone;
}
remix_base_set_instance_data(env, base, player_data);
channels = remix_get_channels(env);
player_data->channels = cd_set_size(env, channels);
if (player_data->channels == 1)
player_data->stereo = 0;
else if (player_data->channels == 2)
player_data->stereo = 1;
player_data->frequency = remix_get_samplerate(env);
alsa_player_reset_device(env, base);
base = alsa_player_optimise(env, base);
return base;
}
static RemixBase *
alsa_player_clone(RemixEnv *env, RemixBase *base __UNUSED__)
{
RemixBase *new_player = remix_base_new (env);
alsa_player_init(env, new_player, NULL);
return new_player;
}
static int
alsa_player_destroy(RemixEnv *env, RemixBase *base)
{
AlsaPlayerData *player_data = remix_base_get_instance_data(env, base);
if (player_data->alsa_dev)
{
snd_pcm_drain(player_data->alsa_dev);
snd_pcm_close(player_data->alsa_dev);
}
free(player_data);
return 0;
}
static int
alsa_player_ready(RemixEnv *env, RemixBase *base)
{
AlsaPlayerData *player_data = remix_base_get_instance_data(env, base);
RemixCount nr_channels;
CDSet *channels;
int samplerate;
channels = remix_get_channels (env);
samplerate = (int)remix_get_samplerate(env);
nr_channels = cd_set_size(env, channels);
return ((samplerate == (int)player_data->frequency) &&
(((nr_channels == 1) && (player_data->stereo == 0)) ||
((nr_channels > 1) && (player_data->stereo == 1))));
}
static RemixBase *
alsa_player_prepare(RemixEnv *env, RemixBase *base)
{
alsa_player_reset_device(env, base);
return base;
}
static RemixCount
alsa_player_playbuffer(RemixEnv *env __UNUSED__, AlsaPlayerData *player, RemixPCM *data, RemixCount count)
{
return snd_pcm_writei(player->alsa_dev, data, count);
}
static RemixCount
alsa_player_chunk(RemixEnv *env, RemixChunk *chunk, RemixCount offset, RemixCount count, int channelname __UNUSED__, void *data)
{
AlsaPlayerData *player = data;
RemixCount remaining = count, written = 0, n, playcount;
RemixPCM *d;
while (remaining > 0)
{
playcount = MIN(remaining, ALSA_PLAYER_BUFFERLEN);
d = &chunk->data[offset];
n = alsa_player_playbuffer(env, player, d, playcount);
if (n == -1) return -1;
else n /= sizeof (PLAYER_PCM);
offset += n;
written += n;
remaining -= n;
}
return written;
}
static RemixCount
alsa_player_process(RemixEnv *env, RemixBase *base, RemixCount count, RemixStream *input, RemixStream *output __UNUSED__)
{
AlsaPlayerData *player_data = remix_base_get_instance_data(env, base);
RemixCount nr_channels = remix_stream_nr_channels(env, input);
RemixCount remaining = count, processed = 0, n, nn;
if ((nr_channels == 1) && (player_data->stereo == 0))
{ /*MONO*/
return remix_stream_chunkfuncify(env, input, count,
alsa_player_chunk, player_data);
}
else if ((nr_channels == 2) && (player_data->stereo == 1))
{ /*STEREO*/
while (processed < count)
{
n = MIN(remaining, ALSA_PLAYER_BUFFERLEN);
n = remix_stream_interleave_2(env, input,
REMIX_CHANNEL_LEFT,
REMIX_CHANNEL_RIGHT,
player_data->databuffer, n);
nn = alsa_player_playbuffer(env, player_data,
player_data->databuffer, n);
processed += n;
remaining -= n;
}
return processed;
}
printf ("[alsa_player_process] unsupported stream/output channel\n");
printf ("combination %ld / %d\n", nr_channels, player_data->stereo ? 2 : 1);
return -1;
}
static RemixCount
alsa_player_length(RemixEnv *env __UNUSED__, RemixBase *base __UNUSED__)
{
return REMIX_COUNT_INFINITE;
}
static RemixCount
alsa_player_seek(RemixEnv *env __UNUSED__, RemixBase *base __UNUSED__, RemixCount count __UNUSED__)
{
return count;
}
static int
alsa_player_flush (RemixEnv *env, RemixBase *base)
{
alsa_player_reset_device(env, base);
return 0;
}
static struct _RemixMethods _alsa_player_methods =
{
alsa_player_clone,
alsa_player_destroy,
alsa_player_ready,
alsa_player_prepare,
alsa_player_process,
alsa_player_length,
alsa_player_seek,
alsa_player_flush,
};
static RemixBase *
alsa_player_optimise(RemixEnv *env, RemixBase *base)
{
remix_base_set_methods(env, base, &_alsa_player_methods);
return base;
}
static struct _RemixMetaText alsa_player_metatext =
{
"alsa_snd_player",
"ALSA sound player for Remix",
"Output the audio stream into ALSA Driver",
"Copyright (C) 2011, Samsung Electronics Co., Ltd.",
"http://www.samsung.com",
REMIX_ONE_AUTHOR("Govindaraju SM", "prince.dubey@samsung.com"),
};
static struct _RemixPlugin alsa_player_plugin =
{
&alsa_player_metatext,
REMIX_FLAGS_NONE,
CD_EMPTY_SET, /* init scheme */
alsa_player_init,
CD_EMPTY_SET, /* process scheme */
NULL, /* suggests */
NULL, /* plugin data */
NULL /* destroy */
};
EAPI CDList *
remix_load(RemixEnv *env)
{
CDList *plugins = cd_list_new(env);
plugins = cd_list_prepend(env, plugins, CD_POINTER(&alsa_player_plugin));
return plugins;
}

View File

@ -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

View File

@ -0,0 +1,498 @@
/*
* RemixSnd_eetfile: a libsnd EET Virtual file handler
*
* Govindaraju SM <govi.sm@samsung.com>, August 2011
* Prince Kumar Dubey <prince.dubey@samsung.com>, August 2011
*/
#include "config.h"
#include <math.h>
#include <sndfile.h>
#include <remix/remix.h>
#include <Eet.h>
#define PATH_KEY 1
#define SOUND_ID_KEY 2
#define SPEED_KEY 3
#define BLOCK_FRAMES 8192
static RemixBase *remix_eet_sndfile_optimise(RemixEnv *env, RemixBase *sndfile);
typedef struct _VIO_DATA VIO_DATA;
typedef struct _SndInstanceData SndInstanceData;
struct _VIO_DATA
{
sf_count_t offset, length;
const char *data;
};
struct _SndInstanceData
{
/* plugin parameters */
char *path;
char *sound_id;
double speed;
/* Edj & Sndfile Reader */
Eet_File *efp;
SNDFILE *pcm_fp;
SF_INFO *snd_info;
VIO_DATA *vio_data;
/* PCM buffers */
RemixPCM *readbuf;
RemixPCM *inbuf;
RemixPCM *outbuf;
/* Resample stuffs */
RemixPCM prevreadbuf[2];
int enable_resample;
double rs_ratio;
RemixCount resample_len;
RemixCount in_avail;
RemixCount out_generated;
RemixCount required_resamples;
};
static sf_count_t
eet_snd_file_get_length(void *user_data)
{
VIO_DATA *vf = user_data;
return vf->length;
}
static sf_count_t
eet_snd_file_seek(sf_count_t offset, int whence, void *user_data)
{
VIO_DATA *vf = user_data;
switch (whence)
{
case SEEK_SET:
vf->offset = offset;
break;
case SEEK_CUR:
vf->offset += offset;
break;
case SEEK_END:
vf->offset = vf->length + offset;
break;
default:
break;
}
return vf->offset;
}
static sf_count_t
eet_snd_file_read(void *ptr, sf_count_t count, void *user_data)
{
VIO_DATA *vf = user_data;
if ((vf->offset + count) > vf->length)
count = vf->length - vf->offset;
memcpy(ptr, vf->data + vf->offset, count);
vf->offset += count;
return count;
}
static sf_count_t
eet_snd_file_tell(void *user_data)
{
VIO_DATA *vf = user_data;
return vf->offset;
}
static int
remix_init_resampler_data(RemixEnv *env, RemixBase *base)
{
SndInstanceData *si = remix_base_get_instance_data(env, base);
si->rs_ratio = remix_get_samplerate(env) / si->snd_info->samplerate;
si->rs_ratio /= si->speed;
si->resample_len = (si->snd_info->frames * si->rs_ratio);
si->outbuf = malloc(sizeof(RemixPCM) * BLOCK_FRAMES * 2);
if (!si->outbuf) return 0;
if ((si->rs_ratio == 1.0)/* && (si->snd_info->channels == 2)*/)
{
si->enable_resample = 0;
return 1;
}
else
si->enable_resample = 1;
si->in_avail = 0;
si->out_generated = 0;
si->inbuf = malloc(sizeof(RemixPCM) * BLOCK_FRAMES *
si->snd_info->channels);
if (!si->inbuf) return 0;
return 1;
}
static RemixBase *
remix_eet_sndfile_create(RemixEnv *env, RemixBase *sndfile, const char *path, const char *sound_id, const double speed)
{
SF_VIRTUAL_IO *eet_vio;
SndInstanceData *si;
const void *sound_data;
int sound_size;
if ((!path) || (!sound_id)) return NULL;
si = calloc(1, sizeof(SndInstanceData));
if (!si) goto err;
remix_base_set_instance_data(env, sndfile, si);
si->path = strdup(path);
si->sound_id = strdup(sound_id);
si->speed = speed;
si->efp = eet_open(path, EET_FILE_MODE_READ);
if (!si->efp) goto err;
// xxx: eet_read_direct does not work on Threads, using eet_read.
sound_data = eet_read(si->efp, sound_id, &(sound_size));
eet_close(si->efp);
si->efp = NULL;
if (sound_data == NULL) goto err;
eet_vio = calloc(1, sizeof(SF_VIRTUAL_IO));
if (!eet_vio) goto err;
/* Set up func pointers to read snd file directly from EET. */
eet_vio->get_filelen = eet_snd_file_get_length;
eet_vio->seek = eet_snd_file_seek;
eet_vio->read = eet_snd_file_read;
eet_vio->tell = eet_snd_file_tell;
si->vio_data = calloc(1, sizeof(VIO_DATA));
if (!si->vio_data) goto err;
si->vio_data->offset = 0;
si->vio_data->length = sound_size;
si->vio_data->data = sound_data;
si->snd_info = calloc(1, sizeof(SF_INFO));
if (!si->snd_info) goto err;
si->pcm_fp = sf_open_virtual(eet_vio, SFM_READ, si->snd_info, si->vio_data);
if (!si->pcm_fp) goto err;
free(eet_vio);
eet_vio = NULL;
if (!remix_init_resampler_data(env, sndfile)) goto err;
si->out_generated = 0;
return sndfile;
err:
if (eet_vio) free(eet_vio);
remix_set_error(env, REMIX_ERROR_SYSTEM);
remix_destroy(env, (RemixBase *)sndfile);
return RemixNone;
}
static RemixBase *
remix_eet_sndfile_reader_init(RemixEnv *env, RemixBase *base, CDSet *parameters)
{
char *file_path, *sound_id;
double speed;
file_path = (cd_set_find(env, parameters, PATH_KEY)).s_string;
sound_id = (cd_set_find(env, parameters, SOUND_ID_KEY)).s_string;
speed = (cd_set_find(env, parameters, SPEED_KEY)).s_double;
if (!remix_eet_sndfile_create(env, base, file_path, sound_id, speed))
return RemixNone;
remix_eet_sndfile_optimise (env, base);
return base;
}
static RemixBase *
remix_eet_sndfile_clone(RemixEnv *env, RemixBase *base)
{
SndInstanceData *si = remix_base_get_instance_data(env, base);
RemixBase *new_sndfile = remix_base_new(env);
remix_eet_sndfile_create(env, new_sndfile, si->path, si->sound_id, si->speed);
remix_eet_sndfile_optimise(env, new_sndfile);
return new_sndfile;
}
static int
remix_eet_sndfile_destroy(RemixEnv *env, RemixBase *base)
{
SndInstanceData *si = remix_base_get_instance_data(env, base);
if (si)
{
sf_close (si->pcm_fp);
eet_close(si->efp);
if (si->path) free(si->path);
if (si->sound_id) free(si->sound_id);
if (si->snd_info) free(si->snd_info);
if (si->efp) eet_close(si->efp);
if (si->inbuf) free(si->inbuf);
if (si->outbuf) free(si->outbuf);
if (si->vio_data) free(si->vio_data);
free(si);
}
if (base) free (base);
return 0;
}
static int
remix_pcm_resample(SndInstanceData *si)
{
RemixPCM *src, *dst, *srcbase;
int i = 0, in_samples, pos, total, chnum, reqsamp, avail;
int interp = 1;
dst = si->outbuf + (si->out_generated * 2);
in_samples = (double)si->required_resamples / si->rs_ratio;
chnum = si->snd_info->channels;
reqsamp = si->required_resamples;
avail = si->in_avail;
srcbase = si->readbuf;
if ((interp) && (si->rs_ratio >= 1.0))
{
// linear interpolation of resampling for lower quality samples
// so they don't get high requency aliasing effects
for (i = 0; i < reqsamp; i++)
{
float fpos, fpos1;
RemixPCM psam[2];
fpos = (float)(i * in_samples) / (float)reqsamp;
pos = fpos;
if (pos >= avail) break;
fpos -= pos;
fpos1 = 1.0 - fpos;
src = srcbase + (pos * chnum);
if (chnum == 2)
{
if (i == 0)
{
psam[0] = si->prevreadbuf[0];
psam[1] = si->prevreadbuf[1];
}
else
{
psam[0] = src[0 - 2];
psam[1] = src[1 - 2];
}
*dst++ = (src[0] * fpos) + (psam[0] * fpos1);
*dst++ = (src[1] * fpos) + (psam[1] * fpos1);
}
else
{
if (i == 0)
psam[0] = si->prevreadbuf[0];
else
psam[0] = src[0 - 1];
*dst++ = (src[0] * fpos) + (psam[0] * fpos1);
}
}
}
else
{
// simple sample-picking/nearest. faster and simpler
for (i = 0; i < reqsamp; i++)
{
pos = (i * in_samples) / reqsamp;
if (pos >= avail) break;
src = srcbase + (pos * chnum);
if (chnum == 2)
{
*dst++ = src[0];
*dst++ = src[1];
}
else
*dst++ = src[0];
}
}
si->out_generated += i;
total = (i * in_samples) / reqsamp;
si->readbuf += total * chnum;
si->in_avail -= total;
return total;
}
/* An RemixChunkFunc for creating sndfile */
static RemixCount
remix_eet_sndfile_read_update(RemixEnv *env, RemixBase *sndfile, RemixCount count)
{
SndInstanceData *si = remix_base_get_instance_data(env, sndfile);
si->out_generated = 0;
if (si->enable_resample)
{
RemixCount gen = 0;
while (gen < count)
{
if (si->in_avail <= 0)
{
si->in_avail = sf_readf_float(si->pcm_fp, si->inbuf, BLOCK_FRAMES);
si->readbuf = si->inbuf;
}
si->required_resamples = (count - gen);
remix_pcm_resample(si);
if (si->snd_info->channels == 2)
{
si->prevreadbuf[0] = si->readbuf[-2];
si->prevreadbuf[1] = si->readbuf[-1];
}
else
{
si->prevreadbuf[0] = si->readbuf[-1];
}
gen += si->out_generated;
}
si->out_generated = gen;
}
else
{
si->out_generated = sf_readf_float(si->pcm_fp, si->outbuf, count);
}
return si->out_generated;
}
static RemixCount
remix_eet_sndfile_read_into_chunk(RemixEnv *env, RemixChunk *chunk, RemixCount offset, RemixCount count, int channelname, void *data)
{
RemixBase *sndfile = data;
SndInstanceData *si = remix_base_get_instance_data(env, sndfile);
RemixPCM *d, *p;
RemixCount remaining = count, written = 0, n, i;
d = &chunk->data[offset];
n = MIN(remaining, BLOCK_FRAMES);
// Need parameter support to advance the data reading
if (channelname == 0)
remix_eet_sndfile_read_update(env, sndfile, n);
n = MIN(si->out_generated, remaining);
p = si->outbuf;
if (si->snd_info->channels > 1) p += channelname;
for (i = 0; i < n; i++)
{
*d++ = *p;
p += si->snd_info->channels;
}
if (n == 0) n = _remix_pcm_set(d, 0.0, remaining);
remaining -= n;
written += n;
return written;
}
static RemixCount
remix_eet_sndfile_reader_process(RemixEnv *env, RemixBase *base, RemixCount count, RemixStream *input __UNUSED__, RemixStream *output)
{
return remix_stream_chunkfuncify(env, output, count,
remix_eet_sndfile_read_into_chunk,
base);
}
static RemixCount
remix_eet_sndfile_length(RemixEnv *env, RemixBase *base)
{
SndInstanceData *si = remix_base_get_instance_data(env, base);
return si->resample_len;
}
static RemixCount
remix_eet_sndfile_seek(RemixEnv *env, RemixBase *base, RemixCount offset)
{
SndInstanceData *si = remix_base_get_instance_data(env, base);
return sf_seek(si->pcm_fp, offset, SEEK_SET);
}
static struct _RemixMethods _remix_eet_sndfile_reader_methods =
{
remix_eet_sndfile_clone,
remix_eet_sndfile_destroy,
NULL, /* ready */
NULL, /* prepare */
remix_eet_sndfile_reader_process,
remix_eet_sndfile_length,
remix_eet_sndfile_seek,
NULL, /* flush */
};
static RemixBase *
remix_eet_sndfile_optimise(RemixEnv *env, RemixBase *sndfile)
{
remix_base_set_methods(env, sndfile, &_remix_eet_sndfile_reader_methods);
return sndfile;
}
static struct _RemixParameterScheme path_scheme =
{
"path",
"Path to sound file",
REMIX_TYPE_STRING,
REMIX_CONSTRAINT_TYPE_NONE,
{NULL},
REMIX_HINT_FILENAME,
};
static struct _RemixParameterScheme sound_id_scheme =
{
"sound_id",
"Sound Id (Key) inside EET",
REMIX_TYPE_STRING,
REMIX_CONSTRAINT_TYPE_NONE,
{NULL},
REMIX_HINT_DEFAULT,
};
static struct _RemixParameterScheme speed_scheme =
{
"speed",
"Sound Play Speed",
REMIX_TYPE_FLOAT,
REMIX_CONSTRAINT_TYPE_NONE,
{NULL},
REMIX_HINT_DEFAULT,
};
static struct _RemixMetaText eet_sndfile_reader_metatext =
{
"eet_sndfile_reader",
"File:: Sound file Reader from EET",
"Reads PCM audio files from EET bundle using libsndfile",
"Copyright (C) 2011, Samsung Electronics Co., Ltd.",
"http://www.samsung.com",
REMIX_ONE_AUTHOR ("govi.sm@samsung.com", "prince.dubey@samsung.com"),
};
static struct _RemixPlugin eet_sndfile_reader_plugin =
{
&eet_sndfile_reader_metatext,
REMIX_FLAGS_NONE,
CD_EMPTY_SET, /* init scheme */
remix_eet_sndfile_reader_init,
CD_EMPTY_SET, /* process scheme */
NULL, /* suggests */
NULL, /* plugin data */
NULL /* destroy */
};
EAPI CDList *
remix_load(RemixEnv *env)
{
CDList *plugins = cd_list_new(env);
eet_sndfile_reader_plugin.init_scheme =
cd_set_insert(env, eet_sndfile_reader_plugin.init_scheme, PATH_KEY,
CD_POINTER(&path_scheme));
eet_sndfile_reader_plugin.init_scheme =
cd_set_insert(env, eet_sndfile_reader_plugin.init_scheme, SOUND_ID_KEY,
CD_POINTER(&sound_id_scheme));
eet_sndfile_reader_plugin.init_scheme =
cd_set_insert(env, eet_sndfile_reader_plugin.init_scheme, SPEED_KEY,
CD_POINTER(&speed_scheme));
plugins = cd_list_prepend(env, plugins,
CD_POINTER(&eet_sndfile_reader_plugin));
return plugins;
}

View File

@ -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

View File

@ -0,0 +1,33 @@
#include "config.h"
#include <edje_private.h>
#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;
}