⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sample.c

📁 A GTK sound font editor. Sound font files are used to synthesize instruments from audio samples for
💻 C
📖 第 1 页 / 共 2 页
字号:
/*================================================================== * sample.c - Audio sample routines * * 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 "config.h"#include <stdio.h>#include <string.h>#include "uif_sfont.h"#include "sfont.h"#include "sample.h"#include "util.h"#include "smurfcfg.h"#include "i18n.h"/* use libsndfile as default, use audiofile only if explicitly requested */#ifndef WITH_AUDIOFILE#include <sndfile.h>#else#include <audiofile.h>/* using audiofile 0.2.0 or newer? define AUDIOFILE_ZERO_TWO if so */#if defined (LIBAUDIOFILE_MAJOR_VERSION) && (LIBAUDIOFILE_MAJOR_VERSION > 0 || LIBAUDIOFILE_MINOR_VERSION >= 2)#define AUDIOFILE_ZERO_TWO 1#endif#endif/* sample data policy:Sample data info is stored in a linked list of SFSamDataInfo structures,sam_datainfo_list. Sample data resides in an open sound font or the samplebuffer, which is a temporary file used for storing unsaved and undo sampledata. Multiple samples can reference the same sample data (SFSamDataInfostructure), this occurs if a sample is copied from one sound font to another.The default policy is to try to use sample data in open sound fonts to reducethe amount of temporary buffer storage. So if 2 or more unsaved samples fromdifferent sound fonts refer to the same sample data in the sample buffer, thenthe first sound font saved will cause those samples to then refer to the sampledata in that sound font file. A subsequent save of one of the other SF fileswill cause a new SFSamDataInfo structure to be created for that sample.Closing a sound font involves making sure that sample data referencedby samples in other sound fonts gets duplicated into the sample buffer, andthose samples pointed to the new data.*/GSList *sam_datainfo_list = NULL;  /* linked list of SFSamDataInfo structs */FILE *sambuf_fd = NULL;gint sambuf_length;		/* sample buffer length in samples */SFSample *sam_in_view = NULL;	/* ptr to sample in samview or NULL */gint16 *sam_data_in_view;	/* data of sample in samview */static gint sam_buf_write (void *data, SFSample * sam);static void sam_buf_clean (void);/* initialize the sample buffer */intsam_buf_init (void){  if (sambuf_fd)    return (OK);  if (!(sambuf_fd = tmpfile ()))    return (logit (LogFubar | LogErrno,	_("Failed to create temporary file for sample buffer")));  sambuf_length = 0;  return (OK);}/* destroy sample buffer (closing a file opened by tmpfile() destroys it) */voidsam_buf_destroy (void){  if (!sambuf_fd)    return;  fclose (sambuf_fd);  sambuf_fd = NULL;}/* allocates a SFSamDataInfo structure and adds it to sam_datainfo_list */SFSamDataInfo *sam_datainfo_new (void){  SFSamDataInfo *datainfo;  datainfo = sfont_samdatainfo_alloc ();  sam_datainfo_list = g_slist_append (sam_datainfo_list, datainfo);  return (datainfo);}/* removes a SFSamDataInfo structure from sam_datainfo_list and frees it */voidsam_datainfo_destroy (SFSamDataInfo *datainfo){  sam_datainfo_list = g_slist_remove (sam_datainfo_list, datainfo);  sfont_samdatainfo_free (datainfo);}/* relocates sample data from a sound font into the sample buffer */gintsam_datainfo_move2sambuf (SFSample *sam, SFData *sf){  gpointer buf;  if (sam->datainfo->samfile) return (OK); /* already in sample buffer? */  if (!(buf = sam_load_sample (sam, sam->datainfo->size, 0, NULL)))    return (FAIL);  sam_buf_write (buf, sam);  return (OK);}/* write sample data to sample buffer and update sample */static gintsam_buf_write (void *data, SFSample * sam){  if (!sambuf_fd)    if (!sam_buf_init ())      return (FAIL);  if (!safe_fseek (sambuf_fd, (long int) (sambuf_length * 2), SEEK_SET))    return (logit (LogFubar,	_("Failed to seek to end of sample buffer file")));  /* save the sample to the sample file buffer */  if (!safe_fwrite (data, (sam->end + 1) * 2, sambuf_fd))    return (FAIL);  sam->datainfo->samfile = 1;  sam->datainfo->sf = NULL;  sam->datainfo->start = sambuf_length;  sambuf_length += sam->end + 1;  return (OK);}/* "cleans" up sample buffer if more than SMURFCFG_SAM_BUF_WASTE bytes arewasted by unused samples, opens new file and writes used samples to it anddeletes old */static voidsam_buf_clean (void){  struct st_saminfo  /* structure stores old sample info */  {    SFSamDataInfo *datainfo;    gint start;  };  gint maxwaste;  FILE *temp_fd;	/* temp file descriptor for new sample buffer */  GSList *p;  gint used = 0;		/* amount of used sample buffer space */  gint size, i;  gboolean error = FALSE;  gint newpos = 0;		/* current position in new sample buffer */  guint8 *buf;  GArray *backup_saminfo;  /* array of old samdata info (in case of error) */  SFSamDataInfo *datainfo;  struct st_saminfo bakinfo;	/* structure stores old sample info */  struct st_saminfo *reinfo;  if (!sambuf_fd)    return;  /* calc used space in sample buffer and remove unused data info structs */  p = sam_datainfo_list;  while (p)  /* loop over sample data information */    {      datainfo = (SFSamDataInfo *)(p->data);      p = g_slist_next (p);      if (!datainfo->refcount && !datainfo->dorefcount)  /* no refs? */	sam_datainfo_destroy (datainfo);  /* destroy unused sam data info */      else if (datainfo->samfile)	used += datainfo->size;  /* add to used size accumulator */    }  /* SAM_BUF_WASTE is in megabytes */  maxwaste = smurfcfg_get_int (SMURFCFG_SAM_BUF_WASTE);  /* if wasted space is less than max tolerated, then return */  if ((sambuf_length - used) * 2 <= maxwaste * 1024 * 1024)    return;  if (!(temp_fd = tmpfile ()))    {      logit (LogFubar | LogErrno, _("Failed to create temporary file for sample buffer"));      return;    }  backup_saminfo = g_array_new (FALSE, FALSE, sizeof (bakinfo));  /* copy used samples from old sample buffer to new */  p = sam_datainfo_list;  while (p)  /* loop over sample data info */    {      datainfo = (SFSamDataInfo *) (p->data);      p = g_slist_next (p);      if (!datainfo->samfile)	continue;		/* only samples in sam buffer */      /* save sample info (in case of error) */      bakinfo.datainfo = datainfo;      bakinfo.start = datainfo->start;      g_array_append_val (backup_saminfo, bakinfo);      size = datainfo->size * 2;      /* copy sample to new sample buffer */      if (!(buf = safe_malloc (size)))	error = TRUE;      /* seek to start of sample buffer */      if (!error && !safe_fseek (sambuf_fd, datainfo->start * 2, SEEK_SET))	error = TRUE;            if (!error && !safe_fread (buf, size, sambuf_fd))	error = TRUE;      if (!error && !safe_fwrite (buf, size, temp_fd))	error = TRUE;      g_free (buf);            datainfo->start = newpos;      newpos += datainfo->size;      if (error)	{		/* if error occured, then restore sample info */	  i = backup_saminfo->len - 1;	  while (i >= 0)	    {	      reinfo = &g_array_index (backup_saminfo, struct st_saminfo, i);	      datainfo = reinfo->datainfo;	      datainfo->start = reinfo->start;	      i--;	    }	  g_array_free (backup_saminfo, TRUE);	  fclose (temp_fd);	  return;	}    }  g_array_free (backup_saminfo, TRUE);  fclose (sambuf_fd);		/* close defunct sample buffer */  sambuf_fd = temp_fd;		/* set temp buffer to new one */  sambuf_length = newpos;	/* set length of buffer to new length */}/*  sam_load_sample() - load a sound font sample (possibly "cached" in samview)    sam = the sample to load    size = size to load (in samples)    ofs = offset from start of sample (in samples)    bufptr is an optional pointer to place sample data (NULL to allocate one)    returns: pointer to sample data which should be free'd (if !bufptr) */gpointersam_load_sample (SFSample * sam, gint size, gint ofs, gpointer bufptr){  guint32 pos;  FILE *fd;  gpointer buf;  /* if sample is a ROM sample, can't load it :( */  if (sam->sampletype & SF_SAMPLETYPE_ROM)    return (NULL);  if (!bufptr)    {  /* allocate buffer space if no bufptr supplied */      if (!(buf = safe_malloc (size * 2)))	return (NULL);    }  else				/* use supplied buffer ptr */    buf = bufptr;  /* if sample is already loaded (for viewing purposes) then memcopy it */  if (sam == sam_in_view && sam_data_in_view)    {      memcpy (buf, (gint16 *) sam_data_in_view + ofs, size * 2);      return (buf);    }  pos = (sam->datainfo->start + ofs) * 2;  if (sam->datainfo->samfile == 0)    {      fd = sam->datainfo->sf->sffd;      pos += sam->datainfo->sf->samplepos;    }  else    fd = sambuf_fd;  if (!safe_fseek (fd, pos, SEEK_SET))    {      if (!bufptr) g_free (buf);      return (NULL);    }  if (!safe_fread (buf, size * 2, fd))    {      if (!bufptr) g_free (buf);      return (NULL);    }  return (buf);}/* creates a new sample and adds it to a sound font, name is name of sample,   rate is sampling rate, samdata is the audio data for new sample, size is   the # of samples in samdata */SFSample *sam_create_sample (gchar *name, gint rate, gint16 *samdata, gint size,  SFData *sf){  SFSample *sam;  sam = sfont_sample_alloc ();  /* allocate SFSample structure */  /* create SFSamDataInfo structure and assign it to new sample */  sam->datainfo = sam_datainfo_new ();  sam->datainfo->size = size;  sam->datainfo->refcount++;  /* increment reference count */  sfont_set_namestr (sf, sam->name, name);  sam->end = size - 1;	/* end is last point of sample (ofs from start) */  sam->loopstart = 8;		/* offset from start to start of loop */  sam->loopend = size - 8;	/* ofs from start to loop end */  sam->samplerate = rate;  sam->origpitch = 60;  sam->pitchadj = 0;  sam->sampletype = SF_SAMPLETYPE_MONO;	/* from sfont.h !libsndfile! */  /* write to sample file buffer */  if (!sam_buf_write (samdata, sam))      return (NULL);  sfont_add_sample (sf, sam);  return(sam);}/* clone a sample */SFSample *sam_clone_sample (SFData * dst, SFData * src, SFSample * sam){  SFSample *dupsam;  dupsam = sfont_sample_dup (sam, SFDUP_NORMAL, TRUE);  sfont_add_sample (dst, dupsam);  return (dupsam);}/* cut a portion of a sample */gintsam_cut_sample (SFData * sf, SFSample * sam, guint spos, guint epos){  gint after;		/* size of sample data after cut */  gint newsize;		/* size of sample minus cut data */  gint oldend;  gint16 *buf;  SFSamDataInfo *oldinfo;  if (spos > epos || epos > sam->end)    return (FAIL);  newsize = sam->end + 1 - (epos - spos + 1);	/* size of sample - cut */  if (newsize < smurfcfg_get_int (SMURFCFG_SAM_MINLOOP)      + smurfcfg_get_int (SMURFCFG_SAM_MINLOOPPAD) * 2)    {      logit (LogFubar,	_("Cutting requested area of sample would make it too small"));      return (FAIL);    }  /* load the sample */  if (!(buf = sam_load_sample (sam, sam->end + 1, 0, NULL)))      return (FAIL);  oldinfo = sam->datainfo;  /* save old sample data info structure */  sam->datainfo = sam_datainfo_new ();  /* create new data info struct */  sam->datainfo->size = newsize;  sam->datainfo->refcount++;  /* increment reference count */  after = (sam->end - epos) * 2;	/* size of data after cut */  if (after)			/* join portions before and after cut */    memcpy (buf + spos, buf + epos + 1, after);  oldend = sam->end;		/* save old end position in case of error */  sam->end = newsize - 1;	/* set sample end position */  if (!sam_buf_write (buf, sam))  /* write new sample to sample buffer */    {      sam_datainfo_destroy (sam->datainfo);      sam->datainfo = oldinfo;      sam->end = oldend;      g_free (buf);      return (FAIL);    }  g_free (buf);  oldinfo->refcount--;  /* decrement old sample data reference counter */  /* update loop pointers if needed */  /* if loop start within cut, then reset to beginning of sample */  if (sam->loopstart >= spos && sam->loopstart <= epos)    sam->loopstart = smurfcfg_get_int (SMURFCFG_SAM_MINLOOPPAD);  else if (sam->loopstart > epos)  /* if loop start after cut.. */    sam->loopstart -= epos - spos + 1;  /* subtract cut length */  /* if loop end within cut, then reset to end of sample */  if (sam->loopend >= spos && sam->loopend <= epos)    sam->loopend = sam->end - smurfcfg_get_int (SMURFCFG_SAM_MINLOOPPAD);  else if (sam->loopend > epos)  /* if loop end after cut.. */    sam->loopend -= epos - spos + 1;  /* subtract cut length */  return (OK);}/* Load audio file data as an SFSample (2 samples in the case of stereo) */SFSample *

⌨️ 快捷键说明

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