[beast/devel: 11/28] FLAC: support compressed flac data handles stored in .bsewave / .bse files



commit 682b286bdcd2712517663e90d494d672fadf58d0
Author: Stefan Westerfeld <stefan space twc de>
Date:   Wed Mar 20 20:22:46 2013 +0100

    FLAC: support compressed flac data handles stored in .bsewave / .bse files

 bse/Makefile.am           |    2 +-
 bse/bsedatahandle-flac.cc |  274 ++++++++++++++++++++++++++++++++++++++++++---
 bse/bseloader-bsewave.cc  |   46 ++++++++-
 bse/bseloader-flac.cc     |    1 +
 bse/bsestorage.cc         |   52 +++++++--
 bse/gsldatahandle.hh      |    6 -
 tools/bwtwave.cc          |    9 ++
 7 files changed, 356 insertions(+), 34 deletions(-)
---
diff --git a/bse/Makefile.am b/bse/Makefile.am
index b05260c..1014e31 100644
--- a/bse/Makefile.am
+++ b/bse/Makefile.am
@@ -55,7 +55,7 @@ bse_public_headers = $(strip \
        bsenote.hh              bsemidifile.hh          bseblockutils.hh                \
        bsecxxvalue.hh          bsecxxutils.hh          bsecxxbase.hh                   bsecxxclosure.hh \
        bsecxxarg.hh            bsecxxmodule.hh         bsecxxplugin.hh                 bseloader.hh \
-       bseresampler.hh         bseresamplerimpl.hh     \
+       bseresampler.hh         bseresamplerimpl.hh     bsedatahandle-flac.hh           \
        testobject.hh           \
 )
 # BSE C & C++ sources
diff --git a/bse/bsedatahandle-flac.cc b/bse/bsedatahandle-flac.cc
index 303ea83..f9c4949 100644
--- a/bse/bsedatahandle-flac.cc
+++ b/bse/bsedatahandle-flac.cc
@@ -1,5 +1,6 @@
 // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
 #include "gsldatahandle.hh"
+#include "bsedatahandle-flac.hh"
 #include "gsldatautils.hh"
 #include "gslfilter.hh"
 #include "bseblockutils.hh"
@@ -16,6 +17,10 @@ using std::vector;
 using std::string;
 using std::min;
 
+namespace {
+  enum FlacZOffset { NO_ZOFFSET, ADD_ZOFFSET };
+}
+
 class DataHandleFlac;
 
 struct CDataHandleFlac : public GslDataHandle
@@ -26,6 +31,80 @@ struct CDataHandleFlac : public GslDataHandle
 
 class DataHandleFlac {
 private:
+// ***************************** virtual file I/O ********************************
+  GslLong   m_file_byte_offset;
+  GslLong   m_file_byte_size;
+  GslRFile *m_rfile;
+
+  static FLAC__StreamDecoderReadStatus
+  file_read_callback (const FLAC__StreamDecoder  *decoder,
+                      FLAC__byte                  buffer[],
+                      size_t                     *bytes,
+                      void                       *client_data)
+  {
+    DataHandleFlac *dh = static_cast<DataHandleFlac *> (client_data);
+
+    const size_t bytes_to_eof = dh->m_file_byte_size - (gsl_rfile_position (dh->m_rfile) - 
dh->m_file_byte_offset);
+    GslLong l = gsl_rfile_read (dh->m_rfile, MIN (*bytes, bytes_to_eof), buffer);
+    if (l < 0)
+      return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+
+    *bytes = l;
+    if (*bytes == 0)
+      return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+    else
+      return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+  }
+
+  static FLAC__StreamDecoderSeekStatus
+  file_seek_callback (const FLAC__StreamDecoder *decoder,
+                      FLAC__uint64               absolute_byte_offset,
+                      void                      *client_data)
+  {
+    DataHandleFlac *dh = static_cast<DataHandleFlac *> (client_data);
+
+    int64 l = dh->m_file_byte_offset + absolute_byte_offset;
+    l = CLAMP (l, dh->m_file_byte_offset, dh->m_file_byte_offset + dh->m_file_byte_size);
+    l = gsl_rfile_seek_set (dh->m_rfile, l);
+    if (l >= 0)
+      return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+    else
+      return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+  }
+
+  static FLAC__StreamDecoderTellStatus
+  file_tell_callback (const FLAC__StreamDecoder *decoder,
+                      FLAC__uint64              *absolute_byte_offset,
+                      void                      *client_data)
+  {
+    DataHandleFlac *dh = static_cast<DataHandleFlac *> (client_data);
+
+    *absolute_byte_offset = gsl_rfile_position (dh->m_rfile) - dh->m_file_byte_offset;
+    return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+  }
+
+  static FLAC__StreamDecoderLengthStatus
+  file_length_callback (const FLAC__StreamDecoder *decoder,
+                        FLAC__uint64              *stream_length,
+                        void                      *client_data)
+  {
+    DataHandleFlac *dh = static_cast<DataHandleFlac *> (client_data);
+
+    *stream_length = dh->m_file_byte_size;
+    return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+  }
+
+  static FLAC__bool
+  file_eof_callback (const FLAC__StreamDecoder *decoder,
+                     void *client_data)
+  {
+    DataHandleFlac *dh = static_cast<DataHandleFlac *> (client_data);
+
+    return dh->m_file_byte_size == (gsl_rfile_position (dh->m_rfile) - dh->m_file_byte_offset);
+  }
+
+// *******************************************************************************
+
   static FLAC__StreamDecoderWriteStatus
   flac_write_callback (const FLAC__StreamDecoder  *decoder,
                        const FLAC__Frame          *frame,
@@ -70,12 +149,21 @@ protected:
   int64                 m_buffer_start;
   vector<float>         m_buffer;
   float                 m_osc_freq;
+  FlacZOffset           m_init_add_zoffset;
+  GslLong               m_init_byte_offset;
+  GslLong               m_init_byte_size;
 
 public:
   DataHandleFlac (const string& file_name,
-                 float         osc_freq) :
+                 float         osc_freq,
+                  FlacZOffset   add_zoffset,
+                  GslLong       byte_offset = -1,
+                  GslLong       byte_size = -1) :
     m_init_ok (false),
-    m_decoder (NULL)
+    m_decoder (NULL),
+    m_init_add_zoffset (add_zoffset),
+    m_init_byte_offset (byte_offset),
+    m_init_byte_size (byte_size)
   {
     memset (&m_dhandle, 0, sizeof (m_dhandle));
     m_init_ok = gsl_data_handle_common_init (&m_dhandle, NULL);
@@ -99,9 +187,37 @@ public:
     if (!m_decoder)
       return BSE_ERROR_IO;
 
+    m_rfile = gsl_rfile_open (m_file_name.c_str());
+    if (!m_rfile)
+      return gsl_error_from_errno (errno, BSE_ERROR_FILE_OPEN_FAILED);
+
+    if (m_init_byte_offset >= 0 && m_init_byte_size >= 0)
+      {
+        m_file_byte_offset = m_init_byte_offset;
+        m_file_byte_size = m_init_byte_size;
+      }
+    else
+      {
+        m_file_byte_offset = 0;
+        m_file_byte_size = gsl_rfile_length (m_rfile);
+      }
+
+    if (m_init_add_zoffset == ADD_ZOFFSET)
+      {
+        m_file_byte_offset += gsl_hfile_zoffset (m_rfile->hfile) + 1;
+      }
+
+    /* seek to beginning of the virtual file */
+    file_seek_callback (m_decoder, 0, this);
+
     m_error_occurred = false;
-    int err = FLAC__stream_decoder_init_file (m_decoder, m_file_name.c_str(),
-                                              flac_write_callback, NULL, flac_error_callback, this);
+    int err = FLAC__stream_decoder_init_stream (m_decoder,
+                                                file_read_callback,
+                                                file_seek_callback,
+                                                file_tell_callback,
+                                                file_length_callback,
+                                                file_eof_callback,
+                                                flac_write_callback, NULL, flac_error_callback, this);
     if (err != 0)
       return BSE_ERROR_IO;
 
@@ -167,19 +283,10 @@ public:
     return 0;
   }
 
+  static GslDataHandleFuncs dh_vtable;
   static GslDataHandle*
   dh_create (DataHandleFlac *cxx_dh)
   {
-    static GslDataHandleFuncs dh_vtable =
-    {
-      dh_open,
-      dh_read,
-      dh_close,
-      NULL,
-      NULL,
-      dh_destroy,
-    };
-
     if (cxx_dh->m_init_ok)
       {
        cxx_dh->m_dhandle.vtable = &dh_vtable;
@@ -197,6 +304,17 @@ public:
   {
     return static_cast<CDataHandleFlac *> (dhandle)->cxx_dh;
   }
+
+  GslLong
+  file_byte_offset()
+  {
+    return m_file_byte_offset;
+  }
+  GslLong
+  file_byte_size()
+  {
+    return m_file_byte_size;
+  }
 private:
 /* for the "C" API (vtable) */
   static BseErrorType
@@ -224,14 +342,138 @@ private:
   }
 };
 
+GslDataHandleFuncs DataHandleFlac::dh_vtable
+{
+  dh_open,
+  dh_read,
+  dh_close,
+  NULL,
+  NULL,
+  dh_destroy,
+};
+
 }
 
 using namespace Bse;
 
-extern "C" GslDataHandle*
+GslDataHandle*
 bse_data_handle_new_flac (const char    *file_name,
                           gfloat         osc_freq)
 {
-  DataHandleFlac *cxx_dh = new DataHandleFlac (file_name, osc_freq);
+  DataHandleFlac *cxx_dh = new DataHandleFlac (file_name, osc_freq, NO_ZOFFSET);
   return DataHandleFlac::dh_create (cxx_dh);
 }
+
+GslDataHandle*
+bse_data_handle_new_flac_zoffset (const char *file_name,
+                                  float       osc_freq,
+                                  GslLong     byte_offset,
+                                  GslLong     byte_size,
+                                  uint       *n_channels_p,
+                                  gfloat     *mix_freq_p)
+{
+  g_return_val_if_fail (file_name != NULL, NULL);
+  g_return_val_if_fail (byte_offset >= 0, NULL);
+  g_return_val_if_fail (byte_size > 0, NULL);
+
+  DataHandleFlac *cxx_dh = new DataHandleFlac (file_name, osc_freq, ADD_ZOFFSET, byte_offset, byte_size);
+  GslDataHandle *dhandle = DataHandleFlac::dh_create (cxx_dh);
+  if (!dhandle)
+    return NULL;
+
+  /* figure out mix_freq, n_channels */
+  BseErrorType error = gsl_data_handle_open (dhandle);
+  if (!error)
+    {
+      if (n_channels_p)
+        *n_channels_p = dhandle->setup.n_channels;
+      if (mix_freq_p)
+        *mix_freq_p = dhandle->setup.mix_freq;
+
+      gsl_data_handle_close (dhandle);
+      return dhandle;
+    }
+  else
+    {
+      gsl_data_handle_unref (dhandle);
+      return NULL;
+    }
+}
+
+/* flac storage */
+
+Flac1Handle *
+Flac1Handle::create (GslDataHandle *dhandle)
+{
+  if (dhandle->vtable == &DataHandleFlac::dh_vtable &&
+      gsl_data_handle_open (dhandle) == BSE_ERROR_NONE)
+    {
+      return new Flac1Handle (dhandle);
+    }
+  else
+    {
+      return NULL;
+    }
+}
+
+void
+Flac1Handle::destroy_fn (gpointer data)
+{
+  delete (Flac1Handle *) data;
+}
+
+int
+Flac1Handle::read_data_fn (void *data, void *buffer, uint blength)
+{
+  Flac1Handle *flac_handle = (Flac1Handle*) data;
+
+  return flac_handle->read_data (buffer, blength);
+}
+
+Flac1Handle::Flac1Handle (GslDataHandle *dhandle) :
+  rfile (nullptr),
+  dhandle (dhandle)
+{
+  flac_handle = DataHandleFlac::dh_cast (dhandle);
+}
+
+Flac1Handle::~Flac1Handle()
+{
+  if (rfile)
+    {
+      gsl_rfile_close (rfile);
+      rfile = NULL;
+    }
+  gsl_data_handle_close (dhandle);
+  dhandle = NULL;
+}
+
+int
+Flac1Handle::read_data (void *buffer, uint blength)
+{
+  if (!rfile)
+    {
+      rfile = gsl_rfile_open (dhandle->name);
+      if (!rfile)
+        return gsl_error_from_errno (errno, BSE_ERROR_FILE_OPEN_FAILED);
+      byte_length = gsl_rfile_length (rfile);
+      gsl_rfile_seek_set (rfile, flac_handle->file_byte_offset());
+    }
+  const uint bytes_to_eof = flac_handle->file_byte_size() - (gsl_rfile_position (rfile) - 
flac_handle->file_byte_offset());
+
+  int n_bytes_read;
+  do
+    n_bytes_read = gsl_rfile_read (rfile, std::min (blength, bytes_to_eof), buffer);
+  while (n_bytes_read < 0 && errno == EINTR);
+
+  if (n_bytes_read <= 0)               /* bail on errors */
+    return errno ? -errno : -EIO;
+
+  return n_bytes_read;
+}
+
+void
+Flac1Handle::put_wstore (SfiWStore *wstore)
+{
+  sfi_wstore_put_binary (wstore, read_data_fn, this, destroy_fn);
+}
diff --git a/bse/bseloader-bsewave.cc b/bse/bseloader-bsewave.cc
index b8e3ee9..80a6397 100644
--- a/bse/bseloader-bsewave.cc
+++ b/bse/bseloader-bsewave.cc
@@ -3,6 +3,7 @@
 #include "bsemain.hh"
 #include "gsldatahandle.hh"
 #include "gsldatahandle-vorbis.hh"
+#include "bsedatahandle-flac.hh"
 #include "bsemath.hh"
 #include <sfi/sfistore.hh>
 #include <fcntl.h>
@@ -27,6 +28,7 @@ typedef enum
   BSEWAVE_TOKEN_OSC_FREQ,
   BSEWAVE_TOKEN_XINFO,
   BSEWAVE_TOKEN_VORBIS_LINK,
+  BSEWAVE_TOKEN_FLAC_LINK,
   BSEWAVE_TOKEN_FILE,
   BSEWAVE_TOKEN_INDEX,          /* file (auto detect loader) */
   BSEWAVE_TOKEN_RAW_FILE,
@@ -61,7 +63,7 @@ typedef enum
 static const char *bsewave_tokens[] = {
   /* keyword tokens */
   "wave",       "chunk",        "name",         "n-channels",
-  "midi-note",  "osc-freq",     "xinfo",        "vorbis-link",
+  "midi-note",  "osc-freq",     "xinfo",        "vorbis-link",    "flac-link",
   "file",       "index",        "raw-file",     "boffset",
   "n-values",   "raw-link",     "byte-order",   "format",
   "mix-freq",
@@ -102,6 +104,7 @@ typedef struct
 #define RAW_FILE_MAGIC          (('R' << 24) | ('a' << 16) | ('w' << 8) | 'F')
 #define RAW_LINK_MAGIC          (('R' << 24) | ('a' << 16) | ('w' << 8) | 'L')
 #define VORBIS_LINK_MAGIC       (('O' << 24) | ('/' << 16) | ('V' << 8) | '1')
+#define FLAC_LINK_MAGIC         (('F' << 24) | ('L' << 16) | ('C' << 8) | '1')
 
 /* --- functions --- */
 static GTokenType
@@ -310,6 +313,21 @@ bsewave_parse_chunk_dsc (GScanner        *scanner,
        LOADER_FILE (chunk) = NULL;
         LOADER_TYPE (chunk) = VORBIS_LINK_MAGIC;
        break;
+      case BSEWAVE_TOKEN_FLAC_LINK:
+       parse_or_return (scanner, '=');
+       parse_or_return (scanner, '(');
+       parse_or_return (scanner, G_TOKEN_IDENTIFIER);
+       if (strcmp (scanner->value.v_identifier, "binary-appendix") != 0)
+         return G_TOKEN_IDENTIFIER;
+       parse_or_return (scanner, G_TOKEN_INT);
+       LOADER_BOFFSET (chunk) = scanner->value.v_int64;        /* byte offset */
+       parse_or_return (scanner, G_TOKEN_INT);
+       LOADER_LENGTH (chunk) = scanner->value.v_int64;         /* byte length */
+       parse_or_return (scanner, ')');
+       g_free (LOADER_FILE (chunk));
+       LOADER_FILE (chunk) = NULL;
+        LOADER_TYPE (chunk) = FLAC_LINK_MAGIC;
+       break;
       case BSEWAVE_TOKEN_FILE:
        parse_or_return (scanner, '=');
        parse_or_return (scanner, G_TOKEN_STRING);
@@ -788,6 +806,32 @@ bsewave_create_chunk_handle (void         *data,
       else
         *error_p = BSE_ERROR_WAVE_NOT_FOUND;
       break;
+    case FLAC_LINK_MAGIC:
+      if (LOADER_LENGTH (chunk))        /* inlined binary data */
+        {
+          *error_p = BSE_ERROR_IO;
+          uint vnch = 0;
+         dhandle = bse_data_handle_new_flac_zoffset (fi->wfi.file_name,
+                                                      chunk->osc_freq,
+                                                      LOADER_BOFFSET (chunk),     /* byte offset */
+                                                      LOADER_LENGTH (chunk),      /* byte length */
+                                                      &vnch, NULL);
+          if (dhandle && vnch != dsc->wdsc.n_channels)
+            {
+              *error_p = BSE_ERROR_WRONG_N_CHANNELS;
+              gsl_data_handle_unref (dhandle);
+              dhandle = NULL;
+            }
+          if (dhandle && chunk->xinfos)
+            {
+              GslDataHandle *tmp_handle = dhandle;
+              dhandle = gsl_data_handle_new_add_xinfos (dhandle, chunk->xinfos);
+              gsl_data_handle_unref (tmp_handle);
+            }
+        }
+      else
+        *error_p = BSE_ERROR_WAVE_NOT_FOUND;
+      break;
     default:    /* no file_name and no loader specified */
       *error_p = BSE_ERROR_FORMAT_UNKNOWN;
       break;
diff --git a/bse/bseloader-flac.cc b/bse/bseloader-flac.cc
index 6d38fd6..dff0fba 100644
--- a/bse/bseloader-flac.cc
+++ b/bse/bseloader-flac.cc
@@ -1,5 +1,6 @@
 // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
 #include "bseloader.hh"
+#include "bsedatahandle-flac.hh"
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
diff --git a/bse/bsestorage.cc b/bse/bsestorage.cc
index 6d8b5f2..4db8024 100644
--- a/bse/bsestorage.cc
+++ b/bse/bsestorage.cc
@@ -3,6 +3,7 @@
 #include "bseitem.hh"
 #include "gsldatahandle.hh"
 #include "gsldatahandle-vorbis.hh"
+#include "bsedatahandle-flac.hh"
 #include "gsldatautils.hh"
 #include "gslcommon.hh"
 #include "bseproject.hh"
@@ -13,6 +14,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+
+using Bse::Flac1Handle;
+
 /* --- macros --- */
 #define parse_or_return sfi_scanner_parse_or_return
 #define peek_or_return  sfi_scanner_peek_or_return
@@ -65,6 +69,7 @@ static GTokenType compat_parse_data_handle         (BseStorage       *self,
 static gpointer parent_class = NULL;
 static GQuark   quark_raw_data_handle = 0;
 static GQuark   quark_vorbis_data_handle = 0;
+static GQuark   quark_flac_data_handle = 0;
 static GQuark   quark_dblock_data_handle = 0;
 static GQuark   quark_bse_storage_binary_v0 = 0;
 
@@ -101,6 +106,7 @@ bse_storage_class_init (BseStorageClass *klass)
 
   quark_raw_data_handle = g_quark_from_static_string ("raw-data-handle");
   quark_vorbis_data_handle = g_quark_from_static_string ("vorbis-data-handle");
+  quark_flac_data_handle = g_quark_from_static_string ("flac-data-handle");
   quark_dblock_data_handle = g_quark_from_static_string ("dblock-data-handle");
   quark_bse_storage_binary_v0 = g_quark_from_static_string ("BseStorageBinaryV0");
 
@@ -1322,6 +1328,7 @@ bse_storage_put_data_handle (BseStorage    *self,
     }
   while (tmp_handle);   /* skip comment or cache handles */
   GslVorbis1Handle *vhandle = gsl_vorbis1_handle_new (test_handle, gsl_vorbis_make_serialno());
+  Flac1Handle      *flac_handle = Flac1Handle::create (dhandle);
   if (vhandle)  /* save already compressed Ogg/Vorbis data */
     {
       bse_storage_break (self);
@@ -1333,6 +1340,17 @@ bse_storage_put_data_handle (BseStorage    *self,
       bse_storage_pop_level (self);
       bse_storage_putc (self, ')');
     }
+  else if (flac_handle) /* save flac compressed handle */
+    {
+      bse_storage_break (self);
+      bse_storage_printf (self, "(%s ", g_quark_to_string (quark_flac_data_handle));
+      bse_storage_putf (self, gsl_data_handle_osc_freq (dhandle));
+      bse_storage_push_level (self);
+      bse_storage_break (self);
+      flac_handle->put_wstore (self->wstore);
+      bse_storage_pop_level (self);
+      bse_storage_putc (self, ')');
+    }
   else          /* save raw data handle */
     {
       if (significant_bits < 1)
@@ -1434,11 +1452,12 @@ parse_raw_data_handle (BseStorage     *self,
   return G_TOKEN_NONE;
 }
 static GTokenType
-parse_vorbis_data_handle (BseStorage     *self,
-                          GslDataHandle **data_handle_p,
-                          guint          *n_channels_p,
-                          gfloat         *mix_freq_p,
-                          gfloat         *osc_freq_p)
+parse_vorbis_or_flac_data_handle (BseStorage     *self,
+                                  GQuark          quark,
+                                  GslDataHandle **data_handle_p,
+                                  guint          *n_channels_p,
+                                  gfloat         *mix_freq_p,
+                                  gfloat         *osc_freq_p)
 {
   GScanner *scanner = bse_storage_get_scanner (self);
   GTokenType token;
@@ -1467,8 +1486,20 @@ parse_vorbis_data_handle (BseStorage     *self,
   else
     {
       gfloat mix_freq;
-      *data_handle_p = gsl_data_handle_new_ogg_vorbis_zoffset (self->rstore->fname, osc_freq,
-                                                               offset, length, n_channels_p, &mix_freq);
+      if (quark == quark_vorbis_data_handle)
+        {
+          *data_handle_p = gsl_data_handle_new_ogg_vorbis_zoffset (self->rstore->fname, osc_freq,
+                                                                   offset, length, n_channels_p, &mix_freq);
+        }
+      else if (quark == quark_flac_data_handle)
+        {
+          *data_handle_p = bse_data_handle_new_flac_zoffset (self->rstore->fname, osc_freq,
+                                                             offset, length, n_channels_p, &mix_freq);
+        }
+      else
+        {
+          return bse_storage_warn_skip (self, "unknown compressed data handle type in 
parse_vorbis_or_flac_data_handle");
+        }
       if (osc_freq <= 0 || mix_freq < 4000 || osc_freq >= mix_freq / 2)
         return bse_storage_warn_skip (self, "invalid oscillating/mixing frequencies: %.7g/%.7g", osc_freq, 
mix_freq);
       if (mix_freq_p)
@@ -1484,7 +1515,8 @@ bse_storage_match_data_handle (BseStorage *self,
       quark == quark_dblock_data_handle)
     return TRUE;
   if (quark == quark_raw_data_handle ||
-      quark == quark_vorbis_data_handle)
+      quark == quark_vorbis_data_handle ||
+      quark == quark_flac_data_handle)
     return TRUE;
   return FALSE;
 }
@@ -1513,8 +1545,8 @@ parse_data_handle_trampoline (BseStorage     *self,
     return parse_dblock_data_handle (self, data_handle_p, n_channels_p, mix_freq_p, osc_freq_p);
   if (quark == quark_raw_data_handle)
     return parse_raw_data_handle (self, data_handle_p, n_channels_p, mix_freq_p, osc_freq_p);
-  else if (quark == quark_vorbis_data_handle)
-    return parse_vorbis_data_handle (self, data_handle_p, n_channels_p, mix_freq_p, osc_freq_p);
+  else if (quark == quark_vorbis_data_handle || quark == quark_flac_data_handle)
+    return parse_vorbis_or_flac_data_handle (self, quark, data_handle_p, n_channels_p, mix_freq_p, 
osc_freq_p);
   if (BSE_STORAGE_COMPAT (self, 0, 5, 1) && quark == quark_bse_storage_binary_v0)
     return compat_parse_data_handle (self, data_handle_p, n_channels_p, mix_freq_p, osc_freq_p);
   bse_storage_error (self, "unknown data handle keyword: %s", scanner->value.v_identifier);
diff --git a/bse/gsldatahandle.hh b/bse/gsldatahandle.hh
index 6d064a2..521f8b7 100644
--- a/bse/gsldatahandle.hh
+++ b/bse/gsldatahandle.hh
@@ -115,12 +115,6 @@ GslDataHandle*       bse_data_handle_new_fir_lowpass   (GslDataHandle *src_handle,
 gdouble           bse_data_handle_fir_response_db   (GslDataHandle *fir_handle,         // implemented in 
bsedatahandle-fir.cc
                                                      gdouble        freq);
 
-/* --- flac datahandle --- */
-GslDataHandle*    bse_data_handle_new_flac          (const gchar*   file_name,
-                                                     gfloat         osc_freq);
-
-
-
 /* --- xinfo handling --- */
 GslDataHandle* gsl_data_handle_new_add_xinfos      (GslDataHandle *src_handle,
                                                     gchar        **xinfos);
diff --git a/tools/bwtwave.cc b/tools/bwtwave.cc
index 49570ff..c3b80be 100644
--- a/tools/bwtwave.cc
+++ b/tools/bwtwave.cc
@@ -3,6 +3,7 @@
 #include <bse/bsemath.hh>
 #include <bse/gsldatautils.hh>
 #include <bse/gsldatahandle-vorbis.hh>
+#include <bse/bsedatahandle-flac.hh>
 #include <bse/bseloader.hh>
 #include <bse/bsecxxutils.hh>
 #include <sys/stat.h>
@@ -14,6 +15,7 @@
 #include <vector>
 #include <map>
 
+using Bse::Flac1Handle;
 
 namespace BseWaveTool {
 
@@ -340,12 +342,19 @@ Wave::store (const string file_name)
         }
       while (tmp_handle);
       GslVorbis1Handle *vhandle = gsl_vorbis1_handle_new (dhandle, gsl_vorbis_make_serialno());
+      Flac1Handle      *flac_handle = Flac1Handle::create (dhandle);
       if (vhandle)      /* save already compressed Ogg/Vorbis data */
         {
           sfi_wstore_puts (wstore, "    vorbis-link = ");
           gsl_vorbis1_handle_put_wstore (vhandle, wstore);
           sfi_wstore_puts (wstore, "\n");
         }
+      else if (flac_handle)
+        {
+          sfi_wstore_puts (wstore, "    flac-link = ");
+          flac_handle->put_wstore (wstore);
+          sfi_wstore_puts (wstore, "\n");
+        }
       else
         {
           sfi_wstore_puts (wstore, "    raw-link = ");


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]