Re: Datahandle State API changes
- From: Stefan Westerfeld <stefan space twc de>
- To: Tim Janik <timj gtk org>
- Cc: Beast Liste <beast beast gtk org>
- Subject: Re: Datahandle State API changes
- Date: Mon, 27 Nov 2006 18:15:50 +0100
Hi!
On Sat, Nov 25, 2006 at 05:48:51PM +0100, Tim Janik wrote:
> On Mon, 6 Nov 2006, Stefan Westerfeld wrote:
>
> >There is one issue I was unsure with, and that is the actual meaning of
> >the gsl_data_handle_get_source() function. I had assumed that this
> >function would return the datahandle which provided the data, and thus,
> >for the resampling case, it should return the unresampled datahandle.
> >
> >So I added a get_source() method to the resampling datahandle. However,
> >some other datahandles where I find it obvious to implement get_source
> >in a similar way, for instance the reversed handle, do not have any
> >get_source function. Especially, there is no chain_handle_get_source()
> >function in gsldatahandle.c, and any handle derived from the chained
> >handle doesn't have a get_source function.
> >
> >Additionally, there is no documentation for
> >gsl_data_handle_get_source(), so there is no way to look up whats the
> >intended meaning. So maybe I was wrong about implementing it for the
> >resampling handle, or maybe it should be implemented for more handles.
>
> it usually is a good idea to look at the actual use cases to find out
> about an unknown function. in this case:
> bse_storage_put_data_handle()
> do /* skip comment or cache handles */
> {
> test_handle = tmp_handle;
> tmp_handle = gsl_data_handle_get_source (test_handle);
> }
> while (tmp_handle); /* skip comment or cache handles */
I see.
> so:
> no, resmaplers should not implement get_source, that function is only
> intended
> for unrolling the datahandle chain as long as the data (length, number of
> channels, accuracy) stays exactly the same.
Ok, I removed it again from the resampling handles.
> [...]
>
> >Index: bse/gsldatahandle.c
> >===================================================================
> >--- bse/gsldatahandle.c (revision 4068)
> >+++ bse/gsldatahandle.c (working copy)
> >@@ -195,6 +195,41 @@ gsl_data_handle_get_source (GslDataHandl
> > return src_handle;
> >}
> >
> >+/**
> >+ * @param data_handle a DataHandle
> >+ * @return the state length of the data handle
> >+ *
> >+ * Some data handles produce output samples from an input data handle,
>
> s/some/most/
>
> >+ * like filtering and resampling datahandles. Usually, they have an
> >internal
>
> s/usually they/some/
Ok, I made these changes, but since the examples I give
(resample/filter) fall in the category with state, I reordered the
comment a bit. See below.
> >+ * state which means that the value of one input sample affects not only
> >one
> >+ * output sample, but some samples before and some samples after the
>
> s/and/or/ (since that depends on the filter type)
Writing "or" could mean that either some samples before or some samples
after the corresponding sample are affected, but not both. I used the
somewhat technical but more precise "and/or" now. The new version is:
* Most data handles produce output samples from an input data handle.
* Some of them, like filtering and resampling datahandles, have an internal
* state which means that the value of one input sample affects not only one
* output sample, but some samples before and/or some samples after the
* "corresponding" output sample.
> >+ * "corresponding" output sample.
> >+ *
> >+ * Often the state is symmetric, so that the number of output samples
> >affected
> >+ * before and after the "corresponding" output sample is the same. Then
> >the
> >+ * function returns this number. If the state is asymmetric, this function
> >+ * shall return the maximum of the two numbers.
> >+ *
> >+ * If multiple data handles are cascaded (for instance when resampling a
>
> hm, "cascaded"? i'd rather say "nested" (or "chained") here.
Ok: I'll use cascaded.
> >+ * filtered signal), the function propagates the state length, so that the
> >+ * state of the chain of all operations together is returned.
>
> "state of the chain"? shouldn't that be "accumulated state length" or so?
Ok, I'll use "accumulated state length" - it already sounded somewhat
clumsy to me when I wrote it. :)
> [...]
>
> >Index: bse/bsedatahandle-resample.cc
> >===================================================================
> >--- bse/bsedatahandle-resample.cc (revision 4068)
> >+++ bse/bsedatahandle-resample.cc (working copy)
> >@@ -136,7 +136,7 @@ protected:
> > }
> >
> > /* implemented by upsampling and downsampling datahandle */
> >- virtual BseResampler2Mode mode () = 0;
> >+ virtual BseResampler2Mode mode () const = 0;
> > virtual int64 read_frame (int64 frame) = 0;
> >
> >public:
> >@@ -222,18 +222,38 @@ public:
> >
> > return n_values;
> > }
> >+ GslDataHandle*
> >+ get_source() const
> >+ {
> >+ return gsl_data_handle_get_source (m_src_handle);
> >+ }
> >+ int64
> >+ get_state_length() const
> >+ {
> >+ int64 source_state_length = gsl_data_handle_get_state_length
> >(m_src_handle);
> >+ if (source_state_length < 0)
> >+ return source_state_length;
>
> huh? why should a datahandle every return a negative state?
Well, I thought of that line as a similar error propagation as I do in
read - that is, if the source handle does something strange, I pass it
on.
What if the source handle had infinite state (like an IIR filter)? But I
can also simplify it to a g_return_if_fail(), for as long as there are
no datahandles with non-finite state or othor "errors".
> >+ if (mode() == BSE_RESAMPLER2_MODE_UPSAMPLE)
> >+ source_state_length *= 2;
> >+ else
> >+ source_state_length = (source_state_length + 1) / 2;
> >+
> >+ if (m_resamplers.size())
> >+ {
> >+ /* For fractional delays, a delay of 10.5 for instance means that
> >input[0]
> >+ * affects samples 10 and 11 are affected, and thus the state length
> >we
> >+ * assume for that case is 11.
> >+ */
>
> the comment needs rewording, you use "affect" two times.
Ok, done.
> >+ int64 per_channel_state = ceil (m_resamplers[0]->delay());
> >+ return source_state_length + per_channel_state *
> >m_dhandle.setup.n_channels;
> >+ }
> >+ // should never happen
> >+ return -1;
>
> eeeek!
> -1?
> how is that *possibly* a valid state?
>
> note that gsl_data_handle_get_state_length() was not
> defined/discussed/documented as a function that can possibly fail,
> so why don't you return 0 here?
I don't want to silently return a valid state when something unpredicted
happens. But I think I can make my preconditions explicit using
g_return_if_fail(). Like this:
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);
if (mode() == BSE_RESAMPLER2_MODE_UPSAMPLE)
source_state_length *= 2;
else
source_state_length = (source_state_length + 1) / 2;
// we must be opened => n_channels > 0, 1 Resampler per Channel
g_return_val_if_fail (!m_resamplers.empty(), 0);
/* For fractional delays, a delay of 10.5 for instance means that input[0]
* affects samples 10 and 11, and thus the state length we assume for
* that case is 11.
*/
int64 per_channel_state = ceil (m_resamplers[0]->delay());
return source_state_length + per_channel_state * m_dhandle.setup.n_channels;
}
> >+ }
> > static GslDataHandle*
> > dh_create (DataHandleResample2 *cxx_dh)
> > {
> >- static GslDataHandleFuncs dh_vtable =
> >- {
> >- dh_open,
> >- dh_read,
> >- dh_close,
> >- NULL,
> >- dh_destroy,
> >- };
>
> huh?
>
> > if (cxx_dh->m_init_ok)
> > {
> > cxx_dh->m_dhandle.vtable = &dh_vtable;
> >@@ -246,9 +266,10 @@ public:
> > return NULL;
> > }
> > }
> > [...]
> >+
> >+GslDataHandleFuncs DataHandleResample2::dh_vtable =
> >+{
> >+ dh_open,
> >+ dh_read,
> >+ dh_close,
> >+ dh_get_source,
> >+ dh_get_state_length,
> >+ dh_destroy,
> >};
>
> erk. declaring the table inside the class is not neccessary
> and defines an additional external symbol. decls should be
> moved into the innermost scope possible, so please revert that
> part by moving the table back into dh_create.
Ok.
Here is the new patch:
Index: bse/gsldatahandle-vorbis.c
===================================================================
--- bse/gsldatahandle-vorbis.c (revision 4108)
+++ bse/gsldatahandle-vorbis.c (working copy)
@@ -365,6 +365,7 @@ static GslDataHandleFuncs dh_vorbis_vtab
dh_vorbis_read,
dh_vorbis_close,
NULL,
+ NULL,
dh_vorbis_destroy,
};
Index: bse/gsldatahandle-mad.c
===================================================================
--- bse/gsldatahandle-mad.c (revision 4108)
+++ bse/gsldatahandle-mad.c (working copy)
@@ -673,6 +673,7 @@ static GslDataHandleFuncs dh_mad_vtable
dh_mad_read,
dh_mad_close,
NULL,
+ NULL,
dh_mad_destroy,
};
Index: bse/ChangeLog
===================================================================
--- bse/ChangeLog (revision 4108)
+++ bse/ChangeLog (working copy)
@@ -1,3 +1,19 @@
+Mon Nov 27 17:53:34 2006 Stefan Westerfeld <stefan space twc de>
+
+ * gsldatahandle.[hc]: Added new gsl_data_handle_get_state_length
+ function for datahandles, with a corresponding vtable entry. For
+ filtering datahandles (such as lowpass handles), which are usually
+ stateful, it returns the filter state length.
+
+ * gsldatahandle-vorbis.c:
+ * gsldatahandle-mad.c:
+ * bsedatahandle-resample.cc:
+ * tests/loophandle.c: Implement the get_state_length datahandle
+ method.
+
+ * tests/resamplehandle.cc: Test the resampler get_state_length
+ function.
+
Mon Nov 27 15:19:47 2006 Stefan Westerfeld <stefan space twc de>
* tests/firhandle.cc: Check that the filter is zero phase in the
Index: bse/gsldatahandle.c
===================================================================
--- bse/gsldatahandle.c (revision 4108)
+++ bse/gsldatahandle.c (working copy)
@@ -195,6 +195,41 @@ gsl_data_handle_get_source (GslDataHandl
return src_handle;
}
+/**
+ * @param data_handle a DataHandle
+ * @return the state length of the data handle
+ *
+ * Most data handles produce output samples from an input data handle.
+ * Some of them, like filtering and resampling datahandles, have an internal
+ * state which means that the value of one input sample affects not only one
+ * output sample, but some samples before and/or some samples after the
+ * "corresponding" output sample.
+ *
+ * Often the state is symmetric, so that the number of output samples affected
+ * before and after the "corresponding" output sample is the same. Then the
+ * function returns this number. If the state is asymmetric, this function
+ * shall return the maximum of the two numbers.
+ *
+ * If multiple data handles are nested (for instance when resampling a
+ * filtered signal), the function propagates the state length, so that the
+ * accumulated state length of all operations together is returned.
+ *
+ * Note: This function can only be used while the data handle is opened.
+ *
+ * This function is MT-safe and may be called from any thread.
+ */
+int64
+gsl_data_handle_get_state_length (GslDataHandle *dhandle)
+{
+ g_return_val_if_fail (dhandle != NULL, -1);
+ g_return_val_if_fail (dhandle->open_count > 0, -1);
+
+ GSL_SPIN_LOCK (&dhandle->mutex);
+ int64 state_length = dhandle->vtable->get_state_length ? dhandle->vtable->get_state_length (dhandle) : 0;
+ GSL_SPIN_UNLOCK (&dhandle->mutex);
+ return state_length;
+}
+
int64
gsl_data_handle_length (GslDataHandle *dhandle)
{
@@ -355,6 +390,7 @@ gsl_data_handle_new_mem (guint n
mem_handle_read,
mem_handle_close,
NULL,
+ NULL,
mem_handle_destroy,
};
MemHandle *mhandle;
@@ -500,6 +536,14 @@ xinfo_get_source_handle (GslDataHandle *
return chandle->src_handle;
}
+static int64
+xinfo_get_state_length (GslDataHandle *dhandle)
+{
+ XInfoHandle *chandle = (XInfoHandle*) dhandle;
+ return gsl_data_handle_get_state_length (chandle->src_handle);
+}
+
+
static GslDataHandle*
xinfo_data_handle_new (GslDataHandle *src_handle,
gboolean clear_xinfos,
@@ -511,6 +555,7 @@ xinfo_data_handle_new (GslDataHandle *sr
xinfo_handle_read,
xinfo_handle_close,
xinfo_get_source_handle,
+ xinfo_get_state_length,
xinfo_handle_destroy,
};
SfiRing *dest_added = NULL, *dest_remove = NULL;
@@ -686,6 +731,12 @@ chain_handle_close (GslDataHandle *dhand
gsl_data_handle_close (chandle->src_handle);
}
+static int64
+chain_handle_get_state_length (GslDataHandle *dhandle)
+{
+ ChainHandle *chandle = (ChainHandle*) dhandle;
+ return gsl_data_handle_get_state_length (chandle->src_handle);
+}
/* --- reversed handle --- */
static void
@@ -745,6 +796,7 @@ gsl_data_handle_new_reverse (GslDataHand
reverse_handle_read,
chain_handle_close,
NULL,
+ chain_handle_get_state_length,
reverse_handle_destroy,
};
ReversedHandle *rhandle;
@@ -853,6 +905,7 @@ gsl_data_handle_new_translate (GslDataHa
cut_handle_read,
chain_handle_close,
NULL,
+ chain_handle_get_state_length,
cut_handle_destroy,
};
CutHandle *chandle;
@@ -1032,6 +1085,14 @@ insert_handle_read (GslDataHandle *dhand
return orig_n_values - n_values;
}
+static int64
+insert_handle_get_state_length (GslDataHandle *dhandle)
+{
+ InsertHandle *ihandle = (InsertHandle*) dhandle;
+ return gsl_data_handle_get_state_length (ihandle->src_handle);
+}
+
+
GslDataHandle*
gsl_data_handle_new_insert (GslDataHandle *src_handle,
guint paste_bit_depth,
@@ -1045,6 +1106,7 @@ gsl_data_handle_new_insert (GslDataHandl
insert_handle_read,
insert_handle_close,
NULL,
+ insert_handle_get_state_length,
insert_handle_destroy,
};
InsertHandle *ihandle;
@@ -1161,6 +1223,7 @@ gsl_data_handle_new_looped (GslDataHandl
loop_handle_read,
chain_handle_close,
NULL,
+ chain_handle_get_state_length,
loop_handle_destroy,
};
LoopHandle *lhandle;
@@ -1259,6 +1322,13 @@ dcache_handle_get_source_handle (GslData
return chandle->dcache->dhandle;
}
+static int64
+dcache_handle_get_state_length (GslDataHandle *dhandle)
+{
+ DCacheHandle *chandle = (DCacheHandle*) dhandle;
+ return gsl_data_handle_get_state_length (chandle->dcache->dhandle);
+}
+
GslDataHandle*
gsl_data_handle_new_dcached (GslDataCache *dcache)
{
@@ -1267,6 +1337,7 @@ gsl_data_handle_new_dcached (GslDataCach
dcache_handle_read,
dcache_handle_close,
dcache_handle_get_source_handle,
+ dcache_handle_get_state_length,
dcache_handle_destroy,
};
DCacheHandle *dhandle;
@@ -1495,6 +1566,7 @@ gsl_wave_handle_new (const gchar *f
wave_handle_read,
wave_handle_close,
NULL,
+ NULL,
wave_handle_destroy,
};
WaveHandle *whandle;
Index: bse/gsldatahandle.h
===================================================================
--- bse/gsldatahandle.h (revision 4108)
+++ bse/gsldatahandle.h (working copy)
@@ -63,6 +63,7 @@ struct _GslDataHandleFuncs
gfloat *values);
void (*close) (GslDataHandle *data_handle);
GslDataHandle* (*get_source) (GslDataHandle *data_handle);
+ int64 (*get_state_length) (GslDataHandle *data_handle);
void (*destroy) (GslDataHandle *data_handle);
};
@@ -85,6 +86,7 @@ int64 gsl_data_handle_read (GslDataH
int64 value_offset,
int64 n_values,
gfloat *values);
+int64 gsl_data_handle_get_state_length (GslDataHandle *dhandle);
GslDataHandle* gsl_data_handle_get_source (GslDataHandle *dhandle);
GslDataHandle* gsl_data_handle_new_cut (GslDataHandle *src_handle,
int64 cut_offset,
Index: bse/tests/loophandle.c
===================================================================
--- bse/tests/loophandle.c (revision 4108)
+++ bse/tests/loophandle.c (working copy)
@@ -105,6 +105,14 @@ loop_handle_reference_read (GslDataHandl
}
}
+static int64
+loop_handle_reference_get_state_length (GslDataHandle *dhandle)
+{
+ LoopHandleReference *lhandle = (LoopHandleReference*) dhandle;
+ return gsl_data_handle_get_state_length (lhandle->src_handle);
+}
+
+
static GslDataHandle*
gsl_data_handle_new_looped_reference (GslDataHandle *src_handle,
GslLong loop_first,
@@ -115,6 +123,7 @@ gsl_data_handle_new_looped_reference (Gs
loop_handle_reference_read,
loop_handle_reference_close,
NULL,
+ loop_handle_reference_get_state_length,
loop_handle_reference_destroy,
};
LoopHandleReference *lhandle;
Index: bse/tests/resamplehandle.cc
===================================================================
--- bse/tests/resamplehandle.cc (revision 4108)
+++ bse/tests/resamplehandle.cc (working copy)
@@ -371,6 +371,111 @@ test_delay_compensation (const char *run
TDONE();
}
+static void
+test_state_length (const char *run_type)
+{
+ TSTART ("Resampler State Length Info (%s)", run_type);
+
+ //-----------------------------------------------------------------------------------
+ // usampling
+ //-----------------------------------------------------------------------------------
+ {
+ const guint period_size = 107;
+
+ /* fill input with 2 periods of a sine wave, so that while at the start and
+ * at the end clicks occur (because the unwindowed signal is assumed to 0 by
+ * the resamplehandle), in the middle 1 period can be found that is clickless
+ */
+ vector<float> input (period_size * 2);
+ for (size_t i = 0; i < input.size(); i++)
+ input[i] = sin (i * 2 * M_PI / period_size);
+
+ const guint precision_bits = 16;
+ GslDataHandle *ihandle = gsl_data_handle_new_mem (1, 32, 44100, 440, input.size(), &input[0], NULL);
+ GslDataHandle *rhandle = bse_data_handle_new_upsample2 (ihandle, precision_bits);
+ BseErrorType open_error = gsl_data_handle_open (rhandle);
+ TASSERT (open_error == 0);
+ TASSERT (gsl_data_handle_get_state_length (ihandle) == 0);
+
+ // determine how much of the end of the signal is "unusable" due to the resampler state:
+ const int64 state_length = gsl_data_handle_get_state_length (rhandle);
+
+ /* read resampled signal in the range unaffected by the resampler state (that
+ * is: not at the directly at the beginning, and not directly at the end)
+ */
+ vector<float> output (input.size() * 3);
+ for (size_t values_done = 0; values_done < output.size(); values_done++)
+ {
+ /* NOTE: this is an inlined implementation of a loop, which you normally would
+ * implement with a loop handle, and it is inefficient because we read the
+ * samples one-by-one -> usually: don't use such code, always read in blocks */
+ int64 read_pos = (values_done + state_length) % (period_size * 2) + (period_size * 2 - state_length);
+ TCHECK (read_pos >= state_length); /* check that input signal was long enough to be for this test */
+ int64 values_read = gsl_data_handle_read (rhandle, read_pos, 1, &output[values_done]);
+ TCHECK (values_read == 1);
+ }
+ double error = 0;
+ for (size_t i = 0; i < output.size(); i++)
+ {
+ double expected = sin (i * 2 * M_PI / (period_size * 2));
+ error = MAX (error, fabs (output[i] - expected));
+ }
+ double error_db = bse_db_from_factor (error, -200);
+ TASSERT (error_db < -97);
+ }
+
+ //-----------------------------------------------------------------------------------
+ // downsampling
+ //-----------------------------------------------------------------------------------
+
+ {
+ const guint period_size = 190;
+
+ /* fill input with 2 periods of a sine wave, so that while at the start and
+ * at the end clicks occur (because the unwindowed signal is assumed to 0 by
+ * the resamplehandle), in the middle 1 period can be found that is clickless
+ */
+ vector<float> input (period_size * 2);
+ for (size_t i = 0; i < input.size(); i++)
+ input[i] = sin (i * 2 * M_PI / period_size);
+
+ const guint precision_bits = 16;
+ GslDataHandle *ihandle = gsl_data_handle_new_mem (1, 32, 44100, 440, input.size(), &input[0], NULL);
+ GslDataHandle *rhandle = bse_data_handle_new_downsample2 (ihandle, precision_bits);
+ BseErrorType open_error = gsl_data_handle_open (rhandle);
+ TASSERT (open_error == 0);
+ TASSERT (gsl_data_handle_get_state_length (ihandle) == 0);
+
+ // determine how much of the end of the signal is "unusable" due to the resampler state:
+ const int64 state_length = gsl_data_handle_get_state_length (rhandle);
+
+ /* read resampled signal in the range unaffected by the resampler state (that
+ * is: not at the directly at the beginning, and not directly at the end)
+ */
+ vector<float> output (input.size() * 3 / 2);
+ for (size_t values_done = 0; values_done < output.size(); values_done++)
+ {
+ /* NOTE: this is an inlined implementation of a loop, which you normally would
+ * implement with a loop handle, and it is inefficient because we read the
+ * samples one-by-one -> usually: don't use such code, always read in blocks */
+ int64 read_pos = (values_done + state_length) % (period_size / 2) + (period_size / 2 - state_length);
+ TCHECK (read_pos >= state_length); /* check that input signal was long enough to be for this test */
+ int64 values_read = gsl_data_handle_read (rhandle, read_pos, 1, &output[values_done]);
+ TCHECK (values_read == 1);
+ }
+ double error = 0;
+ for (size_t i = 0; i < output.size(); i++)
+ {
+ double expected = sin (i * 2 * M_PI / (period_size / 2));
+ error = MAX (error, fabs (output[i] - expected));
+ }
+ double error_db = bse_db_from_factor (error, -200);
+ TASSERT (error_db < -105);
+ }
+ TDONE();
+}
+
+
int
main (int argc,
char *argv[])
@@ -385,6 +490,7 @@ main (int argc,
test_c_api ("FPU");
test_delay_compensation ("FPU");
+ test_state_length ("FPU");
run_tests ("FPU");
/* load plugins */
@@ -399,6 +505,7 @@ main (int argc,
test_c_api ("SSE");
test_delay_compensation ("SSE");
+ test_state_length ("SSE");
run_tests ("SSE");
return 0;
Index: bse/bsedatahandle-resample.cc
===================================================================
--- bse/bsedatahandle-resample.cc (revision 4108)
+++ bse/bsedatahandle-resample.cc (working copy)
@@ -137,7 +137,7 @@ protected:
}
/* implemented by upsampling and downsampling datahandle */
- virtual BseResampler2Mode mode () = 0;
+ virtual BseResampler2Mode mode () const = 0;
virtual int64 read_frame (int64 frame) = 0;
public:
@@ -238,7 +238,28 @@ public:
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);
+ if (mode() == BSE_RESAMPLER2_MODE_UPSAMPLE)
+ source_state_length *= 2;
+ else
+ source_state_length = (source_state_length + 1) / 2;
+
+ // we must be opened => n_channels > 0, 1 Resampler per Channel
+ g_return_val_if_fail (!m_resamplers.empty(), 0);
+
+ /* For fractional delays, a delay of 10.5 for instance means that input[0]
+ * affects samples 10 and 11, and thus the state length we assume for
+ * that case is 11.
+ */
+ int64 per_channel_state = ceil (m_resamplers[0]->delay());
+ return source_state_length + per_channel_state * m_dhandle.setup.n_channels;
+ }
static GslDataHandle*
dh_create (DataHandleResample2 *cxx_dh)
{
@@ -248,8 +269,10 @@ public:
dh_read,
dh_close,
NULL,
+ dh_get_state_length,
dh_destroy,
};
+
if (cxx_dh->m_init_ok)
{
cxx_dh->m_dhandle.vtable = &dh_vtable;
@@ -262,7 +285,6 @@ public:
return NULL;
}
}
-
private:
/* for the "C" API (vtable) */
static DataHandleResample2*
@@ -294,6 +316,11 @@ private:
{
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 DataHandleUpsample2 : public DataHandleResample2
@@ -307,7 +334,7 @@ public:
m_dhandle.name = g_strconcat (m_src_handle->name, "// #upsample2 /", NULL);
}
BseResampler2Mode
- mode()
+ mode() const
{
return BSE_RESAMPLER2_MODE_UPSAMPLE;
}
@@ -382,7 +409,7 @@ public:
{
}
BseResampler2Mode
- mode()
+ mode() const
{
return BSE_RESAMPLER2_MODE_DOWNSAMPLE;
}
Cu... Stefan
--
Stefan Westerfeld, Hamburg/Germany, http://space.twc.de/~stefan
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]