r4111 - in trunk/bse: . tests



Author: stw
Date: 2006-11-27 16:39:30 -0500 (Mon, 27 Nov 2006)
New Revision: 4111

Modified:
   trunk/bse/ChangeLog
   trunk/bse/bsedatahandle-fir.cc
   trunk/bse/gsldatahandle.h
   trunk/bse/tests/firhandle.cc
Log:
Mon Nov 27 22:32:24 2006  Stefan Westerfeld  <stefan space twc de>

	* bsedatahandle-fir.cc:
	* gsldatahandle.h:
	* tests/firhandle.cc: Move highpass handle from gsl to bse namespace.

	* bsedatahandle-fir.cc: Implement a "real" data handle. It is not yet
	performance optimized, though.


Modified: trunk/bse/ChangeLog
===================================================================
--- trunk/bse/ChangeLog	2006-11-27 19:51:35 UTC (rev 4110)
+++ trunk/bse/ChangeLog	2006-11-27 21:39:30 UTC (rev 4111)
@@ -1,3 +1,12 @@
+Mon Nov 27 22:32:24 2006  Stefan Westerfeld  <stefan space twc de>
+
+	* bsedatahandle-fir.cc:
+	* gsldatahandle.h:
+	* tests/firhandle.cc: Move highpass handle from gsl to bse namespace.
+
+	* bsedatahandle-fir.cc: Implement a "real" data handle. It is not yet
+	performance optimized, though.
+
 Mon Nov 27 20:29:53 2006  Stefan Westerfeld  <stefan space twc de>
 
 	* gsldatahandle.[hc]: Added new gsl_data_handle_get_state_length

Modified: trunk/bse/bsedatahandle-fir.cc
===================================================================
--- trunk/bse/bsedatahandle-fir.cc	2006-11-27 19:51:35 UTC (rev 4110)
+++ trunk/bse/bsedatahandle-fir.cc	2006-11-27 21:39:30 UTC (rev 4111)
@@ -20,52 +20,248 @@
 #include "gsldatautils.h"
 #include "gslfilter.h"
 #include <complex>
+#include <vector>
 #include <string.h>
 #include <stdio.h>
 #include <math.h>
 
-/*
- * 0db ----------           __________
- *                         /
- *                        /
- *                       /
- * f1_level (dB) - _____/
- *
- *                      |   |
- *                      f1 f2
- *
- * @f1: high pass start frequency [0:PI] (SR = 2*PI)
- * @f2: high pass end frequency [0:PI] (SR = 2*PI)
- */
+namespace Bse {
 
-static void
-fir_hp (const gfloat *src,
-	const guint   n_samples,
-	gfloat       *dest,
-	gdouble       cutoff_freq,
-	guint         iorder)
+using std::vector;
+
+class DataHandleFir;
+
+struct CDataHandleFir : public GslDataHandle
 {
-  double a[iorder + 1];
+  // back pointer to get casting right, even in presence of C++ vtable:
+  DataHandleFir* cxx_dh;
+};
 
-  //const guint transfer_func_length = 64;
-  const guint transfer_func_length = 4;
-  double transfer_func_freqs[transfer_func_length];
-  double transfer_func_values[transfer_func_length];
+class DataHandleFir {
+protected:
+  CDataHandleFir	m_dhandle;
+  GslDataHandle	       *m_src_handle;
+  vector<double>        m_a;	      /* FIR coefficients: [0..order] */
+  bool			m_init_ok;
 
-  transfer_func_freqs[0]  = 0;
-  transfer_func_values[0] = 0;
+public:
+  DataHandleFir (GslDataHandle *src_handle,
+		 guint          order) :
+    m_src_handle (src_handle),
+    m_a (order),
+    m_init_ok (false)
+  {
+    g_return_if_fail (src_handle != NULL);
 
-  transfer_func_freqs[1]  = cutoff_freq;
-  transfer_func_values[1] = 0;
+    memset (&m_dhandle, 0, sizeof (m_dhandle));
+    m_init_ok = gsl_data_handle_common_init (&m_dhandle, NULL);
+    if (m_init_ok)
+      gsl_data_handle_ref (m_src_handle);
+  }
 
-  transfer_func_freqs[2]  = cutoff_freq;
-  transfer_func_values[2] = 1.0; // 0 dB
+  /* protected destructor: (use reference counting instead) */
+  virtual
+  ~DataHandleFir()
+  {
+    if (m_init_ok)
+      {
+	gsl_data_handle_unref (m_src_handle);
+	gsl_data_handle_common_free (&m_dhandle);
+      }
+  }
 
-  transfer_func_freqs[3]  = PI;
-  transfer_func_values[3] = 1.0; // 0 dB
+  BseErrorType
+  open (GslDataHandleSetup *setup)
+  {
+    BseErrorType error = gsl_data_handle_open (m_src_handle);
+    if (error != BSE_ERROR_NONE)
+      return error;
 
-  gsl_filter_fir_approx (iorder, a, transfer_func_length, transfer_func_freqs, transfer_func_values, false);
+    /* !not! m_dhandle.setup; the framework magically ensures that *m_dhandle.setup
+     * is initialized by whatever we write into *setup if open is successful
+     */
+    *setup = m_src_handle->setup; /* copies setup.xinfos by pointer */
+    setup->bit_depth = 32;	  /* possibly increased by filtering */
 
+    design_filter_coefficients (gsl_data_handle_mix_freq (m_src_handle));
+
+    return BSE_ERROR_NONE;
+  }
+
+  virtual void
+  design_filter_coefficients (double mix_freq) = 0;
+
+  void
+  close()
+  {
+    m_dhandle.setup.xinfos = NULL;	/* cleanup pointer reference */
+    gsl_data_handle_close (m_src_handle);
+  }
+
+  void
+  fir_apply (const gfloat *src,
+	     const guint   n_samples,
+	     gfloat       *dest)
+  {
+    /* tiny FIR evaluation: not optimized for speed */
+    guint i, j;
+    const guint iorder = m_a.size();
+    for (i = 0; i < n_samples; i++)
+      {
+	gdouble accu = 0;
+	for (j = 0; j <= iorder; j++)
+	  {
+	    GslLong p = i + j;
+	    p -= iorder / 2;
+
+	    if (p >= 0 && p < n_samples)
+	      accu += m_a[j] * src[p];
+	  }
+	dest[i] = accu;
+      }
+  }
+
+  int64
+  read (int64  voffset,
+	int64  n_values,
+	float *values)
+  {
+    GslLong src_handle_n_values = gsl_data_handle_n_values (m_src_handle);
+    GslDataPeekBuffer pbuf = { +1, };
+    vector<float> src_data;
+    int64 history = m_a.size() / 2 + 1;
+    for (int64 i = -history; i < n_values + history; i++)
+      {
+	int64 offset = voffset + i;
+	float v = 0.0;
+	if (offset >= 0 && offset < src_handle_n_values)
+	  v = gsl_data_handle_peek_value (m_src_handle, offset, &pbuf);
+	src_data.push_back (v);
+	/* FIXME: use gsl_data_handle_read() */
+      }
+    // return gsl_data_handle_read (m_src_handle, voffset, n_values, values);
+    vector<float> dest_data (src_data.size());
+    fir_apply (&src_data[0], src_data.size(), &dest_data[0]);
+    std::copy (&dest_data[history], &dest_data[history + n_values], values);
+    return n_values;
+  }
+
+  int64
+  get_state_length() const
+  {
+    int64 source_state_length = gsl_data_handle_get_state_length (m_src_handle);
+    // m_src_handle must be opened and have valid state size
+    g_return_val_if_fail (source_state_length >= 0, 0);  
+
+    int64 per_channel_state = 0;
+    return source_state_length + per_channel_state * m_dhandle.setup.n_channels;
+  }
+
+  static GslDataHandle*
+  dh_create (DataHandleFir *cxx_dh)
+  {
+    static GslDataHandleFuncs dh_vtable =
+    {
+      dh_open,
+      dh_read,
+      dh_close,
+      NULL,
+      dh_get_state_length,
+      dh_destroy,
+    };
+
+    if (cxx_dh->m_init_ok)
+      {
+	cxx_dh->m_dhandle.vtable = &dh_vtable;
+	cxx_dh->m_dhandle.cxx_dh = cxx_dh;	/* make casts work, later on */
+	return &cxx_dh->m_dhandle;
+      }
+    else
+      {
+	delete cxx_dh;
+	return NULL;
+      }
+  }
+private:
+/* for the "C" API (vtable) */
+  static DataHandleFir*
+  dh_cast (GslDataHandle *dhandle)
+  {
+    return static_cast<CDataHandleFir *> (dhandle)->cxx_dh;
+  }
+  static BseErrorType
+  dh_open (GslDataHandle *dhandle, GslDataHandleSetup *setup)
+  {
+    return dh_cast (dhandle)->open (setup);
+  }
+  static void
+  dh_close (GslDataHandle *dhandle)
+  {
+    dh_cast (dhandle)->close();
+  }
+  static void
+  dh_destroy (GslDataHandle *dhandle)
+  {
+    delete dh_cast (dhandle);
+  }
+  static int64
+  dh_read (GslDataHandle *dhandle,
+	   int64          voffset,
+	   int64          n_values,
+	   gfloat        *values)
+  {
+    return dh_cast (dhandle)->read (voffset, n_values, values);
+  }
+  static int64
+  dh_get_state_length (GslDataHandle *dhandle)
+  {
+    return dh_cast (dhandle)->get_state_length();
+  }
+};
+
+class DataHandleFirHighpass : public DataHandleFir
+{
+protected:
+  gdouble m_cutoff_freq;
+
+public:
+  DataHandleFirHighpass (GslDataHandle *src_handle,
+			 gdouble        cutoff_freq,
+			 guint          order) :
+    DataHandleFir (src_handle, order),
+    m_cutoff_freq (cutoff_freq)
+  {
+    if (m_init_ok)
+      m_dhandle.name = g_strconcat (m_src_handle->name, "// #highpass /", NULL);
+  }
+
+  virtual void
+  design_filter_coefficients (double mix_freq)
+  {
+    const guint transfer_func_length = 4;
+    double transfer_func_freqs[transfer_func_length];
+    double transfer_func_values[transfer_func_length];
+
+    transfer_func_freqs[0]  = 0;
+    transfer_func_values[0] = 0;
+
+    transfer_func_freqs[1]  = m_cutoff_freq / mix_freq * 2 * M_PI;
+    transfer_func_values[1] = 0;
+
+    transfer_func_freqs[2]  = m_cutoff_freq / mix_freq * 2 * M_PI;
+    transfer_func_values[2] = 1.0; // 0 dB
+
+    transfer_func_freqs[3]  = PI;
+    transfer_func_values[3] = 1.0; // 0 dB
+
+    gsl_filter_fir_approx (m_a.size(), &m_a[0],
+                           transfer_func_length, transfer_func_freqs, transfer_func_values,
+			   false); // interpolate dB
+  }
+};
+
+}
+
 #if 0 // debugging
   gfloat freq;
   for (freq = 0; freq < PI; freq += 0.01)
@@ -81,34 +277,10 @@
 	}
       printf ("%f %f\n", freq, cabs (r));
     }
-
-  /* normalize */
-  gdouble norm = 0;
-  guint k;
-  for (k = 0; k <= iorder; k++)
-    norm += fabs (a[k]);
-
-  printf ("# norm = %f\n", norm);
-  for (k = 0; k <= iorder; k++)
-    a[k] /= norm;
 #endif
 
-  /* tiny FIR evaluation: not optimized for speed */
-  guint i, j;
-  for (i = 0; i < n_samples; i++)
-    {
-      gdouble accu = 0;
-      for (j = 0; j <= iorder; j++)
-	{
-	  GslLong p = i + j;
-	  p -= iorder / 2;
 
-	  if (p >= 0 && p < n_samples)
-	    accu += a[j] * src[p];
-	}
-      dest[i] = accu;
-    }
-}
+using namespace Bse;
 
 /*
  *           __________
@@ -123,43 +295,10 @@
  * @order:       number of filter coefficients
  */
 extern "C" GslDataHandle*
-gsl_data_handle_new_fir_highpass (GslDataHandle *src_handle,
+bse_data_handle_new_fir_highpass (GslDataHandle *src_handle,
 				  gdouble        cutoff_freq,
 				  guint          order)
 {
-  g_return_val_if_fail (src_handle != NULL, NULL);
-  
-  /* check out data handle */
-  if (gsl_data_handle_open (src_handle) != BSE_ERROR_NONE)
-    return NULL;
-  
-  GslLong src_handle_n_values   = gsl_data_handle_n_values (src_handle);
-  GslLong src_handle_n_channels = gsl_data_handle_n_channels (src_handle);
-  GslLong src_handle_mix_freq   = gsl_data_handle_mix_freq (src_handle);
-  GslLong src_handle_osc_freq   = gsl_data_handle_osc_freq (src_handle);
-  
-  /* read input */
-  gfloat *src_values = g_new (gfloat, src_handle_n_values);
-  GslLong i;
-  GslDataPeekBuffer pbuf = { +1, };
-  for (i = 0; i < src_handle_n_values; i++) /* FIXME: use gsl_data_handle_read() */
-    src_values[i] = gsl_data_handle_peek_value (src_handle, i, &pbuf);
-  
-  /* apply fir filter to new memory buffer */
-  gfloat *dest_values = g_new (gfloat, src_handle_n_values);
-  fir_hp (src_values, src_handle_n_values, dest_values, cutoff_freq * 2 * M_PI / src_handle_mix_freq, order);
-  g_free (src_values);
-  
-  /* create a mem handle with filtered data */
-  GslDataHandle *mhandle = gsl_data_handle_new_mem (src_handle_n_channels,
-                                                    32, // bit_depth: possibly increased by filtering
-                                                    src_handle_mix_freq,
-                                                    src_handle_osc_freq,
-                                                    src_handle_n_values,
-                                                    dest_values,
-                                                    g_free);
-  GslDataHandle *dhandle = gsl_data_handle_new_add_xinfos (mhandle, src_handle->setup.xinfos);
-  gsl_data_handle_close (src_handle);
-  gsl_data_handle_unref (mhandle);
-  return dhandle;
+  DataHandleFir *cxx_dh = new DataHandleFirHighpass (src_handle, cutoff_freq, order);
+  return DataHandleFir::dh_create (cxx_dh);
 }

Modified: trunk/bse/gsldatahandle.h
===================================================================
--- trunk/bse/gsldatahandle.h	2006-11-27 19:51:35 UTC (rev 4110)
+++ trunk/bse/gsldatahandle.h	2006-11-27 21:39:30 UTC (rev 4111)
@@ -120,9 +120,9 @@
 GslDataHandle*	  bse_data_handle_new_downsample2   (GslDataHandle  *src_handle,
 						     int             precision_bits);	// implemented in bsedatahandle-resample.cc
 
-GslDataHandle* gsl_data_handle_new_fir_highpass   (GslDataHandle *src_handle, // implemented in bsedatahandle-fir.cc
-				                   gdouble        cutoff_freq,
-						   guint          order);
+GslDataHandle*	  bse_data_handle_new_fir_highpass  (GslDataHandle *src_handle,		// implemented in bsedatahandle-fir.cc
+						     gdouble        cutoff_freq,
+						     guint          order);
 
 
 /* --- xinfo handling --- */

Modified: trunk/bse/tests/firhandle.cc
===================================================================
--- trunk/bse/tests/firhandle.cc	2006-11-27 19:51:35 UTC (rev 4110)
+++ trunk/bse/tests/firhandle.cc	2006-11-27 21:39:30 UTC (rev 4111)
@@ -77,8 +77,8 @@
   GslDataHandle *ihandle_cos = gsl_data_handle_new_mem (1, 32, mix_freq, 440, sweep_cos.size(), &sweep_cos[0], NULL);
 
   const int order = 64;
-  GslDataHandle *fir_handle_sin = gsl_data_handle_new_fir_highpass (ihandle_sin, 9000.0, order);
-  GslDataHandle *fir_handle_cos = gsl_data_handle_new_fir_highpass (ihandle_cos, 9000.0, order);
+  GslDataHandle *fir_handle_sin = bse_data_handle_new_fir_highpass (ihandle_sin, 9000.0, order);
+  GslDataHandle *fir_handle_cos = bse_data_handle_new_fir_highpass (ihandle_cos, 9000.0, order);
 
   BseErrorType error;
   error = gsl_data_handle_open (fir_handle_sin);




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]