[beast/wip/soundfont: 829/832] Merge branch 'master' of github.com/tim-janik/beast into soundfont
- From: Tim Janik <timj src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [beast/wip/soundfont: 829/832] Merge branch 'master' of github.com/tim-janik/beast into soundfont
- Date: Sun, 6 Nov 2016 11:52:23 +0000 (UTC)
commit b2a845e3d86e7a8a1f27ed83718608c33e76534f
Merge: 9b2fd45 12973ff
Author: Stefan Westerfeld <timj gnu org>
Date: Tue Oct 18 14:46:42 2016 +0200
Merge branch 'master' of github.com/tim-janik/beast into soundfont
Replace old .proc files with proper bseapi.idl entries.
Signed-off-by: Stefan Westerfeld <stefan space twc de>
beast-gtk/Makefile.am | 2 +-
beast-gtk/bstapp.cc | 168 ++++++++++----------
beast-gtk/bstapp.hh | 1 +
beast-gtk/bstbseutils.cc | 65 ++++----
beast-gtk/bstbseutils.hh | 2 +-
beast-gtk/bstbusmixer.cc | 14 +-
beast-gtk/bstcanvassource.cc | 6 +-
beast-gtk/bstfiledialog.cc | 28 ++--
beast-gtk/bstmain.cc | 13 +-
beast-gtk/bstmenus.cc | 47 +++----
beast-gtk/bstmenus.hh | 24 ++--
beast-gtk/bstpartdialog.cc | 7 +-
beast-gtk/bstpianorollctrl.cc | 14 ++-
beast-gtk/bstplayback.cc | 3 +-
beast-gtk/bstprojectctrl.cc | 25 ++--
beast-gtk/bstprojectctrl.hh | 1 +
beast-gtk/bstsnetrouter.cc | 22 +--
beast-gtk/bstsoundfontview.cc | 6 +-
beast-gtk/bsttrackview.cc | 24 ++--
beast-gtk/bsttreestores.cc | 13 +-
beast-gtk/bstusermessage.cc | 6 +-
beast-gtk/bstutils.cc | 62 +++-----
beast-gtk/bstutils.hh | 16 +--
beast-gtk/bstwaveeditor.cc | 21 ++--
beast-gtk/bstwaveview.cc | 10 +-
beast-gtk/gxk/Makefile.am | 2 +-
bse/Makefile.am | 11 +-
bse/bseapi.idl | 127 +++++++++++-----
bse/bsebasics.idl | 19 ---
bse/bsecategories.cc | 270 ++++++++++-----------------------
bse/bsecategories.hh | 30 +---
bse/bsecategories.proc | 72 ---------
bse/bsecontainer.cc | 56 ++++----
bse/bsecontainer.hh | 3 +-
bse/bsecontainer.proc | 60 -------
bse/bsecsynth.cc | 1 +
bse/bseengine.cc | 2 +-
bse/bseenginemaster.cc | 2 +-
bse/bseenginenode.hh | 2 +-
bse/bseglue.cc | 21 +--
bse/bseitem.cc | 10 +-
bse/bsemain.cc | 1 -
bse/bsemidisynth.cc | 2 +
bse/bseobject.cc | 57 +++----
bse/bseobject.hh | 4 +-
bse/bseprocidl.cc | 12 +-
bse/bseproject.cc | 202 +++++++++++++++++++++----
bse/bseproject.hh | 67 +++++----
bse/bseproject.proc | 340 -----------------------------------------
bse/bseserver.cc | 12 ++
bse/bseserver.hh | 2 +
bse/bsesong.cc | 151 ++++++++++++++++---
bse/bsesong.hh | 5 +
bse/bsesong.proc | 225 ---------------------------
bse/bsesoundfont.cc | 11 ++
bse/bsesoundfont.hh | 12 ++
bse/bsesoundfontrepo.cc | 101 ++++++++++++
bse/bsesoundfontrepo.hh | 14 ++
bse/bsesoundfontrepo.proc | 155 -------------------
bse/bsesuper.cc | 9 +-
bse/bsetool.cc | 7 +-
bse/bseutils.cc | 69 ++++-----
bse/bseutils.hh | 2 +-
bse/bsewave.cc | 41 +++++
bse/bsewave.hh | 6 +-
bse/bsewave.proc | 133 ----------------
bse/bsewaverepo.cc | 65 ++++++++-
bse/bsewaverepo.hh | 4 +-
bse/bsewaverepo.proc | 117 --------------
configure.ac | 13 ++
plugins/Makefile.am | 2 +-
plugins/bseadder.cc | 7 +-
plugins/bseadder.hh | 2 +-
po/Makefile.am | 2 +-
po/POTSCAN | 9 +-
sfi/sfitypes.hh | 2 +-
sfi/sfiwrapper.hh | 2 +-
77 files changed, 1221 insertions(+), 1932 deletions(-)
---
diff --cc beast-gtk/bstfiledialog.cc
index 05cd582,9c7d01e..3ce886c
--- a/beast-gtk/bstfiledialog.cc
+++ b/beast-gtk/bstfiledialog.cc
@@@ -752,37 -738,6 +751,36 @@@ bst_file_dialog_load_wave (BstFileDialo
}
GtkWidget*
+bst_file_dialog_popup_load_sound_font (gpointer parent_widget,
+ SfiProxy sound_font_repo,
+ gboolean show_lib)
+{
+ BstFileDialog *self = bst_file_dialog_global_sound_font ();
+ GtkWidget *widget = GTK_WIDGET (self);
+
+ bst_file_dialog_set_mode (self, parent_widget,
+ show_lib ? BST_FILE_DIALOG_LOAD_SOUND_FONT_LIB : BST_FILE_DIALOG_LOAD_SOUND_FONT,
+ _("Load Sound Font"), Bse::ProjectH(), 0, sound_font_repo);
+ gxk_widget_showraise (widget);
+
+ return widget;
+}
+
+static gboolean
+bst_file_dialog_load_sound_font (BstFileDialog *self,
+ const gchar *file_name)
+{
- Bse::Error error;
-
+ gxk_status_printf (0, NULL, _("Loading sound font `%s'"), file_name);
- error = bse_sound_font_repo_load_file (self->sound_font_repo, file_name);
++ Bse::SoundFontRepoH repo = Bse::SoundFontRepoH::down_cast (bse_server.from_proxy (self->sound_font_repo));
++ Bse::Error error = repo.load_file (file_name);
+ bst_status_eprintf (error, _("Loading sound font `%s'"), file_name);
+ if (error != 0)
+ sfi_error (_("Failed to load sound font \"%s\": %s"), file_name, Bse::error_blurb (error));
+
+ return TRUE;
+}
+
+GtkWidget*
bst_file_dialog_create (void)
{
BstFileDialog *self = (BstFileDialog*) g_object_new (BST_TYPE_FILE_DIALOG, NULL);
diff --cc beast-gtk/bstsoundfontview.cc
index d93de99,0000000..0e40d0b
mode 100644,000000..100644
--- a/beast-gtk/bstsoundfontview.cc
+++ b/beast-gtk/bstsoundfontview.cc
@@@ -1,139 -1,0 +1,143 @@@
+// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+#include "bstsoundfontview.hh"
+#include "bstsoundfontpresetview.hh"
+#include "bstfiledialog.hh"
+
+/* --- prototypes --- */
+
+static void sound_font_view_action_exec (gpointer data,
+ gulong action);
+static gboolean sound_font_view_action_check (gpointer data,
+ gulong action,
+ guint64 action_stamp);
+
+
+/* --- sound font actions --- */
+
+enum {
+ ACTION_LOAD_SOUND_FONT,
+ ACTION_LOAD_SOUND_FONT_LIB,
+ ACTION_DELETE_SOUND_FONT,
+ ACTION_SOUND_FONT_LAST
+};
+static const GxkStockAction sound_font_view_actions[] = {
+ { N_("Load..."), NULL, N_("Load a new sound font file from disk"),
+ ACTION_LOAD_SOUND_FONT, BST_STOCK_LOAD, },
+ { N_("Lib..."), NULL, N_("Load a sound font file from library paths"),
+ ACTION_LOAD_SOUND_FONT_LIB, BST_STOCK_LOAD_LIB, },
+ { N_("Delete"), NULL, N_("Delete the currently selected sound font from project"),
+ ACTION_DELETE_SOUND_FONT, BST_STOCK_TRASHCAN, },
+};
+
+
+/* --- functions --- */
+
+G_DEFINE_TYPE (BstSoundFontView, bst_sound_font_view, BST_TYPE_ITEM_VIEW);
+
+static void
+bst_sound_font_view_class_init (BstSoundFontViewClass *klass)
+{
+ BstItemViewClass *item_view_class = BST_ITEM_VIEW_CLASS (klass);
+
+ item_view_class->item_type = "BseSoundFont";
+}
+
+static void
+sound_font_selection_changed (BstSoundFontView *self)
+{
+ BstItemView *iview = BST_ITEM_VIEW (self);
+ bst_item_view_set_container (BST_ITEM_VIEW (self->preset_view), bst_item_view_get_current (iview));
+}
+
+static void
+bst_sound_font_view_init (BstSoundFontView *self)
+{
+ BstItemView *iview = BST_ITEM_VIEW (self);
+ /* complete GUI */
+ GxkRadget *radget = gxk_radget_complete (GTK_WIDGET (self), "beast", "sound-font-view", NULL);
+ gxk_widget_publish_actions (self, "sound-font-view-actions",
+ G_N_ELEMENTS (sound_font_view_actions), sound_font_view_actions,
+ NULL, sound_font_view_action_check, sound_font_view_action_exec);
+ /* setup tree view */
+ GtkTreeView *tview = (GtkTreeView *) gxk_radget_find (radget, "tree-view");
+ bst_item_view_complete_tree (iview, tview);
+
+ g_object_connect (gtk_tree_view_get_selection (tview),
+ "swapped_object_signal::changed", sound_font_selection_changed, self,
+ NULL);
+
+
+ /* setup preset view */
+ GtkTreeView *pview = (GtkTreeView *) gxk_radget_find (radget, "preset-view");
+ self->preset_view = BST_SOUND_FONT_PRESET_VIEW (bst_sound_font_preset_view_new());
+ bst_item_view_complete_tree (BST_ITEM_VIEW (self->preset_view), pview);
+}
+
+GtkWidget*
+bst_sound_font_view_new (SfiProxy sfrepo)
+{
+ GtkWidget *sound_font_view;
+
+ g_return_val_if_fail (BSE_IS_SOUND_FONT_REPO (sfrepo), NULL);
+
+ sound_font_view = gtk_widget_new (BST_TYPE_SOUND_FONT_VIEW, NULL);
+ bst_item_view_set_container (BST_ITEM_VIEW (sound_font_view), sfrepo);
+
+ return sound_font_view;
+}
+
+SfiProxy
+bst_sound_font_view_get_preset (BstSoundFontView *self)
+{
+ return bst_item_view_get_current (BST_ITEM_VIEW (self->preset_view));
+}
+
+static void
+sound_font_view_action_exec (gpointer data,
+ gulong action)
+{
+ BstSoundFontView *self = BST_SOUND_FONT_VIEW (data);
+ BstItemView *item_view = BST_ITEM_VIEW (self);
+ SfiProxy sfrepo = item_view->container;
+ switch (action)
+ {
+ SfiProxy item;
+ case ACTION_LOAD_SOUND_FONT:
+ bst_file_dialog_popup_load_sound_font (item_view, BST_ITEM_VIEW (self)->container, FALSE);
+ break;
+ case ACTION_LOAD_SOUND_FONT_LIB:
+ bst_file_dialog_popup_load_sound_font (item_view, BST_ITEM_VIEW (self)->container, TRUE);
+ break;
+ case ACTION_DELETE_SOUND_FONT:
+ item = bst_item_view_get_current (BST_ITEM_VIEW (self));
- bse_sound_font_repo_remove_sound_font (sfrepo, item);
++ {
++ Bse::SoundFontRepoH repo = Bse::SoundFontRepoH::down_cast (bse_server.from_proxy (sfrepo));
++ Bse::SoundFontH sound_font = Bse::SoundFontH::down_cast (bse_server.from_proxy (item));
++ repo.remove_sound_font (sound_font);
++ }
+ break;
+ default:
+ break;
+ }
+ gxk_widget_update_actions_downwards (self);
+}
+
+static gboolean
+sound_font_view_action_check (gpointer data,
+ gulong action,
+ guint64 action_stamp)
+{
+ BstSoundFontView *self = BST_SOUND_FONT_VIEW (data);
+ BstItemView *item_view = BST_ITEM_VIEW (self);
+
+ switch (action)
+ {
+ case ACTION_LOAD_SOUND_FONT:
+ case ACTION_LOAD_SOUND_FONT_LIB:
+ return TRUE;
+ case ACTION_DELETE_SOUND_FONT:
+ return bst_item_view_get_current (item_view) != 0;
+ default:
+ return FALSE;
+ }
+}
diff --cc beast-gtk/bsttrackview.cc
index 1cc8ea9,63f63ae..8ead85e
--- a/beast-gtk/bsttrackview.cc
+++ b/beast-gtk/bsttrackview.cc
@@@ -139,21 -140,11 +140,21 @@@ track_view_fill_value (BstItemView *ivi
break;
case COL_SYNTH:
snet = 0;
- bse_proxy_get (item.proxy_id(), "snet", &snet, "wave", &wave, NULL);
- g_value_set_string (value, snet || wave ? bse_item_get_name (snet ? snet : wave) : "");
+ wave = 0;
+ sound_font_preset = 0;
- bse_proxy_get (item, "snet", &snet, "wave", &wave, "sound_font_preset", &sound_font_preset, NULL);
++ bse_proxy_get (item.proxy_id(), "snet", &snet, "wave", &wave, "sound_font_preset",
&sound_font_preset, NULL);
+ if (snet)
+ string = bse_item_get_name (snet);
+ else if (wave)
+ string = bse_item_get_name (wave);
+ else if (sound_font_preset)
+ string = bse_item_get_name (sound_font_preset);
+ else
+ string = "";
+ g_value_set_string (value, string);
break;
case COL_MIDI_CHANNEL:
- bse_proxy_get (item, "midi-channel", &vint, NULL);
+ bse_proxy_get (item.proxy_id(), "midi-channel", &vint, NULL);
sfi_value_take_string (value, g_strdup_format ("%2d", vint));
break;
case COL_OUTPUTS:
@@@ -294,10 -282,7 +296,10 @@@ track_view_synth_popup (BstTrackVie
pc->label, pc->tooltip, pc->items,
_("Available Waves"),
_("List of available waves to choose a track
instrument from"),
- bse_project_get_wave_repo (bse_item_get_project
(item)),
+ project.get_wave_repo().proxy_id(),
+ _("Available Sound Fonts"),
+ _("List of available sound fonts to choose track
instrument from"),
- bse_project_get_sound_font_repo
(bse_item_get_project (item)),
++ project.get_sound_font_repo().proxy_id(),
track_view_synth_popup_cb, g_memdup (&sdata,
sizeof (sdata)), track_view_synth_popup_cleanup);
gxk_cell_renderer_popup_dialog (pcell, dialog);
}
diff --cc bse/bseapi.idl
index 8154e62,0379f34..9422708
--- a/bse/bseapi.idl
+++ b/bse/bseapi.idl
@@@ -791,8 -808,10 +808,19 @@@ interface Wave : Source
/// Interface serving as container for Wave objects.
interface WaveRepo : Super {
+ Error load_file (String file_name); ///< Load wave from file.
+ void remove_wave (Wave wave); ///< Remove a wave from repository.
+ };
+
++/// Interface for sound fonts
++interface SoundFont : Container {
++};
++
++interface SoundFontRepo : Super {
++ Error load_file (String file_name); ///< Load sound font from file.
++ Error remove_sound_font (SoundFont sound_font); ///< Remove a sound font from repository.
+};
+
/// Interface for MIDI event notification.
interface MidiNotifier : Item {
};
@@@ -801,31 -820,48 +829,49 @@@
interface MidiSynth : SNet {
};
+ /// Enumeration describing the current activation and playback state of a project.
+ enum ProjectState {
+ INACTIVE, ///< The project is not yet hooked to the sound engine.
+ ACTIVE, ///< The sound engine is activated (rnuning) for this project.
+ PLAYING ///< The project is active and the sequencer is running.
+ };
+
/// Projects support loading, saving, playback and act as containers for all other sound objects.
interface Project : Container {
- void change_name (String name); ///< Change a project name without recording undo steps.
- Error play(); ///< Activate a project and start project playback (an already playing project is first
halted).
- Error activate(); ///< Activate a project, precondition to start playback.
- //ProjectState get_state(); ///< Retrieve the current project activation/playback state.
- bool can_play(); ///< Check whether project playback would makes sense.
- bool is_playing(); ///< Check whether a project is currently playing (song sequencing).
- bool is_active (); ///< Check whether a project is active (currently synthesizing).
- void start_playback(); ///< Start playback in an activated project.
- void stop_playback(); ///< Stop project playback.
- void deactivate(); ///< Deactivate the project, automatically stop playback.
- void stop(); ///< Stop project playback and deactivate project.
- void auto_deactivate (int32 msec_delay); ///< Automatically deactivate a few milliseconds after playback
stopped.
- int32 undo_depth(); ///< Check whether a project can perform undo steps.
- void undo(); ///< Undo a previous operation in a project.
- int32 redo_depth(); ///< Get the number of times redo can be called on the project.
- void redo(); ///< Redo a previously undone operation in a project.
- void clear_undo(); ///< Delete all recorded undo or redo steps.
- void clean_dirty(); ///< Clear a project's dirty flags.
- bool is_dirty(); ///< Check whether a project needs saving.
+ signal void state_changed (ProjectState newstate); ///< Signal notifies of project state changes.
+ ProjectState get_state (); ///< Retrieve the current project activation/playback state.
+ void change_name (String name); ///< Change a project name without recording undo steps.
+ Error play (); ///< Activate a project and start project playback (an already
playing project is first halted).
+ Error activate (); ///< Activate a project, precondition to start playback.
+ bool can_play (); ///< Check whether project playback would makes sense.
+ bool is_playing (); ///< Check whether a project is currently playing (song sequencing).
+ bool is_active (); ///< Check whether a project is active (currently synthesizing).
+ void start_playback (); ///< Start playback in an activated project.
+ void stop_playback (); ///< Stop project playback.
+ void deactivate (); ///< Deactivate the project, automatically stop playback.
+ void stop (); ///< Stop project playback and deactivate project.
+ void auto_deactivate (int32 msec_delay); ///< Automatically deactivate a few milliseconds
after playback stopped.
+ int32 undo_depth (); ///< Check whether a project can perform undo steps.
+ void undo (); ///< Undo a previous operation in a project.
+ int32 redo_depth (); ///< Get the number of times redo can be called on the project.
+ void redo (); ///< Redo a previously undone operation in a project.
+ void clear_undo (); ///< Delete all recorded undo or redo steps.
+ void clean_dirty (); ///< Clear a project's dirty flags.
+ bool is_dirty (); ///< Check whether a project needs saving.
+ SuperSeq get_supers (); ///< Retrieve all Super type objects of this project.
+ Error store_bse (Super super, String file_name, bool self_contained);
+ Song create_song (String name); ///< Create a song for this project.
+ WaveRepo get_wave_repo (); ///< Retrieve the project's unique wave repository.
++ SoundFontRepo get_sound_font_repo (); ///< Retrieve the project's unique sound font repository.
+ CSynth create_csynth (String name); ///< Create a synthsizer network for this project.
+ MidiSynth create_midi_synth (String name); ///< Create a MIDI synthesizer network for this project.
+ MidiNotifier get_midi_notifier (); ///< Retrieve the project's midi notifier object.
+ void remove_snet (SNet snet); ///< Remove an existing synthesizer network from this
project.
+ Error restore_from_file (String file_name); ///< Load a project from file.
/// Inject a MIDI control event into the project's MIDI receiver.
- void inject_midi_control (int32 midi_channel, int32 midi_control, float64 control_value);
+ void inject_midi_control (int32 midi_channel, int32 midi_control, float64 control_value);
+ Error import_midi_file (String file_name); ///< Import a song from a MIDI file.
//Item find_item (String uname_path); ///< Find an item within a project, given its uname path.
- //ItemSeq get_supers(); ///< Retrieve all Super type objects of this project.
/// List uname paths for all items of a specified type within a project.
/// By their uname paths, items are uniquely identifyable within a project.
//StringSeq list_uname_paths (String item_type);
diff --cc bse/bseobject.cc
index 158c451,4df911d..4c635e4
--- a/bse/bseobject.cc
+++ b/bse/bseobject.cc
@@@ -932,6 -917,6 +917,8 @@@ bse_object_new (GType object_type, cons
#include "bsemidinotifier.hh"
#include "bsemidisynth.hh"
#include "bsewaverepo.hh"
++#include "bsesoundfont.hh"
++#include "bsesoundfontrepo.hh"
#include "bsebus.hh"
#include "bsesnet.hh"
#include "bsepart.hh"
@@@ -962,6 -947,6 +949,10 @@@ bse_object_new_valist (GType object_typ
cxxo = new Bse::WaveImpl (object);
else if (g_type_is_a (object_type, BSE_TYPE_WAVE_REPO))
cxxo = new Bse::WaveRepoImpl (object);
++ else if (g_type_is_a (object_type, BSE_TYPE_SOUND_FONT))
++ cxxo = new Bse::SoundFontImpl (object);
++ else if (g_type_is_a (object_type, BSE_TYPE_SOUND_FONT_REPO))
++ cxxo = new Bse::SoundFontRepoImpl (object);
else if (g_type_is_a (object_type, BSE_TYPE_MIDI_NOTIFIER))
cxxo = new Bse::MidiNotifierImpl (object);
else if (g_type_is_a (object_type, BSE_TYPE_MIDI_SYNTH))
diff --cc bse/bseproject.cc
index b38b6ca,ef9d37f..51b9170
--- a/bse/bseproject.cc
+++ b/bse/bseproject.cc
@@@ -1202,4 -1171,142 +1196,150 @@@ ProjectImpl::restore_from_file (const S
return Bse::Error (error);
}
+ ProjectState
+ ProjectImpl::get_state ()
+ {
+ BseProject *self = as<BseProject*>();
+ return self->state;
+ }
+
+ SuperSeq
+ ProjectImpl::get_supers ()
+ {
+ BseProject *self = as<BseProject*>();
+ SuperSeq sseq;
+ for (GSList *slist = self->supers; slist; slist = slist->next)
+ {
+ BseItem *bseitem = (BseItem*) slist->data;
+ sseq.push_back (bseitem->as<SuperIfaceP>());
+ }
+ return sseq;
+ }
+
+ void
+ ProjectImpl::remove_snet (SNetIface &snet_iface)
+ {
+ BseProject *self = as<BseProject*>();
+ SNetImpl &snet = dynamic_cast<SNetImpl&> (snet_iface);
+ assert_return (snet.parent() == this);
+ return_unless (BSE_SOURCE_PREPARED (self) == false);
+ BseItem *child = snet.as<BseItem*>();
+ BseUndoStack *ustack = bse_item_undo_open (self, __func__);
+ // backup object references to undo stack
+ bse_container_uncross_undoable (BSE_CONTAINER (self), child);
+ // implement "undo" of bse_container_remove_backedup, i.e. redo
+ UndoDescriptor<SNetImpl> snet_descriptor = undo_descriptor (snet);
+ auto lambda = [snet_descriptor] (ProjectImpl &self, BseUndoStack *ustack) -> Error {
+ SNetImpl &snet = self.undo_resolve (snet_descriptor);
+ self.remove_snet (snet);
+ return Error::NONE;
+ };
+ push_undo_to_redo (__func__, *this, lambda);
+ // backup and remove (without redo queueing)
+ bse_container_remove_backedup (BSE_CONTAINER (self), child, ustack);
+ // done
+ bse_item_undo_close (ustack);
+ }
+
+ Error
+ ProjectImpl::store_bse (SuperIface &super_iface, const String &file_name, bool self_contained)
+ {
+ BseProject *self = as<BseProject*>();
+ SuperImpl *super = dynamic_cast<SuperImpl*> (&super_iface);
+ BseSuper *bsesuper = super ? super->as<BseSuper*>() : NULL;
+ if (super)
+ assert_return (super->parent() == this, Error::INTERNAL);
+ return bse_project_store_bse (self, bsesuper, file_name.c_str(), self_contained);
+ }
+
+ SongIfaceP
+ ProjectImpl::create_song (const String &name)
+ {
+ BseProject *self = as<BseProject*>();
+ BseUndoStack *ustack = bse_item_undo_open (self, __func__);
+ BseSong *song = (BseSong*) bse_container_new_child (self, BSE_TYPE_SONG, NULL);
+ if (song)
+ {
+ if (!name.empty())
+ bse_item_set (song, "uname", name.c_str(), NULL);
+ UndoDescriptor<SongImpl> song_descriptor = undo_descriptor (*song->as<SongImpl*>());
+ auto remove_song_lambda = [song_descriptor] (ProjectImpl &self, BseUndoStack *ustack) -> Error {
+ SongImpl &song = self.undo_resolve (song_descriptor);
+ self.remove_snet (song);
+ return Error::NONE;
+ };
+ push_undo (__func__, *this, remove_song_lambda);
+ }
+ bse_item_undo_close (ustack);
+ return song->as<SongIfaceP>();
+ }
+
+ CSynthIfaceP
+ ProjectImpl::create_csynth (const String &name)
+ {
+ BseProject *self = as<BseProject*>();
+ BseUndoStack *ustack = bse_item_undo_open (self, __func__);
+ BseCSynth *csynth = (BseCSynth*) bse_container_new_child (self, BSE_TYPE_CSYNTH, NULL);
+ if (csynth)
+ {
+ if (!name.empty())
+ bse_item_set (csynth, "uname", name.c_str(), NULL);
+ UndoDescriptor<CSynthImpl> csynth_descriptor = undo_descriptor (*csynth->as<CSynthImpl*>());
+ auto remove_csynth_lambda = [csynth_descriptor] (ProjectImpl &self, BseUndoStack *ustack) -> Error {
+ CSynthImpl &csynth = self.undo_resolve (csynth_descriptor);
+ self.remove_snet (csynth);
+ return Error::NONE;
+ };
+ push_undo (__func__, *this, remove_csynth_lambda);
+ }
+ bse_item_undo_close (ustack);
+ return csynth->as<CSynthIfaceP>();
+ }
+
+ MidiSynthIfaceP
+ ProjectImpl::create_midi_synth (const String &name)
+ {
+ BseProject *self = as<BseProject*>();
+ BseUndoStack *ustack = bse_item_undo_open (self, __func__);
+ BseMidiSynth *midi_synth = (BseMidiSynth*) bse_container_new_child (self, BSE_TYPE_MIDI_SYNTH, NULL);
+ if (midi_synth)
+ {
+ if (!name.empty())
+ bse_item_set (midi_synth, "uname", name.c_str(), NULL);
+ UndoDescriptor<MidiSynthImpl> midi_synth_descriptor = undo_descriptor
(*midi_synth->as<MidiSynthImpl*>());
+ auto remove_midi_synth_lambda = [midi_synth_descriptor] (ProjectImpl &self, BseUndoStack *ustack) ->
Error {
+ MidiSynthImpl &midi_synth = self.undo_resolve (midi_synth_descriptor);
+ self.remove_snet (midi_synth);
+ return Error::NONE;
+ };
+ push_undo (__func__, *this, remove_midi_synth_lambda);
+ }
+ bse_item_undo_close (ustack);
+ return midi_synth->as<MidiSynthIfaceP>();
+ }
+
+ WaveRepoIfaceP
+ ProjectImpl::get_wave_repo ()
+ {
+ BseProject *self = as<BseProject*>();
+ BseWaveRepo *wrepo = bse_project_get_wave_repo (self);
+ return wrepo ? wrepo->as<WaveRepoIfaceP>() : NULL;
+ }
+
++SoundFontRepoIfaceP
++ProjectImpl::get_sound_font_repo ()
++{
++ BseProject *self = as<BseProject*>();
++ BseSoundFontRepo *sfrepo = bse_project_get_sound_font_repo (self);
++ return sfrepo ? sfrepo->as<SoundFontRepoIfaceP>() : NULL;
++}
++
+ MidiNotifierIfaceP
+ ProjectImpl::get_midi_notifier ()
+ {
+ BseProject *self = as<BseProject*>();
+ BseMidiNotifier *notifier = bse_project_get_midi_notifier (self);
+ return notifier ? notifier->as<MidiNotifierIfaceP>() : NULL;
+ }
+
} // Bse
diff --cc bse/bseproject.hh
index aaa8fa8,2d6aa28..7702d86
--- a/bse/bseproject.hh
+++ b/bse/bseproject.hh
@@@ -80,30 -72,39 +73,40 @@@ namespace Bse
class ProjectImpl : public ContainerImpl, public virtual ProjectIface {
protected:
- virtual ~ProjectImpl ();
+ virtual ~ProjectImpl ();
public:
- explicit ProjectImpl (BseObject*);
- virtual void change_name (const String &name) override;
- virtual Error play () override;
- virtual Error activate () override;
- virtual bool can_play () override;
- virtual bool is_playing () override;
- virtual bool is_active () override;
- virtual void start_playback () override;
- virtual void stop_playback () override;
- virtual void deactivate () override;
- virtual void stop () override;
- virtual void auto_deactivate (int msec_delay) override;
- virtual int undo_depth () override;
- virtual void undo () override;
- virtual int redo_depth () override;
- virtual void redo () override;
- virtual void clear_undo () override;
- virtual void clean_dirty () override;
- virtual bool is_dirty () override;
- virtual void inject_midi_control (int midi_channel, int midi_control, double control_value) override;
- virtual Error import_midi_file (const String &file_name) override;
- virtual Error restore_from_file (const String &file_name) override;
+ explicit ProjectImpl (BseObject*);
+ virtual void change_name (const String &name) override;
+ virtual Error play () override;
+ virtual Error activate () override;
+ virtual bool can_play () override;
+ virtual bool is_playing () override;
+ virtual bool is_active () override;
+ virtual void start_playback () override;
+ virtual void stop_playback () override;
+ virtual void deactivate () override;
+ virtual void stop () override;
+ virtual void auto_deactivate (int msec_delay) override;
+ virtual int undo_depth () override;
+ virtual void undo () override;
+ virtual int redo_depth () override;
+ virtual void redo () override;
+ virtual void clear_undo () override;
+ virtual void clean_dirty () override;
+ virtual bool is_dirty () override;
+ virtual void inject_midi_control (int midi_channel, int midi_control, double control_value)
override;
+ virtual Error import_midi_file (const String &file_name) override;
+ virtual Error restore_from_file (const String &file_name) override;
+ virtual ProjectState get_state () override;
+ virtual SuperSeq get_supers () override;
+ virtual Error store_bse (SuperIface &super, const String &file_name, bool
self_contained) override;
+ virtual SongIfaceP create_song (const String &name) override;
+ virtual WaveRepoIfaceP get_wave_repo () override;
++ virtual SoundFontRepoIfaceP get_sound_font_repo () override;
+ virtual CSynthIfaceP create_csynth (const String &name) override;
+ virtual MidiSynthIfaceP create_midi_synth (const String &name) override;
+ virtual MidiNotifierIfaceP get_midi_notifier () override;
+ virtual void remove_snet (SNetIface &snet) override;
};
} // Bse
diff --cc bse/bsesoundfont.cc
index 199e089,0000000..e9893ba
mode 100644,000000..100644
--- a/bse/bsesoundfont.cc
+++ b/bse/bsesoundfont.cc
@@@ -1,379 -1,0 +1,390 @@@
+// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+#include "bsesoundfont.hh"
+#include "bsesoundfontrepo.hh"
+#include "bsesoundfontpreset.hh"
+#include "bsemain.hh"
+#include "bsestorage.hh"
+#include "bseprocedure.hh"
+#include "gsldatahandle.hh"
+#include "bseserver.hh"
+#include "bseloader.hh"
+
+#include <string.h>
+
+#define parse_or_return bse_storage_scanner_parse_or_return
+
+enum {
+ PARAM_0,
+ PARAM_FILE_NAME,
+};
+
+/* --- prototypes --- */
+
+
+/* --- variables --- */
+static void *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);
+}
+
+Bse::Error
+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);
+ Bse::Error 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;
+ sound_font_preset = (BseSoundFontPreset *) bse_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;
+}
+
+Bse::Error
+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 GTokenType
+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;
+ Bse::Error 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 GTokenType (')');
+ }
+ parse_or_return (scanner, ')');
+ error = bse_sound_font_load_blob (sound_font, blob, FALSE);
+ if (error != 0)
+ 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 = BSE_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, BSE_ITEM (self->presets->data));
+
+ /* chain parent class' handler */
+ BSE_CONTAINER_CLASS (parent_class)->release_children (container);
+}
+
+
+static void
+bse_sound_font_class_init (BseSoundFontClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ BseObjectClass *object_class = BSE_OBJECT_CLASS (klass);
+ BseContainerClass *container_class = BSE_CONTAINER_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ 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);
+}
++
++namespace Bse {
++
++SoundFontImpl::SoundFontImpl (BseObject *bobj) :
++ ContainerImpl (bobj)
++{}
++
++SoundFontImpl::~SoundFontImpl ()
++{}
++
++} // Bse
diff --cc bse/bsesoundfont.hh
index ab0784b,0000000..254cf20
mode 100644,000000..100644
--- a/bse/bsesoundfont.hh
+++ b/bse/bsesoundfont.hh
@@@ -1,35 -1,0 +1,47 @@@
+// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+#ifndef __BSE_SOUND_FONT_HH__
+#define __BSE_SOUND_FONT_HH__
+
+#include <bse/bsecontainer.hh>
+#include <bse/bsestorage.hh>
+
+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))
+
+struct BseSoundFont : BseContainer {
+ BseStorageBlob *blob;
+ int sfont_id;
+ BseSoundFontRepo *sfrepo;
+ GList *presets;
+};
+struct BseSoundFontClass : BseContainerClass
+{};
+
+Bse::Error bse_sound_font_load_blob (BseSoundFont *sound_font,
+ BseStorageBlob *blob,
+ gboolean init_presets);
+void bse_sound_font_unload (BseSoundFont *sound_font);
+Bse::Error bse_sound_font_reload (BseSoundFont *sound_font);
+
+G_END_DECLS
+
++namespace Bse {
++
++class SoundFontImpl : public ContainerImpl, public virtual SoundFontIface {
++protected:
++ virtual ~SoundFontImpl ();
++public:
++ explicit SoundFontImpl (BseObject*);
++};
++
++} // Bse
++
++
+#endif /* __BSE_SOUND_FONT_HH__ */
diff --cc bse/bsesoundfontrepo.cc
index 4ee9d0a,0000000..dd7d6f3
mode 100644,000000..100644
--- a/bse/bsesoundfontrepo.cc
+++ b/bse/bsesoundfontrepo.cc
@@@ -1,389 -1,0 +1,490 @@@
+// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+#include "bsesoundfontrepo.hh"
+#include "bsesoundfont.hh"
+#include "bsesoundfontpreset.hh"
+#include "bsedefs.hh"
+#include "bseblockutils.hh"
+
+
+/* --- parameters --- */
+enum
+{
+ PARAM_0,
+};
+
+
+/* --- prototypes --- */
+static void bse_sound_font_repo_class_init (BseSoundFontRepoClass *klass);
+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 gpointer 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_finalize (GObject *object)
+{
+ BseSoundFontRepo *sfrepo = BSE_SOUND_FONT_REPO (object);
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+ sfrepo->fluid_synth_mutex.~Mutex();
+}
+
+static void
+bse_sound_font_repo_class_init (BseSoundFontRepoClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ BseContainerClass *container_class = BSE_CONTAINER_CLASS (klass);
+ BseSourceClass *source_class = BSE_SOURCE_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ 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;
+ gobject_class->finalize = bse_sound_font_repo_finalize;
+
+ 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)
+{
+ new (&sfrepo->fluid_synth_mutex) Bse::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);
+ /* soundfont instruments should be as loud as beast synthesis network instruments */
+ fluid_settings_setnum (sfrepo->fluid_settings, "synth.gain", 1.0);
+ 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, BSE_ITEM (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 = BSE_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,
+ void *pitems)
+{
+ BseIt3mSeq *items = (BseIt3mSeq *) pitems;
+ 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_it3m_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,
+ BseIt3mSeq *items)
+{
+ gather_presets (BSE_ITEM (sfrepo), items);
+}
+
+fluid_synth_t *
+bse_sound_font_repo_lock_fluid_synth (BseSoundFontRepo *sfrepo)
+{
+ sfrepo->fluid_synth_mutex.lock();
+ return sfrepo->fluid_synth;
+}
+
+void
+bse_sound_font_repo_unlock_fluid_synth (BseSoundFontRepo *sfrepo)
+{
+ sfrepo->fluid_synth_mutex.unlock();
+}
+
+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 = (guint *) 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;
+}
++
++namespace Bse {
++
++SoundFontRepoImpl::SoundFontRepoImpl (BseObject *bobj) :
++ SuperImpl (bobj)
++{}
++
++SoundFontRepoImpl::~SoundFontRepoImpl ()
++{}
++
++static Error
++repo_load_file (BseSoundFontRepo *sfrepo, const String &file_name, BseSoundFont **sound_font_p)
++{
++ String fname = Path::basename (file_name);
++ BseSoundFont *sound_font = (BseSoundFont*) bse_object_new (BSE_TYPE_SOUND_FONT, "uname", fname.c_str(),
NULL);
++ bse_container_add_item (BSE_CONTAINER (sfrepo), BSE_ITEM (sound_font));
++
++ BseStorageBlob *blob = bse_storage_blob_new_from_file (file_name.c_str(), FALSE);
++ Error 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;
++ error = Error::NONE;
++ }
++ else
++ {
++ bse_container_remove_item (BSE_CONTAINER (sfrepo), BSE_ITEM (sound_font));
++ *sound_font_p = NULL;
++ }
++ g_object_unref (sound_font);
++ return error;
++}
++
++
++Error
++SoundFontRepoImpl::load_file (const String &file_name)
++{
++ BseSoundFontRepo *self = as<BseSoundFontRepo*>();
++
++ 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 ...
++ */
++ return Bse::Error::SOURCE_BUSY;
++ }
++
++ BseSoundFont *sound_font = NULL;
++ Bse::Error error = repo_load_file (self, file_name, &sound_font);
++ if (sound_font)
++ {
++ UndoDescriptor<SoundFontImpl> sound_font_descriptor = undo_descriptor
(*sound_font->as<SoundFontImpl*>());
++ auto remove_sound_font_lambda = [sound_font_descriptor] (SoundFontRepoImpl &self, BseUndoStack
*ustack) -> Error {
++ SoundFontImpl &sound_font = self.undo_resolve (sound_font_descriptor);
++ self.remove_sound_font (sound_font);
++ return Error::NONE;
++ };
++ push_undo (__func__, *this, remove_sound_font_lambda);
++ }
++ return error;
++}
++
++Error
++SoundFontRepoImpl::remove_sound_font (SoundFontIface &sound_font_iface)
++{
++ BseSoundFontRepo *self = as<BseSoundFontRepo*>();
++ BseSoundFont *sound_font = sound_font_iface.as<BseSoundFont*>();
++
++ assert_return (sound_font->parent == self, Bse::Error::INTERNAL);
++
++ 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.
++ */
++ return Bse::Error::SOURCE_BUSY;
++ }
++ BseUndoStack *ustack = bse_item_undo_open (self, __func__);
++ bse_container_uncross_undoable (self, sound_font); // removes object references
++ if (sound_font) // push undo for 'remove_backedup'
++ {
++ UndoDescriptor<SoundFontImpl> sound_font_descriptor = undo_descriptor
(*sound_font->as<SoundFontImpl*>());
++ auto remove_sound_font_lambda = [sound_font_descriptor] (SoundFontRepoImpl &self, BseUndoStack
*ustack) -> Error {
++ SoundFontImpl &sound_font = self.undo_resolve (sound_font_descriptor);
++ self.remove_sound_font (sound_font);
++ return Error::NONE;
++ };
++ push_undo_to_redo (__func__, *this, remove_sound_font_lambda);
++ }
++ bse_container_remove_backedup (self, sound_font, ustack); // removes without undo
++ bse_item_undo_close (ustack);
++
++ return Bse::Error::NONE;
++
++}
++
++} // Bse
diff --cc bse/bsesoundfontrepo.hh
index f76831b,0000000..2588758
mode 100644,000000..100644
--- a/bse/bsesoundfontrepo.hh
+++ b/bse/bsesoundfontrepo.hh
@@@ -1,68 -1,0 +1,82 @@@
+// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
+#ifndef __BSE_SOUND_FONT_REPO_HH__
+#define __BSE_SOUND_FONT_REPO_HH__
+
+#include <bse/bsesuper.hh>
+#include <fluidsynth.h>
+#include <bse/bsesoundfontosc.hh>
+#include <bse/bseengine.hh>
+
+G_BEGIN_DECLS
+
+#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))
+
+#define BSE_FLUID_SYNTH_PROGRAM_SELECT -1
+
+struct BseFluidEvent {
+ guint64 tick_stamp;
+ int channel;
+ int command;
+ int arg1;
+ int arg2;
+ int sfont_id; /* required for program selection only */
+};
+
+struct BseSoundFontRepo : BseSuper {
+ Bse::Mutex 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
+{};
+
+
+/* --- prototypes --- */
+void bse_sound_font_repo_list_all_presets (BseSoundFontRepo *sfrepo,
+ BseIt3mSeq *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
+
++namespace Bse {
++
++class SoundFontRepoImpl : public SuperImpl, public virtual SoundFontRepoIface {
++protected:
++ virtual ~SoundFontRepoImpl ();
++public:
++ explicit SoundFontRepoImpl (BseObject*);
++ virtual Error load_file (const String &file_name) override;
++ virtual Error remove_sound_font (SoundFontIface &wave) override;
++};
++
++} // Bse
++
++
+#endif /* __BSE_SOUND_FONT_REPO_HH__ */
diff --cc po/POTSCAN
index 8665400,2db2d88..272ec9e
--- a/po/POTSCAN
+++ b/po/POTSCAN
@@@ -86,8 -85,6 +86,7 @@@ bse/bsepcmoutput.c
bse/bseserver.cc
bse/bsesnooper.cc
bse/bsesong.cc
- bse/bsesong.proc
+bse/bsesoundfontosc.cc
bse/bsesource.proc
bse/bsestandardosc.cc
bse/bsesubiport.cc
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]