diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-05 00:01:18 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-05 00:01:18 +0000 |
commit | 42995d7bf396933ee60c5f89c354ea89cf13df0d (patch) | |
tree | cfdcea0ac57420e7baf570bfe435e107bb842541 /flow/gsl/gsldatahandle.c | |
download | arts-42995d7bf396933ee60c5f89c354ea89cf13df0d.tar.gz arts-42995d7bf396933ee60c5f89c354ea89cf13df0d.zip |
Copy of aRts for Trinity modifications
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/dependencies/arts@1070145 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'flow/gsl/gsldatahandle.c')
-rw-r--r-- | flow/gsl/gsldatahandle.c | 1241 |
1 files changed, 1241 insertions, 0 deletions
diff --git a/flow/gsl/gsldatahandle.c b/flow/gsl/gsldatahandle.c new file mode 100644 index 0000000..c746ec7 --- /dev/null +++ b/flow/gsl/gsldatahandle.c @@ -0,0 +1,1241 @@ +/* GSL - Generic Sound Layer + * Copyright (C) 2001 Tim Janik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include "gsldatahandle.h" + +#include "gslcommon.h" +#include "gsldatacache.h" +#include "gslfilehash.h" + +#include <string.h> +#include <errno.h> + + +/* --- typedefs --- */ +typedef struct { + GslDataHandle dhandle; + guint n_channels; + guint bit_depth; + GslLong n_values; + const gfloat *values; + void (*free_values) (gpointer); +} MemHandle; +typedef struct { + GslDataHandle dhandle; + GslDataHandle *src_handle; +} ChainHandle; +typedef ChainHandle ReversedHandle; +typedef struct { + GslDataHandle dhandle; + GslDataHandle *src_handle; /* mirror ChainHandle */ + GslLong cut_offset; + GslLong n_cut_values; + GslLong tail_cut; +} CutHandle; +typedef struct { + GslDataHandle dhandle; + GslDataHandle *src_handle; /* mirror ChainHandle */ + GslLong requested_paste_offset; + GslLong paste_offset; + GslLong n_paste_values; + guint paste_bit_depth; + const gfloat *paste_values; + void (*free_values) (gpointer); +} InsertHandle; +typedef struct { + GslDataHandle dhandle; + GslDataHandle *src_handle; /* mirror ChainHandle */ + GslLong requested_first; + GslLong requested_last; + GslLong loop_start; + GslLong loop_width; +} LoopHandle; +typedef struct { + GslDataHandle dhandle; + GslDataCache *dcache; + guint node_size; +} DCacheHandle; +typedef struct { + GslDataHandle dhandle; + guint n_channels; + GslWaveFormatType format; + guint byte_order; + GslLong byte_offset; + GslLong requested_length; + GslHFile *hfile; +} WaveHandle; + + +/* --- standard functions --- */ +gboolean +gsl_data_handle_common_init (GslDataHandle *dhandle, + const gchar *file_name) +{ + g_return_val_if_fail (dhandle != NULL, FALSE); + g_return_val_if_fail (dhandle->vtable == NULL, FALSE); + g_return_val_if_fail (dhandle->name == NULL, FALSE); + g_return_val_if_fail (dhandle->ref_count == 0, FALSE); + + dhandle->name = g_strdup (file_name); + gsl_mutex_init (&dhandle->mutex); + dhandle->ref_count = 1; + dhandle->open_count = 0; + memset (&dhandle->setup, 0, sizeof (dhandle->setup)); + + return TRUE; +} + +GslDataHandle* +gsl_data_handle_ref (GslDataHandle *dhandle) +{ + g_return_val_if_fail (dhandle != NULL, NULL); + g_return_val_if_fail (dhandle->ref_count > 0, NULL); + + GSL_SPIN_LOCK (&dhandle->mutex); + dhandle->ref_count++; + GSL_SPIN_UNLOCK (&dhandle->mutex); + + return dhandle; +} + +void +gsl_data_handle_common_free (GslDataHandle *dhandle) +{ + g_return_if_fail (dhandle != NULL); + g_return_if_fail (dhandle->vtable != NULL); + g_return_if_fail (dhandle->ref_count == 0); + + g_free (dhandle->name); + dhandle->name = NULL; + gsl_mutex_destroy (&dhandle->mutex); +} + +void +gsl_data_handle_unref (GslDataHandle *dhandle) +{ + gboolean destroy; + + g_return_if_fail (dhandle != NULL); + g_return_if_fail (dhandle->ref_count > 0); + + GSL_SPIN_LOCK (&dhandle->mutex); + dhandle->ref_count--; + destroy = dhandle->ref_count == 0; + GSL_SPIN_UNLOCK (&dhandle->mutex); + if (destroy) + { + g_return_if_fail (dhandle->open_count == 0); + dhandle->vtable->destroy (dhandle); + } +} + +GslErrorType +gsl_data_handle_open (GslDataHandle *dhandle) +{ + g_return_val_if_fail (dhandle != NULL, GSL_ERROR_INTERNAL); + g_return_val_if_fail (dhandle->ref_count > 0, GSL_ERROR_INTERNAL); + + GSL_SPIN_LOCK (&dhandle->mutex); + if (dhandle->open_count == 0) + { + GslErrorType error; + + memset (&dhandle->setup, 0, sizeof (dhandle->setup)); + error = dhandle->vtable->open (dhandle, &dhandle->setup); + if (!error && (dhandle->setup.n_values < 0 || + dhandle->setup.n_channels < 1 || + dhandle->setup.bit_depth < 1)) + { + g_warning ("internal error in data handle open() (%p): nv=%ld nc=%u bd=%u", + dhandle->vtable->open, dhandle->setup.n_values, dhandle->setup.n_channels, dhandle->setup.bit_depth); + dhandle->vtable->close (dhandle); + error = GSL_ERROR_INTERNAL; + } + if (error) + { + memset (&dhandle->setup, 0, sizeof (dhandle->setup)); + GSL_SPIN_UNLOCK (&dhandle->mutex); + return error; + } + dhandle->ref_count++; + dhandle->open_count++; + } + else + dhandle->open_count++; + GSL_SPIN_UNLOCK (&dhandle->mutex); + + return GSL_ERROR_NONE; +} + +void +gsl_data_handle_close (GslDataHandle *dhandle) +{ + gboolean need_unref; + + g_return_if_fail (dhandle != NULL); + g_return_if_fail (dhandle->ref_count > 0); + g_return_if_fail (dhandle->open_count > 0); + + GSL_SPIN_LOCK (&dhandle->mutex); + dhandle->open_count--; + need_unref = !dhandle->open_count; + if (!dhandle->open_count) + dhandle->vtable->close (dhandle); + GSL_SPIN_UNLOCK (&dhandle->mutex); + if (need_unref) + gsl_data_handle_unref (dhandle); +} + +GslLong +gsl_data_handle_read (GslDataHandle *dhandle, + GslLong value_offset, + GslLong n_values, + gfloat *values) +{ + GslLong l; + + g_return_val_if_fail (dhandle != NULL, -1); + g_return_val_if_fail (dhandle->open_count > 0, -1); + g_return_val_if_fail (value_offset >= 0, -1); + if (n_values < 1) + return 0; + g_return_val_if_fail (values != NULL, -1); + g_return_val_if_fail (value_offset < dhandle->setup.n_values, -1); + + n_values = MIN (n_values, dhandle->setup.n_values - value_offset); + GSL_SPIN_LOCK (&dhandle->mutex); + l = dhandle->vtable->read (dhandle, value_offset, n_values, values); + GSL_SPIN_UNLOCK (&dhandle->mutex); + + return l; +} + +GslLong +gsl_data_handle_length (GslDataHandle *dhandle) +{ + GslLong l; + + g_return_val_if_fail (dhandle != NULL, 0); + g_return_val_if_fail (dhandle->open_count > 0, 0); + + GSL_SPIN_LOCK (&dhandle->mutex); + l = dhandle->open_count ? dhandle->setup.n_values : 0; + GSL_SPIN_UNLOCK (&dhandle->mutex); + + return l; +} + +guint +gsl_data_handle_n_channels (GslDataHandle *dhandle) +{ + guint n; + + g_return_val_if_fail (dhandle != NULL, 0); + g_return_val_if_fail (dhandle->open_count > 0, 0); + + GSL_SPIN_LOCK (&dhandle->mutex); + n = dhandle->open_count ? dhandle->setup.n_channels : 0; + GSL_SPIN_UNLOCK (&dhandle->mutex); + + return n; +} + +guint +gsl_data_handle_bit_depth (GslDataHandle *dhandle) +{ + guint n; + + g_return_val_if_fail (dhandle != NULL, 0); + g_return_val_if_fail (dhandle->open_count > 0, 0); + + GSL_SPIN_LOCK (&dhandle->mutex); + n = dhandle->open_count ? dhandle->setup.bit_depth : 0; + GSL_SPIN_UNLOCK (&dhandle->mutex); + + return n; +} + +const gchar* +gsl_data_handle_name (GslDataHandle *dhandle) +{ + g_return_val_if_fail (dhandle != NULL, NULL); + + return dhandle->name; +} + + +/* --- const memory handle --- */ +static GslErrorType +mem_handle_open (GslDataHandle *dhandle, + GslDataHandleSetup *setup) +{ + MemHandle *mhandle = (MemHandle*) dhandle; + + setup->n_values = mhandle->n_values; + setup->n_channels = mhandle->n_channels; + setup->bit_depth = mhandle->bit_depth; + + return GSL_ERROR_NONE; +} + +static void +mem_handle_close (GslDataHandle *dhandle) +{ + /* MemHandle *mhandle = (MemHandle*) dhandle; */ +} + +static void +mem_handle_destroy (GslDataHandle *dhandle) +{ + MemHandle *mhandle = (MemHandle*) dhandle; + void (*free_values) (gpointer) = mhandle->free_values; + const gfloat *mem_values = mhandle->values; + + gsl_data_handle_common_free (dhandle); + mhandle->values = NULL; + mhandle->free_values = NULL; + gsl_delete_struct (MemHandle, mhandle); + + if (free_values) + free_values ((gpointer) mem_values); +} + +static GslLong +mem_handle_read (GslDataHandle *dhandle, + GslLong voffset, + GslLong n_values, + gfloat *values) +{ + MemHandle *mhandle = (MemHandle*) dhandle; + + g_return_val_if_fail (voffset + n_values <= mhandle->n_values, -1); + + memcpy (values, mhandle->values + voffset, n_values * sizeof (values[0])); + + return n_values; +} + +GslDataHandle* +gsl_data_handle_new_mem (guint n_channels, + guint bit_depth, + GslLong n_values, + const gfloat *values, + void (*free) (gpointer values)) +{ + static GslDataHandleFuncs mem_handle_vtable = { + mem_handle_open, + mem_handle_read, + mem_handle_close, + mem_handle_destroy, + }; + MemHandle *mhandle; + gboolean success; + + g_return_val_if_fail (n_channels > 0, NULL); + g_return_val_if_fail (bit_depth > 0, NULL); + g_return_val_if_fail (n_values >= n_channels, NULL); + if (n_values) + g_return_val_if_fail (values != NULL, NULL); + + mhandle = gsl_new_struct0 (MemHandle, 1); + success = gsl_data_handle_common_init (&mhandle->dhandle, NULL); + if (success) + { + mhandle->dhandle.name = g_strconcat ("// #memory /", NULL); + mhandle->dhandle.vtable = &mem_handle_vtable; + mhandle->n_channels = n_channels; + mhandle->bit_depth = bit_depth; + mhandle->n_values = n_values / mhandle->n_channels; + mhandle->n_values *= mhandle->n_channels; + mhandle->values = values; + mhandle->free_values = free; + } + else + { + gsl_delete_struct (MemHandle, mhandle); + return NULL; + } + return &mhandle->dhandle; +} + + +/* --- chain handle --- */ +static GslErrorType +chain_handle_open (GslDataHandle *dhandle, + GslDataHandleSetup *setup) +{ + ChainHandle *chandle = (ChainHandle*) dhandle; + GslErrorType error; + + error = gsl_data_handle_open (chandle->src_handle); + if (error != GSL_ERROR_NONE) + return error; + *setup = chandle->src_handle->setup; + + return GSL_ERROR_NONE; +} + +static void +chain_handle_close (GslDataHandle *dhandle) +{ + ChainHandle *chandle = (ChainHandle*) dhandle; + + gsl_data_handle_close (chandle->src_handle); +} + + +/* --- reversed handle --- */ +static void +reverse_handle_destroy (GslDataHandle *data_handle) +{ + ReversedHandle *rhandle = (ReversedHandle*) data_handle; + + gsl_data_handle_unref (rhandle->src_handle); + + gsl_data_handle_common_free (data_handle); + gsl_delete_struct (ReversedHandle, rhandle); +} + +static GslLong +reverse_handle_read (GslDataHandle *dhandle, + GslLong voffset, + GslLong n_values, + gfloat *values) +{ + ReversedHandle *rhandle = (ReversedHandle*) dhandle; + GslLong left, new_offset = dhandle->setup.n_values - (voffset + n_values); + gfloat *t, *p = values; + + g_assert (new_offset >= 0); + + left = n_values; + do + { + GslLong l = gsl_data_handle_read (rhandle->src_handle, new_offset, left, p); + + if (l < 0) + return l; /* pass on errors */ + + new_offset += l; + left -= l; + p += l; + } + while (left > 0); + + p = values; + t = values + n_values - 1; + while (p < t) + { + gfloat v = *t; + + *t-- = *p; + *p++ = v; + } + return n_values; +} + +GslDataHandle* +gsl_data_handle_new_reverse (GslDataHandle *src_handle) +{ + static GslDataHandleFuncs reverse_handle_vtable = { + chain_handle_open, + reverse_handle_read, + chain_handle_close, + reverse_handle_destroy, + }; + ReversedHandle *rhandle; + gboolean success; + + g_return_val_if_fail (src_handle != NULL, NULL); + + rhandle = gsl_new_struct0 (ReversedHandle, 1); + success = gsl_data_handle_common_init (&rhandle->dhandle, NULL); + if (success) + { + rhandle->dhandle.name = g_strconcat (src_handle->name, "// #reversed /", NULL); + rhandle->dhandle.vtable = &reverse_handle_vtable; + rhandle->src_handle = gsl_data_handle_ref (src_handle); + } + else + { + gsl_delete_struct (ReversedHandle, rhandle); + return NULL; + } + return &rhandle->dhandle; +} + + +/* --- cut handle --- */ +static GslErrorType +cut_handle_open (GslDataHandle *dhandle, + GslDataHandleSetup *setup) +{ + CutHandle *chandle = (CutHandle*) dhandle; + GslErrorType error; + + error = gsl_data_handle_open (chandle->src_handle); + if (error != GSL_ERROR_NONE) + return error; + *setup = chandle->src_handle->setup; + setup->n_values -= MIN (setup->n_values, chandle->tail_cut); + setup->n_values -= MIN (setup->n_values, chandle->n_cut_values); + + return GSL_ERROR_NONE; +} + +static void +cut_handle_destroy (GslDataHandle *data_handle) +{ + CutHandle *chandle = (CutHandle*) data_handle; + + gsl_data_handle_unref (chandle->src_handle); + + gsl_data_handle_common_free (data_handle); + gsl_delete_struct (CutHandle, chandle); +} + +static GslLong +cut_handle_read (GslDataHandle *dhandle, + GslLong voffset, + GslLong n_values, + gfloat *values) +{ + CutHandle *chandle = (CutHandle*) dhandle; + GslLong orig_n_values = n_values; + + if (voffset < chandle->cut_offset) + { + GslLong l = MIN (chandle->cut_offset - voffset, n_values); + + l = gsl_data_handle_read (chandle->src_handle, voffset, l, values); + if (l < 0) + return l; /* pass on errors */ + n_values -= l; + values += l; + voffset += l; + } + + if (voffset >= chandle->cut_offset && n_values) + { + GslLong l = gsl_data_handle_read (chandle->src_handle, voffset + chandle->n_cut_values, n_values, values); + + if (l < 0 && orig_n_values == n_values) + return l; /* pass on errors */ + else if (l < 0) + l = 0; + + n_values -= l; + } + + return orig_n_values - n_values; +} + +static GslDataHandle* +gsl_data_handle_new_translate (GslDataHandle *src_handle, + GslLong cut_offset, + GslLong n_cut_values, + GslLong tail_cut) +{ + static GslDataHandleFuncs cut_handle_vtable = { + cut_handle_open, + cut_handle_read, + chain_handle_close, + cut_handle_destroy, + }; + CutHandle *chandle; + gboolean success; + + g_return_val_if_fail (src_handle != NULL, NULL); + g_return_val_if_fail (cut_offset >= 0 && n_cut_values >= 0 && tail_cut >= 0, NULL); + + chandle = gsl_new_struct0 (CutHandle, 1); + success = gsl_data_handle_common_init (&chandle->dhandle, NULL); + if (success) + { + chandle->dhandle.name = g_strconcat (src_handle->name, "// #translate /", NULL); + chandle->dhandle.vtable = &cut_handle_vtable; + chandle->src_handle = gsl_data_handle_ref (src_handle); + chandle->cut_offset = n_cut_values ? cut_offset : 0; + chandle->n_cut_values = n_cut_values; + chandle->tail_cut = tail_cut; + } + else + { + gsl_delete_struct (CutHandle, chandle); + return NULL; + } + return &chandle->dhandle; +} + +/** + * gsl_data_handle_new_cut + * @src_handle: source GslDataHandle + * @cut_offset: offset of gap into @src_handle + * @n_cut_values: length of gap in @src_handle + * @RETURNS: a newly created data handle + * + * Create a new data handle containing the contents of @src_handle + * minus @n_cut_values at offset @cut_offset. + */ +GslDataHandle* +gsl_data_handle_new_cut (GslDataHandle *src_handle, + GslLong cut_offset, + GslLong n_cut_values) +{ + return gsl_data_handle_new_translate (src_handle, cut_offset, n_cut_values, 0); +} + +/** + * gsl_data_handle_new_crop + * @src_handle: source GslDataHandle + * @n_head_cut: number of values to cut at data handle head + * @n_tail_cut: number of values to cut at data handle tail + * @RETURNS: a newly created data handle + * + * Create a new data handle containing the contents of @src_handle + * minus @n_head_cut values at the start and @n_tail_cut values at + * the end. + */ +GslDataHandle* +gsl_data_handle_new_crop (GslDataHandle *src_handle, + GslLong n_head_cut, + GslLong n_tail_cut) +{ + return gsl_data_handle_new_translate (src_handle, 0, n_head_cut, n_tail_cut); +} + + +/* --- insert handle --- */ +static GslErrorType +insert_handle_open (GslDataHandle *dhandle, + GslDataHandleSetup *setup) +{ + InsertHandle *ihandle = (InsertHandle*) dhandle; + GslErrorType error; + + error = gsl_data_handle_open (ihandle->src_handle); + if (error != GSL_ERROR_NONE) + return error; + *setup = ihandle->src_handle->setup; + ihandle->paste_offset = ihandle->requested_paste_offset < 0 ? setup->n_values : ihandle->requested_paste_offset; + if (setup->n_values < ihandle->paste_offset) + setup->n_values = ihandle->paste_offset + ihandle->n_paste_values; + else + setup->n_values += ihandle->n_paste_values; + setup->bit_depth = MAX (setup->bit_depth, ihandle->paste_bit_depth); + + return GSL_ERROR_NONE; +} + +static void +insert_handle_destroy (GslDataHandle *data_handle) +{ + InsertHandle *ihandle = (InsertHandle*) data_handle; + void (*free_values) (gpointer) = ihandle->free_values; + const gfloat *paste_values = ihandle->paste_values; + + gsl_data_handle_unref (ihandle->src_handle); + + gsl_data_handle_common_free (data_handle); + ihandle->paste_values = NULL; + ihandle->free_values = NULL; + gsl_delete_struct (InsertHandle, ihandle); + + if (free_values) + free_values ((gpointer) paste_values); +} + +static GslLong +insert_handle_read (GslDataHandle *data_handle, + GslLong voffset, + GslLong n_values, + gfloat *values) +{ + InsertHandle *ihandle = (InsertHandle*) data_handle; + GslLong l, orig_n_values = n_values; + + if (voffset < ihandle->src_handle->setup.n_values && + voffset < ihandle->paste_offset) + { + l = MIN (n_values, MIN (ihandle->paste_offset, ihandle->src_handle->setup.n_values) - voffset); + l = gsl_data_handle_read (ihandle->src_handle, voffset, l, values); + if (l < 0) + return l; /* pass on errors */ + + voffset += l; + n_values -= l; + values += l; + } + + if (n_values && voffset >= ihandle->src_handle->setup.n_values && voffset < ihandle->paste_offset) + { + l = MIN (n_values, ihandle->paste_offset - voffset); + memset (values, 0, l * sizeof (values[0])); + voffset += l; + n_values -= l; + values += l; + } + + if (n_values && voffset >= ihandle->paste_offset && voffset < ihandle->paste_offset + ihandle->n_paste_values) + { + l = MIN (n_values, ihandle->paste_offset + ihandle->n_paste_values - voffset); + memcpy (values, ihandle->paste_values + voffset - ihandle->paste_offset, l * sizeof (values[0])); + voffset += l; + n_values -= l; + values += l; + } + + if (n_values && voffset >= ihandle->paste_offset + ihandle->n_paste_values) + { + l = gsl_data_handle_read (ihandle->src_handle, voffset - ihandle->n_paste_values, n_values, values); + if (l < 0 && orig_n_values == n_values) + return l; /* pass on errors */ + else if (l < 0) + l = 0; + n_values -= l; + } + + return orig_n_values - n_values; +} + +GslDataHandle* +gsl_data_handle_new_insert (GslDataHandle *src_handle, + guint paste_bit_depth, + GslLong insertion_offset, + GslLong n_paste_values, + const gfloat *paste_values, + void (*free) (gpointer values)) +{ + static GslDataHandleFuncs insert_handle_vtable = { + insert_handle_open, + insert_handle_read, + chain_handle_close, + insert_handle_destroy, + }; + InsertHandle *ihandle; + gboolean success; + + g_return_val_if_fail (src_handle != NULL, NULL); + g_return_val_if_fail (n_paste_values >= 0, NULL); + if (n_paste_values) + g_return_val_if_fail (paste_values != NULL, NULL); + + ihandle = gsl_new_struct0 (InsertHandle, 1); + success = gsl_data_handle_common_init (&ihandle->dhandle, NULL); + if (success) + { + ihandle->dhandle.name = g_strconcat (src_handle ? src_handle->name : "", "// #insert /", NULL); + ihandle->dhandle.vtable = &insert_handle_vtable; + ihandle->src_handle = gsl_data_handle_ref (src_handle); + ihandle->requested_paste_offset = insertion_offset; + ihandle->paste_offset = 0; + ihandle->n_paste_values = n_paste_values; + ihandle->paste_bit_depth = paste_bit_depth; + ihandle->paste_values = paste_values; + ihandle->free_values = free; + } + else + { + gsl_delete_struct (InsertHandle, ihandle); + return NULL; + } + return &ihandle->dhandle; +} + + +/* --- loop handle --- */ +static GslErrorType +loop_handle_open (GslDataHandle *dhandle, + GslDataHandleSetup *setup) +{ + LoopHandle *lhandle = (LoopHandle*) dhandle; + GslErrorType error; + + error = gsl_data_handle_open (lhandle->src_handle); + if (error != GSL_ERROR_NONE) + return error; + + *setup = lhandle->src_handle->setup; + if (setup->n_values > lhandle->requested_last) + { + lhandle->loop_start = lhandle->requested_first; + lhandle->loop_width = lhandle->requested_last - lhandle->requested_first + 1; + setup->n_values = GSL_MAXLONG; + } + else /* cannot loop */ + { + lhandle->loop_start = setup->n_values; + lhandle->loop_width = 0; + } + + return GSL_ERROR_NONE; +} + +static void +loop_handle_destroy (GslDataHandle *data_handle) +{ + LoopHandle *lhandle = (LoopHandle*) data_handle; + + gsl_data_handle_unref (lhandle->src_handle); + + gsl_data_handle_common_free (data_handle); + gsl_delete_struct (LoopHandle, lhandle); +} + +static GslLong +loop_handle_read (GslDataHandle *data_handle, + GslLong voffset, + GslLong n_values, + gfloat *values) +{ + LoopHandle *lhandle = (LoopHandle*) data_handle; + + if (voffset < lhandle->loop_start) + return gsl_data_handle_read (lhandle->src_handle, voffset, + MIN (lhandle->loop_start - voffset, n_values), + values); + else + { + GslLong noffset = voffset - lhandle->loop_start; + + noffset %= lhandle->loop_width; + + return gsl_data_handle_read (lhandle->src_handle, + lhandle->loop_start + noffset, + MIN (lhandle->loop_width - noffset, n_values), + values); + } +} + +GslDataHandle* +gsl_data_handle_new_looped (GslDataHandle *src_handle, + GslLong loop_first, + GslLong loop_last) +{ + static GslDataHandleFuncs loop_handle_vtable = { + loop_handle_open, + loop_handle_read, + chain_handle_close, + loop_handle_destroy, + }; + LoopHandle *lhandle; + gboolean success; + + g_return_val_if_fail (src_handle != NULL, NULL); + g_return_val_if_fail (loop_first >= 0, NULL); + g_return_val_if_fail (loop_last >= loop_first, NULL); + + lhandle = gsl_new_struct0 (LoopHandle, 1); + success = gsl_data_handle_common_init (&lhandle->dhandle, NULL); + if (success) + { + lhandle->dhandle.name = g_strdup_printf ("%s// #loop(0x%lx:0x%lx) /", src_handle->name, loop_first, loop_last); + lhandle->dhandle.vtable = &loop_handle_vtable; + lhandle->src_handle = gsl_data_handle_ref (src_handle); + lhandle->requested_first = loop_first; + lhandle->requested_last = loop_last; + lhandle->loop_start = 0; + lhandle->loop_width = 0; + } + else + { + gsl_delete_struct (LoopHandle, lhandle); + return NULL; + } + return &lhandle->dhandle; +} + + +/* --- dcache handle --- */ +static void +dcache_handle_destroy (GslDataHandle *data_handle) +{ + DCacheHandle *dhandle = (DCacheHandle*) data_handle; + + gsl_data_cache_unref (dhandle->dcache); + + gsl_data_handle_common_free (data_handle); + gsl_delete_struct (DCacheHandle, dhandle); +} + +static GslErrorType +dcache_handle_open (GslDataHandle *dhandle, + GslDataHandleSetup *setup) +{ + DCacheHandle *chandle = (DCacheHandle*) dhandle; + GslErrorType error; + + error = gsl_data_handle_open (chandle->dcache->dhandle); + if (error != GSL_ERROR_NONE) + return error; + gsl_data_cache_open (chandle->dcache); + *setup = chandle->dcache->dhandle->setup; + gsl_data_handle_close (chandle->dcache->dhandle); + + return GSL_ERROR_NONE; +} + +static void +dcache_handle_close (GslDataHandle *data_handle) +{ + DCacheHandle *dhandle = (DCacheHandle*) data_handle; + + gsl_data_cache_close (dhandle->dcache); +} + +static GslLong +dcache_handle_read (GslDataHandle *data_handle, + GslLong voffset, + GslLong n_values, + gfloat *values) +{ + DCacheHandle *dhandle = (DCacheHandle*) data_handle; + GslDataCacheNode *node; + + node = gsl_data_cache_ref_node (dhandle->dcache, voffset, TRUE); + voffset -= node->offset; + n_values = MIN (n_values, dhandle->node_size - voffset); + memcpy (values, node->data + voffset, sizeof (values[0]) * n_values); + + return n_values; +} + +GslDataHandle* +gsl_data_handle_new_dcached (GslDataCache *dcache) +{ + static GslDataHandleFuncs dcache_handle_vtable = { + dcache_handle_open, + dcache_handle_read, + dcache_handle_close, + dcache_handle_destroy, + }; + DCacheHandle *dhandle; + gboolean success; + + g_return_val_if_fail (dcache != NULL, NULL); + + dhandle = gsl_new_struct0 (DCacheHandle, 1); + success = gsl_data_handle_common_init (&dhandle->dhandle, NULL); + if (success) + { + dhandle->dhandle.name = g_strdup_printf ("%s// #dcache /", dcache->dhandle->name); + dhandle->dhandle.vtable = &dcache_handle_vtable; + dhandle->dcache = gsl_data_cache_ref (dcache); + dhandle->node_size = GSL_DATA_CACHE_NODE_SIZE (dcache) + dcache->padding; + } + else + { + gsl_delete_struct (DCacheHandle, dhandle); + return NULL; + } + return &dhandle->dhandle; +} + + +/* --- wave handle --- */ +static inline const guint G_GNUC_CONST +wave_format_bit_depth (const GslWaveFormatType format) +{ + switch (format) + { + case GSL_WAVE_FORMAT_UNSIGNED_8: + case GSL_WAVE_FORMAT_SIGNED_8: + return 8; + case GSL_WAVE_FORMAT_UNSIGNED_12: + case GSL_WAVE_FORMAT_SIGNED_12: + return 12; + case GSL_WAVE_FORMAT_UNSIGNED_16: + case GSL_WAVE_FORMAT_SIGNED_16: + return 16; + case GSL_WAVE_FORMAT_FLOAT: + return 32; + default: + return 0; + } +} +#define wave_format_byte_width(f) ((wave_format_bit_depth (f) + 7) / 8) + +static void +wave_handle_destroy (GslDataHandle *data_handle) +{ + WaveHandle *whandle = (WaveHandle*) data_handle; + + gsl_data_handle_common_free (data_handle); + gsl_delete_struct (WaveHandle, whandle); +} + +static GslErrorType +wave_handle_open (GslDataHandle *data_handle, + GslDataHandleSetup *setup) +{ + WaveHandle *whandle = (WaveHandle*) data_handle; + + whandle->hfile = gsl_hfile_open (whandle->dhandle.name); + if (!whandle->hfile) + return gsl_error_from_errno (errno, GSL_ERROR_OPEN_FAILED); + else + { + GslLong l, fwidth = wave_format_byte_width (whandle->format); + /* convert size into n_values, i.e. float length */ + l = whandle->hfile->n_bytes; + l -= MIN (l, whandle->byte_offset); + if (l >= fwidth) + { + l /= fwidth; + if (whandle->requested_length < 0) + setup->n_values = l; + else + setup->n_values = MIN (l, whandle->requested_length); + } + else + setup->n_values = 0; + setup->n_channels = whandle->n_channels; + setup->bit_depth = wave_format_bit_depth (whandle->format); + return GSL_ERROR_NONE; + } +} + +static void +wave_handle_close (GslDataHandle *dhandle) +{ + WaveHandle *whandle = (WaveHandle*) dhandle; + + gsl_hfile_close (whandle->hfile); + whandle->hfile = NULL; +} + +static GslLong +wave_handle_read (GslDataHandle *data_handle, + GslLong voffset, + GslLong n_values, + gfloat *values) +{ + WaveHandle *whandle = (WaveHandle*) data_handle; + gpointer buffer = values; + GslLong l, i, byte_offset; + + byte_offset = voffset * wave_format_byte_width (whandle->format); /* float offset into bytes */ + byte_offset += whandle->byte_offset; + + switch (whandle->format) + { + guint8 *u8; gint8 *s8; guint16 *u16; guint32 *u32; + case GSL_WAVE_FORMAT_UNSIGNED_8: + u8 = buffer; u8 += n_values * 3; + l = gsl_hfile_pread (whandle->hfile, byte_offset, n_values, u8); + if (l < 1) + return l; + for (i = 0; i < l; i++) + { + int v = u8[i] - 128; + values[i] = v * (1. / 128.); + } + break; + case GSL_WAVE_FORMAT_SIGNED_8: + s8 = buffer; s8 += n_values * 3; + l = gsl_hfile_pread (whandle->hfile, byte_offset, n_values, s8); + if (l < 1) + return l; + for (i = 0; i < l; i++) + values[i] = s8[i] * (1. / 128.); + break; + case GSL_WAVE_FORMAT_SIGNED_12: + case GSL_WAVE_FORMAT_UNSIGNED_12: + case GSL_WAVE_FORMAT_SIGNED_16: + case GSL_WAVE_FORMAT_UNSIGNED_16: + u16 = buffer; u16 += n_values; + l = gsl_hfile_pread (whandle->hfile, byte_offset, n_values << 1, u16); + if (l < 2) + return l < 0 ? l : 0; + l >>= 1; + switch (whandle->format) + { + case GSL_WAVE_FORMAT_UNSIGNED_16: + if (whandle->byte_order != G_BYTE_ORDER) + for (i = 0; i < l; i++) + { + int v = GUINT16_SWAP_LE_BE (u16[i]); v -= 32768; + values[i] = v * (1. / 32768.); + } + else /* whandle->byte_order == G_BYTE_ORDER */ + for (i = 0; i < l; i++) + { + int v = u16[i]; v -= 32768; + values[i] = v * (1. / 32768.); + } + break; + case GSL_WAVE_FORMAT_UNSIGNED_12: + if (whandle->byte_order != G_BYTE_ORDER) + for (i = 0; i < l; i++) + { + int v = GUINT16_SWAP_LE_BE (u16[i]); v &= 0x0fff; v -= 4096; + values[i] = v * (1. / 4096.); + } + else /* whandle->byte_order == G_BYTE_ORDER */ + for (i = 0; i < l; i++) + { + int v = u16[i]; v &= 0x0fff; v -= 4096; + values[i] = v * (1. / 4096.); + } + break; + case GSL_WAVE_FORMAT_SIGNED_16: + if (whandle->byte_order != G_BYTE_ORDER) + for (i = 0; i < l; i++) + { + gint16 v = GUINT16_SWAP_LE_BE (u16[i]); + values[i] = v * (1. / 32768.); + } + else /* whandle->byte_order == G_BYTE_ORDER */ + for (i = 0; i < l; i++) + { + gint16 v = u16[i]; + values[i] = v * (1. / 32768.); + } + break; + case GSL_WAVE_FORMAT_SIGNED_12: + if (whandle->byte_order != G_BYTE_ORDER) + for (i = 0; i < l; i++) + { + gint16 v = GUINT16_SWAP_LE_BE (u16[i]); + values[i] = CLAMP (v, -4096, 4096) * (1. / 4096.); + } + else /* whandle->byte_order == G_BYTE_ORDER */ + for (i = 0; i < l; i++) + { + gint16 v = u16[i]; + values[i] = CLAMP (v, -4096, 4096) * (1. / 4096.); + } + break; + default: + g_assert_not_reached (); + } + break; + case GSL_WAVE_FORMAT_FLOAT: + u32 = buffer; + l = gsl_hfile_pread (whandle->hfile, byte_offset, n_values << 2, u32); + if (l < 4) + return l < 0 ? l : 0; + l >>= 2; + if (whandle->byte_order != G_BYTE_ORDER) + for (i = 0; i < l; i++) + u32[i] = GUINT32_SWAP_LE_BE (u32[i]); + break; + default: + l = -1; + g_assert_not_reached (); + } + + return l; +} + +GslDataHandle* +gsl_wave_handle_new (const gchar *file_name, + guint n_channels, + GslWaveFormatType format, + guint byte_order, + GslLong byte_offset, + GslLong n_values) +{ + static GslDataHandleFuncs wave_handle_vtable = { + wave_handle_open, + wave_handle_read, + wave_handle_close, + wave_handle_destroy, + }; + WaveHandle *whandle; + + g_return_val_if_fail (file_name != NULL, NULL); + g_return_val_if_fail (format > GSL_WAVE_FORMAT_NONE && format < GSL_WAVE_FORMAT_LAST, NULL); + g_return_val_if_fail (byte_order == G_LITTLE_ENDIAN || byte_order == G_BIG_ENDIAN, NULL); + g_return_val_if_fail (byte_offset >= 0, NULL); + g_return_val_if_fail (n_channels >= 1, NULL); + g_return_val_if_fail (n_values >= 1 || n_values == -1, NULL); + + whandle = gsl_new_struct0 (WaveHandle, 1); + if (gsl_data_handle_common_init (&whandle->dhandle, file_name)) + { + whandle->dhandle.vtable = &wave_handle_vtable; + whandle->n_channels = n_channels; + whandle->format = format; + whandle->byte_order = byte_order; + whandle->byte_offset = byte_offset; + whandle->requested_length = n_values; + whandle->hfile = NULL; + return &whandle->dhandle; + } + else + { + gsl_delete_struct (WaveHandle, whandle); + return NULL; + } +} + +const gchar* +gsl_wave_format_to_string (GslWaveFormatType format) +{ + switch (format) + { + case GSL_WAVE_FORMAT_UNSIGNED_8: return "unsigned_8"; + case GSL_WAVE_FORMAT_SIGNED_8: return "signed_8"; + case GSL_WAVE_FORMAT_UNSIGNED_12: return "unsigned_12"; + case GSL_WAVE_FORMAT_SIGNED_12: return "signed_12"; + case GSL_WAVE_FORMAT_UNSIGNED_16: return "unsigned_16"; + case GSL_WAVE_FORMAT_SIGNED_16: return "signed_16"; + case GSL_WAVE_FORMAT_FLOAT: return "float"; + case GSL_WAVE_FORMAT_NONE: + case GSL_WAVE_FORMAT_LAST: + default: + g_return_val_if_fail (format >= GSL_WAVE_FORMAT_UNSIGNED_8 && format <= GSL_WAVE_FORMAT_FLOAT, NULL); + return NULL; + } +} + +GslWaveFormatType +gsl_wave_format_from_string (const gchar *string) +{ + gboolean is_unsigned = FALSE; + + g_return_val_if_fail (string != NULL, GSL_WAVE_FORMAT_NONE); + + while (*string == ' ') + string++; + if (strncasecmp (string, "float", 5) == 0) + return GSL_WAVE_FORMAT_FLOAT; + if ((string[0] == 'u' || string[0] == 'U') && + (string[1] == 'n' || string[1] == 'N')) + { + is_unsigned = TRUE; + string += 2; + } + if (strncasecmp (string, "signed", 6) != 0) + return GSL_WAVE_FORMAT_NONE; + string += 6; + if (string[0] != '-' && string[0] != '_') + return GSL_WAVE_FORMAT_NONE; + string += 1; + if (string[0] == '8') + return is_unsigned ? GSL_WAVE_FORMAT_UNSIGNED_8 : GSL_WAVE_FORMAT_SIGNED_8; + if (string[0] != '1') + return GSL_WAVE_FORMAT_NONE; + string += 1; + if (string[0] == '2') + return is_unsigned ? GSL_WAVE_FORMAT_UNSIGNED_12 : GSL_WAVE_FORMAT_SIGNED_12; + if (string[0] == '6') + return is_unsigned ? GSL_WAVE_FORMAT_UNSIGNED_16 : GSL_WAVE_FORMAT_SIGNED_16; + return GSL_WAVE_FORMAT_NONE; +} |