/* 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., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "gsldatahandle.h" #include "gslcommon.h" #include "gsldatacache.h" #include "gslfilehash.h" #include #include /* --- 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; }