diff options
Diffstat (limited to 'libraries/edje/src/lib/edje_multisense.c')
-rw-r--r-- | libraries/edje/src/lib/edje_multisense.c | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/libraries/edje/src/lib/edje_multisense.c b/libraries/edje/src/lib/edje_multisense.c new file mode 100644 index 0000000..f9c7f91 --- /dev/null +++ b/libraries/edje/src/lib/edje_multisense.c | |||
@@ -0,0 +1,408 @@ | |||
1 | #include "config.h" | ||
2 | #include <string.h> | ||
3 | #include <fcntl.h> | ||
4 | #include <Eina.h> | ||
5 | #include <Edje.h> | ||
6 | #include "edje_private.h" | ||
7 | |||
8 | typedef struct _Multisense_Data | ||
9 | { | ||
10 | Edje_Multisense_Env *msenv; | ||
11 | #ifdef HAVE_LIBREMIX | ||
12 | RemixDeck *deck; | ||
13 | RemixTrack *track; | ||
14 | RemixLayer *snd_layer, *player_layer; | ||
15 | RemixBase *player; | ||
16 | RemixBase *player_snd; | ||
17 | int remaining; | ||
18 | int offset; | ||
19 | Eina_List *snd_src_list; | ||
20 | |||
21 | MULTISENSE_SOUND_PLAYER_GET_FUNC multisense_sound_player_get; | ||
22 | #endif | ||
23 | }Multisense_Data; | ||
24 | |||
25 | #define BUF_LEN 64 | ||
26 | #define SND_PROCESS_LENGTH 2048 | ||
27 | |||
28 | #ifdef HAVE_LIBREMIX | ||
29 | static Ecore_Thread *player_thread = NULL; | ||
30 | static int command_pipe[2]; | ||
31 | static Eina_Bool pipe_initialized = EINA_FALSE; | ||
32 | #endif | ||
33 | |||
34 | typedef enum _Edje_Sound_Action_Type | ||
35 | { | ||
36 | EDJE_PLAY_SAMPLE = 0, | ||
37 | EDJE_PLAY_TONE, | ||
38 | /* | ||
39 | EDJE_PLAY_PATTERN, | ||
40 | EDJE_PLAY_INSTRUMENT, | ||
41 | EDJE_PLAY_SONG, | ||
42 | */ | ||
43 | EDJE_SOUND_LAST | ||
44 | } Edje_Sound_Action_Type; | ||
45 | |||
46 | typedef struct _Edje_Sample_Action Edje_Sample_Action; | ||
47 | typedef struct _Edje_Tone_Action Edje_Tone_Action; | ||
48 | typedef struct _Edje_Multisense_Sound_Action Edje_Multisense_Sound_Action; | ||
49 | |||
50 | struct _Edje_Sample_Action | ||
51 | { | ||
52 | char sample_name[BUF_LEN]; | ||
53 | double speed; | ||
54 | }; | ||
55 | |||
56 | struct _Edje_Tone_Action | ||
57 | { | ||
58 | char tone_name[BUF_LEN]; | ||
59 | double duration; | ||
60 | }; | ||
61 | |||
62 | struct _Edje_Multisense_Sound_Action | ||
63 | { | ||
64 | Edje *ed; | ||
65 | Edje_Sound_Action_Type action; | ||
66 | union { | ||
67 | Edje_Sample_Action sample; | ||
68 | Edje_Tone_Action tone; | ||
69 | } type; | ||
70 | }; | ||
71 | |||
72 | #ifdef HAVE_LIBREMIX | ||
73 | static Multisense_Data * | ||
74 | init_multisense_environment(void) | ||
75 | { | ||
76 | Multisense_Data *msdata; | ||
77 | char ms_factory[BUF_LEN]; | ||
78 | char *ms_factory_env; | ||
79 | Eina_Module *m = NULL; | ||
80 | MULTISENSE_FACTORY_INIT_FUNC multisense_factory_init; | ||
81 | |||
82 | msdata = calloc(1, sizeof(Multisense_Data)); | ||
83 | if (!msdata) goto err; | ||
84 | |||
85 | msdata->msenv = calloc(1, sizeof(Edje_Multisense_Env)); | ||
86 | if (!msdata->msenv) goto err; | ||
87 | |||
88 | ms_factory_env = getenv("MULTISENSE_FACTORY"); | ||
89 | if (ms_factory_env) | ||
90 | strncpy(ms_factory, ms_factory_env, BUF_LEN); | ||
91 | else | ||
92 | strcpy(ms_factory, "multisense_factory"); | ||
93 | |||
94 | m = _edje_module_handle_load(ms_factory); | ||
95 | if (!m) goto err; | ||
96 | |||
97 | msdata->msenv->remixenv = remix_init(); | ||
98 | |||
99 | multisense_factory_init = | ||
100 | eina_module_symbol_get(m, "multisense_factory_init"); | ||
101 | if (multisense_factory_init) multisense_factory_init(msdata->msenv); | ||
102 | |||
103 | msdata->multisense_sound_player_get = | ||
104 | eina_module_symbol_get(m, "multisense_sound_player_get"); | ||
105 | if (!msdata->multisense_sound_player_get) goto err; | ||
106 | |||
107 | msdata->deck = remix_deck_new(msdata->msenv->remixenv); | ||
108 | msdata->track = remix_track_new(msdata->msenv->remixenv, msdata->deck); | ||
109 | msdata->snd_layer = remix_layer_new_ontop(msdata->msenv->remixenv, | ||
110 | msdata->track, | ||
111 | REMIX_TIME_SAMPLES); | ||
112 | msdata->player_layer = remix_layer_new_ontop(msdata->msenv->remixenv, | ||
113 | msdata->track, | ||
114 | REMIX_TIME_SAMPLES); | ||
115 | msdata->player = msdata->multisense_sound_player_get(msdata->msenv); | ||
116 | if (!msdata->player) goto err; | ||
117 | msdata->player_snd = remix_sound_new(msdata->msenv->remixenv, | ||
118 | msdata->player, msdata->player_layer, | ||
119 | REMIX_SAMPLES(0), | ||
120 | REMIX_SAMPLES(REMIX_COUNT_INFINITE)); | ||
121 | return msdata; | ||
122 | |||
123 | err: | ||
124 | if (msdata) | ||
125 | { | ||
126 | if (msdata->deck) remix_destroy(msdata->msenv->remixenv, msdata->deck); | ||
127 | if (msdata->msenv->remixenv) remix_purge(msdata->msenv->remixenv); | ||
128 | if (msdata->msenv) free(msdata->msenv); | ||
129 | free(msdata); | ||
130 | } | ||
131 | return NULL; | ||
132 | } | ||
133 | #endif | ||
134 | |||
135 | #ifdef HAVE_LIBREMIX | ||
136 | static RemixBase * | ||
137 | eet_sound_reader_get(Edje_Multisense_Env *msenv, const char *path, const char *sound_id, const double speed) | ||
138 | { | ||
139 | RemixPlugin *sf_plugin = NULL; | ||
140 | RemixBase * eet_snd_reader = NULL; | ||
141 | int sf_path_key = 0; | ||
142 | int sf_sound_id_key = 0; | ||
143 | int sf_speed_key = 0; | ||
144 | CDSet *sf_parms = NULL; | ||
145 | RemixEnv *env = msenv->remixenv; | ||
146 | |||
147 | if (sf_plugin == NULL) | ||
148 | { | ||
149 | sf_plugin = remix_find_plugin(env, "eet_sndfile_reader"); | ||
150 | if (sf_plugin == NULL) | ||
151 | { | ||
152 | ERR ("Multisense EET Sound reader plugin NULL\n"); | ||
153 | return NULL; | ||
154 | } | ||
155 | |||
156 | sf_path_key = remix_get_init_parameter_key(env, sf_plugin, "path"); | ||
157 | sf_sound_id_key = remix_get_init_parameter_key(env, sf_plugin, "sound_id"); | ||
158 | sf_speed_key = remix_get_init_parameter_key(env, sf_plugin, "speed"); | ||
159 | } | ||
160 | sf_parms = cd_set_replace(env, sf_parms, sf_path_key, CD_STRING(path)); | ||
161 | sf_parms = cd_set_replace(env, sf_parms, sf_sound_id_key, CD_STRING(sound_id)); | ||
162 | sf_parms = cd_set_replace(env, sf_parms, sf_speed_key, CD_DOUBLE(speed)); | ||
163 | eet_snd_reader = remix_new(env, sf_plugin, sf_parms); | ||
164 | |||
165 | return eet_snd_reader; | ||
166 | } | ||
167 | |||
168 | |||
169 | static RemixBase * | ||
170 | edje_remix_sample_create(Multisense_Data *msdata, Edje*ed, Edje_Sample_Action *action) | ||
171 | { | ||
172 | RemixBase *remix_snd = NULL; | ||
173 | Edje_Sound_Sample *sample; | ||
174 | int i; | ||
175 | char snd_id_str[16]; | ||
176 | |||
177 | if ((!ed) || (!ed->file) || (!ed->file->sound_dir)) | ||
178 | return NULL; | ||
179 | |||
180 | for (i = 0; i < (int)ed->file->sound_dir->samples_count; i++) | ||
181 | { | ||
182 | sample = &ed->file->sound_dir->samples[i]; | ||
183 | if (!strcmp(sample->name, action->sample_name)) | ||
184 | { | ||
185 | snprintf(snd_id_str, sizeof(snd_id_str), "edje/sounds/%i", sample->id); | ||
186 | remix_snd = eet_sound_reader_get(msdata->msenv, ed->file->path, | ||
187 | snd_id_str, action->speed); | ||
188 | break; | ||
189 | } | ||
190 | } | ||
191 | return remix_snd; | ||
192 | } | ||
193 | |||
194 | static RemixBase * | ||
195 | edje_remix_tone_create(Multisense_Data *msdata, Edje*ed, Edje_Tone_Action *action) | ||
196 | { | ||
197 | Edje_Sound_Tone *tone; | ||
198 | RemixSquareTone *square = NULL; | ||
199 | unsigned int i; | ||
200 | |||
201 | if ((!ed) || (!ed->file) || (!ed->file->sound_dir)) | ||
202 | return NULL; | ||
203 | |||
204 | for (i = 0; i < ed->file->sound_dir->tones_count; i++) | ||
205 | { | ||
206 | tone = &ed->file->sound_dir->tones[i]; | ||
207 | if (!strcmp(tone->name, action->tone_name)) | ||
208 | { | ||
209 | square = remix_squaretone_new (msdata->msenv->remixenv, tone->value); | ||
210 | break; | ||
211 | } | ||
212 | } | ||
213 | return square; | ||
214 | } | ||
215 | |||
216 | static void | ||
217 | sound_command_handler(Multisense_Data *msdata) | ||
218 | { | ||
219 | RemixCount length; | ||
220 | Edje_Multisense_Sound_Action command; | ||
221 | RemixBase *base = NULL; | ||
222 | RemixBase *sound; | ||
223 | |||
224 | if (read(command_pipe[0], &command, sizeof(command)) <= 0) return; | ||
225 | switch (command.action) | ||
226 | { | ||
227 | case EDJE_PLAY_SAMPLE: | ||
228 | base = edje_remix_sample_create(msdata, command.ed, | ||
229 | &command.type.sample); | ||
230 | length = remix_length(msdata->msenv->remixenv, base); | ||
231 | break; | ||
232 | case EDJE_PLAY_TONE: | ||
233 | base = edje_remix_tone_create(msdata, command.ed, &command.type.tone); | ||
234 | length = (command.type.tone.duration * | ||
235 | remix_get_samplerate(msdata->msenv->remixenv)); | ||
236 | break; | ||
237 | default: | ||
238 | ERR("Invalid Sound Play Command\n"); | ||
239 | break; | ||
240 | } | ||
241 | if (base) | ||
242 | { | ||
243 | sound = remix_sound_new(msdata->msenv->remixenv, base, msdata->snd_layer, | ||
244 | REMIX_SAMPLES(msdata->offset), | ||
245 | REMIX_SAMPLES(length)); | ||
246 | if (msdata->remaining < length) msdata->remaining = length; | ||
247 | msdata->snd_src_list = eina_list_append(msdata->snd_src_list, sound); | ||
248 | msdata->snd_src_list = eina_list_append(msdata->snd_src_list, base); | ||
249 | } | ||
250 | } | ||
251 | #endif | ||
252 | |||
253 | #ifdef HAVE_LIBREMIX | ||
254 | // msdata outside of thread due to thread issues in dlsym etc. | ||
255 | static Multisense_Data *msdata = NULL; | ||
256 | |||
257 | static void | ||
258 | _msdata_free(void) | ||
259 | { | ||
260 | // cleanup msdata outside of thread due to thread issues in dlsym etc. | ||
261 | if (!msdata) return; | ||
262 | //cleanup Remix stuffs | ||
263 | remix_destroy(msdata->msenv->remixenv, msdata->player); | ||
264 | remix_destroy(msdata->msenv->remixenv, msdata->deck); | ||
265 | remix_purge(msdata->msenv->remixenv); | ||
266 | |||
267 | free(msdata->msenv); | ||
268 | free(msdata); | ||
269 | msdata = NULL; | ||
270 | } | ||
271 | |||
272 | static void | ||
273 | _player_job(void *data __UNUSED__, Ecore_Thread *th) | ||
274 | { | ||
275 | fd_set wait_fds; | ||
276 | RemixBase *sound; | ||
277 | RemixCount process_len; | ||
278 | // disable and move outside of thread due to dlsym etc. thread issues | ||
279 | // Multisense_Data * msdata = init_multisense_environment(); | ||
280 | |||
281 | if (!msdata) return; | ||
282 | |||
283 | fcntl(command_pipe[0], F_SETFL, O_NONBLOCK); | ||
284 | FD_ZERO(&wait_fds); | ||
285 | FD_SET(command_pipe[0], &wait_fds); | ||
286 | |||
287 | while (!ecore_thread_check(th)) | ||
288 | { | ||
289 | if (!msdata->remaining) | ||
290 | { | ||
291 | //Cleanup already played sound sources | ||
292 | EINA_LIST_FREE(msdata->snd_src_list, sound) | ||
293 | { | ||
294 | remix_destroy(msdata->msenv->remixenv, sound); | ||
295 | } | ||
296 | //wait for new sound | ||
297 | select(command_pipe[0] + 1, &wait_fds, NULL, NULL, 0); | ||
298 | } | ||
299 | //read sound command , if any | ||
300 | sound_command_handler(msdata); | ||
301 | process_len = MIN(msdata->remaining, SND_PROCESS_LENGTH); | ||
302 | remix_process(msdata->msenv->remixenv, msdata->deck, process_len, | ||
303 | RemixNone, RemixNone); | ||
304 | msdata->offset += process_len; | ||
305 | msdata->remaining -= process_len; | ||
306 | } | ||
307 | |||
308 | //Cleanup last played sound sources | ||
309 | EINA_LIST_FREE(msdata->snd_src_list, sound) | ||
310 | { | ||
311 | remix_destroy(msdata->msenv->remixenv, sound); | ||
312 | } | ||
313 | |||
314 | close(command_pipe[0]); | ||
315 | close(command_pipe[1]); | ||
316 | } | ||
317 | #endif | ||
318 | |||
319 | #ifdef HAVE_LIBREMIX | ||
320 | static void | ||
321 | _player_cancel(void *data __UNUSED__, Ecore_Thread *th __UNUSED__) | ||
322 | { | ||
323 | // cleanup msdata outside of thread due to thread issues in dlsym etc. | ||
324 | _msdata_free(); | ||
325 | player_thread = NULL; | ||
326 | } | ||
327 | #endif | ||
328 | |||
329 | #ifdef HAVE_LIBREMIX | ||
330 | static void | ||
331 | _player_end(void *data __UNUSED__, Ecore_Thread *th __UNUSED__) | ||
332 | { | ||
333 | // cleanup msdata outside of thread due to thread issues in dlsym etc. | ||
334 | _msdata_free(); | ||
335 | player_thread = NULL; | ||
336 | } | ||
337 | #endif | ||
338 | |||
339 | Eina_Bool | ||
340 | _edje_multisense_internal_sound_sample_play(Edje *ed, const char *sample_name, const double speed) | ||
341 | { | ||
342 | ssize_t size = 0; | ||
343 | #ifdef ENABLE_MULTISENSE | ||
344 | Edje_Multisense_Sound_Action command; | ||
345 | |||
346 | if ((!pipe_initialized) && (!player_thread)) return EINA_FALSE; | ||
347 | |||
348 | command.action = EDJE_PLAY_SAMPLE; | ||
349 | command.ed = ed; | ||
350 | strncpy(command.type.sample.sample_name, sample_name, BUF_LEN); | ||
351 | command.type.sample.speed = speed; | ||
352 | size = write(command_pipe[1], &command, sizeof(command)); | ||
353 | #else | ||
354 | ed = NULL; // warning shh | ||
355 | if (speed > 0) sample_name = NULL; // warning shh | ||
356 | #endif | ||
357 | return (size == sizeof(Edje_Multisense_Sound_Action)); | ||
358 | } | ||
359 | |||
360 | Eina_Bool | ||
361 | _edje_multisense_internal_sound_tone_play(Edje *ed, const char *tone_name, const double duration) | ||
362 | { | ||
363 | ssize_t size = 0; | ||
364 | #ifdef ENABLE_MULTISENSE | ||
365 | Edje_Multisense_Sound_Action command; | ||
366 | |||
367 | if ((!pipe_initialized) && (!player_thread)) return EINA_FALSE; | ||
368 | command.action = EDJE_PLAY_TONE; | ||
369 | command.ed = ed; | ||
370 | strncpy(command.type.tone.tone_name, tone_name, BUF_LEN); | ||
371 | command.type.tone.duration = duration; | ||
372 | size = write(command_pipe[1], &command, sizeof(command)); | ||
373 | #else | ||
374 | ed = NULL; // warning shh | ||
375 | if (duration > 0) tone_name = NULL; // warning shh | ||
376 | #endif | ||
377 | return (size == sizeof(Edje_Multisense_Sound_Action)); | ||
378 | |||
379 | } | ||
380 | |||
381 | /* Initialize the modules in main thread. to avoid dlopen issue in the Threads */ | ||
382 | void | ||
383 | _edje_multisense_init(void) | ||
384 | { | ||
385 | #ifdef ENABLE_MULTISENSE | ||
386 | if (!pipe_initialized && (pipe(command_pipe) != -1)) | ||
387 | pipe_initialized = EINA_TRUE; | ||
388 | |||
389 | // init msdata outside of thread due to thread issues in dlsym etc. | ||
390 | if (!msdata) msdata = init_multisense_environment(); | ||
391 | |||
392 | if (!player_thread) | ||
393 | player_thread = ecore_thread_run(_player_job, _player_end, _player_cancel, NULL); | ||
394 | #endif | ||
395 | } | ||
396 | |||
397 | void | ||
398 | _edje_multisense_shutdown(void) | ||
399 | { | ||
400 | #ifdef ENABLE_MULTISENSE | ||
401 | if (pipe_initialized) | ||
402 | { | ||
403 | close(command_pipe[1]); | ||
404 | close(command_pipe[0]); | ||
405 | } | ||
406 | if (player_thread) ecore_thread_cancel(player_thread); | ||
407 | #endif | ||
408 | } | ||