diff options
Diffstat (limited to 'flow/gsl/gslloader.c')
-rw-r--r-- | flow/gsl/gslloader.c | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/flow/gsl/gslloader.c b/flow/gsl/gslloader.c new file mode 100644 index 0000000..002e39f --- /dev/null +++ b/flow/gsl/gslloader.c @@ -0,0 +1,335 @@ +/* GSL - Generic Sound Layer + * Copyright (C) 2001-2002 Tim Janik and Stefan Westerfeld + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library 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 General Public License for more details. + * + * You should have received a copy of the GNU Library 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 "gslloader.h" + +#include "gslcommon.h" +#include "gsldatahandle.h" +#include "gslmagic.h" +#include <string.h> + + +/* --- variables --- */ +static GslLoader *gsl_loader_list = NULL; +static GslRing *gsl_magic_list = NULL; + + +/* --- functions --- */ +static GslLoader* +loader_find_by_name (const gchar *name) +{ + GslLoader *loader; + + for (loader = gsl_loader_list; loader != NULL; loader = loader->next) + if (strcmp (name, loader->name) == 0) + return loader; + return NULL; +} + +void +gsl_loader_register (GslLoader *loader) +{ + g_return_if_fail (loader != NULL); + g_return_if_fail (loader->name != NULL); + g_return_if_fail (loader->extensions || loader->mime_types || loader->magic_specs); + g_return_if_fail (loader_find_by_name (loader->name) == NULL); + g_return_if_fail (loader->next == NULL); + g_return_if_fail (loader->load_file_info != NULL); + g_return_if_fail (loader->free_file_info != NULL); + g_return_if_fail (loader->load_wave_dsc != NULL); + g_return_if_fail (loader->free_wave_dsc != NULL); + g_return_if_fail (loader->create_chunk_handle != NULL); + + loader->next = gsl_loader_list; + gsl_loader_list = loader; + + if (loader->magic_specs) + { + GslMagic *magic; + guint i, j; + + for (i = 0; loader->magic_specs[i]; i++) + { + if (loader->extensions) + for (j = 0; loader->extensions[j]; j++) + { + magic = gsl_magic_create (loader, loader->priority, + loader->extensions[j], loader->magic_specs[i]); + gsl_magic_list = gsl_ring_append (gsl_magic_list, magic); + } + else + { + magic = gsl_magic_create (loader, loader->priority, + NULL, loader->magic_specs[i]); + gsl_magic_list = gsl_ring_append (gsl_magic_list, magic); + } + } + } +} + +GslLoader* +gsl_loader_match (const gchar *file_name) +{ + GslMagic *magic; + + g_return_val_if_fail (file_name != NULL, NULL); + + magic = gsl_magic_list_match_file (gsl_magic_list, file_name); + if (magic) + return magic->data; + + return NULL; +} + +GslWaveFileInfo* +gsl_wave_file_info_load (const gchar *file_name, + GslErrorType *error_p) +{ + GslWaveFileInfo *finfo = NULL; + GslErrorType error = GSL_ERROR_NONE; + GslLoader *loader; + + if (error_p) + *error_p = GSL_ERROR_INTERNAL; + g_return_val_if_fail (file_name != NULL, NULL); + + loader = gsl_loader_match (file_name); + if (loader) + { + finfo = loader->load_file_info (loader->data, file_name, &error); + if (error && finfo) + { + /* loaders shouldn't do this */ + loader->free_file_info (loader->data, finfo); + finfo = NULL; + } + if (!finfo && !error) + error = GSL_ERROR_FILE_EMPTY; /* FIXME: try next loader */ + if (finfo) + { + if (finfo->n_waves > 0) + { + guint i; + + g_return_val_if_fail (finfo->loader == NULL, NULL); + g_return_val_if_fail (finfo->file_name == NULL, NULL); + + for (i = 0; i < finfo->n_waves; i++) + g_return_val_if_fail (finfo->waves[i].name != NULL, NULL); + + finfo->file_name = g_strdup (file_name); + finfo->loader = loader; + finfo->ref_count = 1; + } + else + { + loader->free_file_info (loader->data, finfo); + finfo = NULL; + error = GSL_ERROR_FILE_EMPTY; /* FIXME: try next loader */ + } + } + } + else /* no loader match */ + { + /* try to provide appropriate error code */ + error = gsl_check_file (file_name, "rf"); + if (!error) + error = GSL_ERROR_FORMAT_UNKNOWN; + } + + if (error_p) + *error_p = error; + + return finfo; +} + +void +gsl_wave_file_info_unref (GslWaveFileInfo *wave_file_info) +{ + g_return_if_fail (wave_file_info != NULL); + g_return_if_fail (wave_file_info->ref_count > 0); + + wave_file_info->ref_count--; + if (!wave_file_info->ref_count) + { + GslLoader *loader = wave_file_info->loader; + + g_free (wave_file_info->file_name); + wave_file_info->file_name = NULL; + wave_file_info->loader = NULL; + + loader->free_file_info (loader->data, wave_file_info); + } +} + +GslWaveFileInfo* +gsl_wave_file_info_ref (GslWaveFileInfo *wave_file_info) +{ + g_return_val_if_fail (wave_file_info != NULL, NULL); + g_return_val_if_fail (wave_file_info->ref_count > 0, NULL); + + wave_file_info->ref_count++; + + return wave_file_info; +} + +GslWaveDsc* +gsl_wave_dsc_load (GslWaveFileInfo *wave_file_info, + guint nth_wave, + GslErrorType *error_p) +{ + GslErrorType error = GSL_ERROR_NONE; + GslWaveDsc *wdsc; + GslLoader *loader; + + if (error_p) + *error_p = GSL_ERROR_INTERNAL; + g_return_val_if_fail (wave_file_info != NULL, NULL); + g_return_val_if_fail (wave_file_info->loader != NULL, NULL); + g_return_val_if_fail (nth_wave < wave_file_info->n_waves, NULL); + + loader = wave_file_info->loader; + wdsc = loader->load_wave_dsc (loader->data, wave_file_info, nth_wave,&error); + + if (error && wdsc) + { + /* loaders shouldn't do this */ + loader->free_wave_dsc (loader->data, wdsc); + wdsc = NULL; + } + if (!wdsc && !error) + error = GSL_ERROR_FILE_EMPTY; + if (wdsc) + { + if (wdsc->n_chunks > 0) + { + g_return_val_if_fail (wdsc->file_info == NULL, NULL); + g_return_val_if_fail (wdsc->name && strcmp (wdsc->name, wave_file_info->waves[nth_wave].name) == 0, NULL); + + wdsc->file_info = wave_file_info; + gsl_wave_file_info_ref (wave_file_info); + } + else + { + loader->free_wave_dsc (loader->data, wdsc); + wdsc = NULL; + error = GSL_ERROR_FILE_EMPTY; + } + } + + if (error_p) + *error_p = error; + + return wdsc; +} + +void +gsl_wave_dsc_free (GslWaveDsc *wave_dsc) +{ + GslWaveFileInfo *file_info; + + g_return_if_fail (wave_dsc != NULL); + g_return_if_fail (wave_dsc->file_info != NULL); + + file_info = wave_dsc->file_info; + wave_dsc->file_info = NULL; + + file_info->loader->free_wave_dsc (file_info->loader->data, wave_dsc); + + gsl_wave_file_info_unref (file_info); +} + +GslDataHandle* +gsl_wave_handle_create (GslWaveDsc *wave_dsc, + guint nth_chunk, + GslErrorType *error_p) +{ + GslErrorType error = GSL_ERROR_NONE; + GslDataHandle *dhandle; + GslLoader *loader; + + if (error_p) + *error_p = GSL_ERROR_INTERNAL; + g_return_val_if_fail (wave_dsc != NULL, NULL); + g_return_val_if_fail (wave_dsc->file_info != NULL, NULL); + g_return_val_if_fail (nth_chunk < wave_dsc->n_chunks, NULL); + + loader = wave_dsc->file_info->loader; + + dhandle = loader->create_chunk_handle (loader->data, + wave_dsc, + nth_chunk, + &error); + if (error && dhandle) + { + /* loaders shouldn't do this */ + gsl_data_handle_unref (dhandle); + dhandle = NULL; + } + if (!dhandle && !error) + error = GSL_ERROR_FORMAT_INVALID; + + if (error_p) + *error_p = error; + + return dhandle; +} + +GslWaveChunk* +gsl_wave_chunk_create (GslWaveDsc *wave_dsc, + guint nth_chunk, + GslErrorType *error_p) +{ + GslDataHandle *dhandle; + GslDataCache *dcache; + GslWaveChunk *wchunk; + + if (error_p) + *error_p = GSL_ERROR_INTERNAL; + g_return_val_if_fail (wave_dsc != NULL, NULL); + g_return_val_if_fail (nth_chunk < wave_dsc->n_chunks, NULL); + + dhandle = gsl_wave_handle_create (wave_dsc, nth_chunk, error_p); + if (!dhandle) + return NULL; + + if (error_p) + *error_p = GSL_ERROR_IO; + + /* FIXME: we essentially create a dcache for each wchunk here ;( */ + + dcache = gsl_data_cache_from_dhandle (dhandle, gsl_get_config ()->wave_chunk_padding * wave_dsc->n_channels); + gsl_data_handle_unref (dhandle); + if (!dcache) + return NULL; + /* dcache keeps dhandle alive */ + + wchunk = gsl_wave_chunk_new (dcache, + wave_dsc->chunks[nth_chunk].osc_freq, + wave_dsc->chunks[nth_chunk].mix_freq, + wave_dsc->chunks[nth_chunk].loop_type, + wave_dsc->chunks[nth_chunk].loop_start, + wave_dsc->chunks[nth_chunk].loop_end, + wave_dsc->chunks[nth_chunk].loop_count); + gsl_data_cache_unref (dcache); + + if (error_p && wchunk) + *error_p = GSL_ERROR_NONE; + + return wchunk; +} |