ecore_audio: Add sndfile in- and output
authorDaniel Willmann <d.willmann@samsung.com>
Fri, 12 Apr 2013 16:45:12 +0000 (17:45 +0100)
committerDaniel Willmann <d.willmann@samsung.com>
Thu, 18 Apr 2013 18:12:17 +0000 (19:12 +0100)
Signed-off-by: Daniel Willmann <d.willmann@samsung.com>
src/Makefile_Ecore_Audio.am
src/lib/ecore_audio/ecore_audio_obj_in_sndfile.c [new file with mode: 0644]
src/lib/ecore_audio/ecore_audio_obj_in_sndfile.h [new file with mode: 0644]
src/lib/ecore_audio/ecore_audio_obj_out_sndfile.c [new file with mode: 0644]
src/lib/ecore_audio/ecore_audio_obj_out_sndfile.h [new file with mode: 0644]

index f19cae2..ad6a4d6 100644 (file)
@@ -10,6 +10,8 @@ lib/ecore_audio/Ecore_Audio.h \
 lib/ecore_audio/ecore_audio_obj.h \
 lib/ecore_audio/ecore_audio_obj_in.h \
 lib/ecore_audio/ecore_audio_obj_out.h \
+lib/ecore_audio/ecore_audio_obj_in_sndfile.h \
+lib/ecore_audio/ecore_audio_obj_out_sndfile.h \
 lib/ecore_audio/ecore_audio_protected.h
 
 
@@ -18,6 +20,8 @@ lib/ecore_audio/ecore_audio.c \
 lib/ecore_audio/ecore_audio_obj.c \
 lib/ecore_audio/ecore_audio_obj_in.c \
 lib/ecore_audio/ecore_audio_obj_out.c \
+lib/ecore_audio/ecore_audio_obj_in_sndfile.c \
+lib/ecore_audio/ecore_audio_obj_out_sndfile.c \
 lib/ecore_audio/ecore_audio_private.h
 
 lib_ecore_audio_libecore_audio_la_CPPFLAGS = @ECORE_AUDIO_CFLAGS@
diff --git a/src/lib/ecore_audio/ecore_audio_obj_in_sndfile.c b/src/lib/ecore_audio/ecore_audio_obj_in_sndfile.c
new file mode 100644 (file)
index 0000000..75eafbd
--- /dev/null
@@ -0,0 +1,196 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_FEATURES_H
+#include <features.h>
+#endif
+
+#include <Eo.h>
+#include "ecore_audio_private.h"
+#include <sndfile.h>
+
+EAPI Eo_Op ECORE_AUDIO_OBJ_IN_SNDFILE_BASE_ID = EO_NOOP;
+
+#define MY_CLASS ECORE_AUDIO_OBJ_IN_SNDFILE_CLASS
+#define MY_CLASS_NAME "ecore_audio_obj_in_sndfile"
+
+struct _Ecore_Audio_Sndfile
+{
+  SNDFILE *handle;
+  SF_INFO sfinfo;
+  Ecore_Audio_Vio *vio;
+};
+
+typedef struct _Ecore_Audio_Sndfile Ecore_Audio_Sndfile;
+
+static void _read(Eo *eo_obj, void *_pd, va_list *list)
+{
+  Ecore_Audio_Sndfile *obj = _pd;
+  int read;
+  void *data = va_arg(*list, void *);
+  int len = va_arg(*list, int);
+  int *ret = va_arg(*list, int *);
+
+  read = sf_read_float(obj->handle, data, len/4)*4;
+
+  if (ret)
+    *ret = read;
+}
+
+static void _seek(Eo *eo_obj, void *_pd, va_list *list)
+{
+  Ecore_Audio_Sndfile *obj = _pd;
+  sf_count_t count, pos;
+
+  double offs = va_arg(*list, double);
+  int mode = va_arg(*list, int);
+  double *ret = va_arg(*list, double *);
+
+  count = offs * obj->sfinfo.samplerate;
+  pos = sf_seek(obj->handle, count, mode);
+
+  if (ret)
+    *ret = (double)pos / obj->sfinfo.samplerate;
+}
+
+static void _source_set(Eo *eo_obj, void *_pd, va_list *list)
+{
+  Ecore_Audio_Sndfile *obj = _pd;
+
+  Ecore_Audio_Object *ea_obj = eo_data_get(eo_obj, ECORE_AUDIO_OBJ_CLASS);
+  Ecore_Audio_Input *in_obj = eo_data_get(eo_obj, ECORE_AUDIO_OBJ_IN_CLASS);
+
+  const char *source = va_arg(*list, const char *);
+
+  if (obj->handle) {
+    sf_close(obj->handle);
+    obj->handle = NULL;
+  }
+
+  eina_stringshare_replace(&ea_obj->source, source);
+
+  if (!ea_obj->source)
+    return;
+
+  obj->handle = sf_open(ea_obj->source, SFM_READ, &obj->sfinfo);
+
+  if (!obj->handle) {
+    eina_stringshare_del(ea_obj->source);
+    ea_obj->source = NULL;
+    return;
+  }
+
+  in_obj->length = (double)obj->sfinfo.frames / obj->sfinfo.samplerate;
+
+  in_obj->samplerate =  obj->sfinfo.samplerate;
+  in_obj->channels =  obj->sfinfo.channels;
+
+  if (obj->sfinfo.format& SF_FORMAT_WAV)
+    ea_obj->format = ECORE_AUDIO_FORMAT_WAV;
+  else if (obj->sfinfo.format& SF_FORMAT_OGG)
+    ea_obj->format = ECORE_AUDIO_FORMAT_OGG;
+  else if (obj->sfinfo.format& SF_FORMAT_FLAC)
+    ea_obj->format = ECORE_AUDIO_FORMAT_FLAC;
+  else
+    ea_obj->format = ECORE_AUDIO_FORMAT_AUTO;
+}
+
+static void _source_get(Eo *eo_obj, void *_pd EINA_UNUSED, va_list *list)
+{
+  Ecore_Audio_Object *obj = eo_data_get(eo_obj, ECORE_AUDIO_OBJ_CLASS);
+
+  const char **ret = va_arg(*list, const char **);
+
+  if (ret)
+    *ret = obj->source;
+}
+
+static void _format_set(Eo *eo_obj, void *_pd, va_list *list)
+{
+  Ecore_Audio_Sndfile *obj = _pd;
+  Ecore_Audio_Object *ea_obj = eo_data_get(eo_obj, ECORE_AUDIO_OBJ_CLASS);
+
+  Ecore_Audio_Format format= va_arg(*list, Ecore_Audio_Format);
+
+  if (ea_obj->source) {
+      ERR("Input is already open - cannot change format");
+      return;
+  }
+
+  switch (format) {
+    case ECORE_AUDIO_FORMAT_AUTO:
+      obj->sfinfo.format = 0;
+    case ECORE_AUDIO_FORMAT_WAV:
+      obj->sfinfo.format = SF_FORMAT_WAV|SF_FORMAT_PCM_16;
+      break;
+    case ECORE_AUDIO_FORMAT_OGG:
+      obj->sfinfo.format = SF_FORMAT_OGG|SF_FORMAT_VORBIS;
+      break;
+    case ECORE_AUDIO_FORMAT_FLAC:
+      obj->sfinfo.format = SF_FORMAT_FLAC;
+      break;
+    default:
+      ERR("Format not supported!");
+      return;
+  }
+  ea_obj->format = format;
+}
+
+static void _format_get(Eo *eo_obj, void *_pd EINA_UNUSED, va_list *list)
+{
+  Ecore_Audio_Object *obj = eo_data_get(eo_obj, ECORE_AUDIO_OBJ_CLASS);
+
+  Ecore_Audio_Format *ret = va_arg(*list, Ecore_Audio_Format *);
+
+  if (ret)
+    *ret = obj->format;
+}
+
+static void _constructor(Eo *eo_obj, void *_pd, va_list *list EINA_UNUSED)
+{
+  eo_do_super(eo_obj, MY_CLASS, eo_constructor());
+
+}
+
+static void _class_constructor(Eo_Class *klass)
+{
+  const Eo_Op_Func_Description func_desc[] = {
+      /* Virtual functions of parent class implemented in this class */
+      EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor),
+      //EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_DESTRUCTOR), _destructor),
+
+      EO_OP_FUNC(ECORE_AUDIO_OBJ_ID(ECORE_AUDIO_OBJ_SUB_ID_SOURCE_SET), _source_set),
+      EO_OP_FUNC(ECORE_AUDIO_OBJ_ID(ECORE_AUDIO_OBJ_SUB_ID_SOURCE_GET), _source_get),
+      EO_OP_FUNC(ECORE_AUDIO_OBJ_ID(ECORE_AUDIO_OBJ_SUB_ID_FORMAT_SET), _format_set),
+      EO_OP_FUNC(ECORE_AUDIO_OBJ_ID(ECORE_AUDIO_OBJ_SUB_ID_FORMAT_GET), _format_get),
+
+      EO_OP_FUNC(ECORE_AUDIO_OBJ_IN_ID(ECORE_AUDIO_OBJ_IN_SUB_ID_SEEK), _seek),
+      EO_OP_FUNC(ECORE_AUDIO_OBJ_IN_ID(ECORE_AUDIO_OBJ_IN_SUB_ID_READ_INTERNAL), _read),
+
+      EO_OP_FUNC_SENTINEL
+  };
+
+  eo_class_funcs_set(klass, func_desc);
+}
+
+static const Eo_Op_Description op_desc[] = {
+    EO_OP_DESCRIPTION_SENTINEL
+};
+
+static const Eo_Class_Description class_desc = {
+    EO_VERSION,
+    MY_CLASS_NAME,
+    EO_CLASS_TYPE_REGULAR,
+    EO_CLASS_DESCRIPTION_OPS(&ECORE_AUDIO_OBJ_IN_SNDFILE_BASE_ID, op_desc, ECORE_AUDIO_OBJ_IN_SNDFILE_SUB_ID_LAST),
+    NULL,
+    sizeof(Ecore_Audio_Sndfile),
+    _class_constructor,
+    NULL
+};
+
+EO_DEFINE_CLASS(ecore_audio_obj_in_sndfile_class_get, &class_desc, ECORE_AUDIO_OBJ_IN_CLASS, NULL);
diff --git a/src/lib/ecore_audio/ecore_audio_obj_in_sndfile.h b/src/lib/ecore_audio/ecore_audio_obj_in_sndfile.h
new file mode 100644 (file)
index 0000000..98a56ca
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef ECORE_AUDIO_IN_SNDFILE_H
+#define ECORE_AUDIO_IN_SNDFILE_H
+
+#include <Eina.h>
+#include <Eo.h>
+
+#ifdef EAPI
+#undef EAPI
+#endif
+
+#ifdef __GNUC__
+#if __GNUC__ >= 4
+#define EAPI __attribute__ ((visibility("default")))
+#else
+#define EAPI
+#endif
+#else
+#define EAPI
+#endif
+
+/**
+ * @file ecore_audio_obj_in_sndfile.h
+ * @brief Audio Module
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup Ecore_Audio_Group
+ * @{
+ */
+
+#define ECORE_AUDIO_OBJ_IN_SNDFILE_CLASS ecore_audio_obj_in_sndfile_class_get()
+
+const Eo_Class *ecore_audio_obj_in_sndfile_class_get() EINA_CONST;
+
+extern EAPI Eo_Op ECORE_AUDIO_OBJ_IN_SNDFILE_BASE_ID;
+
+enum Ecore_Audio_Obj_In_Sndfile_Sub_Ids
+{
+   ECORE_AUDIO_OBJ_IN_SNDFILE_SUB_ID_LAST
+};
+
+#define ECORE_AUDIO_OBJ_IN_SNDFILE_ID(sub_id) (ECORE_AUDIO_OBJ_IN_SNDFILE_BASE_ID + EO_TYPECHECK(enum Ecore_Audio_Obj_In_Sndfile_Sub_Ids, sub_id)
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/ecore_audio/ecore_audio_obj_out_sndfile.c b/src/lib/ecore_audio/ecore_audio_obj_out_sndfile.c
new file mode 100644 (file)
index 0000000..b5fd2d5
--- /dev/null
@@ -0,0 +1,218 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_FEATURES_H
+#include <features.h>
+#endif
+
+#include <Eo.h>
+#include "ecore_audio_private.h"
+#include <sndfile.h>
+
+EAPI Eo_Op ECORE_AUDIO_OBJ_OUT_SNDFILE_BASE_ID = EO_NOOP;
+
+#define MY_CLASS ECORE_AUDIO_OBJ_OUT_SNDFILE_CLASS
+#define MY_CLASS_NAME "ecore_audio_obj_out_sndfile"
+
+struct _Ecore_Audio_Sndfile
+{
+  SNDFILE *handle;
+  SF_INFO sfinfo;
+  Ecore_Audio_Vio *vio;
+  Ecore_Idler *idler;
+};
+
+typedef struct _Ecore_Audio_Sndfile Ecore_Audio_Sndfile;
+
+static Eina_Bool _write_cb(void *data)
+{
+  Eo *eo_obj = data;
+  Eo *in;
+
+  Ecore_Audio_Sndfile *obj = eo_data_get(eo_obj, ECORE_AUDIO_OBJ_OUT_SNDFILE_CLASS);
+  Ecore_Audio_Output *out_obj = eo_data_get(eo_obj, ECORE_AUDIO_OBJ_OUT_CLASS);
+
+  int written, bread;
+  float buf[1024];
+
+  /* TODO: Support mixing of multiple inputs */
+  in = eina_list_data_get(out_obj->inputs);
+
+  eo_do(in, ecore_audio_obj_in_read(buf, 4*1024, &bread));
+
+  if (bread == 0) {
+      sf_write_sync(obj->handle);
+      out_obj->paused = EINA_TRUE;
+      obj->idler = NULL;
+      return EINA_FALSE;
+  }
+  written = sf_write_float(obj->handle, buf, bread/4)*4;
+
+  if (written != bread)
+    ERR("Short write! (%s)\n", sf_strerror(obj->handle));
+
+  return EINA_TRUE;
+}
+
+static void _input_attach(Eo *eo_obj, void *_pd, va_list *list)
+{
+  Ecore_Audio_Sndfile *obj = _pd;
+  Ecore_Audio_Object *ea_obj = eo_data_get(eo_obj, ECORE_AUDIO_OBJ_CLASS);
+  Ecore_Audio_Output *out_obj = eo_data_get(eo_obj, ECORE_AUDIO_OBJ_OUT_CLASS);
+
+  Eo *in = va_arg(*list, Eo *);
+
+  eo_do_super(eo_obj, MY_CLASS, ecore_audio_obj_out_input_attach(in));
+
+  eo_do(in, ecore_audio_obj_in_samplerate_get(&obj->sfinfo.samplerate));
+  eo_do(in, ecore_audio_obj_in_channels_get(&obj->sfinfo.channels));
+
+  obj->handle = sf_open(ea_obj->source, SFM_WRITE, &obj->sfinfo);
+
+  if (!obj->handle) {
+    eina_stringshare_del(ea_obj->source);
+    ea_obj->source = NULL;
+    return;
+  }
+
+  if (ea_obj->paused)
+    return;
+
+  if (out_obj->inputs) {
+    obj->idler = ecore_idler_add(_write_cb, eo_obj);
+  }
+}
+
+static void _source_set(Eo *eo_obj, void *_pd, va_list *list)
+{
+  Ecore_Audio_Sndfile *obj = _pd;
+
+  Ecore_Audio_Object *ea_obj = eo_data_get(eo_obj, ECORE_AUDIO_OBJ_CLASS);
+
+  const char *source = va_arg(*list, const char *);
+
+  if (obj->handle) {
+    sf_close(obj->handle);
+    obj->handle = NULL;
+  }
+
+  eina_stringshare_replace(&ea_obj->source, source);
+
+  if (!ea_obj->source)
+    return;
+
+}
+
+static void _source_get(Eo *eo_obj, void *_pd EINA_UNUSED, va_list *list)
+{
+  Ecore_Audio_Object *obj = eo_data_get(eo_obj, ECORE_AUDIO_OBJ_CLASS);
+
+  const char **ret = va_arg(*list, const char **);
+
+  if (ret)
+    *ret = obj->source;
+}
+
+static void _format_set(Eo *eo_obj, void *_pd, va_list *list)
+{
+  Ecore_Audio_Sndfile *obj = _pd;
+  Ecore_Audio_Object *ea_obj = eo_data_get(eo_obj, ECORE_AUDIO_OBJ_CLASS);
+
+  Ecore_Audio_Format format= va_arg(*list, Ecore_Audio_Format);
+
+  if (ea_obj->source) {
+      ERR("Input is already open - cannot change format");
+      return;
+  }
+
+  switch (format) {
+    case ECORE_AUDIO_FORMAT_AUTO:
+      obj->sfinfo.format = 0;
+    case ECORE_AUDIO_FORMAT_WAV:
+      obj->sfinfo.format = SF_FORMAT_WAV|SF_FORMAT_PCM_16;
+      break;
+    case ECORE_AUDIO_FORMAT_OGG:
+      obj->sfinfo.format = SF_FORMAT_OGG|SF_FORMAT_VORBIS;
+      break;
+    case ECORE_AUDIO_FORMAT_FLAC:
+      obj->sfinfo.format = SF_FORMAT_FLAC;
+      break;
+    default:
+      ERR("Format not supported!");
+      return;
+  }
+  ea_obj->format = format;
+}
+
+static void _format_get(Eo *eo_obj, void *_pd EINA_UNUSED, va_list *list)
+{
+  Ecore_Audio_Object *obj = eo_data_get(eo_obj, ECORE_AUDIO_OBJ_CLASS);
+
+  Ecore_Audio_Format *ret = va_arg(*list, Ecore_Audio_Format *);
+
+  if (ret)
+    *ret = obj->format;
+}
+
+static void _constructor(Eo *eo_obj, void *_pd, va_list *list EINA_UNUSED)
+{
+  Ecore_Audio_Sndfile *obj = _pd;
+
+  eo_do_super(eo_obj, MY_CLASS, eo_constructor());
+
+  eo_do(eo_obj, ecore_audio_obj_format_set(ECORE_AUDIO_FORMAT_OGG));
+}
+
+static void _destructor(Eo *eo_obj, void *_pd, va_list *list EINA_UNUSED)
+{
+  Ecore_Audio_Sndfile *obj = _pd;
+
+  if (obj->handle)
+    sf_close(obj->handle);
+  if (obj->idler)
+    ecore_idler_del(obj->idler);
+
+  eo_do_super(eo_obj, MY_CLASS, eo_destructor());
+}
+
+static void _class_constructor(Eo_Class *klass)
+{
+  const Eo_Op_Func_Description func_desc[] = {
+      /* Virtual functions of parent class implemented in this class */
+      EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor),
+      EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_DESTRUCTOR), _destructor),
+
+      EO_OP_FUNC(ECORE_AUDIO_OBJ_ID(ECORE_AUDIO_OBJ_SUB_ID_SOURCE_SET), _source_set),
+      EO_OP_FUNC(ECORE_AUDIO_OBJ_ID(ECORE_AUDIO_OBJ_SUB_ID_SOURCE_GET), _source_get),
+      EO_OP_FUNC(ECORE_AUDIO_OBJ_ID(ECORE_AUDIO_OBJ_SUB_ID_FORMAT_SET), _format_set),
+      EO_OP_FUNC(ECORE_AUDIO_OBJ_ID(ECORE_AUDIO_OBJ_SUB_ID_FORMAT_GET), _format_get),
+
+      EO_OP_FUNC(ECORE_AUDIO_OBJ_OUT_ID(ECORE_AUDIO_OBJ_OUT_SUB_ID_INPUT_ATTACH), _input_attach),
+      //EO_OP_FUNC(ECORE_AUDIO_OBJ_ID(ECORE_AUDIO_OBJ_OUT_SUB_ID_FORMAT_GET), _format_get),
+      EO_OP_FUNC_SENTINEL
+  };
+
+  eo_class_funcs_set(klass, func_desc);
+}
+
+static const Eo_Op_Description op_desc[] = {
+    EO_OP_DESCRIPTION_SENTINEL
+};
+
+static const Eo_Class_Description class_desc = {
+    EO_VERSION,
+    MY_CLASS_NAME,
+    EO_CLASS_TYPE_REGULAR,
+    EO_CLASS_DESCRIPTION_OPS(&ECORE_AUDIO_OBJ_OUT_SNDFILE_BASE_ID, op_desc, ECORE_AUDIO_OBJ_OUT_SNDFILE_SUB_ID_LAST),
+    NULL,
+    sizeof(Ecore_Audio_Sndfile),
+    _class_constructor,
+    NULL
+};
+
+EO_DEFINE_CLASS(ecore_audio_obj_out_sndfile_class_get, &class_desc, ECORE_AUDIO_OBJ_OUT_CLASS, NULL);
diff --git a/src/lib/ecore_audio/ecore_audio_obj_out_sndfile.h b/src/lib/ecore_audio/ecore_audio_obj_out_sndfile.h
new file mode 100644 (file)
index 0000000..faea33c
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef ECORE_AUDIO_OUT_SNDFILE_H
+#define ECORE_AUDIO_OUT_SNDFILE_H
+
+#include <Eina.h>
+#include <Eo.h>
+
+#ifdef EAPI
+#undef EAPI
+#endif
+
+#ifdef __GNUC__
+#if __GNUC__ >= 4
+#define EAPI __attribute__ ((visibility("default")))
+#else
+#define EAPI
+#endif
+#else
+#define EAPI
+#endif
+
+/**
+ * @file ecore_audio_obj_out_sndfile.h
+ * @brief Audio Module
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * @addtogroup Ecore_Audio_Group
+ * @{
+ */
+
+#define ECORE_AUDIO_OBJ_OUT_SNDFILE_CLASS ecore_audio_obj_out_sndfile_class_get()
+
+const Eo_Class *ecore_audio_obj_out_sndfile_class_get() EINA_CONST;
+
+extern EAPI Eo_Op ECORE_AUDIO_OBJ_OUT_SNDFILE_BASE_ID;
+
+enum _Ecore_Audio_Obj_Out_Sndfile_Sub_Ids
+{
+   ECORE_AUDIO_OBJ_OUT_SNDFILE_SUB_ID_LAST
+};
+
+#define ECORE_AUDIO_OBJ_OUT_SNDFILE_ID(sub_id) (ECORE_AUDIO_OBJ_OUT_SNDFILE_BASE_ID + EO_TYPECHECK(enum _Ecore_Audio_Obj_Out_Sndfile_Sub_Ids, sub_id))
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif