r4121 - in trunk/bse: . tests
- From: stw svn gnome org
- To: svn-commits-list gnome org
- Subject: r4121 - in trunk/bse: . tests
- Date: Sun, 3 Dec 2006 15:28:06 -0500 (EST)
Author: stw
Date: 2006-12-03 15:27:33 -0500 (Sun, 03 Dec 2006)
New Revision: 4121
Modified:
trunk/bse/ChangeLog
trunk/bse/bsedatahandle-fir.cc
trunk/bse/gsldatahandle.h
trunk/bse/tests/firhandle.cc
Log:
Sun Dec 3 21:13:32 2006 Stefan Westerfeld <stefan space twc de>
* bsedatahandle-fir.cc: Made state size computation work correctly.
Added lowpass handle.
* tests/firhandle.cc: Extended tests to cover both, the highpass and
the lowpass handle.
Modified: trunk/bse/ChangeLog
===================================================================
--- trunk/bse/ChangeLog 2006-12-03 13:08:42 UTC (rev 4120)
+++ trunk/bse/ChangeLog 2006-12-03 20:27:33 UTC (rev 4121)
@@ -1,3 +1,11 @@
+Sun Dec 3 21:13:32 2006 Stefan Westerfeld <stefan space twc de>
+
+ * bsedatahandle-fir.cc: Made state size computation work correctly.
+ Added lowpass handle.
+
+ * tests/firhandle.cc: Extended tests to cover both, the highpass and
+ the lowpass handle.
+
Sat Dec 2 23:55:44 2006 Stefan Westerfeld <stefan space twc de>
* tests/Makefile.am:
Modified: trunk/bse/bsedatahandle-fir.cc
===================================================================
--- trunk/bse/bsedatahandle-fir.cc 2006-12-03 13:08:42 UTC (rev 4120)
+++ trunk/bse/bsedatahandle-fir.cc 2006-12-03 20:27:33 UTC (rev 4121)
@@ -205,8 +205,7 @@
// 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;
+ return source_state_length + m_history;
}
static GslDataHandle*
@@ -312,6 +311,48 @@
}
};
+class DataHandleFirLowpass : public DataHandleFir
+{
+protected:
+ gdouble m_cutoff_freq;
+
+public:
+ DataHandleFirLowpass (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, "// #lowpass /", 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] = 1; // 0 dB
+ transfer_func_values[0] = 1;
+
+ transfer_func_freqs[1] = m_cutoff_freq / mix_freq * 2 * M_PI;
+ transfer_func_values[1] = 1; // 0 dB
+
+ transfer_func_freqs[2] = m_cutoff_freq / mix_freq * 2 * M_PI;
+ transfer_func_values[2] = 0;
+
+ transfer_func_freqs[3] = PI;
+ transfer_func_values[3] = 0;
+
+ gsl_filter_fir_approx (m_a.size() - 1, &m_a[0],
+ transfer_func_length, transfer_func_freqs, transfer_func_values,
+ false); // interpolate dB
+ }
+};
+
+
}
#if 0 // debugging
@@ -334,7 +375,7 @@
using namespace Bse;
-/*
+/**
* __________
* /
* /
@@ -354,3 +395,24 @@
DataHandleFir *cxx_dh = new DataHandleFirHighpass (src_handle, cutoff_freq, order);
return DataHandleFir::dh_create (cxx_dh);
}
+
+/**
+ * ______
+ * \
+ * \
+ * \
+ * \__________
+ * |
+ * cutoff_freq
+ *
+ * @cutoff_freq: cutoff frequency in Hz in intervall [0..SR/2]
+ * @order: number of filter coefficients
+ */
+extern "C" GslDataHandle*
+bse_data_handle_new_fir_lowpass (GslDataHandle *src_handle,
+ gdouble cutoff_freq,
+ guint order)
+{
+ DataHandleFir *cxx_dh = new DataHandleFirLowpass (src_handle, cutoff_freq, order);
+ return DataHandleFir::dh_create (cxx_dh);
+}
Modified: trunk/bse/gsldatahandle.h
===================================================================
--- trunk/bse/gsldatahandle.h 2006-12-03 13:08:42 UTC (rev 4120)
+++ trunk/bse/gsldatahandle.h 2006-12-03 20:27:33 UTC (rev 4121)
@@ -123,6 +123,9 @@
GslDataHandle* bse_data_handle_new_fir_highpass (GslDataHandle *src_handle, // implemented in bsedatahandle-fir.cc
gdouble cutoff_freq,
guint order);
+GslDataHandle* bse_data_handle_new_fir_lowpass (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-12-03 13:08:42 UTC (rev 4120)
+++ trunk/bse/tests/firhandle.cc 2006-12-03 20:27:33 UTC (rev 4121)
@@ -30,6 +30,7 @@
using std::vector;
using std::min;
using std::max;
+using Birnet::string_printf;
static void
read_through (GslDataHandle *handle)
@@ -65,10 +66,81 @@
return diff;
}
-void
-test_highpass_with_sine_sweep()
+static double
+band_min (const vector<double>& scanned_freq,
+ const vector<double>& scanned_values,
+ double start_freq,
+ double end_freq)
{
- TSTART ("Highpass Handle (sweep)");
+ g_assert (scanned_freq.size() == scanned_values.size());
+
+ bool init = false;
+ double min_value = 1e19;
+ for (size_t i = 0; i < scanned_values.size(); i++)
+ {
+ if (scanned_freq[i] >= start_freq && scanned_freq[i] <= end_freq)
+ {
+ if (init)
+ min_value = min (scanned_values[i], min_value);
+ else
+ {
+ min_value = scanned_values[i];
+ init = true;
+ }
+ }
+ }
+ g_assert (init);
+ return min_value;
+}
+
+static double
+band_max (const vector<double>& scanned_freq,
+ const vector<double>& scanned_values,
+ double start_freq,
+ double end_freq)
+{
+ g_assert (scanned_freq.size() == scanned_values.size());
+
+ bool init = false;
+ double max_value = -1e19;
+ for (size_t i = 0; i < scanned_values.size(); i++)
+ {
+ if (scanned_freq[i] >= start_freq && scanned_freq[i] <= end_freq)
+ {
+ if (init)
+ max_value = max (scanned_values[i], max_value);
+ else
+ {
+ max_value = scanned_values[i];
+ init = true;
+ }
+ }
+ }
+ g_assert (init);
+ return max_value;
+}
+
+enum FirHandleType
+{
+ FIR_HIGHPASS,
+ FIR_LOWPASS
+};
+
+static const char*
+handle_name (FirHandleType type)
+{
+ switch (type)
+ {
+ case FIR_HIGHPASS: return "Highpass";
+ case FIR_LOWPASS: return "Lowpass";
+ default: g_assert_not_reached();
+ }
+}
+
+static void
+test_with_sine_sweep (FirHandleType type)
+{
+ TSTART ("%s Handle (sweep)", handle_name (type));
vector<float> sweep_sin (50000);
vector<float> sweep_cos (50000);
vector<double> sweep_freq (50000);
@@ -94,9 +166,20 @@
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 = 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);
+ GslDataHandle *fir_handle_sin = NULL;
+ GslDataHandle *fir_handle_cos = NULL;
+ if (type == FIR_HIGHPASS)
+ {
+ fir_handle_sin = bse_data_handle_new_fir_highpass (ihandle_sin, 9000.0, order);
+ fir_handle_cos = bse_data_handle_new_fir_highpass (ihandle_cos, 9000.0, order);
+ }
+ else if (type == FIR_LOWPASS)
+ {
+ fir_handle_sin = bse_data_handle_new_fir_lowpass (ihandle_sin, 6000.0, order);
+ fir_handle_cos = bse_data_handle_new_fir_lowpass (ihandle_cos, 6000.0, order);
+ }
+
BseErrorType error;
error = gsl_data_handle_open (fir_handle_sin);
TASSERT (error == 0);
@@ -106,63 +189,66 @@
GslDataPeekBuffer peek_buffer_sin = { +1 /* incremental direction */, 0, };
GslDataPeekBuffer peek_buffer_cos = { +1 /* incremental direction */, 0, };
- double stop_min_db = 1e19, stop_max_db = -1e19;
- double trans_min_db = 1e19, trans_max_db = -1e19;
- double pass1_min_db = 1e19, pass1_max_db = -1e19;
- double pass2_min_db = 1e19, pass2_max_db = -1e19;
- double phase_diff_max = 0;
+ vector<double> scanned_freq, scanned_level_db, scanned_abs_phase_diff;
+
for (size_t i = ((order + 2) / 2); i < sweep_sin.size() - ((order + 2) / 2); i++)
{
double filtered_sin = gsl_data_handle_peek_value (fir_handle_sin, i, &peek_buffer_sin);
double filtered_cos = gsl_data_handle_peek_value (fir_handle_cos, i, &peek_buffer_cos);
std::complex<double> filtered (filtered_sin, filtered_cos);
- double level = abs (filtered);
- double level_db = bse_db_from_factor (level, -200);
// check frequency response
- // printf ("%f %.17g\n", sweep_freq[i], level_db);
- if (sweep_freq[i] < 7050)
- {
- stop_min_db = min (stop_min_db, level_db);
- stop_max_db = max (stop_max_db, level_db);
- }
- if (sweep_freq[i] > 7050 && sweep_freq[i] < 9500)
- {
- trans_min_db = min (trans_min_db, level_db);
- trans_max_db = max (trans_max_db, level_db);
- }
- if (sweep_freq[i] > 9500 && sweep_freq[i] < 11000)
- {
- pass1_min_db = min (pass1_min_db, level_db);
- pass1_max_db = max (pass1_max_db, level_db);
- }
- if (sweep_freq[i] > 11000)
- {
- pass2_min_db = min (pass2_min_db, level_db);
- pass2_max_db = max (pass2_max_db, level_db);
- }
+ double level = abs (filtered);
+ scanned_freq.push_back (sweep_freq[i]);
+ scanned_level_db.push_back (bse_db_from_factor (level, -200));
+ // printf ("%f %.17g\n", sweep_freq[i], scanned_level_db.back());
// check phase response in passband
std::complex<double> orig (sweep_sin[i], sweep_cos[i]);
- double abs_phase_diff = fabs (phase_diff (arg (orig), arg (filtered)));
- if (sweep_freq[i] > 11000)
- {
- phase_diff_max = max (phase_diff_max, abs_phase_diff);
- // printf ("%f %.17g\n", sweep_freq[i], abs_phase_diff);
- }
+ scanned_abs_phase_diff.push_back (fabs (phase_diff (arg (orig), arg (filtered))));
+ // printf ("%f %.17g\n", sweep_freq[i], scanned_abs_phase_diff.back());
}
-#if 0
- printf ("stop = %f..%f dB\n", stop_min_db, stop_max_db);
- printf ("trans = %f..%f dB\n", trans_min_db, trans_max_db);
- printf ("pass1 = %f..%f dB\n", pass1_min_db, pass1_max_db);
- printf ("pass2 = %f..%f dB\n", pass2_min_db, pass2_max_db);
- printf ("max phase diff = %f\n", phase_diff_max);
-#endif
- TASSERT (stop_max_db < -75);
- TASSERT (trans_min_db > -77 && trans_max_db < -2.8);
- TASSERT (pass1_min_db > -2.82 && pass1_max_db < -0.002);
- TASSERT (pass2_min_db > -0.004 && pass2_max_db < 0.002);
- TASSERT (phase_diff_max < 0.0002);
+
+ if (type == FIR_HIGHPASS)
+ {
+ // stop band
+ TASSERT_CMP (band_max (scanned_freq, scanned_level_db, 0, 7050), <, -75);
+
+ // transition band
+ TASSERT_CMP (band_min (scanned_freq, scanned_level_db, 7050, 9500), >, -77);
+ TASSERT_CMP (band_max (scanned_freq, scanned_level_db, 7050, 9500), <, -2.8);
+
+ // passband (1)
+ TASSERT_CMP (band_min (scanned_freq, scanned_level_db, 9500, 11000), >, -2.82);
+ TASSERT_CMP (band_max (scanned_freq, scanned_level_db, 9500, 11000), <, -0.002);
+
+ // passband (2)
+ TASSERT_CMP (band_min (scanned_freq, scanned_level_db, 11000, 24000), >, -0.004);
+ TASSERT_CMP (band_max (scanned_freq, scanned_level_db, 11000, 24000), <, 0.002);
+
+ // zero phase in passband (2)
+ TASSERT_CMP (band_max (scanned_freq, scanned_abs_phase_diff, 11000, 24000), <, 0.0002);
+ }
+ else // FIR_LOWPASS
+ {
+ // passband (2)
+ TASSERT_CMP (band_min (scanned_freq, scanned_level_db, 0, 5500), >, -0.002);
+ TASSERT_CMP (band_max (scanned_freq, scanned_level_db, 0, 5500), <, 0.002);
+
+ // passband (1)
+ TASSERT_CMP (band_min (scanned_freq, scanned_level_db, 5500, 7000), >, -1.9);
+ TASSERT_CMP (band_max (scanned_freq, scanned_level_db, 5500, 7000), <, -0.001);
+
+ // transition band
+ TASSERT_CMP (band_min (scanned_freq, scanned_level_db, 7000, 10000), >, -81);
+ TASSERT_CMP (band_max (scanned_freq, scanned_level_db, 7000, 10000), <, -1.8);
+
+ // stop band
+ TASSERT_CMP (band_max (scanned_freq, scanned_level_db, 10000, 24000), <, -75);
+
+ // zero phase in passband (2)
+ TASSERT_CMP (band_max (scanned_freq, scanned_abs_phase_diff, 0, 5500), <, 0.00002);
+ }
TDONE();
/* test speed */
@@ -185,12 +271,14 @@
m = e;
}
samples_per_second = sweep_sin.size() / (m / dups);
- treport_maximized ("Highpass O64 mono", samples_per_second, TUNIT (SAMPLE, SECOND));
- treport_maximized ("CPU Highpass mono", samples_per_second / 44100.0, TUNIT_STREAM);
+ treport_maximized (string_printf ("%s O64 mono", handle_name (type)).c_str(),
+ samples_per_second, TUNIT (SAMPLE, SECOND));
+ treport_maximized (string_printf ("CPU %s mono", handle_name (type)).c_str(),
+ samples_per_second / 44100.0, TUNIT_STREAM);
}
}
-double
+static double
raised_cosine_fade (int64 pos,
int64 length,
int64 fade_length)
@@ -203,10 +291,10 @@
return (0.5 - cos (fade_factor * PI) * 0.5);
}
-void
-test_highpass_multi_channel()
+static void
+test_multi_channel (FirHandleType type)
{
- TSTART ("Highpass Handle (multichannel)");
+ TSTART ("%s Handle (multichannel)", handle_name (type));
for (int n_channels = 1; n_channels <= 10; n_channels++)
{
const double mix_freq = 48000;
@@ -230,7 +318,8 @@
const double invalue = sin (phase[c]) * fade_factor;
input[i] = invalue;
- expected[i] = (freq[c] > cutoff_freq) ? invalue : 0.0;
+ if ((freq[c] > cutoff_freq && type == FIR_HIGHPASS) || (freq[c] < cutoff_freq && type == FIR_LOWPASS))
+ expected[i] = invalue;
phase[c] += freq[c] / mix_freq * 2.0 * M_PI;
if (phase[c] > 2.0 * M_PI)
@@ -239,7 +328,12 @@
GslDataHandle *ihandle = gsl_data_handle_new_mem (n_channels, 32, mix_freq, 440, input.size(), &input[0], NULL);
const int order = 116;
- GslDataHandle *fir_handle = bse_data_handle_new_fir_highpass (ihandle, cutoff_freq, order);
+ GslDataHandle *fir_handle = NULL;
+
+ if (type == FIR_HIGHPASS)
+ fir_handle = bse_data_handle_new_fir_highpass (ihandle, cutoff_freq, order);
+ else
+ fir_handle = bse_data_handle_new_fir_lowpass (ihandle, cutoff_freq, order);
BseErrorType error;
error = gsl_data_handle_open (fir_handle);
@@ -268,7 +362,12 @@
char **argv)
{
bse_init_test (&argc, &argv, NULL);
- test_highpass_with_sine_sweep();
- test_highpass_multi_channel();
+
+ test_with_sine_sweep (FIR_HIGHPASS);
+ test_multi_channel (FIR_HIGHPASS);
+
+ test_with_sine_sweep (FIR_LOWPASS);
+ test_multi_channel (FIR_LOWPASS);
+
return 0;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]