aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/edje/src/modules/eet_snd_reader/eet_snd_reader.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/edje/src/modules/eet_snd_reader/eet_snd_reader.c')
-rw-r--r--libraries/edje/src/modules/eet_snd_reader/eet_snd_reader.c498
1 files changed, 498 insertions, 0 deletions
diff --git a/libraries/edje/src/modules/eet_snd_reader/eet_snd_reader.c b/libraries/edje/src/modules/eet_snd_reader/eet_snd_reader.c
new file mode 100644
index 0000000..4e2dec9
--- /dev/null
+++ b/libraries/edje/src/modules/eet_snd_reader/eet_snd_reader.c
@@ -0,0 +1,498 @@
1/*
2 * RemixSnd_eetfile: a libsnd EET Virtual file handler
3 *
4 * Govindaraju SM <govi.sm@samsung.com>, August 2011
5 * Prince Kumar Dubey <prince.dubey@samsung.com>, August 2011
6 */
7
8#include "config.h"
9#include <math.h>
10#include <sndfile.h>
11#include <remix/remix.h>
12#include <Eet.h>
13
14#define PATH_KEY 1
15#define SOUND_ID_KEY 2
16#define SPEED_KEY 3
17#define BLOCK_FRAMES 8192
18
19static RemixBase *remix_eet_sndfile_optimise(RemixEnv *env, RemixBase *sndfile);
20
21typedef struct _VIO_DATA VIO_DATA;
22typedef struct _SndInstanceData SndInstanceData;
23
24struct _VIO_DATA
25{
26 sf_count_t offset, length;
27 const char *data;
28};
29
30struct _SndInstanceData
31{
32 /* plugin parameters */
33 char *path;
34 char *sound_id;
35 double speed;
36
37 /* Edj & Sndfile Reader */
38 Eet_File *efp;
39 SNDFILE *pcm_fp;
40 SF_INFO *snd_info;
41 VIO_DATA *vio_data;
42
43 /* PCM buffers */
44 RemixPCM *readbuf;
45 RemixPCM *inbuf;
46 RemixPCM *outbuf;
47
48 /* Resample stuffs */
49 RemixPCM prevreadbuf[2];
50 int enable_resample;
51 double rs_ratio;
52 RemixCount resample_len;
53 RemixCount in_avail;
54 RemixCount out_generated;
55 RemixCount required_resamples;
56};
57
58static sf_count_t
59eet_snd_file_get_length(void *user_data)
60{
61 VIO_DATA *vf = user_data;
62 return vf->length;
63}
64
65static sf_count_t
66eet_snd_file_seek(sf_count_t offset, int whence, void *user_data)
67{
68 VIO_DATA *vf = user_data;
69
70 switch (whence)
71 {
72 case SEEK_SET:
73 vf->offset = offset;
74 break;
75 case SEEK_CUR:
76 vf->offset += offset;
77 break;
78 case SEEK_END:
79 vf->offset = vf->length + offset;
80 break;
81 default:
82 break;
83 }
84 return vf->offset;
85}
86
87static sf_count_t
88eet_snd_file_read(void *ptr, sf_count_t count, void *user_data)
89{
90 VIO_DATA *vf = user_data;
91
92 if ((vf->offset + count) > vf->length)
93 count = vf->length - vf->offset;
94 memcpy(ptr, vf->data + vf->offset, count);
95 vf->offset += count;
96 return count;
97}
98
99static sf_count_t
100eet_snd_file_tell(void *user_data)
101{
102 VIO_DATA *vf = user_data;
103 return vf->offset;
104}
105
106static int
107remix_init_resampler_data(RemixEnv *env, RemixBase *base)
108{
109 SndInstanceData *si = remix_base_get_instance_data(env, base);
110
111 si->rs_ratio = remix_get_samplerate(env) / si->snd_info->samplerate;
112 si->rs_ratio /= si->speed;
113 si->resample_len = (si->snd_info->frames * si->rs_ratio);
114
115 si->outbuf = malloc(sizeof(RemixPCM) * BLOCK_FRAMES * 2);
116 if (!si->outbuf) return 0;
117 if ((si->rs_ratio == 1.0)/* && (si->snd_info->channels == 2)*/)
118 {
119 si->enable_resample = 0;
120 return 1;
121 }
122 else
123 si->enable_resample = 1;
124
125 si->in_avail = 0;
126 si->out_generated = 0;
127 si->inbuf = malloc(sizeof(RemixPCM) * BLOCK_FRAMES *
128 si->snd_info->channels);
129 if (!si->inbuf) return 0;
130 return 1;
131}
132
133static RemixBase *
134remix_eet_sndfile_create(RemixEnv *env, RemixBase *sndfile, const char *path, const char *sound_id, const double speed)
135{
136 SF_VIRTUAL_IO *eet_vio = NULL;
137 SndInstanceData *si;
138 const void *sound_data;
139 int sound_size;
140
141 if ((!path) || (!sound_id)) return NULL;
142
143 si = calloc(1, sizeof(SndInstanceData));
144 if (!si) goto err;
145 remix_base_set_instance_data(env, sndfile, si);
146
147 si->path = strdup(path);
148 si->sound_id = strdup(sound_id);
149 si->speed = speed;
150
151 si->efp = eet_open(path, EET_FILE_MODE_READ);
152 if (!si->efp) goto err;
153
154 // xxx: eet_read_direct does not work on Threads, using eet_read.
155 sound_data = eet_read(si->efp, sound_id, &(sound_size));
156 eet_close(si->efp);
157 si->efp = NULL;
158 if (sound_data == NULL) goto err;
159
160 eet_vio = calloc(1, sizeof(SF_VIRTUAL_IO));
161 if (!eet_vio) goto err;
162
163 /* Set up func pointers to read snd file directly from EET. */
164 eet_vio->get_filelen = eet_snd_file_get_length;
165 eet_vio->seek = eet_snd_file_seek;
166 eet_vio->read = eet_snd_file_read;
167 eet_vio->tell = eet_snd_file_tell;
168
169 si->vio_data = calloc(1, sizeof(VIO_DATA));
170 if (!si->vio_data) goto err;
171 si->vio_data->offset = 0;
172 si->vio_data->length = sound_size;
173 si->vio_data->data = sound_data;
174
175 si->snd_info = calloc(1, sizeof(SF_INFO));
176 if (!si->snd_info) goto err;
177
178 si->pcm_fp = sf_open_virtual(eet_vio, SFM_READ, si->snd_info, si->vio_data);
179 if (!si->pcm_fp) goto err;
180 free(eet_vio);
181 eet_vio = NULL;
182
183 if (!remix_init_resampler_data(env, sndfile)) goto err;
184 si->out_generated = 0;
185
186 return sndfile;
187
188err:
189 if (eet_vio) free(eet_vio);
190 remix_set_error(env, REMIX_ERROR_SYSTEM);
191 remix_destroy(env, (RemixBase *)sndfile);
192 return RemixNone;
193}
194
195static RemixBase *
196remix_eet_sndfile_reader_init(RemixEnv *env, RemixBase *base, CDSet *parameters)
197{
198 char *file_path, *sound_id;
199 double speed;
200
201 file_path = (cd_set_find(env, parameters, PATH_KEY)).s_string;
202 sound_id = (cd_set_find(env, parameters, SOUND_ID_KEY)).s_string;
203 speed = (cd_set_find(env, parameters, SPEED_KEY)).s_double;
204
205 if (!remix_eet_sndfile_create(env, base, file_path, sound_id, speed))
206 return RemixNone;
207 remix_eet_sndfile_optimise (env, base);
208 return base;
209}
210
211static RemixBase *
212remix_eet_sndfile_clone(RemixEnv *env, RemixBase *base)
213{
214 SndInstanceData *si = remix_base_get_instance_data(env, base);
215 RemixBase *new_sndfile = remix_base_new(env);
216
217 remix_eet_sndfile_create(env, new_sndfile, si->path, si->sound_id, si->speed);
218 remix_eet_sndfile_optimise(env, new_sndfile);
219 return new_sndfile;
220}
221
222static int
223remix_eet_sndfile_destroy(RemixEnv *env, RemixBase *base)
224{
225 SndInstanceData *si = remix_base_get_instance_data(env, base);
226 if (si)
227 {
228 sf_close (si->pcm_fp);
229 eet_close(si->efp);
230 if (si->path) free(si->path);
231 if (si->sound_id) free(si->sound_id);
232 if (si->snd_info) free(si->snd_info);
233 if (si->efp) eet_close(si->efp);
234 if (si->inbuf) free(si->inbuf);
235 if (si->outbuf) free(si->outbuf);
236 if (si->vio_data) free(si->vio_data);
237 free(si);
238 }
239 if (base) free (base);
240 return 0;
241}
242
243static int
244remix_pcm_resample(SndInstanceData *si)
245{
246 RemixPCM *src, *dst, *srcbase;
247 int i = 0, in_samples, pos, total, chnum, reqsamp, avail;
248 int interp = 1;
249
250 dst = si->outbuf + (si->out_generated * 2);
251 in_samples = (double)si->required_resamples / si->rs_ratio;
252 chnum = si->snd_info->channels;
253 reqsamp = si->required_resamples;
254 avail = si->in_avail;
255 srcbase = si->readbuf;
256 if ((interp) && (si->rs_ratio >= 1.0))
257 {
258 // linear interpolation of resampling for lower quality samples
259 // so they don't get high requency aliasing effects
260 for (i = 0; i < reqsamp; i++)
261 {
262 float fpos, fpos1;
263 RemixPCM psam[2];
264
265 fpos = (float)(i * in_samples) / (float)reqsamp;
266 pos = fpos;
267 if (pos >= avail) break;
268 fpos -= pos;
269 fpos1 = 1.0 - fpos;
270 src = srcbase + (pos * chnum);
271 if (chnum == 2)
272 {
273 if (pos == 0)
274 {
275 psam[0] = si->prevreadbuf[0];
276 psam[1] = si->prevreadbuf[1];
277 }
278 else
279 {
280 psam[0] = src[0 - 2];
281 psam[1] = src[1 - 2];
282 }
283 *dst++ = (src[0] * fpos) + (psam[0] * fpos1);
284 *dst++ = (src[1] * fpos) + (psam[1] * fpos1);
285 }
286 else
287 {
288 if (pos == 0)
289 psam[0] = si->prevreadbuf[0];
290 else
291 psam[0] = src[0 - 1];
292 *dst++ = (src[0] * fpos) + (psam[0] * fpos1);
293 }
294 }
295 }
296 else
297 {
298 // simple sample-picking/nearest. faster and simpler
299 for (i = 0; i < reqsamp; i++)
300 {
301 pos = (i * in_samples) / reqsamp;
302 if (pos >= avail) break;
303 src = srcbase + (pos * chnum);
304 if (chnum == 2)
305 {
306 *dst++ = src[0];
307 *dst++ = src[1];
308 }
309 else
310 *dst++ = src[0];
311 }
312 }
313 si->out_generated += i;
314 total = (i * in_samples) / reqsamp;
315 si->readbuf += total * chnum;
316 si->in_avail -= total;
317 return total;
318}
319
320/* An RemixChunkFunc for creating sndfile */
321static RemixCount
322remix_eet_sndfile_read_update(RemixEnv *env, RemixBase *sndfile, RemixCount count)
323{
324 SndInstanceData *si = remix_base_get_instance_data(env, sndfile);
325
326 si->out_generated = 0;
327 if (si->enable_resample)
328 {
329 RemixCount gen = 0;
330
331 while (gen < count)
332 {
333 if (si->in_avail <= 0)
334 {
335 si->in_avail = sf_readf_float(si->pcm_fp, si->inbuf, BLOCK_FRAMES);
336 si->readbuf = si->inbuf;
337 }
338 si->required_resamples = (count - gen);
339 remix_pcm_resample(si);
340 if (si->snd_info->channels == 2)
341 {
342 si->prevreadbuf[0] = si->readbuf[-2];
343 si->prevreadbuf[1] = si->readbuf[-1];
344 }
345 else
346 {
347 si->prevreadbuf[0] = si->readbuf[-1];
348 }
349 gen += si->out_generated;
350 }
351 si->out_generated = gen;
352 }
353 else
354 {
355 si->out_generated = sf_readf_float(si->pcm_fp, si->outbuf, count);
356 }
357 return si->out_generated;
358}
359
360static RemixCount
361remix_eet_sndfile_read_into_chunk(RemixEnv *env, RemixChunk *chunk, RemixCount offset, RemixCount count, int channelname, void *data)
362{
363 RemixBase *sndfile = data;
364 SndInstanceData *si = remix_base_get_instance_data(env, sndfile);
365 RemixPCM *d, *p;
366 RemixCount remaining = count, written = 0, n, i;
367
368 d = &chunk->data[offset];
369 n = MIN(remaining, BLOCK_FRAMES);
370 // Need parameter support to advance the data reading
371 if (channelname == 0)
372 remix_eet_sndfile_read_update(env, sndfile, n);
373 n = MIN(si->out_generated, remaining);
374 p = si->outbuf;
375 if (si->snd_info->channels > 1) p += channelname;
376 for (i = 0; i < n; i++)
377 {
378 *d++ = *p;
379 p += si->snd_info->channels;
380 }
381 if (n == 0) n = _remix_pcm_set(d, 0.0, remaining);
382 remaining -= n;
383 written += n;
384 return written;
385}
386
387static RemixCount
388remix_eet_sndfile_reader_process(RemixEnv *env, RemixBase *base, RemixCount count, RemixStream *input __UNUSED__, RemixStream *output)
389{
390 return remix_stream_chunkfuncify(env, output, count,
391 remix_eet_sndfile_read_into_chunk,
392 base);
393}
394
395static RemixCount
396remix_eet_sndfile_length(RemixEnv *env, RemixBase *base)
397{
398 SndInstanceData *si = remix_base_get_instance_data(env, base);
399 return si->resample_len;
400}
401
402static RemixCount
403remix_eet_sndfile_seek(RemixEnv *env, RemixBase *base, RemixCount offset)
404{
405 SndInstanceData *si = remix_base_get_instance_data(env, base);
406 return sf_seek(si->pcm_fp, offset, SEEK_SET);
407}
408
409static struct _RemixMethods _remix_eet_sndfile_reader_methods =
410{
411 remix_eet_sndfile_clone,
412 remix_eet_sndfile_destroy,
413 NULL, /* ready */
414 NULL, /* prepare */
415 remix_eet_sndfile_reader_process,
416 remix_eet_sndfile_length,
417 remix_eet_sndfile_seek,
418 NULL, /* flush */
419};
420
421static RemixBase *
422remix_eet_sndfile_optimise(RemixEnv *env, RemixBase *sndfile)
423{
424 remix_base_set_methods(env, sndfile, &_remix_eet_sndfile_reader_methods);
425 return sndfile;
426}
427
428static struct _RemixParameterScheme path_scheme =
429{
430 "path",
431 "Path to sound file",
432 REMIX_TYPE_STRING,
433 REMIX_CONSTRAINT_TYPE_NONE,
434 {NULL},
435 REMIX_HINT_FILENAME,
436};
437
438static struct _RemixParameterScheme sound_id_scheme =
439{
440 "sound_id",
441 "Sound Id (Key) inside EET",
442 REMIX_TYPE_STRING,
443 REMIX_CONSTRAINT_TYPE_NONE,
444 {NULL},
445 REMIX_HINT_DEFAULT,
446};
447
448static struct _RemixParameterScheme speed_scheme =
449{
450 "speed",
451 "Sound Play Speed",
452 REMIX_TYPE_FLOAT,
453 REMIX_CONSTRAINT_TYPE_NONE,
454 {NULL},
455 REMIX_HINT_DEFAULT,
456};
457
458static struct _RemixMetaText eet_sndfile_reader_metatext =
459{
460 "eet_sndfile_reader",
461 "File:: Sound file Reader from EET",
462 "Reads PCM audio files from EET bundle using libsndfile",
463 "Copyright (C) 2011, Samsung Electronics Co., Ltd.",
464 "http://www.samsung.com",
465 REMIX_ONE_AUTHOR ("govi.sm@samsung.com", "prince.dubey@samsung.com"),
466};
467
468static struct _RemixPlugin eet_sndfile_reader_plugin =
469{
470 &eet_sndfile_reader_metatext,
471 REMIX_FLAGS_NONE,
472 CD_EMPTY_SET, /* init scheme */
473 remix_eet_sndfile_reader_init,
474 CD_EMPTY_SET, /* process scheme */
475 NULL, /* suggests */
476 NULL, /* plugin data */
477 NULL /* destroy */
478};
479
480EAPI CDList *
481remix_load(RemixEnv *env)
482{
483 CDList *plugins = cd_list_new(env);
484
485 eet_sndfile_reader_plugin.init_scheme =
486 cd_set_insert(env, eet_sndfile_reader_plugin.init_scheme, PATH_KEY,
487 CD_POINTER(&path_scheme));
488 eet_sndfile_reader_plugin.init_scheme =
489 cd_set_insert(env, eet_sndfile_reader_plugin.init_scheme, SOUND_ID_KEY,
490 CD_POINTER(&sound_id_scheme));
491 eet_sndfile_reader_plugin.init_scheme =
492 cd_set_insert(env, eet_sndfile_reader_plugin.init_scheme, SPEED_KEY,
493 CD_POINTER(&speed_scheme));
494
495 plugins = cd_list_prepend(env, plugins,
496 CD_POINTER(&eet_sndfile_reader_plugin));
497 return plugins;
498}