[beast/wip/soundfont: 13/832] BSE: added sound font support for bse projects wrapping fluid synths structures.



commit a2138869b4ba39d6c67ed987c9823c7fbdc92ae4
Author: Stefan Westerfeld <stefan space twc de>
Date:   Mon Nov 8 23:07:48 2010 +0100

    BSE: added sound font support for bse projects wrapping fluid synths structures.

 bse/bsesoundfont.c        |  394 +++++++++++++++++++++++++++++++++++++++++++++
 bse/bsesoundfont.h        |   59 +++++++
 bse/bsesoundfontpreset.c  |  195 ++++++++++++++++++++++
 bse/bsesoundfontpreset.h  |   54 ++++++
 bse/bsesoundfontrepo.c    |  393 ++++++++++++++++++++++++++++++++++++++++++++
 bse/bsesoundfontrepo.h    |   94 +++++++++++
 bse/bsesoundfontrepo.proc |  155 ++++++++++++++++++
 7 files changed, 1344 insertions(+), 0 deletions(-)
---
diff --git a/bse/bsesoundfont.c b/bse/bsesoundfont.c
new file mode 100644
index 0000000..096d749
--- /dev/null
+++ b/bse/bsesoundfont.c
@@ -0,0 +1,394 @@
+/* BSE - Bedevilled Sound Engine
+ * Copyright (C) 1997-1999, 2000-2005 Tim Janik
+ * Copyright (C) 2009 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 "bsesoundfont.h"
+#include "bsesoundfontrepo.h"
+#include "bsesoundfontpreset.h"
+#include "bsemain.h"
+#include "bsestorage.h"
+#include "bseprocedure.h"
+#include "gsldatahandle.h"
+#include "bseserver.h"
+#include "bseloader.h"
+
+#include <string.h>
+
+#define parse_or_return         bse_storage_scanner_parse_or_return
+
+enum {
+  PARAM_0,
+  PARAM_FILE_NAME,
+};
+
+/* --- prototypes --- */
+
+
+/* --- variables --- */
+static GTypeClass *parent_class = NULL;
+static GQuark      quark_load_sound_font = 0;
+
+
+/* --- functions --- */
+static void
+bse_sound_font_init (BseSoundFont *sound_font)
+{
+  sound_font->blob = NULL;
+  sound_font->sfont_id = -1;
+  sound_font->sfrepo = NULL;
+}
+
+static void
+bse_sound_font_set_property (GObject      *object,
+                            guint         param_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+  switch (param_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+      break;
+    }
+}
+
+static void
+bse_sound_font_get_property (GObject    *object,
+                            guint       param_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  BseSoundFont *sound_font = BSE_SOUND_FONT (object);
+  switch (param_id)
+    {
+    case PARAM_FILE_NAME:
+      if (sound_font->blob)
+        sfi_value_set_string (value, bse_storage_blob_file_name (sound_font->blob));
+      else
+        sfi_value_set_string (value, NULL);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+      break;
+    }
+}
+
+static void
+bse_sound_font_dispose (GObject *object)
+{
+  BseSoundFont *sound_font = BSE_SOUND_FONT (object);
+  if (sound_font->sfont_id != -1)
+    bse_sound_font_unload (sound_font);
+  if (sound_font->sfrepo)
+    {
+      g_object_unref (sound_font->sfrepo);
+      sound_font->sfrepo = NULL;
+    }
+  /* chain parent class' handler */
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+bse_sound_font_finalize (GObject *object)
+{
+  BseSoundFont *sound_font = BSE_SOUND_FONT (object);
+
+  /* free blob */
+  if (sound_font->blob)
+    {
+      bse_storage_blob_unref (sound_font->blob);
+      sound_font->blob = NULL;
+    }
+
+  if (sound_font->sfrepo != NULL || sound_font->blob != NULL || sound_font->sfont_id != -1)
+    g_warning (G_STRLOC ": some resources could not be freed.");
+
+  /* chain parent class' handler */
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+BseErrorType
+bse_sound_font_load_blob (BseSoundFont    *self,
+                          BseStorageBlob  *blob,
+                         gboolean         init_presets)
+{
+  if (self->sfrepo == NULL)
+    {
+      self->sfrepo = BSE_SOUND_FONT_REPO (BSE_ITEM (self)->parent);
+      g_object_ref (self->sfrepo);
+    }
+
+  g_return_val_if_fail (blob != NULL, BSE_ERROR_INTERNAL);
+  g_return_val_if_fail (self->sfrepo != NULL, BSE_ERROR_INTERNAL);
+  g_return_val_if_fail (self->sfont_id == -1, BSE_ERROR_INTERNAL);
+
+  bse_storage_blob_ref (blob);
+  if (self->blob)
+    {
+      bse_storage_blob_unref (self->blob);
+      self->blob = NULL;
+    }
+
+  fluid_synth_t *fluid_synth = bse_sound_font_repo_lock_fluid_synth (self->sfrepo);
+  int sfont_id = fluid_synth_sfload (fluid_synth, bse_storage_blob_file_name (blob), 0);
+  BseErrorType error;
+  if (sfont_id != -1)
+    {
+      if (init_presets)
+       {
+         fluid_sfont_t *fluid_sfont = fluid_synth_get_sfont_by_id (fluid_synth, sfont_id);
+         fluid_preset_t fluid_preset;
+
+         fluid_sfont->iteration_start (fluid_sfont);
+         while (fluid_sfont->iteration_next (fluid_sfont, &fluid_preset))
+           {
+             BseSoundFontPreset *sound_font_preset = g_object_new (BSE_TYPE_SOUND_FONT_PRESET,
+                                                                   "uname", fluid_preset.get_name 
(&fluid_preset),
+                                                                   NULL);
+             bse_container_add_item (BSE_CONTAINER (self), BSE_ITEM (sound_font_preset));
+             bse_sound_font_preset_init_preset (sound_font_preset, &fluid_preset);
+           }
+       }
+      self->sfont_id = sfont_id;
+      self->blob = blob;
+      error = BSE_ERROR_NONE;
+    }
+  else
+    {
+      bse_storage_blob_unref (blob);
+      error = BSE_ERROR_WAVE_NOT_FOUND;
+    }
+  bse_sound_font_repo_unlock_fluid_synth (self->sfrepo);
+  return error;
+}
+
+void
+bse_sound_font_unload (BseSoundFont *sound_font)
+{
+  g_return_if_fail (sound_font->sfrepo != NULL);
+
+  if (sound_font->sfont_id != -1)
+    {
+      fluid_synth_t *fluid_synth = bse_sound_font_repo_lock_fluid_synth (sound_font->sfrepo);
+      fluid_synth_sfunload (fluid_synth, sound_font->sfont_id, 1 /* reset presets */);
+      bse_sound_font_repo_unlock_fluid_synth (sound_font->sfrepo);
+    }
+  sound_font->sfont_id = -1;
+}
+
+BseErrorType
+bse_sound_font_reload (BseSoundFont *sound_font)
+{
+  g_return_val_if_fail (sound_font->sfont_id == -1, BSE_ERROR_INTERNAL);
+
+  return bse_sound_font_load_blob (sound_font, sound_font->blob, FALSE);
+}
+
+static void
+bse_sound_font_store_private (BseObject  *object,
+                             BseStorage *storage)
+{
+  BseSoundFont *sound_font = BSE_SOUND_FONT (object);
+  /* chain parent class' handler */
+  BSE_OBJECT_CLASS (parent_class)->store_private (object, storage);
+
+  if (!BSE_STORAGE_SELF_CONTAINED (storage) && !bse_storage_blob_is_temp_file (sound_font->blob))
+    {
+      bse_storage_break (storage);
+      bse_storage_printf (storage, "(load-sound-font \"%s\")", bse_storage_blob_file_name 
(sound_font->blob));
+    }
+  else
+    {
+      bse_storage_break (storage);
+      bse_storage_printf (storage, "(load-sound-font ");
+      bse_storage_put_blob (storage, sound_font->blob);
+      bse_storage_printf (storage, ")");
+    }
+}
+
+static SfiTokenType
+bse_sound_font_restore_private (BseObject  *object,
+                               BseStorage *storage,
+                                GScanner   *scanner)
+{
+  BseSoundFont *sound_font = BSE_SOUND_FONT (object);
+  GTokenType expected_token;
+  GQuark quark;
+
+  /* chain parent class' handler */
+  if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
+    return BSE_OBJECT_CLASS (parent_class)->restore_private (object, storage, scanner);
+
+  /* parse storage commands */
+  quark = g_quark_try_string (scanner->next_value.v_identifier);
+  if (quark == quark_load_sound_font)
+    {
+      BseStorageBlob *blob;
+      BseErrorType error;
+
+      g_scanner_get_next_token (scanner); /* eat quark identifier */
+      if (g_scanner_peek_next_token (scanner) == G_TOKEN_STRING)
+       {
+         parse_or_return (scanner, G_TOKEN_STRING);
+         blob = bse_storage_blob_new_from_file (scanner->value.v_string, FALSE);
+       }
+      else
+       {
+          GTokenType token = bse_storage_parse_blob (storage, &blob);
+         if (token != G_TOKEN_NONE)
+           {
+             if (blob)
+               bse_storage_blob_unref (blob);
+              return token;
+           }
+       }
+      if (g_scanner_peek_next_token (scanner) != ')')
+       {
+         bse_storage_blob_unref (blob);
+         return ')';
+       }
+      parse_or_return (scanner, ')');
+      error = bse_sound_font_load_blob (sound_font, blob, FALSE);
+      if (error)
+       bse_storage_warn (storage, "failed to load sound font \"%s\": %s",
+                                   bse_storage_blob_file_name (blob), bse_error_blurb (error));
+      bse_storage_blob_unref (blob);
+      expected_token = G_TOKEN_NONE; /* got ')' */
+    }
+  else /* chain parent class' handler */
+    expected_token = BSE_OBJECT_CLASS (parent_class)->restore_private (object, storage, scanner);
+
+  return expected_token;
+}
+
+
+static void
+bse_sound_font_add_item (BseContainer *container,
+                        BseItem      *item)
+{
+  BseSoundFont *sound_font = BSE_SOUND_FONT (container);
+
+  if (g_type_is_a (BSE_OBJECT_TYPE (item), BSE_TYPE_SOUND_FONT_PRESET))
+    sound_font->presets = g_list_append (sound_font->presets, item);
+  else
+    g_warning ("BseSoundFont: cannot hold non-sound-font-preset item type `%s'",
+              BSE_OBJECT_TYPE_NAME (item));
+
+  /* chain parent class' add_item handler */
+  BSE_CONTAINER_CLASS (parent_class)->add_item (container, item);
+}
+
+static void
+bse_sound_font_forall_items (BseContainer      *container,
+                            BseForallItemsFunc func,
+                            gpointer           data)
+{
+  BseSoundFont *sound_font = BSE_SOUND_FONT (container);
+  GList *list;
+
+  list = sound_font->presets;
+  while (list)
+    {
+      BseItem *item;
+
+      item = list->data;
+      list = list->next;
+      if (!func (item, data))
+       return;
+    }
+}
+
+static void
+bse_sound_font_remove_item (BseContainer *container,
+                           BseItem      *item)
+{
+  BseSoundFont *sound_font = BSE_SOUND_FONT (container);
+
+  if (g_type_is_a (BSE_OBJECT_TYPE (item), BSE_TYPE_SOUND_FONT_PRESET))
+    sound_font->presets = g_list_remove (sound_font->presets, item);
+  else
+    g_warning ("BseSoundFontRepo: cannot hold non-sound-font-preset item type `%s'",
+              BSE_OBJECT_TYPE_NAME (item));
+
+  /* chain parent class' remove_item handler */
+  BSE_CONTAINER_CLASS (parent_class)->remove_item (container, item);
+}
+
+static void
+bse_sound_font_release_children (BseContainer *container)
+{
+  BseSoundFont *self = BSE_SOUND_FONT (container);
+
+  while (self->presets)
+    bse_container_remove_item (container, self->presets->data);
+
+  /* chain parent class' handler */
+  BSE_CONTAINER_CLASS (parent_class)->release_children (container);
+}
+
+
+static void
+bse_sound_font_class_init (BseSoundFontClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+  BseObjectClass *object_class = BSE_OBJECT_CLASS (class);
+  BseContainerClass *container_class = BSE_CONTAINER_CLASS (class);
+
+  parent_class = g_type_class_peek_parent (class);
+
+  gobject_class->set_property = bse_sound_font_set_property;
+  gobject_class->get_property = bse_sound_font_get_property;
+  gobject_class->dispose = bse_sound_font_dispose;
+  gobject_class->finalize = bse_sound_font_finalize;
+
+  container_class->add_item = bse_sound_font_add_item;
+  container_class->remove_item = bse_sound_font_remove_item;
+  container_class->forall_items = bse_sound_font_forall_items;
+  container_class->release_children = bse_sound_font_release_children;
+
+  object_class->store_private = bse_sound_font_store_private;
+  object_class->restore_private = bse_sound_font_restore_private;
+
+  quark_load_sound_font = g_quark_from_static_string ("load-sound-font");
+
+  bse_object_class_add_param (object_class, "Locator",
+                             PARAM_FILE_NAME,
+                             sfi_pspec_string ("file_name", "File Name", NULL,
+                                               NULL, "G:r"));
+}
+
+BSE_BUILTIN_TYPE (BseSoundFont)
+{
+  static const GTypeInfo sound_font_info = {
+    sizeof (BseSoundFontClass),
+
+    (GBaseInitFunc) NULL,
+    (GBaseFinalizeFunc) NULL,
+    (GClassInitFunc) bse_sound_font_class_init,
+    (GClassFinalizeFunc) NULL,
+    NULL /* class_data */,
+
+    sizeof (BseSoundFont),
+    0  /* n_preallocs */,
+    (GInstanceInitFunc) bse_sound_font_init,
+  };
+
+  return bse_type_register_static (BSE_TYPE_CONTAINER,
+                                  "BseSoundFont",
+                                  "BSE sound_font type",
+                                   __FILE__, __LINE__,
+                                   &sound_font_info);
+}
diff --git a/bse/bsesoundfont.h b/bse/bsesoundfont.h
new file mode 100644
index 0000000..6705f8e
--- /dev/null
+++ b/bse/bsesoundfont.h
@@ -0,0 +1,59 @@
+/* BSE - Bedevilled Sound Engine
+ * Copyright (C) 1997-1999, 2000-2005 Tim Janik
+ * Copyright (C) 2009 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/.
+ */
+#ifndef __BSE_SOUND_FONT_H__
+#define __BSE_SOUND_FONT_H__
+
+#include       <bse/bsecontainer.h>
+#include        <bse/bsestorage.h>
+
+G_BEGIN_DECLS
+
+/* --- BSE type macros --- */
+#define BSE_TYPE_SOUND_FONT              (BSE_TYPE_ID (BseSoundFont))
+#define BSE_SOUND_FONT(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), BSE_TYPE_SOUND_FONT, 
BseSoundFont))
+#define BSE_SOUND_FONT_CLASS(class)      (G_TYPE_CHECK_CLASS_CAST ((class), BSE_TYPE_SOUND_FONT, 
BseSoundFontClass))
+#define BSE_IS_SOUND_FONT(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), BSE_TYPE_SOUND_FONT))
+#define BSE_IS_SOUND_FONT_CLASS(class)   (G_TYPE_CHECK_CLASS_TYPE ((class), BSE_TYPE_SOUND_FONT))
+#define BSE_SOUND_FONT_GET_CLASS(object)  (G_TYPE_INSTANCE_GET_CLASS ((object), BSE_TYPE_SOUND_FONT, 
BseSoundFontClass))
+
+
+/* --- BseSoundFont --- */
+struct _BseSoundFont
+{
+  BseContainer      parent_object;
+  BseStorageBlob    *blob;
+  int                sfont_id;
+  BseSoundFontRepo  *sfrepo;
+  GList             *presets;
+};
+struct _BseSoundFontClass
+{
+  BseContainerClass  parent_class;
+};
+
+
+/* --- prototypes -- */
+BseErrorType    bse_sound_font_load_blob       (BseSoundFont       *sound_font,
+                                                BseStorageBlob     *blob,
+                                                gboolean            init_presets);
+void           bse_sound_font_unload           (BseSoundFont       *sound_font);
+BseErrorType    bse_sound_font_reload           (BseSoundFont       *sound_font);
+
+G_END_DECLS
+
+#endif /* __BSE_SOUND_FONT_H__ */
diff --git a/bse/bsesoundfontpreset.c b/bse/bsesoundfontpreset.c
new file mode 100644
index 0000000..9de08b3
--- /dev/null
+++ b/bse/bsesoundfontpreset.c
@@ -0,0 +1,195 @@
+/* BSE - Bedevilled Sound Engine
+ * Copyright (C) 1997-1999, 2000-2005 Tim Janik
+ * Copyright (C) 2009 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 "bsesoundfontpreset.h"
+#include "bsemain.h"
+#include "bsestorage.h"
+#include "bseprocedure.h"
+#include "gsldatahandle.h"
+#include "bseserver.h"
+#include "bseloader.h"
+
+#include <string.h>
+#include <fluidsynth.h>
+
+#define parse_or_return         bse_storage_scanner_parse_or_return
+
+/* --- variables --- */
+static GTypeClass *parent_class = NULL;
+static GQuark      quark_program = 0;
+static GQuark      quark_bank = 0;
+
+
+/* --- functions --- */
+static void
+bse_sound_font_preset_init (BseSoundFontPreset *sound_font_preset)
+{
+  // init members here
+}
+
+void
+bse_sound_font_preset_init_preset (BseSoundFontPreset *self,
+                                   fluid_preset_t     *fluid_preset)
+{
+  self->bank = fluid_preset->get_banknum (fluid_preset);
+  self->program = fluid_preset->get_num (fluid_preset);
+}
+
+static void
+bse_sound_font_preset_store_private (BseObject  *object,
+                                    BseStorage *storage)
+{
+  BseSoundFontPreset *self = BSE_SOUND_FONT_PRESET (object);
+  /* chain parent class' handler */
+  BSE_OBJECT_CLASS (parent_class)->store_private (object, storage);
+
+  bse_storage_break (storage);
+  bse_storage_printf (storage, "(bank %d)", self->bank);
+  bse_storage_break (storage);
+  bse_storage_printf (storage, "(program %d)", self->program);
+}
+
+static SfiTokenType
+bse_sound_font_preset_restore_private (BseObject  *object,
+                                      BseStorage *storage,
+                                       GScanner   *scanner)
+{
+  BseSoundFontPreset *sound_font_preset = BSE_SOUND_FONT_PRESET (object);
+  GTokenType expected_token;
+  GQuark quark;
+
+  /* chain parent class' handler */
+  if (g_scanner_peek_next_token (scanner) != G_TOKEN_IDENTIFIER)
+    return BSE_OBJECT_CLASS (parent_class)->restore_private (object, storage, scanner);
+
+  /* parse storage commands */
+  quark = g_quark_try_string (scanner->next_value.v_identifier);
+  if (quark == quark_program)
+    {
+      g_scanner_get_next_token (scanner); /* eat quark identifier */
+      parse_or_return (scanner, G_TOKEN_INT);
+      sound_font_preset->program = scanner->value.v_int;
+      parse_or_return (scanner, ')');
+      expected_token = G_TOKEN_NONE; /* got ')' */
+    }
+  else if (quark == quark_bank)
+    {
+      g_scanner_get_next_token (scanner); /* eat quark identifier */
+      parse_or_return (scanner, G_TOKEN_INT);
+      sound_font_preset->bank = scanner->value.v_int;
+      parse_or_return (scanner, ')');
+      expected_token = G_TOKEN_NONE; /* got ')' */
+    }
+  else /* chain parent class' handler */
+    expected_token = BSE_OBJECT_CLASS (parent_class)->restore_private (object, storage, scanner);
+
+  return expected_token;
+}
+
+
+
+static void
+bse_sound_font_preset_set_property (GObject      *object,
+                                   guint         param_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  switch (param_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+      break;
+    }
+}
+
+static void
+bse_sound_font_preset_get_property (GObject    *object,
+                                   guint       param_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  // BseSoundFontPreset *sound_font_preset = BSE_SOUND_FONT_PRESET (object);
+  switch (param_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+      break;
+    }
+}
+
+static void
+bse_sound_font_preset_dispose (GObject *object)
+{
+  // BseSoundFontPreset *sound_font_preset = BSE_SOUND_FONT_PRESET (object);
+  // bse_sound_font_preset_clear (sound_font_preset);
+
+  /* chain parent class' handler */
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+bse_sound_font_preset_finalize (GObject *object)
+{
+  // BseSoundFontPreset *sound_font_preset = BSE_SOUND_FONT_PRESET (object);
+  // bse_sound_font_preset_clear (sound_font_preset);
+
+  /* chain parent class' handler */
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+bse_sound_font_preset_class_init (BseSoundFontPresetClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+  BseObjectClass *object_class = BSE_OBJECT_CLASS (class);
+
+  parent_class = g_type_class_peek_parent (class);
+
+  gobject_class->set_property = bse_sound_font_preset_set_property;
+  gobject_class->get_property = bse_sound_font_preset_get_property;
+  gobject_class->dispose = bse_sound_font_preset_dispose;
+  gobject_class->finalize = bse_sound_font_preset_finalize;
+
+  object_class->store_private = bse_sound_font_preset_store_private;
+  object_class->restore_private = bse_sound_font_preset_restore_private;
+
+  quark_program = g_quark_from_static_string ("program");
+  quark_bank = g_quark_from_static_string ("bank");
+}
+
+BSE_BUILTIN_TYPE (BseSoundFontPreset)
+{
+  static const GTypeInfo sound_font_preset_info = {
+    sizeof (BseSoundFontPresetClass),
+
+    (GBaseInitFunc) NULL,
+    (GBaseFinalizeFunc) NULL,
+    (GClassInitFunc) bse_sound_font_preset_class_init,
+    (GClassFinalizeFunc) NULL,
+    NULL /* class_data */,
+
+    sizeof (BseSoundFontPreset),
+    0  /* n_preallocs */,
+    (GInstanceInitFunc) bse_sound_font_preset_init,
+  };
+
+  return bse_type_register_static (BSE_TYPE_ITEM,
+                                  "BseSoundFontPreset",
+                                  "BSE sound_font_preset type",
+                                   __FILE__, __LINE__,
+                                   &sound_font_preset_info);
+}
diff --git a/bse/bsesoundfontpreset.h b/bse/bsesoundfontpreset.h
new file mode 100644
index 0000000..a90b931
--- /dev/null
+++ b/bse/bsesoundfontpreset.h
@@ -0,0 +1,54 @@
+/* BSE - Bedevilled Sound Engine
+ * Copyright (C) 1997-1999, 2000-2005 Tim Janik
+ * Copyright (C) 2009 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/.
+ */
+#ifndef __BSE_SOUND_FONT_PRESET_H__
+#define __BSE_SOUND_FONT_PRESET_H__
+
+#include       <bse/bseitem.h>
+#include        <fluidsynth.h>
+
+G_BEGIN_DECLS
+
+/* --- BSE type macros --- */
+#define BSE_TYPE_SOUND_FONT_PRESET             (BSE_TYPE_ID (BseSoundFontPreset))
+#define BSE_SOUND_FONT_PRESET(object)          (G_TYPE_CHECK_INSTANCE_CAST ((object), 
BSE_TYPE_SOUND_FONT_PRESET, BseSoundFontPreset))
+#define BSE_SOUND_FONT_PRESET_CLASS(class)     (G_TYPE_CHECK_CLASS_CAST ((class), 
BSE_TYPE_SOUND_FONT_PRESET, BseSoundFontPresetClass))
+#define BSE_IS_SOUND_FONT_PRESET(object)       (G_TYPE_CHECK_INSTANCE_TYPE ((object), 
BSE_TYPE_SOUND_FONT_PRESET))
+#define BSE_IS_SOUND_FONT_PRESET_CLASS(class)  (G_TYPE_CHECK_CLASS_TYPE ((class), 
BSE_TYPE_SOUND_FONT_PRESET))
+#define BSE_SOUND_FONT_PRESET_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), 
BSE_TYPE_SOUND_FONT_PRESET, BseSoundFontPresetClass))
+
+
+/* --- BseSoundFontPreset --- */
+struct _BseSoundFontPreset
+{
+  BseItem      parent_object;
+  int           program;
+  int           bank;
+};
+struct _BseSoundFontPresetClass
+{
+  BseItemClass  parent_class;
+};
+
+
+/* --- prototypes -- */
+void   bse_sound_font_preset_init_preset (BseSoundFontPreset *self,
+                                         fluid_preset_t     *fluid_preset);
+
+G_END_DECLS
+
+#endif /* __BSE_SOUND_FONT_PRESET_H__ */
diff --git a/bse/bsesoundfontrepo.c b/bse/bsesoundfontrepo.c
new file mode 100644
index 0000000..00c321b
--- /dev/null
+++ b/bse/bsesoundfontrepo.c
@@ -0,0 +1,393 @@
+/* BSE - Bedevilled Sound Engine
+ * Copyright (C) 1996-1999, 2000-2003 Tim Janik
+ * Copyright (C) 2009 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        "bsesoundfontrepo.h"
+#include        "bsesoundfont.h"
+#include        "bsesoundfontpreset.h"
+#include        "bsedefs.h"
+#include        "bseblockutils.hh"
+
+
+/* --- parameters --- */
+enum
+{
+  PARAM_0,
+};
+
+
+/* --- prototypes --- */
+static void    bse_sound_font_repo_class_init          (BseSoundFontRepoClass  *class);
+static void    bse_sound_font_repo_init                (BseSoundFontRepo       *wrepo);
+static void    bse_sound_font_repo_dispose             (GObject                *object);
+static void     bse_sound_font_repo_release_children    (BseContainer          *container);
+static void    bse_sound_font_repo_set_property        (GObject                *object,
+                                                        guint                   param_id,
+                                                        const GValue           *value,
+                                                        GParamSpec             *pspec);
+static void    bse_sound_font_repo_get_property (GObject               *object,
+                                                 guint                  param_id,
+                                                 GValue                *value,
+                                                 GParamSpec            *pspec);
+static void     bse_sound_font_repo_add_item     (BseContainer         *container,
+                                                 BseItem               *item);
+static void     bse_sound_font_repo_forall_items (BseContainer         *container,
+                                                 BseForallItemsFunc     func,
+                                                 gpointer               data);
+static void     bse_sound_font_repo_remove_item         (BseContainer          *container,
+                                                 BseItem               *item);
+static void     bse_sound_font_repo_prepare      (BseSource             *source);
+
+
+/* --- variables --- */
+static GTypeClass     *parent_class = NULL;
+
+
+/* --- functions --- */
+BSE_BUILTIN_TYPE (BseSoundFontRepo)
+{
+  GType sound_font_repo_type;
+
+  static const GTypeInfo sfrepo_info = {
+    sizeof (BseSoundFontRepoClass),
+
+    (GBaseInitFunc) NULL,
+    (GBaseFinalizeFunc) NULL,
+    (GClassInitFunc) bse_sound_font_repo_class_init,
+    (GClassFinalizeFunc) NULL,
+    NULL /* class_data */,
+
+    sizeof (BseSoundFontRepo),
+    0,
+    (GInstanceInitFunc) bse_sound_font_repo_init,
+  };
+
+  sound_font_repo_type = bse_type_register_static (BSE_TYPE_SUPER,
+                                                  "BseSoundFontRepo",
+                                                  "BSE Sound Font Repository",
+                                                   __FILE__, __LINE__,
+                                                   &sfrepo_info);
+  return sound_font_repo_type;
+}
+
+static void
+bse_sound_font_repo_class_init (BseSoundFontRepoClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+  BseContainerClass *container_class = BSE_CONTAINER_CLASS (class);
+  BseSourceClass *source_class = BSE_SOURCE_CLASS (class);
+
+  parent_class = g_type_class_peek_parent (class);
+
+  gobject_class->set_property = bse_sound_font_repo_set_property;
+  gobject_class->get_property = bse_sound_font_repo_get_property;
+  gobject_class->dispose = bse_sound_font_repo_dispose;
+
+  container_class->add_item = bse_sound_font_repo_add_item;
+  container_class->remove_item = bse_sound_font_repo_remove_item;
+  container_class->forall_items = bse_sound_font_repo_forall_items;
+  container_class->release_children = bse_sound_font_repo_release_children;
+
+  source_class->prepare = bse_sound_font_repo_prepare;
+}
+
+static void
+bse_sound_font_repo_init (BseSoundFontRepo *sfrepo)
+{
+  sfi_mutex_init (&sfrepo->fluid_synth_mutex);
+
+  sfrepo->n_oscs = 0;
+  sfrepo->oscs = NULL;
+  sfrepo->channel_map = NULL;
+
+  sfrepo->fluid_settings = new_fluid_settings();
+  sfrepo->fluid_synth = new_fluid_synth (sfrepo->fluid_settings);
+  sfrepo->fluid_events = NULL;
+  sfrepo->sound_fonts = NULL;
+  sfrepo->fluid_mix_freq = 0;
+
+  sfrepo->n_fluid_channels = 0;
+  sfrepo->channel_values_left = NULL;
+  sfrepo->channel_values_right = NULL;
+  sfrepo->n_silence_samples = NULL;
+
+  sfrepo->n_channel_oscs_active = 0;
+  sfrepo->channel_values_tick_stamp = 0;
+}
+
+static gboolean
+reload_sound_font (BseItem *item,
+                   gpointer data)
+{
+  BseSoundFont *sound_font = BSE_SOUND_FONT (item);
+  bse_sound_font_reload (sound_font);
+  return TRUE;
+}
+
+static gboolean
+unload_sound_font (BseItem *item,
+                   gpointer data)
+{
+  BseSoundFont *sound_font = BSE_SOUND_FONT (item);
+  bse_sound_font_unload (sound_font);
+  return TRUE;
+}
+
+static void
+bse_sound_font_repo_prepare (BseSource *source)
+{
+  BseSoundFontRepo *sfrepo = BSE_SOUND_FONT_REPO (source);
+  int i, channels_required = 0;
+  for (i = 0; i < sfrepo->n_oscs; i++)
+    {
+      if (sfrepo->oscs[i])
+       sfrepo->channel_map[i] = channels_required++;
+    }
+  int mix_freq = bse_engine_sample_freq();
+  if (sfrepo->n_fluid_channels != channels_required || sfrepo->fluid_mix_freq != mix_freq)
+    {
+      for (i = channels_required; i < sfrepo->n_fluid_channels; i++) // n_fluid_channels > channels_required
+       {
+         g_free (sfrepo->channel_values_left[i]);
+         g_free (sfrepo->channel_values_right[i]);
+       }
+      sfrepo->channel_values_left = (float **)g_realloc (sfrepo->channel_values_left, sizeof (float *) * 
channels_required);
+      sfrepo->channel_values_right = (float **)g_realloc (sfrepo->channel_values_right, sizeof (float *) * 
channels_required);
+      sfrepo->n_silence_samples = (gint *) g_realloc (sfrepo->n_silence_samples, sizeof (gint) * 
channels_required);
+      for (i = sfrepo->n_fluid_channels; i < channels_required; i++) // n_fluid_channels < channels_required
+       {
+         sfrepo->channel_values_left[i] = g_new0 (float, BSE_STREAM_MAX_VALUES);
+         sfrepo->channel_values_right[i] = g_new0 (float, BSE_STREAM_MAX_VALUES);
+         sfrepo->n_silence_samples[i] = 0;
+       }
+      sfrepo->n_fluid_channels = channels_required;
+      sfrepo->fluid_mix_freq = mix_freq;
+
+      fluid_settings_setnum (sfrepo->fluid_settings, "synth.sample-rate", mix_freq);
+      fluid_settings_setint (sfrepo->fluid_settings, "synth.midi-channels", channels_required);
+      fluid_settings_setint (sfrepo->fluid_settings, "synth.audio-channels", channels_required);
+      fluid_settings_setint (sfrepo->fluid_settings, "synth.audio-groups", channels_required);
+      fluid_settings_setstr (sfrepo->fluid_settings, "synth.reverb.active", "no");
+      fluid_settings_setstr (sfrepo->fluid_settings, "synth.chorus.active", "no");
+
+      bse_sound_font_repo_forall_items (BSE_CONTAINER (sfrepo), unload_sound_font, sfrepo);
+      if (sfrepo->fluid_synth)
+       delete_fluid_synth (sfrepo->fluid_synth);
+
+      sfrepo->fluid_synth = new_fluid_synth (sfrepo->fluid_settings);
+      bse_sound_font_repo_forall_items (BSE_CONTAINER (sfrepo), reload_sound_font, sfrepo);
+    }
+
+  /* chain parent class' handler */
+  BSE_SOURCE_CLASS (parent_class)->prepare (source);
+}
+
+static void
+bse_sound_font_repo_release_children (BseContainer *container)
+{
+  BseSoundFontRepo *sfrepo = BSE_SOUND_FONT_REPO (container);
+
+  while (sfrepo->sound_fonts)
+    bse_container_remove_item (container, sfrepo->sound_fonts->data);
+
+  /* chain parent class' handler */
+  BSE_CONTAINER_CLASS (parent_class)->release_children (container);
+}
+
+static void
+bse_sound_font_repo_dispose (GObject *object)
+{
+  BseSoundFontRepo *sfrepo = BSE_SOUND_FONT_REPO (object);
+  int i;
+
+  bse_sound_font_repo_forall_items (BSE_CONTAINER (sfrepo), unload_sound_font, sfrepo);
+
+  if (sfrepo->fluid_synth)
+    {
+      delete_fluid_synth (sfrepo->fluid_synth);
+      sfrepo->fluid_synth = NULL;
+    }
+  if (sfrepo->fluid_settings)
+    {
+      delete_fluid_settings (sfrepo->fluid_settings);
+      sfrepo->fluid_settings = NULL;
+    }
+  g_free (sfrepo->channel_map);
+  sfrepo->channel_map = NULL;
+  g_free (sfrepo->oscs);
+  sfrepo->oscs = NULL;
+  for (i = 0; i < sfrepo->n_fluid_channels; i++)
+    {
+      g_free (sfrepo->channel_values_left[i]);
+      g_free (sfrepo->channel_values_right[i]);
+    }
+  sfrepo->n_fluid_channels = 0;
+  g_free (sfrepo->channel_values_left);
+  sfrepo->channel_values_left = NULL;
+  g_free (sfrepo->channel_values_right);
+  sfrepo->channel_values_right = NULL;
+  g_free (sfrepo->n_silence_samples);
+  sfrepo->n_silence_samples = NULL;
+
+  if (sfrepo->fluid_events != NULL)
+    g_warning (G_STRLOC ": fluid event queue should be empty in dispose");
+
+  /* chain parent class' handler */
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+bse_sound_font_repo_set_property (GObject      *object,
+                                 guint         param_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+  BseSoundFontRepo *sfrepo = BSE_SOUND_FONT_REPO (object);
+  switch (param_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (sfrepo, param_id, pspec);
+      break;
+    }
+}
+
+static void
+bse_sound_font_repo_get_property (GObject      *object,
+                                 guint         param_id,
+                                 GValue       *value,
+                                 GParamSpec   *pspec)
+{
+  BseSoundFontRepo *sfrepo = BSE_SOUND_FONT_REPO (object);
+  switch (param_id)
+    {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (sfrepo, param_id, pspec);
+      break;
+    }
+}
+
+static void
+bse_sound_font_repo_add_item (BseContainer *container,
+                             BseItem      *item)
+{
+  BseSoundFontRepo *sfrepo = BSE_SOUND_FONT_REPO (container);
+
+  if (g_type_is_a (BSE_OBJECT_TYPE (item), BSE_TYPE_SOUND_FONT))
+    sfrepo->sound_fonts = g_list_append (sfrepo->sound_fonts, item);
+  else
+    g_warning ("BseSoundFontRepo: cannot hold non-sound-font item type `%s'",
+              BSE_OBJECT_TYPE_NAME (item));
+
+  /* chain parent class' add_item handler */
+  BSE_CONTAINER_CLASS (parent_class)->add_item (container, item);
+}
+
+static void
+bse_sound_font_repo_forall_items (BseContainer      *container,
+                                 BseForallItemsFunc func,
+                                 gpointer           data)
+{
+  BseSoundFontRepo *sfrepo = BSE_SOUND_FONT_REPO (container);
+  GList *list;
+
+  list = sfrepo->sound_fonts;
+  while (list)
+    {
+      BseItem *item;
+
+      item = list->data;
+      list = list->next;
+      if (!func (item, data))
+       return;
+    }
+}
+
+static void
+bse_sound_font_repo_remove_item (BseContainer *container,
+                                BseItem      *item)
+{
+  BseSoundFontRepo *sfrepo = BSE_SOUND_FONT_REPO (container);
+
+  if (g_type_is_a (BSE_OBJECT_TYPE (item), BSE_TYPE_SOUND_FONT))
+    sfrepo->sound_fonts = g_list_remove (sfrepo->sound_fonts, item);
+  else
+    g_warning ("BseSoundFontRepo: cannot hold non-sound-font item type `%s'",
+              BSE_OBJECT_TYPE_NAME (item));
+
+  /* chain parent class' remove_item handler */
+  BSE_CONTAINER_CLASS (parent_class)->remove_item (container, item);
+}
+
+static gboolean
+gather_presets (BseItem  *item,
+                gpointer  items)
+{
+  if (BSE_IS_SOUND_FONT (item) || BSE_IS_SOUND_FONT_REPO (item))
+    bse_container_forall_items (BSE_CONTAINER (item), gather_presets, items);
+  else if (BSE_IS_SOUND_FONT_PRESET (item))
+    bse_item_seq_append (items, item);
+  else
+    g_warning ("Searching for sound font presets, an unexpected `%s' item was found", BSE_OBJECT_TYPE_NAME 
(item));
+  return TRUE;
+}
+
+void
+bse_sound_font_repo_list_all_presets (BseSoundFontRepo *sfrepo,
+                                      BseItemSeq       *items)
+{
+  gather_presets (BSE_ITEM (sfrepo), items);
+}
+
+fluid_synth_t *
+bse_sound_font_repo_lock_fluid_synth (BseSoundFontRepo *sfrepo)
+{
+  sfi_mutex_lock (&sfrepo->fluid_synth_mutex);
+  return sfrepo->fluid_synth;
+}
+
+void
+bse_sound_font_repo_unlock_fluid_synth (BseSoundFontRepo *sfrepo)
+{
+  sfi_mutex_unlock (&sfrepo->fluid_synth_mutex);
+}
+
+int
+bse_sound_font_repo_add_osc (BseSoundFontRepo *sfrepo,
+                             BseSoundFontOsc  *osc)
+{
+  int i;
+  for (i = 0; i < sfrepo->n_oscs; i++)
+    {
+      if (sfrepo->oscs[i] == 0)
+       {
+         sfrepo->oscs[i] = osc;
+         return i;
+       }
+    }
+  sfrepo->oscs = (BseSoundFontOsc **)g_realloc (sfrepo->oscs, sizeof (BseSoundFontOsc *) * (i + 1));
+  sfrepo->oscs[i] = osc;
+  sfrepo->channel_map = g_realloc (sfrepo->channel_map, sizeof (guint) * (i + 1));
+  return sfrepo->n_oscs++;
+}
+
+void
+bse_sound_font_repo_remove_osc (BseSoundFontRepo *sfrepo,
+                                int               osc_id)
+{
+  g_return_if_fail (osc_id >= 0 && osc_id < sfrepo->n_oscs);
+
+  sfrepo->oscs[osc_id] = 0;
+}
diff --git a/bse/bsesoundfontrepo.h b/bse/bsesoundfontrepo.h
new file mode 100644
index 0000000..312d624
--- /dev/null
+++ b/bse/bsesoundfontrepo.h
@@ -0,0 +1,94 @@
+/* BSE - Bedevilled Sound Engine
+ * Copyright (C) 1996-1999, 2000-2003 Tim Janik
+ * Copyright (C) 2009 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/.
+ */
+#ifndef        __BSE_SOUND_FONT_REPO_H__
+#define        __BSE_SOUND_FONT_REPO_H__
+
+#include       <bse/bsesuper.h>
+#include        <fluidsynth.h>
+#include        <bse/bsesoundfontosc.h>
+#include        <bse/bseengine.h>
+
+
+G_BEGIN_DECLS
+
+
+/* --- object type macros --- */
+#define BSE_TYPE_SOUND_FONT_REPO               (BSE_TYPE_ID (BseSoundFontRepo))
+#define BSE_SOUND_FONT_REPO(object)            (G_TYPE_CHECK_INSTANCE_CAST ((object), 
BSE_TYPE_SOUND_FONT_REPO, BseSoundFontRepo))
+#define BSE_SOUND_FONT_REPO_CLASS(class)       (G_TYPE_CHECK_CLASS_CAST ((class), BSE_TYPE_SOUND_FONT_REPO, 
BseSoundFontRepoClass))
+#define BSE_IS_SOUND_FONT_REPO(object)         (G_TYPE_CHECK_INSTANCE_TYPE ((object), 
BSE_TYPE_SOUND_FONT_REPO))
+#define BSE_IS_SOUND_FONT_REPO_CLASS(class)    (G_TYPE_CHECK_CLASS_TYPE ((class), BSE_TYPE_SOUND_FONT_REPO))
+#define BSE_SOUND_FONT_REPO_GET_CLASS(object)  (G_TYPE_INSTANCE_GET_CLASS ((object), 
BSE_TYPE_SOUND_FONT_REPO, BseSoundFontRepoClass))
+
+
+/* --- BseSoundFontRepo object --- */
+#define BSE_FLUID_SYNTH_PROGRAM_SELECT -1
+typedef struct _BseFluidEvent BseFluidEvent;
+struct _BseFluidEvent
+{
+  guint64            tick_stamp;
+  int                channel;
+  int               command;
+  int               arg1;
+  int               arg2;
+  int                sfont_id;   /* required for program selection only */
+};
+struct _BseSoundFontRepo
+{
+  BseSuper          parent_object;
+
+  BirnetMutex       fluid_synth_mutex;
+  fluid_settings_t  *fluid_settings;
+  fluid_synth_t     *fluid_synth;
+  SfiRing           *fluid_events;
+  guint              fluid_mix_freq;
+
+  guint              n_fluid_channels;
+  float                   **channel_values_left;     /* [0..n_fluid_channels-1] */
+  float                   **channel_values_right;    /* [0..n_fluid_channels-1] */
+  guint64           channel_values_tick_stamp;
+  gint              *n_silence_samples;       /* [0..n_fluid_channels-1] */
+
+  guint              n_oscs;
+  BseSoundFontOsc  **oscs;                   /* [0..n_oscs-1] */
+  guint                    *channel_map;             /* [0..n_oscs-1] */
+
+  int               n_channel_oscs_active;       /* SoundFontOscs with an active module in the engine thread 
*/
+
+  GList             *sound_fonts;
+};
+
+struct _BseSoundFontRepoClass
+{
+  BseSuperClass  parent_class;
+};
+
+
+/* --- prototypes --- */
+void          bse_sound_font_repo_list_all_presets   (BseSoundFontRepo *sfrepo,
+                                                      BseItemSeq       *items);
+fluid_synth_t *bse_sound_font_repo_lock_fluid_synth   (BseSoundFontRepo *sfrepo);
+void           bse_sound_font_repo_unlock_fluid_synth (BseSoundFontRepo *sfrepo);
+int           bse_sound_font_repo_add_osc            (BseSoundFontRepo *sfrepo,
+                                                      BseSoundFontOsc  *osc);
+void           bse_sound_font_repo_remove_osc         (BseSoundFontRepo *sfrepo,
+                                                      int               osc_id);
+
+G_END_DECLS
+
+#endif /* __BSE_SOUND_FONT_REPO_H__ */
diff --git a/bse/bsesoundfontrepo.proc b/bse/bsesoundfontrepo.proc
new file mode 100644
index 0000000..8281837
--- /dev/null
+++ b/bse/bsesoundfontrepo.proc
@@ -0,0 +1,155 @@
+/* BSE - Bedevilled Sound Engine       -*-mode: c;-*-
+ * Copyright (C) 2000-2003 Tim Janik
+ *
+ * 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 <bse/bseplugin.h>
+#include <bse/bseprocedure.h>
+#include <bse/bsesoundfontrepo.h>
+#include <bse/bsesoundfont.h>
+#include <bse/bseloader.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+
+/* --- auxlillary functions --- */
+static BseErrorType
+load_file (BseSoundFontRepo *sfrepo,
+          const gchar      *file_name,
+           BseSoundFont    **sound_font_p)
+{
+  gchar *fname = g_path_get_basename (file_name);
+  BseSoundFont *sound_font = g_object_new (BSE_TYPE_SOUND_FONT, "uname", fname, NULL);
+  g_free (fname);
+  bse_container_add_item (BSE_CONTAINER (sfrepo), BSE_ITEM (sound_font));
+
+  BseStorageBlob *blob = bse_storage_blob_new_from_file (file_name, FALSE);
+  BseErrorType error = bse_sound_font_load_blob (sound_font, blob, TRUE);
+  bse_storage_blob_unref (blob);
+  if (error == BSE_ERROR_NONE)
+    {
+      *sound_font_p = sound_font;
+    }
+  else
+    {
+      bse_container_remove_item (BSE_CONTAINER (sfrepo), BSE_ITEM (sound_font));
+      *sound_font_p = NULL;
+    }
+  g_object_unref (sound_font);
+  return error;
+}
+
+/* --- procedures --- */
+AUTHORS        = "Tim Janik <timj gtk org>";
+LICENSE = "GNU Lesser General Public License";
+
+
+METHOD (BseSoundFontRepo, load-file) {
+  HELP = "Load sound font from file";
+  IN    = bse_param_spec_object ("sound_font_repo", "Sound Font Repo", NULL,
+                                BSE_TYPE_SOUND_FONT_REPO, SFI_PARAM_STANDARD);
+  IN   = sfi_pspec_string ("file_name", "File Name", "The file to import sound fonts from",
+                           NULL, SFI_PARAM_STANDARD);
+  OUT   = bse_param_spec_genum ("error", "Error", NULL,
+                               BSE_TYPE_ERROR_TYPE, BSE_ERROR_NONE,
+                               SFI_PARAM_STANDARD);
+}
+BODY (BseProcedureClass *proc,
+      const GValue      *in_values,
+      GValue            *out_values)
+{
+  /* extract parameter values */
+  BseSoundFontRepo *self    = (BseSoundFontRepo*) bse_value_get_object (in_values++);
+  gchar *file_name          = sfi_value_get_string (in_values++);
+  BseUndoStack *ustack;
+  BseErrorType error;
+  BseSoundFont *sound_font;
+
+  /* check parameters */
+  if (!BSE_IS_SOUND_FONT_REPO (self) || !file_name)
+    return BSE_ERROR_PROC_PARAM_INVAL;
+
+  if (BSE_SOURCE_PREPARED (self))
+    {
+      /* In theory, its possible to allow loading sound fonts while
+       * the project is playing; in practice, the sound font repo
+       * lock would be locked for a very long time, which would stall
+       * the audio production ...
+       */
+      error = BSE_ERROR_SOURCE_BUSY;
+    }
+  else
+    {
+      ustack = bse_item_undo_open (self, "load-sound-font");
+      error = load_file (self, file_name, &sound_font);
+      if (sound_font)
+       bse_item_push_undo_proc (self, "remove-sound-font", sound_font);
+      bse_item_undo_close (ustack);
+   }
+
+  /* set output parameters */
+  g_value_set_enum (out_values++, error);
+
+  return BSE_ERROR_NONE;
+}
+
+METHOD (BseSoundFontRepo, remove-sound-font) {
+  HELP  = "Remove a sound font from repository";
+  IN    = bse_param_spec_object ("sound_font_repo", "Sound Font Repo", NULL,
+                                BSE_TYPE_SOUND_FONT_REPO, SFI_PARAM_STANDARD);
+  IN    = bse_param_spec_object ("sound_font", "Sound Font", NULL,
+                                BSE_TYPE_SOUND_FONT, SFI_PARAM_STANDARD);
+} BODY (BseProcedureClass *proc,
+       const GValue      *in_values,
+       GValue            *out_values)
+{
+  /* extract parameter values */
+  BseSoundFontRepo *self = (BseSoundFontRepo*) bse_value_get_object (in_values++);
+  BseItem *child         = (BseItem*) bse_value_get_object (in_values++);
+  BseUndoStack *ustack;
+  BseErrorType error;
+
+  /* check parameters */
+  if (!BSE_IS_SOUND_FONT_REPO (self) || !BSE_IS_SOUND_FONT (child) ||
+      child->parent != BSE_ITEM (self))
+    return BSE_ERROR_PROC_PARAM_INVAL;
+
+  if (BSE_SOURCE_PREPARED (self))
+    {
+      /* Don't allow unloading sound fonts which could be required by engine
+       * modules in the DSP thread currently producing audio output.
+       */
+      error = BSE_ERROR_SOURCE_BUSY;
+    }
+  else
+    {
+      /* action */
+      ustack = bse_item_undo_open (self, "remove-sound-font %s", bse_object_debug_name (child));
+      /* remove object references */
+      bse_container_uncross_undoable (BSE_CONTAINER (self), child);
+      /* how to get rid of the item once backed up */
+      bse_item_push_redo_proc (self, "remove-sound-font", child);
+      /* remove (without redo queueing) */
+      bse_container_remove_backedup (BSE_CONTAINER (self), child, ustack);
+      /* done */
+      bse_item_undo_close (ustack);
+
+      error = BSE_ERROR_NONE;
+    }
+
+  return error;
+}



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