[beast/devel: 2/28] BSE: added FLAC support.
- From: Tim Janik <timj src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [beast/devel: 2/28] BSE: added FLAC support.
- Date: Sat, 4 May 2013 03:52:24 +0000 (UTC)
commit ee8c80df85046d0d2936781542cf7d82f47b67e0
Author: Stefan Westerfeld <stefan space twc de>
Date: Sun Jun 27 21:52:07 2010 +0200
BSE: added FLAC support.
bse/Makefile.am | 2 +-
bse/bsedatahandle-flac.cc | 227 +++++++++++++++++++++++++++++++++++++++++++++
bse/bseloader-flac.cc | 181 ++++++++++++++++++++++++++++++++++++
bse/gslcommon.cc | 1 +
bse/gslcommon.hh | 1 +
bse/gsldatahandle.hh | 4 +
6 files changed, 415 insertions(+), 1 deletions(-)
---
diff --git a/bse/Makefile.am b/bse/Makefile.am
index 9b3c2c6..b05260c 100644
--- a/bse/Makefile.am
+++ b/bse/Makefile.am
@@ -91,7 +91,7 @@ bse_sources = $(strip \
bsecxxarg.cc bsecxxmodule.cc bsecxxplugin.cc bseloader.cc \
bseresampler.cc bsedatahandle-resample.cc bsedatahandle-fir.cc \
bseloader-aiff.cc bseloader-guspatch.cc bseloader-oggvorbis.cc bseloader-bsewave.cc \
- bseloader-mad.cc bseloader-wav.cc \
+ bseloader-mad.cc bseloader-wav.cc bseloader-flac.cc bsedatahandle-flac.cc
\
bsebusmodule.cc \
bsebasics.cc \
bseprobe.cc \
diff --git a/bse/bsedatahandle-flac.cc b/bse/bsedatahandle-flac.cc
new file mode 100644
index 0000000..43f2c01
--- /dev/null
+++ b/bse/bsedatahandle-flac.cc
@@ -0,0 +1,227 @@
+/* BSE - Bedevilled Sound Engine
+ * Copyright (C) 2001, 2003 Tim Janik and Stefan Westerfeld
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * A copy of the GNU Lesser General Public License should ship along
+ * with this library; if not, see http://www.gnu.org/copyleft/.
+ */
+#include "gsldatahandle.h"
+#include "gsldatautils.h"
+#include "gslfilter.h"
+#include "bseblockutils.hh"
+#include <complex>
+#include <vector>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include "stream_decoder.h"
+
+namespace Bse {
+
+using std::vector;
+using std::string;
+using std::min;
+
+class DataHandleFlac;
+
+struct CDataHandleFlac : public GslDataHandle
+{
+ // back pointer to get casting right, even in presence of C++ vtable:
+ DataHandleFlac* cxx_dh;
+};
+
+class DataHandleFlac {
+private:
+ static FLAC__StreamDecoderWriteStatus
+ flac_write_callback (const FLAC__StreamDecoder *decoder,
+ const FLAC__Frame *frame,
+ const FLAC__int32 *const buffer[],
+ void *client_data)
+ {
+ DataHandleFlac *dh = static_cast<DataHandleFlac *> (client_data);
+ dh->m_buffer_start = frame->header.number.sample_number;
+ dh->m_buffer.clear();
+ for (int i = 0; i < frame->header.blocksize; i++)
+ dh->m_buffer.push_back (buffer[0][i] * (1 / 32768.0));
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+ }
+ static void
+ flac_error_callback (const FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderErrorStatus status,
+ void *client_data)
+ {
+ }
+
+protected:
+ CDataHandleFlac m_dhandle;
+ bool m_init_ok;
+ string m_file_name;
+ FLAC__StreamDecoder *m_decoder;
+ int64 m_buffer_start;
+ vector<float> m_buffer;
+ float m_osc_freq;
+
+public:
+ DataHandleFlac (const string& file_name,
+ float osc_freq) :
+ m_init_ok (false),
+ m_decoder (NULL)
+ {
+ memset (&m_dhandle, 0, sizeof (m_dhandle));
+ m_init_ok = gsl_data_handle_common_init (&m_dhandle, NULL);
+ m_file_name = file_name;
+ m_dhandle.name = g_strdup (m_file_name.c_str());
+ m_osc_freq = osc_freq;
+ }
+
+ /* protected destructor: (use reference counting instead) */
+ virtual
+ ~DataHandleFlac()
+ {
+ if (m_init_ok)
+ gsl_data_handle_common_free (&m_dhandle);
+ }
+
+ BseErrorType
+ open (GslDataHandleSetup *setup)
+ {
+ m_decoder = FLAC__stream_decoder_new();
+ if (!m_decoder)
+ return BSE_ERROR_IO;
+
+ int err = FLAC__stream_decoder_init_file (m_decoder, m_file_name.c_str(),
+ flac_write_callback, NULL, flac_error_callback, this);
+ if (err != 0)
+ return BSE_ERROR_IO;
+
+ /* decode enough to figure out number of channels */
+ FLAC__bool mdok;
+ do {
+ mdok = FLAC__stream_decoder_process_single (m_decoder);
+ } while (FLAC__stream_decoder_get_channels (m_decoder) == 0 && mdok);
+
+ if (FLAC__stream_decoder_get_channels (m_decoder) == 0)
+ return BSE_ERROR_IO;
+
+ setup->n_channels = FLAC__stream_decoder_get_channels (m_decoder);
+ setup->n_values = FLAC__stream_decoder_get_total_samples (m_decoder);
+ setup->bit_depth = FLAC__stream_decoder_get_bits_per_sample (m_decoder);
+ setup->mix_freq = FLAC__stream_decoder_get_sample_rate (m_decoder);
+ setup->xinfos = bse_xinfos_add_float (setup->xinfos, "osc-freq", m_osc_freq);
+
+ return BSE_ERROR_NONE;
+ }
+
+ void
+ close()
+ {
+ m_dhandle.setup.xinfos = NULL; /* cleanup pointer reference */
+ }
+
+ int64
+ read (int64 voffset,
+ int64 n_values,
+ float *values)
+ {
+ if (voffset >= m_buffer_start + m_buffer.size())
+ {
+ // try to read on, probably we'll have just the samples we need, then
+ FLAC__bool mdok = FLAC__stream_decoder_process_single (m_decoder);
+ }
+
+ if (voffset >= m_buffer_start && voffset < m_buffer_start + m_buffer.size())
+ {
+ int64 buffer_offset = voffset - m_buffer_start;
+ n_values = MIN (n_values, m_buffer.size() - buffer_offset);
+ std::copy (m_buffer.begin() + buffer_offset, m_buffer.begin() + buffer_offset + n_values, values);
+ return n_values;
+ }
+
+ // need to seek to get to the right location
+ FLAC__bool seek_ok = FLAC__stream_decoder_seek_absolute (m_decoder, voffset);
+ if (!seek_ok)
+ return -1;
+
+ if (voffset == m_buffer_start)
+ return read (voffset, n_values, values); // will work this time, since we have the right samples now
+
+ return 0;
+ }
+
+ 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;
+ cxx_dh->m_dhandle.cxx_dh = cxx_dh; /* make casts work, later on */
+ return &cxx_dh->m_dhandle;
+ }
+ else
+ {
+ delete cxx_dh;
+ return NULL;
+ }
+ }
+ static DataHandleFlac*
+ dh_cast (GslDataHandle *dhandle)
+ {
+ return static_cast<CDataHandleFlac *> (dhandle)->cxx_dh;
+ }
+private:
+/* for the "C" API (vtable) */
+ static BseErrorType
+ dh_open (GslDataHandle *dhandle, GslDataHandleSetup *setup)
+ {
+ return dh_cast (dhandle)->open (setup);
+ }
+ static void
+ dh_close (GslDataHandle *dhandle)
+ {
+ dh_cast (dhandle)->close();
+ }
+ static void
+ dh_destroy (GslDataHandle *dhandle)
+ {
+ delete dh_cast (dhandle);
+ }
+ static int64
+ dh_read (GslDataHandle *dhandle,
+ int64 voffset,
+ int64 n_values,
+ gfloat *values)
+ {
+ return dh_cast (dhandle)->read (voffset, n_values, values);
+ }
+};
+
+}
+
+using namespace Bse;
+
+extern "C" GslDataHandle*
+bse_data_handle_new_flac (const char *file_name,
+ gfloat osc_freq)
+{
+ DataHandleFlac *cxx_dh = new DataHandleFlac (file_name, osc_freq);
+ return DataHandleFlac::dh_create (cxx_dh);
+}
diff --git a/bse/bseloader-flac.cc b/bse/bseloader-flac.cc
new file mode 100644
index 0000000..3a58df5
--- /dev/null
+++ b/bse/bseloader-flac.cc
@@ -0,0 +1,181 @@
+ #include "bseloader.h"
+ #include <stdio.h>
+ #include <errno.h>
+ #include <string.h>
+ #include <vector>
+ #include <string>
+ #include <FLAC/stream_decoder.h>
+
+namespace {
+
+static void
+flac_error_callback (const FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderErrorStatus status,
+ void *client_data)
+{
+}
+
+static FLAC__StreamDecoderWriteStatus
+flac_write_callback (const FLAC__StreamDecoder *decoder,
+ const FLAC__Frame *frame,
+ const FLAC__int32 *const buffer[],
+ void *client_data)
+{
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+struct FileInfo
+{
+ BseWaveFileInfo wfi;
+ BseWaveDsc wdsc;
+
+ FileInfo (const gchar *file_name,
+ BseErrorType *error_p)
+ {
+ /* initialize C structures with zeros */
+ memset (&wfi, 0, sizeof (wfi));
+ memset (&wdsc, 0, sizeof (wdsc));
+
+
+ /* setup decoder, decoding from file */
+ FLAC__StreamDecoder* decoder = FLAC__stream_decoder_new();
+ if (!decoder)
+ {
+ *error_p = BSE_ERROR_INTERNAL; // should not happen
+ return;
+ }
+ int r = FLAC__stream_decoder_init_file (decoder, file_name, flac_write_callback, NULL,
flac_error_callback, NULL);
+ if (r != 0)
+ {
+ *error_p = gsl_error_from_errno (errno, BSE_ERROR_FILE_OPEN_FAILED);
+ return;
+ }
+
+ /* decode enough to figure out channel count */
+ do {
+ FLAC__bool mdok = FLAC__stream_decoder_process_single (decoder);
+ } while (FLAC__stream_decoder_get_channels (decoder) == 0);
+
+ /* allocate and fill BseWaveFileInfo */
+ wfi.n_waves = 1;
+ wfi.waves = (typeof (wfi.waves)) g_malloc0 (sizeof (wfi.waves[0]) * wfi.n_waves);
+ wfi.waves[0].name = g_strdup (file_name);
+
+ /* allocate and fill BseWaveDsc */
+ wdsc.n_chunks = 1;
+ wdsc.chunks = (typeof (wdsc.chunks)) g_malloc0 (sizeof (wdsc.chunks[0]) * wdsc.n_chunks);
+ wdsc.name = g_strdup (file_name);
+ wdsc.n_channels = FLAC__stream_decoder_get_channels (decoder);
+
+ /* fill GslWaveChunk */
+ wdsc.chunks[0].mix_freq = FLAC__stream_decoder_get_sample_rate (decoder);
+ wdsc.chunks[0].osc_freq = 440.0;
+ }
+
+ ~FileInfo()
+ {
+ /* free BseWaveDsc */
+ for (guint i = 0; i < wdsc.n_chunks; i++)
+ g_strfreev (wdsc.chunks[i].xinfos);
+
+ g_strfreev (wdsc.xinfos);
+ g_free (wdsc.name);
+ g_free (wdsc.chunks);
+
+ /* free BseWaveFileInfo */
+ if (wfi.waves)
+ {
+ g_free (wfi.waves[0].name);
+ g_free (wfi.waves);
+ }
+ }
+};
+
+}
+
+static BseWaveFileInfo*
+flac_load_file_info (gpointer data,
+ const gchar *file_name,
+ BseErrorType *error_p)
+{
+ FileInfo *file_info = new FileInfo (file_name, error_p);
+ if (*error_p)
+ {
+ delete file_info;
+ return NULL;
+ }
+
+ return &file_info->wfi;
+}
+
+static void
+flac_free_file_info (gpointer data,
+ BseWaveFileInfo *wave_file_info)
+{
+ FileInfo *file_info = reinterpret_cast<FileInfo*> (wave_file_info);
+ delete file_info;
+}
+
+static BseWaveDsc*
+flac_load_wave_dsc (gpointer data,
+ BseWaveFileInfo *wave_file_info,
+ guint nth_wave,
+ BseErrorType *error_p)
+{
+ FileInfo *file_info = reinterpret_cast<FileInfo*> (wave_file_info);
+ return &file_info->wdsc;
+}
+
+static void
+flac_free_wave_dsc (gpointer data,
+ BseWaveDsc *wave_dsc)
+{
+}
+
+static GslDataHandle*
+flac_create_chunk_handle (gpointer data,
+ BseWaveDsc *wave_dsc,
+ guint nth_chunk,
+ BseErrorType *error_p)
+{
+ g_return_val_if_fail (nth_chunk == 0, NULL);
+
+ FileInfo *file_info = reinterpret_cast<FileInfo*> (wave_dsc->file_info);
+ const BseWaveChunkDsc *chunk = &wave_dsc->chunks[nth_chunk];
+
+ GslDataHandle *dhandle;
+ dhandle = bse_data_handle_new_flac (file_info->wfi.file_name,
+ chunk->osc_freq);
+ return dhandle;
+}
+
+extern "C" void
+bse_init_loader_flac (void)
+{
+ static const gchar *file_exts[] = { "flac", NULL, };
+ static const gchar *mime_types[] = { "audio/x-flac", NULL, };
+ static const gchar *magics[] = {
+ "0 string fLaC", // free lossless audio codec magic
+ NULL,
+ };
+ static BseLoader loader = {
+ "FLAC",
+ file_exts,
+ mime_types,
+ BSE_LOADER_NO_FLAGS,
+ magics,
+ 0, /* priority */
+ NULL,
+ flac_load_file_info,
+ flac_free_file_info,
+ flac_load_wave_dsc,
+ flac_free_wave_dsc,
+ flac_create_chunk_handle,
+ };
+ static gboolean initialized = FALSE;
+
+ g_assert (initialized == FALSE);
+ initialized = TRUE;
+
+ bse_loader_register (&loader);
+}
diff --git a/bse/gslcommon.cc b/bse/gslcommon.cc
index bc5f4ff..cab6e7e 100644
--- a/bse/gslcommon.cc
+++ b/bse/gslcommon.cc
@@ -408,4 +408,5 @@ gsl_init (void)
_gsl_init_loader_oggvorbis ();
_gsl_init_loader_mad ();
bse_init_loader_gus_patch ();
+ bse_init_loader_flac ();
}
diff --git a/bse/gslcommon.hh b/bse/gslcommon.hh
index 8a34ed4..8f21abb 100644
--- a/bse/gslcommon.hh
+++ b/bse/gslcommon.hh
@@ -56,6 +56,7 @@ void _gsl_init_loader_wav (void);
void _gsl_init_loader_oggvorbis (void);
void _gsl_init_loader_mad (void);
void bse_init_loader_gus_patch (void);
+void bse_init_loader_flac (void);
#define GSL_N_IO_RETRIES (5)
G_END_DECLS
diff --git a/bse/gsldatahandle.hh b/bse/gsldatahandle.hh
index a99e625..6d064a2 100644
--- a/bse/gsldatahandle.hh
+++ b/bse/gsldatahandle.hh
@@ -115,6 +115,10 @@ 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 --- */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]