You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
arts/flow/gsl/gslloader.c

336 lines
8.5 KiB

/* 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., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, 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;
}