diff options
Diffstat (limited to 'flow/gsl/gslloader-gslwave.c')
-rw-r--r-- | flow/gsl/gslloader-gslwave.c | 701 |
1 files changed, 701 insertions, 0 deletions
diff --git a/flow/gsl/gslloader-gslwave.c b/flow/gsl/gslloader-gslwave.c new file mode 100644 index 0000000..e851a12 --- /dev/null +++ b/flow/gsl/gslloader-gslwave.c @@ -0,0 +1,701 @@ +/* GSL - Generic Sound Layer + * Copyright (C) 2001, 2002 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 "gslloader.h" + +#include "gsldatahandle.h" +#include "gslmath.h" + +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + + +#define GSL_DEBUG_LOADER g_message + +#define parse_or_return(scanner, token) { guint _t = (token); \ + if (g_scanner_get_next_token (scanner) != _t) \ + return _t; \ + } + + +/* --- token types --- */ +typedef enum +{ + /* wave tokens */ + GSL_WAVE_TOKEN_WAVE = 512, + GSL_WAVE_TOKEN_CHUNK, + GSL_WAVE_TOKEN_NAME, + GSL_WAVE_TOKEN_BYTE_ORDER, + GSL_WAVE_TOKEN_FORMAT, + GSL_WAVE_TOKEN_N_CHANNELS, + GSL_WAVE_TOKEN_MIX_FREQ, + GSL_WAVE_TOKEN_OSC_FREQ, + GSL_WAVE_TOKEN_MIDI_NOTE, + GSL_WAVE_TOKEN_FILE, + GSL_WAVE_TOKEN_INDEX, + GSL_WAVE_TOKEN_BOFFSET, + GSL_WAVE_TOKEN_N_VALUES, + GSL_WAVE_TOKEN_LOOP_TYPE, + GSL_WAVE_TOKEN_LOOP_START, + GSL_WAVE_TOKEN_LOOP_END, + GSL_WAVE_TOKEN_LOOP_COUNT, + GSL_WAVE_TOKEN_LAST_FIELD, + /* data tokens */ + GSL_WAVE_TOKEN_BIG_ENDIAN = 768, + GSL_WAVE_TOKEN_BIG, + GSL_WAVE_TOKEN_LITTLE_ENDIAN, + GSL_WAVE_TOKEN_LITTLE, + GSL_WAVE_TOKEN_SIGNED_8, + GSL_WAVE_TOKEN_SIGNED_12, + GSL_WAVE_TOKEN_SIGNED_16, + GSL_WAVE_TOKEN_UNSIGNED_8, + GSL_WAVE_TOKEN_UNSIGNED_12, + GSL_WAVE_TOKEN_UNSIGNED_16, + GSL_WAVE_TOKEN_FLOAT, + GSL_WAVE_TOKEN_NONE, + GSL_WAVE_TOKEN_JUMP, + GSL_WAVE_TOKEN_PINGPONG, + GSL_WAVE_TOKEN_LAST_DATA +} GslWaveTokenType; + + +/* --- structures --- */ +typedef struct +{ + GslWaveFileInfo wfi; + gchar *cwd; +} FileInfo; + +typedef struct +{ + GslWaveDsc wdsc; + GslWaveFormatType format; + guint byte_order; + gfloat dfl_mix_freq; +} WaveDsc; + + +/* --- tokens --- */ +static const char *wave_tokens_512[] = { + "wave", "chunk", "name", "byte_order", + "format", "n_channels", "mix_freq", "osc_freq", + "midi_note", "file", "index", "boffset", + "n_values", "loop_type", "loop_start", "loop_end", + "loop_count", +}; +static const char *wave_tokens_768[] = { + "big_endian", "big", "little_endian", "little", + "signed_8", "signed_12", "signed_16", + "unsigned_8", "unsigned_12", "unsigned_16", + "float", "none", "jump", "pingpong", +}; + + +/* --- functions --- */ +static const gchar* +gsl_wave_token (GslWaveTokenType token) +{ + if (token >= 768) + { + token -= 768; + return token > sizeof (wave_tokens_768) / sizeof (wave_tokens_768[0]) ? NULL : wave_tokens_768[token]; + } + else + { + token -= 512; + return token > sizeof (wave_tokens_512) / sizeof (wave_tokens_512[0]) ? NULL : wave_tokens_512[token]; + } +} + +static GTokenType +gslwave_skip_rest_statement (GScanner *scanner, + guint level) +{ + g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR); + + while (level) + { + g_scanner_get_next_token (scanner); + switch (scanner->token) + { + case G_TOKEN_EOF: case G_TOKEN_ERROR: return '}'; + case '(': case '{': case '[': level++; break; + case ')': case '}': case ']': level--; break; + default: break; + } + } + + return G_TOKEN_NONE; +} + +static GslWaveFileInfo* +gslwave_load_file_info (gpointer data, + const gchar *_file_name, + GslErrorType *error_p) +{ + FileInfo *fi = NULL; + gboolean in_wave = FALSE, abort = FALSE; + GslRing *wave_names = NULL; + GScanner *scanner; + gchar *cwd, *file_name; + gint fd; + guint i; + + if (g_path_is_absolute (_file_name)) + { + gchar *p = strrchr (_file_name, G_DIR_SEPARATOR); + + g_assert (p != NULL); + cwd = g_strndup (_file_name, p - _file_name + 1); + file_name = g_strdup (_file_name); + } + else + { + cwd = g_get_current_dir (); + file_name = g_strdup_printf ("%s%c%s", cwd, G_DIR_SEPARATOR, _file_name); + } + + fd = open (file_name, O_RDONLY); + if (fd < 0) + { + *error_p = GSL_ERROR_OPEN_FAILED; + g_free (cwd); + g_free (file_name); + return NULL; + } + + scanner = g_scanner_new (NULL); + scanner->config->symbol_2_token = TRUE; + g_scanner_scope_add_symbol (scanner, 0, "wave", GUINT_TO_POINTER (GSL_WAVE_TOKEN_WAVE)); + g_scanner_scope_add_symbol (scanner, 0, "name", GUINT_TO_POINTER (GSL_WAVE_TOKEN_NAME)); + g_scanner_input_file (scanner, fd); + while (!abort) + { + g_scanner_get_next_token (scanner); + switch (scanner->token) + { + case GSL_WAVE_TOKEN_WAVE: + if (g_scanner_peek_next_token (scanner) == '{') + { + g_scanner_get_next_token (scanner); /* eat '{' */ + in_wave = TRUE; + } + break; + case '{': + if (gslwave_skip_rest_statement (scanner, 1) != G_TOKEN_NONE) + abort = TRUE; + break; + case GSL_WAVE_TOKEN_NAME: + if (in_wave && g_scanner_peek_next_token (scanner) == '=') + { + g_scanner_get_next_token (scanner); /* eat '=' */ + if (g_scanner_peek_next_token (scanner) == G_TOKEN_STRING) + { + gchar *wave_name; + + g_scanner_get_next_token (scanner); /* eat string */ + wave_name = g_strdup (scanner->value.v_string); + if (gslwave_skip_rest_statement (scanner, 1) == G_TOKEN_NONE) + { + in_wave = FALSE; + wave_names = gsl_ring_append (wave_names, wave_name); + } + else + { + g_free (wave_name); + abort = TRUE; + } + } + } + break; + default: + if (scanner->token == G_TOKEN_EOF || scanner->token == G_TOKEN_ERROR) + abort = TRUE; + break; + } + } + g_scanner_destroy (scanner); + close (fd); + + if (wave_names) + { + GslRing *ring; + + fi = gsl_new_struct0 (FileInfo, 1); + fi->wfi.n_waves = gsl_ring_length (wave_names); + fi->wfi.waves = g_malloc0 (sizeof (fi->wfi.waves[0]) * fi->wfi.n_waves); + for (i = 0, ring = wave_names; i < fi->wfi.n_waves; i++, ring = ring->next) + fi->wfi.waves[i].name = ring->data; + gsl_ring_free (wave_names); + fi->cwd = cwd; + } + else + g_free (cwd); + g_free (file_name); + + /* FIXME: empty wave error? */ + + return fi ? &fi->wfi : NULL; +} + +static void +gslwave_free_file_info (gpointer data, + GslWaveFileInfo *file_info) +{ + FileInfo *fi = (FileInfo*) file_info; + guint i; + + for (i = 0; i < fi->wfi.n_waves; i++) + g_free (fi->wfi.waves[i].name); + g_free (fi->wfi.waves); + g_free (fi->cwd); + gsl_delete_struct (FileInfo, fi); +} + +static guint +gslwave_parse_chunk_dsc (GScanner *scanner, + GslWaveChunkDsc *chunk) +{ + parse_or_return (scanner, '{'); + do + switch (g_scanner_get_next_token (scanner)) + { + case '}': + return G_TOKEN_NONE; + default: + return '}'; + case GSL_WAVE_TOKEN_FILE: + parse_or_return (scanner, '='); + parse_or_return (scanner, G_TOKEN_STRING); + g_free (chunk->loader_data1); /* file_name */ + chunk->loader_data1 = g_strdup (scanner->value.v_string); + break; + case GSL_WAVE_TOKEN_INDEX: + parse_or_return (scanner, '='); + parse_or_return (scanner, G_TOKEN_STRING); + g_free (chunk->loader_data2); /* wave_name */ + chunk->loader_data2 = g_strdup (scanner->value.v_string); + break; + case GSL_WAVE_TOKEN_MIX_FREQ: + parse_or_return (scanner, '='); + switch (g_scanner_get_next_token (scanner)) + { + case G_TOKEN_FLOAT: chunk->mix_freq = scanner->value.v_float; break; + case G_TOKEN_INT: chunk->mix_freq = scanner->value.v_int; break; + default: return G_TOKEN_FLOAT; + } + break; + case GSL_WAVE_TOKEN_OSC_FREQ: + parse_or_return (scanner, '='); + switch (g_scanner_get_next_token (scanner)) + { + case G_TOKEN_FLOAT: chunk->osc_freq = scanner->value.v_float; break; + case G_TOKEN_INT: chunk->osc_freq = scanner->value.v_int; break; + default: return G_TOKEN_FLOAT; + } + break; + case GSL_WAVE_TOKEN_MIDI_NOTE: + parse_or_return (scanner, '='); + parse_or_return (scanner, G_TOKEN_INT); + chunk->osc_freq = gsl_temp_freq (gsl_get_config ()->kammer_freq, + scanner->value.v_int - gsl_get_config ()->midi_kammer_note); + break; + case GSL_WAVE_TOKEN_BOFFSET: + parse_or_return (scanner, '='); + parse_or_return (scanner, G_TOKEN_INT); + chunk->loader_offset = scanner->value.v_int; /* byte_offset */ + break; + case GSL_WAVE_TOKEN_N_VALUES: + parse_or_return (scanner, '='); + parse_or_return (scanner, G_TOKEN_INT); + chunk->loader_length = scanner->value.v_int; /* n_values */ + break; + case GSL_WAVE_TOKEN_LOOP_TYPE: + parse_or_return (scanner, '='); + switch (g_scanner_get_next_token (scanner)) + { + case GSL_WAVE_TOKEN_NONE: chunk->loop_type = GSL_WAVE_LOOP_NONE; break; + case GSL_WAVE_TOKEN_JUMP: chunk->loop_type = GSL_WAVE_LOOP_JUMP; break; + case GSL_WAVE_TOKEN_PINGPONG: chunk->loop_type = GSL_WAVE_LOOP_PINGPONG; break; + default: return GSL_WAVE_TOKEN_JUMP; + } + break; + case GSL_WAVE_TOKEN_LOOP_START: + parse_or_return (scanner, '='); + parse_or_return (scanner, G_TOKEN_INT); + chunk->loop_start = scanner->value.v_int; + break; + case GSL_WAVE_TOKEN_LOOP_END: + parse_or_return (scanner, '='); + parse_or_return (scanner, G_TOKEN_INT); + chunk->loop_end = scanner->value.v_int; + break; + case GSL_WAVE_TOKEN_LOOP_COUNT: + parse_or_return (scanner, '='); + parse_or_return (scanner, G_TOKEN_INT); + chunk->loop_count = scanner->value.v_int; + break; + } + while (TRUE); +} + +static guint +gslwave_parse_wave_dsc (GScanner *scanner, + WaveDsc *dsc, + const gchar *wave_name) +{ + parse_or_return (scanner, '{'); + do + switch (g_scanner_get_next_token (scanner)) + { + guint i, token; + case '}': + return G_TOKEN_NONE; + default: + return '}'; + case GSL_WAVE_TOKEN_NAME: + if (dsc->wdsc.name) + return '}'; + parse_or_return (scanner, '='); + parse_or_return (scanner, G_TOKEN_STRING); + if (wave_name) + { + if (strcmp (wave_name, scanner->value.v_string) == 0) + dsc->wdsc.name = g_strdup (scanner->value.v_string); + else + return gslwave_skip_rest_statement (scanner, 1); + } + else + dsc->wdsc.name = g_strdup (scanner->value.v_string); + break; + case GSL_WAVE_TOKEN_CHUNK: + if (g_scanner_peek_next_token (scanner) != '{') + parse_or_return (scanner, '{'); + i = dsc->wdsc.n_chunks++; + dsc->wdsc.chunks = g_realloc (dsc->wdsc.chunks, sizeof (dsc->wdsc.chunks[0]) * dsc->wdsc.n_chunks); + memset (dsc->wdsc.chunks + i, 0, sizeof (dsc->wdsc.chunks[0]) * 1); + dsc->wdsc.chunks[i].mix_freq = dsc->dfl_mix_freq; + dsc->wdsc.chunks[i].osc_freq = dsc->dfl_mix_freq; /* we check this later */ + dsc->wdsc.chunks[i].loop_type = GSL_WAVE_LOOP_JUMP; + dsc->wdsc.chunks[i].loop_start = GSL_MAXLONG; + dsc->wdsc.chunks[i].loop_end = -1; + dsc->wdsc.chunks[i].loop_count = 1000000; /* FIXME */ + dsc->wdsc.chunks[i].loader_offset = 0; /* offset in bytes */ + dsc->wdsc.chunks[i].loader_length = 0; /* length in n_values */ + dsc->wdsc.chunks[i].loader_data1 = NULL; /* file_name */ + dsc->wdsc.chunks[i].loader_data2 = NULL; /* wave_name */ + token = gslwave_parse_chunk_dsc (scanner, dsc->wdsc.chunks + i); + if (token != G_TOKEN_NONE) + return token; + if (dsc->wdsc.chunks[i].loop_end < dsc->wdsc.chunks[i].loop_start) + { + dsc->wdsc.chunks[i].loop_type = GSL_WAVE_LOOP_NONE; + dsc->wdsc.chunks[i].loop_start = 0; + dsc->wdsc.chunks[i].loop_end = 0; + dsc->wdsc.chunks[i].loop_count = 0; + } + if (dsc->wdsc.chunks[i].osc_freq >= dsc->wdsc.chunks[i].mix_freq / 2.) + g_scanner_error (scanner, "wave chunk \"%s\" mixing frequency is invalid: mix_freq=%f osc_freq=%f", + dsc->wdsc.chunks[i].loader_data1 ? (gchar*) dsc->wdsc.chunks[i].loader_data1 : "", + dsc->wdsc.chunks[i].mix_freq, + dsc->wdsc.chunks[i].osc_freq); + break; + case GSL_WAVE_TOKEN_BYTE_ORDER: + parse_or_return (scanner, '='); + token = g_scanner_get_next_token (scanner); + switch (token) + { + case GSL_WAVE_TOKEN_LITTLE_ENDIAN: + case GSL_WAVE_TOKEN_LITTLE: dsc->byte_order = G_LITTLE_ENDIAN; break; + case GSL_WAVE_TOKEN_BIG_ENDIAN: + case GSL_WAVE_TOKEN_BIG: dsc->byte_order = G_BIG_ENDIAN; break; + default: return GSL_WAVE_TOKEN_LITTLE_ENDIAN; + } + break; + case GSL_WAVE_TOKEN_FORMAT: + parse_or_return (scanner, '='); + token = g_scanner_get_next_token (scanner); + switch (token) + { + case GSL_WAVE_TOKEN_SIGNED_8: dsc->format = GSL_WAVE_FORMAT_SIGNED_8; break; + case GSL_WAVE_TOKEN_SIGNED_12: dsc->format = GSL_WAVE_FORMAT_SIGNED_12; break; + case GSL_WAVE_TOKEN_SIGNED_16: dsc->format = GSL_WAVE_FORMAT_SIGNED_16; break; + case GSL_WAVE_TOKEN_UNSIGNED_8: dsc->format = GSL_WAVE_FORMAT_UNSIGNED_8; break; + case GSL_WAVE_TOKEN_UNSIGNED_12: dsc->format = GSL_WAVE_FORMAT_UNSIGNED_12; break; + case GSL_WAVE_TOKEN_UNSIGNED_16: dsc->format = GSL_WAVE_FORMAT_UNSIGNED_16; break; + case GSL_WAVE_TOKEN_FLOAT: dsc->format = GSL_WAVE_FORMAT_FLOAT; break; + default: return GSL_WAVE_TOKEN_SIGNED_16; + } + break; + case GSL_WAVE_TOKEN_N_CHANNELS: + parse_or_return (scanner, '='); + parse_or_return (scanner, G_TOKEN_INT); + dsc->wdsc.n_channels = scanner->value.v_int; + if (dsc->wdsc.n_channels < 1) + return G_TOKEN_INT; + break; + case GSL_WAVE_TOKEN_MIX_FREQ: + parse_or_return (scanner, '='); + switch (g_scanner_get_next_token (scanner)) + { + case G_TOKEN_FLOAT: dsc->dfl_mix_freq = scanner->value.v_float; break; + case G_TOKEN_INT: dsc->dfl_mix_freq = scanner->value.v_int; break; + default: return G_TOKEN_FLOAT; + } + break; + } + while (TRUE); +} + +static void +gslwave_wave_dsc_free (WaveDsc *dsc) +{ + guint i; + + for (i = 0; i < dsc->wdsc.n_chunks; i++) + { + g_free (dsc->wdsc.chunks[i].loader_data1); /* file_name */ + g_free (dsc->wdsc.chunks[i].loader_data2); /* wave_name */ + } + g_free (dsc->wdsc.chunks); + g_free (dsc->wdsc.name); + gsl_delete_struct (WaveDsc, dsc); +} + +static GslWaveDsc* +gslwave_load_wave_dsc (gpointer data, + GslWaveFileInfo *file_info, + guint nth_wave, + GslErrorType *error_p) +{ + GScanner *scanner; + WaveDsc *dsc; + guint token, i; + gint fd; + + fd = open (file_info->file_name, O_RDONLY); + if (fd < 0) + { + *error_p = GSL_ERROR_OPEN_FAILED; + return NULL; + } + + scanner = g_scanner_new (NULL); + scanner->config->symbol_2_token = TRUE; + scanner->input_name = file_info->file_name; + g_scanner_input_file (scanner, fd); + for (i = GSL_WAVE_TOKEN_WAVE; i < GSL_WAVE_TOKEN_LAST_FIELD; i++) + g_scanner_scope_add_symbol (scanner, 0, gsl_wave_token (i), GUINT_TO_POINTER (i)); + for (i = GSL_WAVE_TOKEN_BIG_ENDIAN; i < GSL_WAVE_TOKEN_LAST_DATA; i++) + g_scanner_scope_add_symbol (scanner, 0, gsl_wave_token (i), GUINT_TO_POINTER (i)); + + continue_scanning: + dsc = gsl_new_struct0 (WaveDsc, 1); + dsc->wdsc.name = NULL; + dsc->wdsc.n_chunks = 0; + dsc->wdsc.chunks = NULL; + dsc->wdsc.n_channels = 1; + dsc->format = GSL_WAVE_FORMAT_SIGNED_16; + dsc->byte_order = G_LITTLE_ENDIAN; + dsc->dfl_mix_freq = 44100; + if (g_scanner_get_next_token (scanner) != GSL_WAVE_TOKEN_WAVE) + token = GSL_WAVE_TOKEN_WAVE; + else + token = gslwave_parse_wave_dsc (scanner, dsc, file_info->waves[nth_wave].name); + if (token != G_TOKEN_NONE || scanner->parse_errors) + { + gslwave_wave_dsc_free (dsc); + dsc = NULL; + if (!scanner->parse_errors) + g_scanner_unexp_token (scanner, token, "identifier", "keyword", NULL, "discarding wave", TRUE); /* FIXME */ + } + else + { + if (dsc->wdsc.n_chunks && dsc->wdsc.name) + { + /* found the correctly named wave and parsed it */ + } + else + { + /* got invalid/wrong wave */ + gslwave_wave_dsc_free (dsc); + dsc = NULL; + goto continue_scanning; /* next attempt */ + } + } + g_scanner_destroy (scanner); + close (fd); + + return dsc ? &dsc->wdsc : NULL; +} + +static void +gslwave_free_wave_dsc (gpointer data, + GslWaveDsc *wave_dsc) +{ + WaveDsc *dsc = (WaveDsc*) wave_dsc; + + gslwave_wave_dsc_free (dsc); +} + +static GslDataHandle* +gslwave_load_singlechunk_wave (GslWaveFileInfo *fi, + const gchar *wave_name, + GslErrorType *error_p) +{ + GslWaveDsc *wdsc; + guint i; + + if (fi->n_waves == 1 && !wave_name) + i = 0; + else if (!wave_name) + { + /* don't know which wave to pick */ + *error_p = GSL_ERROR_FORMAT_INVALID; + return NULL; + } + else /* find named wave */ + for (i = 0; i < fi->n_waves; i++) + if (strcmp (fi->waves[i].name, wave_name) == 0) + break; + if (i >= fi->n_waves) + { + *error_p = GSL_ERROR_NOT_FOUND; + return NULL; + } + + wdsc = gsl_wave_dsc_load (fi, i, error_p); + if (!wdsc) + return NULL; + + if (wdsc->n_chunks == 1) + { + GslDataHandle *dhandle = gsl_wave_handle_create (wdsc, 0, error_p); + + gsl_wave_dsc_free (wdsc); + return dhandle; + } + + /* this is ridiculous, letting the chunk of a wave + * point to a wave with multiple chunks... + */ + gsl_wave_dsc_free (wdsc); + *error_p = GSL_ERROR_FORMAT_INVALID; + return NULL; +} + +static GslDataHandle* +gslwave_create_chunk_handle (gpointer data, + GslWaveDsc *wave_dsc, + guint nth_chunk, + GslErrorType *error_p) +{ + WaveDsc *dsc = (WaveDsc*) wave_dsc; + FileInfo *fi = (FileInfo*) dsc->wdsc.file_info; + GslWaveChunkDsc *chunk = wave_dsc->chunks + nth_chunk; + + if (chunk->loader_data1) /* file_name */ + { + GslDataHandle *dhandle; + GslWaveFileInfo *cfi; + gchar *string; + + + /* construct chunk file name from (hopefully) relative path + */ + if (g_path_is_absolute (chunk->loader_data1)) + string = g_strdup (chunk->loader_data1); + else + string = g_strdup_printf ("%s%c%s", fi->cwd, G_DIR_SEPARATOR, (char*) chunk->loader_data1); + + + /* first, try to load the chunk via registered loaders + */ + cfi = gsl_wave_file_info_load (string, error_p); + if (cfi) + { + /* FIXME: there's a potential attack here, in letting a single chunk + * wave's chunk point to its own wave. this'll trigger recursions until + * stack overflow + */ + dhandle = gslwave_load_singlechunk_wave (cfi, + chunk->loader_data2, /* wave_name */ + error_p); + gsl_wave_file_info_unref (cfi); + g_free (string); + return dhandle; + } + + + /* didn't work, assume it's a raw sample + */ + if (chunk->loader_data2) /* wave_name */ + { + /* raw samples don't give names to their data */ + *error_p = GSL_ERROR_NOT_FOUND; + g_free (string); + return NULL; + } + dhandle = gsl_wave_handle_new (string, /* file_name */ + dsc->wdsc.n_channels, + dsc->format, + dsc->byte_order, + chunk->loader_offset, /* byte_offset */ + chunk->loader_length > 0 /* n_values */ + ? chunk->loader_length + : -1); + *error_p = dhandle ? GSL_ERROR_NONE : GSL_ERROR_IO; + g_free (string); + return dhandle; + } + else + { + /* no file_name specified */ + *error_p = GSL_ERROR_NOT_FOUND; + return NULL; + } +} + +void +_gsl_init_loader_gslwave (void) +{ + static const gchar *file_exts[] = { "gslwave", NULL, }; + static const gchar *mime_types[] = { "audio/x-gslwave", NULL, }; + static const gchar *magics[] = { "0 string #GslWave", NULL, }; + static GslLoader loader = { + "GslWave", + file_exts, + mime_types, + magics, + 0, /* priority */ + NULL, + gslwave_load_file_info, + gslwave_free_file_info, + gslwave_load_wave_dsc, + gslwave_free_wave_dsc, + gslwave_create_chunk_handle, + }; + static gboolean initialized = FALSE; + + g_assert (initialized == FALSE); + initialized = TRUE; + + gsl_loader_register (&loader); +} |