欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

sfload.c

A GTK sound font editor. Sound font files are used to synthesize instruments from audio samples for
C
第 1 页 / 共 3 页
字号:
/*================================================================== * sfload.c - sound font loading functions * Based on the awesfx utility Copyright (C) 1996-1999 Takashi Iwai * * Smurf Sound Font Editor * Copyright (C) 1999-2001 Josh Green * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA or point your web browser to http://www.gnu.org. * * To contact the author of this program: * Email: Josh Green <jgreen@users.sourceforge.net> * Smurf homepage: http://smurf.sourceforge.net *==================================================================*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <stdarg.h>#include <glib.h>#include "sffile.h"#include "sfont.h"#include "sample.h"#include "util.h"#include "i18n.h"/*   functions for loading data from sfont files, with appropriate byte swapping   on big endian machines. Sfont IDs are not swapped because the ID read is   equivalent to the matching ID list in memory regardless of LE/BE machine*/#define READCHUNK(var,fd)	G_STMT_START {		\    if (!safe_fread(var, 8, fd))			\	return(FAIL);					\    ((SFChunk *)(var))->size = GUINT32_FROM_LE(((SFChunk *)(var))->size);  \} G_STMT_END#define READID(var,fd)		G_STMT_START {		\    if (!safe_fread(var, 4, fd))			\	return(FAIL);					\} G_STMT_END#define READSTR(var,fd)		G_STMT_START {		\    if (!safe_fread(var, 20, fd))			\	return(FAIL);					\    (*var)[20] = '\0';					\} G_STMT_END#define READD(var,fd)		G_STMT_START {		\    guint32 _temp;					\    if (!safe_fread(&_temp, 4, fd))			\	return(FAIL);					\    var = GINT32_FROM_LE(_temp);			\} G_STMT_END#define READW(var,fd)		G_STMT_START {		\    guint16 _temp;					\    if (!safe_fread(&_temp, 2, fd))			\	return(FAIL);					\    var = GINT16_FROM_LE(_temp);			\} G_STMT_END#define READB(var,fd)		G_STMT_START {		\    if (!safe_fread(&var, 1, fd))			\	return(FAIL);					\} G_STMT_END#define FSKIP(size,fd)		G_STMT_START {		\    if (!safe_fseek(fd, size, SEEK_CUR))		\	return(FAIL);					\} G_STMT_END#define FSKIPW(fd)		G_STMT_START {		\    if (!safe_fseek(fd, 2, SEEK_CUR))			\	return(FAIL);					\} G_STMT_END/* removes and advances a GSList pointer */#define SLADVREM(list, item)	G_STMT_START {		\    GSList *_temp = item;				\    item = g_slist_next(item);				\    list = g_slist_remove_link(list, _temp);		\    g_slist_free_1(_temp);				\} G_STMT_ENDstatic gint chunkid (guint32 id);static gint load_body (gint32 size, SFData * sf, FILE * fd);static gint read_listchunk (SFChunk * chunk, FILE * fd);static gint process_info (gint32 size, SFData * sf, FILE * fd);static gint process_sdta (gint32 size, SFData * sf, FILE * fd);static gint pdtahelper (guint32 expid, guint32 reclen, SFChunk * chunk,  gint32 * size, FILE * fd);static gint process_pdta (gint32 size, SFData * sf, FILE * fd);static gint load_phdr (gint32 size, SFData * sf, FILE * fd);static gint load_pbag (gint32 size, SFData * sf, FILE * fd);static gint load_pmod (gint32 size, SFData * sf, FILE * fd);static gint load_pgen (gint32 size, SFData * sf, FILE * fd);static gint load_ihdr (gint32 size, SFData * sf, FILE * fd);static gint load_ibag (gint32 size, SFData * sf, FILE * fd);static gint load_imod (gint32 size, SFData * sf, FILE * fd);static gint load_igen (gint32 size, SFData * sf, FILE * fd);static gint load_shdr (gint32 size, SFData * sf, FILE * fd);static gint fixup_pgen (SFData * sf);static gint fixup_igen (SFData * sf);static gint fixup_sample (SFData * sf);gchar idlist[] = {  "RIFFLISTsfbkINFOsdtapdtaifilisngINAMiromiverICRDIENGIPRD"    "ICOPICMTISFTsnamsmplphdrpbagpmodpgeninstibagimodigenshdr"};static gint sdtachunk_size;/* sound font file load functions */static gintchunkid (guint32 id){  gint i;  guint32 *p;  p = (guint32 *) & idlist;  for (i = 0; i < sizeof (idlist) / sizeof (gint); i++, p += 1)    if (*p == id)      return (i + 1);  return (UNKN_ID);}SFData *sfload_file (gchar * fname){  SFData *sf = NULL;  FILE *fd;  guint32 fsize;  gint err = FALSE;  if (!(fd = fopen (fname, "r")))    {      logit (LogFubar | LogErrno, _("Unable to open file \"%s\""), fname);      return (NULL);    }  if (!(sf = safe_malloc (sizeof (SFData))))    err = TRUE;  if (!err)    {      memset (sf, 0, sizeof (SFData));	/* zero sfdata */      sf->fname = g_strdup (fname);	/* copy file name */      sf->sffd = fd;    }  /* get size of file */  if (!err && fseek (fd, 0L, SEEK_END) == -1)    {				/* seek to end of file */      err = TRUE;      logit (LogFubar | LogErrno, _("Seek to end of file failed"));    }  if (!err && (fsize = ftell (fd)) == -1)    {				/* position = size */      err = TRUE;      logit (LogFubar | LogErrno, _("Get end of file position failed"));    }  if (!err)    rewind (fd);  if (!load_body (fsize, sf, fd))    err = TRUE;			/* load the sfont */  if (err)    {      if (sf)	sfont_close (sf);      return (NULL);    }  /* do this last, as most sfont_* routines set it to FALSE */  sf->up2date = TRUE;		/* sfont in memory is in sync with file */  sf->beensaved = FALSE;	/* has not been saved yet */  return (sf);}static gintload_body (gint32 size, SFData * sf, FILE * fd){  SFChunk chunk;  READCHUNK (&chunk, fd);	/* load RIFF chunk */  if (chunkid (chunk.id) != RIFF_ID)	/* error if not RIFF */    return (logit (LogFubar, _("Not a RIFF file")));  READID (&chunk.id, fd);	/* load file ID */  if (chunkid (chunk.id) != SFBK_ID)	/* error if not SFBK_ID */    return (logit (LogFubar, _("Not a sound font file")));  if (chunk.size != size - 8)    return (logit (LogFubar, _("Sound font file size mismatch")));  /* Process INFO block */  if (!read_listchunk (&chunk, fd))    return (FAIL);  if (chunkid (chunk.id) != INFO_ID)    return (logit (LogFubar, _("Invalid ID found when expecting INFO chunk")));  if (!process_info (chunk.size, sf, fd))    return (FAIL);  /* Process sample chunk */  if (!read_listchunk (&chunk, fd))    return (FAIL);  if (chunkid (chunk.id) != SDTA_ID)    return (logit (LogFubar,	_("Invalid ID found when expecting SAMPLE chunk")));  if (!process_sdta (chunk.size, sf, fd))    return (FAIL);  /* process HYDRA chunk */  if (!read_listchunk (&chunk, fd))    return (FAIL);  if (chunkid (chunk.id) != PDTA_ID)    return (logit (LogFubar, _("Invalid ID found when expecting HYDRA chunk")));  if (!process_pdta (chunk.size, sf, fd))    return (FAIL);  if (!fixup_pgen (sf))    return (FAIL);  if (!fixup_igen (sf))    return (FAIL);  if (!fixup_sample (sf))    return (FAIL);  /* sort preset list by bank, preset # */  sf->preset = g_slist_sort (sf->preset,    (GCompareFunc) sfont_preset_compare_func);  return (OK);}static gintread_listchunk (SFChunk * chunk, FILE * fd){  READCHUNK (chunk, fd);	/* read list chunk */  if (chunkid (chunk->id) != LIST_ID)	/* error if ! list chunk */    return (logit (LogFubar, _("Invalid chunk id in level 0 parse")));  READID (&chunk->id, fd);	/* read id string */  chunk->size -= 4;  return (OK);}static gintprocess_info (gint32 size, SFData * sf, FILE * fd){  SFChunk chunk;  guint8 id;  gchar *item;  guint16 ver;  while (size > 0)    {      READCHUNK (&chunk, fd);      size -= 8;      id = chunkid (chunk.id);      if (id == IFIL_ID)	{			/* sound font version chunk? */	  if (chunk.size != 4)	    return (logit (LogFubar,		_("Sound font version info chunk has invalid size")));	  READW (ver, fd);	  sf->version.major = ver;	  READW (ver, fd);	  sf->version.minor = ver;	  if (sf->version.major < 2)	    return (logit (LogFubar,		_("Sound font version is %d.%d which is not"		  " supported, convert to version 2.0x"), sf->version.major,		sf->version.minor));	  if (sf->version.major > 2)	    logit (LogWarn, _("Sound font version is %d.%d which is newer than"		" what this version of Smurf was designed for (v2.0x)"));	}      else if (id == IVER_ID)	{			/* ROM version chunk? */	  if (chunk.size != 4)	    return (logit (LogFubar,		_("ROM version info chunk has invalid size")));	  READW (ver, fd);	  sf->romver.major = ver;	  READW (ver, fd);	  sf->romver.minor = ver;	}      else if (id != UNKN_ID)	{	  if ((id != ICMT_ID && chunk.size > 256) || (chunk.size > 65536)	    || (chunk.size % 2))	    return (logit (LogFubar,		_("INFO sub chunk %.4s has invalid chunk size"		  " of %d bytes"), &chunk.id, chunk.size));	  /* alloc for chunk id and da chunk */	  if (!(item = safe_malloc (chunk.size + 1)))	    return (FAIL);	  /* attach to INFO list, sfont_close will cleanup if FAIL occurs */	  sf->info = g_slist_append (sf->info, item);	  *(guint8 *) item = id;	  if (!safe_fread (&item[1], chunk.size, fd))	    return (FAIL);	  /* force terminate info item (don't forget uint8 info ID) */	  *(item + chunk.size) = '\0';	}      else	return (logit (LogFubar, _("Invalid chunk id in INFO chunk")));      size -= chunk.size;    }  if (size < 0)    return (logit (LogFubar, _("INFO chunk size mismatch")));  return (OK);}static gintprocess_sdta (gint32 size, SFData * sf, FILE * fd){  SFChunk chunk;  if (size == 0)    return (OK);		/* no sample data? */  /* read sub chunk */  READCHUNK (&chunk, fd);  size -= 8;  if (chunkid (chunk.id) != SMPL_ID)    return (logit (LogFubar,	_("Expected SMPL chunk found invalid id instead")));  if ((size - chunk.size) != 0)    return (logit (LogFubar, _("SDTA chunk size mismatch")));  /* sample data follows */  sf->samplepos = ftell (fd);  /* used in fixup_sample() to check validity of sample headers */  sdtachunk_size = chunk.size;  FSKIP (chunk.size, fd);  return (OK);}static gintpdtahelper (guint32 expid, guint32 reclen, SFChunk * chunk,  gint32 * size, FILE * fd){  guint32 id;  gchar *expstr;  expstr = CHNKIDSTR (expid);	/* in case we need it */  READCHUNK (chunk, fd);  *size -= 8;  if ((id = chunkid (chunk->id)) != expid)    return (logit (LogFubar, _("Expected"	  " PDTA sub-chunk \"%.4s\" found invalid id instead"), expstr));  if (chunk->size % reclen)	/* valid chunk size? */    return (logit (LogFubar,	_("\"%.4s\" chunk size is not a multiple of %d bytes"), expstr,	reclen));  if ((*size -= chunk->size) < 0)    return (logit (LogFubar,	_("\"%.4s\" chunk size exceeds remaining PDTA chunk size"), expstr));  return (OK);}static gintprocess_pdta (gint32 size, SFData * sf, FILE * fd){  SFChunk chunk;  if (!pdtahelper (PHDR_ID, SFPHDRSIZE, &chunk, &size, fd))    return (FAIL);  if (!load_phdr (chunk.size, sf, fd))    return (FAIL);  if (!pdtahelper (PBAG_ID, SFBAGSIZE, &chunk, &size, fd))    return (FAIL);  if (!load_pbag (chunk.size, sf, fd))    return (FAIL);  if (!pdtahelper (PMOD_ID, SFMODSIZE, &chunk, &size, fd))    return (FAIL);  if (!load_pmod (chunk.size, sf, fd))    return (FAIL);  if (!pdtahelper (PGEN_ID, SFGENSIZE, &chunk, &size, fd))    return (FAIL);  if (!load_pgen (chunk.size, sf, fd))    return (FAIL);  if (!pdtahelper (IHDR_ID, SFIHDRSIZE, &chunk, &size, fd))    return (FAIL);  if (!load_ihdr (chunk.size, sf, fd))    return (FAIL);  if (!pdtahelper (IBAG_ID, SFBAGSIZE, &chunk, &size, fd))    return (FAIL);  if (!load_ibag (chunk.size, sf, fd))    return (FAIL);  if (!pdtahelper (IMOD_ID, SFMODSIZE, &chunk, &size, fd))    return (FAIL);  if (!load_imod (chunk.size, sf, fd))    return (FAIL);  if (!pdtahelper (IGEN_ID, SFGENSIZE, &chunk, &size, fd))    return (FAIL);  if (!load_igen (chunk.size, sf, fd))    return (FAIL);  if (!pdtahelper (SHDR_ID, SFSHDRSIZE, &chunk, &size, fd))    return (FAIL);  if (!load_shdr (chunk.size, sf, fd))    return (FAIL);  return (OK);}/* preset header loader */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -