Hi Hamish,

Am Dienstag, den 24.11.2015, 22:40 +1100 schrieb ham...@cloud.net.au:
> Thanks Fabian. I will try tomorrow.

I think I found the real culprit: I had an off-by-one error in the
calculation of the sample sizes. In FluidSynth, sample->end points to
the last valid point in a sample, not to the first point after. This
means that all samples were calculated one byte too short.

Now, all samples are correctly decoded, i.e. there are no samples with
sfinfo.frames == 0 anymore. This also means that the loopstart and
loopend variables are now correctly set; the workaround of setting them
both to 0 that I previously suggested is not necessary anymore. Also,
most of the quality loss that I originally blamed on the compression
seems to be gone now.

Please find a new patch attached.

Thanks,

Fabian
Description: Add support for sound fonts in SF3 format that contain Ogg Vorbis compressed samples
Author: Fabian Greffrath <fab...@debian.org>
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=740710
Forwarded: https://sourceforge.net/p/fluidsynth/tickets/142/
Last-Update: 2015-11-26

--- a/include/fluidsynth/sfont.h
+++ b/include/fluidsynth/sfont.h
@@ -270,6 +270,7 @@ struct _fluid_sample_t
 #define FLUID_SAMPLETYPE_RIGHT	2       /**< Flag for #fluid_sample_t \a sampletype field for right samples of a stereo pair */
 #define FLUID_SAMPLETYPE_LEFT	4       /**< Flag for #fluid_sample_t \a sampletype field for left samples of a stereo pair */
 #define FLUID_SAMPLETYPE_LINKED	8       /**< Flag for #fluid_sample_t \a sampletype field, not used currently */
+#define FLUID_SAMPLETYPE_OGG_VORBIS	0x10 /**< Flag for #fluid_sample_t \a sampletype field for Ogg Vorbis compressed samples */
 #define FLUID_SAMPLETYPE_ROM	0x8000  /**< Flag for #fluid_sample_t \a sampletype field, ROM sample, causes sample to be ignored */
 
 
--- a/src/sfloader/fluid_defsfont.c
+++ b/src/sfloader/fluid_defsfont.c
@@ -26,6 +26,10 @@
 /* Todo: Get rid of that 'include' */
 #include "fluid_sys.h"
 
+#if LIBSNDFILE_SUPPORT
+#include <sndfile.h>
+#endif
+
 /***************************************************************
  *
  *                           SFONT LOADER
@@ -1582,6 +1586,14 @@ new_fluid_sample()
 int
 delete_fluid_sample(fluid_sample_t* sample)
 {
+  if (sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS)
+  {
+#if LIBSNDFILE_SUPPORT
+    if (sample->data)
+      FLUID_FREE(sample->data);
+#endif
+  }
+
   FLUID_FREE(sample);
   return FLUID_OK;
 }
@@ -1598,6 +1610,61 @@ fluid_sample_in_rom(fluid_sample_t* samp
 /*
  * fluid_sample_import_sfont
  */
+#if LIBSNDFILE_SUPPORT
+// virtual file access rountines to allow for handling
+// samples as virtual files in memory
+static sf_count_t sfvio_pos;
+
+static sf_count_t
+sfvio_get_filelen(void* user_data)
+{
+  fluid_sample_t *sample = (fluid_sample_t *)user_data;
+
+  return (sf_count_t)(sample->end + 1 - sample->start);
+};
+
+static sf_count_t
+sfvio_seek(sf_count_t offset, int whence, void* user_data)
+{
+  fluid_sample_t *sample = (fluid_sample_t *)user_data;
+
+  switch (whence)
+  {
+    case SEEK_SET:
+      sfvio_pos = offset;
+      break;
+    case SEEK_CUR:
+      sfvio_pos += offset;
+      break;
+    case SEEK_END:
+      sfvio_pos = sfvio_get_filelen(user_data) + offset;
+      break;
+  }
+
+  return sfvio_pos;
+};
+
+static sf_count_t
+sfvio_read(void* ptr, sf_count_t count, void* user_data)
+{
+  fluid_sample_t *sample = (fluid_sample_t *)user_data;
+
+  if (count > sfvio_get_filelen(user_data) - sfvio_pos)
+      count = sfvio_get_filelen(user_data) - sfvio_pos;
+
+  memcpy(ptr, (char *)sample->data + sample->start + sfvio_pos, count);
+  sfvio_pos += count;
+
+  return count;
+};
+
+static sf_count_t
+sfvio_tell (void* user_data)
+{
+  return sfvio_pos;
+};
+#endif
+
 int
 fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defsfont_t* sfont)
 {
@@ -1612,6 +1679,87 @@ fluid_sample_import_sfont(fluid_sample_t
   sample->pitchadj = sfsample->pitchadj;
   sample->sampletype = sfsample->sampletype;
 
+  if (sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS)
+  {
+#if LIBSNDFILE_SUPPORT
+    SNDFILE *sndfile;
+    SF_INFO sfinfo;
+    SF_VIRTUAL_IO sfvio = {
+      sfvio_get_filelen,
+      sfvio_seek,
+      sfvio_read,
+      NULL,
+      sfvio_tell
+    };
+    short *sampledata_ogg;
+
+    // initialize file position indicator and SF_INFO structure
+    sfvio_pos = 0;
+    memset(&sfinfo, 0, sizeof(sfinfo));
+
+    // open sample as a virtual file in memory
+    sndfile = sf_open_virtual(&sfvio, SFM_READ, &sfinfo, sample);
+    if (!sndfile)
+    {
+      FLUID_LOG(FLUID_ERR, sf_strerror(sndfile));
+      return FLUID_FAILED;
+    }
+
+    // empty sample
+    if (!sfinfo.frames || !sfinfo.channels)
+    {
+      sample->start = sample->end =
+      sample->loopstart = sample->loopend =
+      sample->valid = 0;
+      sample->data = NULL;
+      sf_close(sndfile);
+      return FLUID_OK;
+    }
+
+    // allocate memory for uncompressed sample data stream
+    sampledata_ogg = (short *)FLUID_MALLOC(sfinfo.frames * sfinfo.channels * sizeof(short));
+    if (!sampledata_ogg)
+    {
+      FLUID_LOG(FLUID_ERR, "Out of memory");
+      sf_close(sndfile);
+      return FLUID_FAILED;
+    }
+
+    // uncompress sample data stream
+    if (sf_readf_short(sndfile, sampledata_ogg, sfinfo.frames) < sfinfo.frames)
+    {
+      FLUID_FREE(sampledata_ogg);
+      FLUID_LOG(FLUID_ERR, sf_strerror(sndfile));
+      sf_close(sndfile);
+      return FLUID_FAILED;
+    }
+    sf_close(sndfile);
+
+    // point sample data to uncompressed data stream
+    sample->data = sampledata_ogg;
+    sample->start = 0;
+    sample->end = sfinfo.frames - 1;
+
+    /* loop is fowled?? (cluck cluck :) */
+    if (sample->loopend > sample->end ||
+        sample->loopstart >= sample->loopend ||
+        sample->loopstart <= sample->start)
+    {
+      /* can pad loop by 8 samples and ensure at least 4 for loop (2*8+4) */
+      if ((sample->end - sample->start) >= 20)
+      {
+        sample->loopstart = sample->start + 8;
+        sample->loopend = sample->end - 8;
+      }
+      else /* loop is fowled, sample is tiny (can't pad 8 samples) */
+      {
+        sample->loopstart = sample->start + 1;
+        sample->loopend = sample->end - 1;
+      }
+    }
+#endif
+  }
+
   if (sample->sampletype & FLUID_SAMPLETYPE_ROM) {
     sample->valid = 0;
     FLUID_LOG(FLUID_WARN, "Ignoring sample %s: can't use ROM samples", sample->name);
@@ -1937,6 +2085,10 @@ process_info (int size, SFData * sf, FIL
 	    return (FAIL);
 	  }
 
+#if LIBSNDFILE_SUPPORT
+	  if (sf->version.major == 3) {}
+	  else
+#endif
 	  if (sf->version.major > 2) {
 	    FLUID_LOG (FLUID_WARN,
 		      _("Sound font version is %d.%d which is newer than"
@@ -2958,6 +3110,9 @@ fixup_sample (SFData * sf)
 
 	  return (OK);
 	}
+      /* compressed samples get fixed up after decompression */
+      else if (sam->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS)
+	{}
       else if (sam->loopend > sam->end || sam->loopstart >= sam->loopend
 	|| sam->loopstart <= sam->start)
 	{			/* loop is fowled?? (cluck cluck :) */

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to