[beast/wip/soundfont: 14/832] BSE: implemented BseSoundFontOsc, which wraps fluid synth computations.
- From: Tim Janik <timj src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [beast/wip/soundfont: 14/832] BSE: implemented BseSoundFontOsc, which wraps fluid synth computations.
- Date: Sun, 6 Nov 2016 11:50:07 +0000 (UTC)
commit 44910033f940e653884b86375c0903f0e73b2e1e
Author: Stefan Westerfeld <stefan space twc de>
Date: Mon Nov 8 23:09:09 2010 +0100
BSE: implemented BseSoundFontOsc, which wraps fluid synth computations.
bse/bsesoundfontosc.c | 617 +++++++++++++++++++++++++++++++++++++++++++++++++
bse/bsesoundfontosc.h | 78 +++++++
2 files changed, 695 insertions(+), 0 deletions(-)
---
diff --git a/bse/bsesoundfontosc.c b/bse/bsesoundfontosc.c
new file mode 100644
index 0000000..1ba2b9e
--- /dev/null
+++ b/bse/bsesoundfontosc.c
@@ -0,0 +1,617 @@
+/* BseSoundFontOsc - BSE Fluid Synth
+ * Copyright (C) 1999-2002 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 "bsesoundfontosc.h"
+
+#include <bse/bsecategories.h>
+#include <bse/bseengine.h>
+#include <bse/bseproject.h>
+#include <bse/bsesoundfontrepo.h>
+#include <bse/bsesoundfont.h>
+#include <bse/bsesnet.h>
+#include <bse/bsemidireceiver.h>
+#include "gslcommon.h"
+
+#include <string.h>
+
+/* --- parameters --- */
+enum
+{
+ PARAM_0,
+ PARAM_PRESET
+};
+
+
+/* --- prototypes --- */
+static void bse_sound_font_osc_init (BseSoundFontOsc *sound_font_osc);
+static void bse_sound_font_osc_class_init (BseSoundFontOscClass *class);
+static void bse_sound_font_osc_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void bse_sound_font_osc_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void bse_sound_font_osc_get_candidates (BseItem *item,
+ guint param_id,
+ BsePropertyCandidates *pc,
+ GParamSpec *pspec);
+static void bse_sound_font_osc_context_create (BseSource *source,
+ guint context_handle,
+ BseTrans *trans);
+static void bse_sound_font_osc_context_dismiss (BseSource *source,
+ guint context_handle,
+ BseTrans *trans);
+static void bse_sound_font_osc_update_modules (BseSoundFontOsc *sound_font_osc,
+ BseTrans *trans);
+static void bse_sound_font_osc_dispose (GObject *object);
+static void bse_sound_font_osc_finalize (GObject *object);
+
+
+/* --- variables --- */
+static gpointer parent_class = NULL;
+
+
+/* --- functions --- */
+BSE_BUILTIN_TYPE (BseSoundFontOsc)
+{
+ static const GTypeInfo type_info = {
+ sizeof (BseSoundFontOscClass),
+
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) bse_sound_font_osc_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL /* class_data */,
+
+ sizeof (BseSoundFontOsc),
+ 0 /* n_preallocs */,
+ (GInstanceInitFunc) bse_sound_font_osc_init,
+ };
+ GType type_id;
+
+ type_id = bse_type_register_static (BSE_TYPE_SOURCE,
+ "BseSoundFontOsc",
+ "This internal module wraps fluid synth which plays sound font
contents",
+ __FILE__, __LINE__,
+ &type_info);
+ return type_id;
+}
+
+static void
+bse_sound_font_osc_class_init (BseSoundFontOscClass *class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+ BseObjectClass *object_class = BSE_OBJECT_CLASS (class);
+ BseSourceClass *source_class = BSE_SOURCE_CLASS (class);
+ BseItemClass *item_class = BSE_ITEM_CLASS (class);
+ guint ochannel;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ gobject_class->set_property = bse_sound_font_osc_set_property;
+ gobject_class->get_property = bse_sound_font_osc_get_property;
+ gobject_class->finalize = bse_sound_font_osc_finalize;
+ gobject_class->dispose = bse_sound_font_osc_dispose;
+
+ item_class->get_candidates = bse_sound_font_osc_get_candidates;
+
+ source_class->context_create = bse_sound_font_osc_context_create;
+ source_class->context_dismiss = bse_sound_font_osc_context_dismiss;
+
+ bse_object_class_add_param (object_class, _("Sound Font Preset"),
+ PARAM_PRESET,
+ bse_param_spec_object ("preset", _("Preset"), _("Sound Font Preset to be used
during replay"),
+ BSE_TYPE_SOUND_FONT_PRESET, SFI_PARAM_STANDARD));
+
+ ochannel = bse_source_class_add_ochannel (source_class, "left-out", _("Left Out"), _("Output of the fluid
synth soundfont synthesizer"));
+ g_assert (ochannel == BSE_SOUND_FONT_OSC_OCHANNEL_LEFT_OUT);
+ ochannel = bse_source_class_add_ochannel (source_class, "right-out", _("Right Out"), _("Output of the
fluid synth soundfont synthesizer"));
+ g_assert (ochannel == BSE_SOUND_FONT_OSC_OCHANNEL_RIGHT_OUT);
+ ochannel = bse_source_class_add_ochannel (source_class, "done-out", _("Done Out"), _("Done Output"));
+ g_assert (ochannel == BSE_SOUND_FONT_OSC_OCHANNEL_DONE_OUT);
+}
+
+static void
+bse_sound_font_osc_init (BseSoundFontOsc *self)
+{
+ memset (&self->config, 0, sizeof (self->config));
+ self->preset = NULL;
+}
+
+static void
+bse_sound_font_osc_dispose (GObject *object)
+{
+ BseSoundFontOsc *self = BSE_SOUND_FONT_OSC (object);
+
+ if (self->config.sfrepo)
+ {
+ bse_sound_font_repo_remove_osc (self->config.sfrepo, self->config.osc_id);
+
+ self->config.sfrepo = NULL;
+ }
+
+ /* chain parent class' handler */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+bse_sound_font_osc_finalize (GObject *object)
+{
+ //BseSoundFontOsc *self = BSE_SOUND_FONT_OSC (object);
+
+ /* chain parent class' handler */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+static BseSoundFontRepo*
+get_sfrepo (BseSoundFontOsc *self)
+{
+ if (!self->config.sfrepo)
+ {
+ BseProject *project = bse_item_get_project (BSE_ITEM (self));
+ if (project)
+ {
+ self->config.sfrepo = bse_project_get_sound_font_repo (project);
+ self->config.osc_id = bse_sound_font_repo_add_osc (self->config.sfrepo, self);
+ }
+ else
+ {
+ g_warning ("BseSoundFontOsc: could not find sfrepo\n");
+ self->config.sfrepo = NULL;
+ }
+ }
+ return self->config.sfrepo;
+}
+
+static void
+bse_sound_font_osc_uncross_preset (BseItem *owner,
+ BseItem *ref_item)
+{
+ BseSoundFontOsc *self = BSE_SOUND_FONT_OSC (owner);
+ bse_item_set (self, "preset", NULL, NULL);
+}
+
+
+static void
+bse_sound_font_osc_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ BseSoundFontOsc *self = BSE_SOUND_FONT_OSC (object);
+
+ switch (param_id)
+ {
+ BseSoundFontPreset *preset;
+ case PARAM_PRESET:
+ preset = bse_value_get_object (value);
+ if (preset != self->preset)
+ {
+ self->preset = preset;
+ if (self->preset)
+ {
+ bse_item_cross_link (BSE_ITEM (self), BSE_ITEM (self->preset),
bse_sound_font_osc_uncross_preset);
+ bse_object_proxy_notifies (self->preset, self, "notify::preset");
+ self->config.sfont_id = BSE_SOUND_FONT (BSE_ITEM (self->preset)->parent)->sfont_id;
+ self->config.bank = self->preset->bank;
+ self->config.program = self->preset->program;
+ self->config.update_preset++;
+ bse_sound_font_osc_update_modules (self, NULL);
+ }
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, param_id, pspec);
+ break;
+ }
+}
+
+static void
+bse_sound_font_osc_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ BseSoundFontOsc *self = BSE_SOUND_FONT_OSC (object);
+
+ switch (param_id)
+ {
+ case PARAM_PRESET:
+ bse_value_set_object (value, self->preset);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, param_id, pspec);
+ break;
+ }
+}
+
+
+static void
+bse_sound_font_osc_get_candidates (BseItem *item,
+ guint param_id,
+ BsePropertyCandidates *pc,
+ GParamSpec *pspec)
+{
+ BseSoundFontOsc *self = BSE_SOUND_FONT_OSC (item);
+ switch (param_id)
+ {
+ case PARAM_PRESET:
+ bse_property_candidate_relabel (pc, _("Available Presets"), _("List of available sound font presets to
choose as fluid synth preset"));
+ bse_sound_font_repo_list_all_presets (get_sfrepo (self), pc->items);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (self, param_id, pspec);
+ break;
+ }
+}
+
+
+typedef struct
+{
+ BseSoundFontOscConfig config;
+ int last_update_preset;
+ guint64 n_silence_samples; // for done detection
+} SoundFontOscModule;
+
+static void
+bse_sound_font_osc_update_modules (BseSoundFontOsc *sound_font_osc,
+ BseTrans *trans)
+{
+ get_sfrepo (sound_font_osc);
+
+ if (BSE_SOURCE_PREPARED (sound_font_osc))
+ {
+ bse_source_update_modules (BSE_SOURCE (sound_font_osc),
+ G_STRUCT_OFFSET (SoundFontOscModule, config),
+ &sound_font_osc->config,
+ sizeof (sound_font_osc->config),
+ trans);
+ }
+}
+
+static void
+sound_font_osc_reset (BseModule *module)
+{
+ SoundFontOscModule *flmod = module->user_data;
+
+ flmod->last_update_preset = -1;
+}
+
+/* process_fluid is only called once per block, not once per module
+ */
+static void
+process_fluid_L (BseSoundFontRepo *sfrepo,
+ fluid_synth_t *fluid_synth,
+ guint64 now_tick_stamp)
+{
+ float **channel_values_left = g_alloca (sfrepo->n_fluid_channels * sizeof (float *));
+ float **channel_values_right = g_alloca (sfrepo->n_fluid_channels * sizeof (float *));
+ float null_fx[BSE_STREAM_MAX_VALUES];
+ float *channel_fx_null[2] = { null_fx, null_fx };
+ int i;
+
+ g_return_if_fail (now_tick_stamp > sfrepo->channel_values_tick_stamp);
+ sfrepo->channel_values_tick_stamp = now_tick_stamp;
+
+ /* Sample precise timing: If events don't occur at block boundary, the block
+ is partially calculated, then the event is executed, and then the rest of
+ the block (until the next event) is calculated, and so on */
+ for (i = 0; i < sfrepo->n_fluid_channels; i++)
+ {
+ channel_values_left[i] = sfrepo->channel_values_left[i];
+ channel_values_right[i] = sfrepo->channel_values_right[i];
+ }
+ guint values_remaining = bse_engine_block_size();
+ while (values_remaining)
+ {
+ /* get 1st event tick stamp */
+ BseFluidEvent *event = NULL;
+ guint64 event_tick_stamp;
+ if (sfrepo->fluid_events)
+ {
+ event = (BseFluidEvent *) sfrepo->fluid_events->data;
+ event_tick_stamp = event->tick_stamp;
+ }
+ else
+ {
+ /* if no event is present, the earliest event that can occur is after this block */
+ event_tick_stamp = now_tick_stamp + values_remaining;
+ }
+ if (event_tick_stamp <= now_tick_stamp) /* past or present event -> process it */
+ {
+ switch (event->command)
+ {
+ case BSE_MIDI_NOTE_ON: fluid_synth_noteon (fluid_synth, event->channel, event->arg1,
event->arg2);
+ sfrepo->n_silence_samples[event->channel] = 0;
+ break;
+ case BSE_MIDI_NOTE_OFF: fluid_synth_noteoff (fluid_synth, event->channel, event->arg1);
+ break;
+ case BSE_MIDI_PITCH_BEND: fluid_synth_pitch_bend (fluid_synth, event->channel, event->arg1);
+ break;
+ case BSE_FLUID_SYNTH_PROGRAM_SELECT:
+ fluid_synth_program_select (fluid_synth, event->channel,
+ event->sfont_id,
+ event->arg1, event->arg2);
+ break;
+ case BSE_MIDI_X_CONTINUOUS_CHANGE:
+ fluid_synth_cc (fluid_synth, event->channel,
+ event->arg1, event->arg2);
+ break;
+ }
+ sfrepo->fluid_events = sfi_ring_remove_node (sfrepo->fluid_events, sfrepo->fluid_events);
+ g_free (event);
+ }
+ else /* future event tick stamp: process audio until
then */
+ {
+ gint64 values_todo = MIN (values_remaining, event_tick_stamp - now_tick_stamp);
+ fluid_synth_nwrite_float (fluid_synth, values_todo,
+ channel_values_left, channel_values_right,
+ channel_fx_null, channel_fx_null);
+ values_remaining -= values_todo;
+ now_tick_stamp += values_todo;
+ for (i = 0; i < sfrepo->n_fluid_channels; i++) /* increment fluid synth output buffer
pointers */
+ {
+ channel_values_left[i] += values_todo;
+ channel_values_right[i] += values_todo;
+ }
+ }
+ }
+}
+
+static void
+sound_font_osc_process (BseModule *module,
+ guint n_values)
+{
+ SoundFontOscModule *flmod = module->user_data;
+ BseSoundFontRepo *sfrepo = flmod->config.sfrepo;
+ fluid_synth_t *fluid_synth = bse_sound_font_repo_lock_fluid_synth (sfrepo);
+ guint i;
+ if (flmod->config.update_preset != flmod->last_update_preset)
+ {
+ fluid_synth_program_select (fluid_synth, flmod->config.sfrepo->channel_map[flmod->config.osc_id],
+ flmod->config.sfont_id, flmod->config.bank,
flmod->config.program);
+ flmod->last_update_preset = flmod->config.update_preset;
+ }
+ gint64 now_tick_stamp = GSL_TICK_STAMP;
+ if (sfrepo->channel_values_tick_stamp != now_tick_stamp)
+ process_fluid_L (sfrepo, fluid_synth, now_tick_stamp);
+
+ float *left_output = sfrepo->channel_values_left[sfrepo->channel_map[flmod->config.osc_id]];
+ float *right_output = sfrepo->channel_values_right[sfrepo->channel_map[flmod->config.osc_id]];
+
+ int delta = bse_module_tick_stamp (module) - now_tick_stamp;
+ if (delta + n_values <= bse_engine_block_size()) /* paranoid check, should always pass */
+ {
+ left_output += delta;
+ right_output += delta;
+ BSE_MODULE_OSTREAM (module, BSE_SOUND_FONT_OSC_OCHANNEL_LEFT_OUT).values = left_output;
+ BSE_MODULE_OSTREAM (module, BSE_SOUND_FONT_OSC_OCHANNEL_RIGHT_OUT).values = right_output;
+ }
+ else
+ {
+ g_warning (G_STRLOC ": access past end of channel_values buffer");
+ }
+ if (BSE_MODULE_OSTREAM (module, BSE_SOUND_FONT_OSC_OCHANNEL_DONE_OUT).connected)
+ {
+ for (i = 0; i < n_values && left_output[i] == 0.0 && right_output[i] == 0.0; i++)
+ ;
+ if (i == n_values)
+ sfrepo->n_silence_samples[sfrepo->channel_map[flmod->config.osc_id]] += n_values;
+ else
+ sfrepo->n_silence_samples[sfrepo->channel_map[flmod->config.osc_id]] = 0;
+ float done = (sfrepo->n_silence_samples[sfrepo->channel_map[flmod->config.osc_id]] > 1024 &&
sfrepo->fluid_events == NULL) ? 1.0 : 0.0;
+ BSE_MODULE_OSTREAM (module, BSE_SOUND_FONT_OSC_OCHANNEL_DONE_OUT).values = bse_engine_const_values
(done);
+ }
+
+ bse_sound_font_repo_unlock_fluid_synth (sfrepo);
+}
+
+static int
+event_cmp (gconstpointer a,
+ gconstpointer b,
+ gpointer data)
+{
+ const BseFluidEvent *event1 = (const BseFluidEvent *) a;
+ const BseFluidEvent *event2 = (const BseFluidEvent *) b;
+
+ if (event1->tick_stamp < event2->tick_stamp)
+ return -1;
+ return (event1->tick_stamp > event2->tick_stamp);
+}
+
+static void
+sound_font_osc_process_midi (gpointer null,
+ BseModule *module,
+ const BseMidiEvent *event,
+ BseTrans *trans)
+{
+ SoundFontOscModule *flmod = module->user_data;
+ bse_sound_font_repo_lock_fluid_synth (flmod->config.sfrepo);
+ int note = bse_note_from_freq (BSE_MUSICAL_TUNING_12_TET, event->data.note.frequency);
+ BseFluidEvent *fluid_event = NULL;
+ switch (event->status)
+ {
+ case BSE_MIDI_NOTE_ON:
+ fluid_event = g_new0 (BseFluidEvent, 1);
+ fluid_event->command = BSE_MIDI_NOTE_ON;
+ fluid_event->arg1 = note;
+ fluid_event->arg2 = event->data.note.velocity * 127;
+ break;
+ case BSE_MIDI_NOTE_OFF:
+ fluid_event = g_new0 (BseFluidEvent, 1);
+ fluid_event->command = BSE_MIDI_NOTE_OFF;
+ fluid_event->arg1 = note;
+ break;
+ case BSE_MIDI_PITCH_BEND:
+ fluid_event = g_new0 (BseFluidEvent, 1);
+ fluid_event->command = BSE_MIDI_PITCH_BEND;
+ /* since midi uses 14 bits, the range is 0x0000 ... 0x3fff
+ * however, since beast uses -1 ... 0 ... 1, we use the formula
+ * below with an output range of 0x0000 ... 0x4000 (but fluid synth
+ * seems to accept these values without trouble) - its also the
+ * inverse of whats done to the input in bsemididecoder.c
+ */
+ fluid_event->arg1 = (event->data.pitch_bend * 0x2000) + 0x2000;
+ break;
+ case BSE_MIDI_CONTROL_CHANGE:
+ case BSE_MIDI_X_CONTINUOUS_CHANGE:
+ fluid_event = g_new0 (BseFluidEvent, 1);
+ fluid_event->command = BSE_MIDI_X_CONTINUOUS_CHANGE;
+ fluid_event->arg1 = event->data.control.control;
+ /* we do the inverse of what the BEAST midi file reading code does;
+ * this means we should be able to replay midi files without loosing
+ * any information - however, since midi information has no sign,
+ * we truncate negative numbers to zero
+ *
+ * FIXME: it would be possible to do an almost loss free conversion
+ * if the beast representation of controls would be more MIDI like
+ */
+ fluid_event->arg2 = CLAMP (event->data.control.value * 127, 0, 127);
+ break;
+ case BSE_MIDI_PROGRAM_CHANGE:
+ /* programs should be set at track level, and are thus not changeable here */
+ break;
+ default:
+ printf ("BseSoundFontOsc: unhandled status %02x\n", event->status);
+ break;
+ }
+ if (fluid_event)
+ {
+ fluid_event->tick_stamp = event->delta_time;
+ fluid_event->channel = flmod->config.sfrepo->channel_map[flmod->config.osc_id];
+ flmod->config.sfrepo->fluid_events = sfi_ring_insert_sorted (flmod->config.sfrepo->fluid_events,
fluid_event, event_cmp, NULL);
+ }
+ bse_sound_font_repo_unlock_fluid_synth (flmod->config.sfrepo);
+}
+
+typedef struct
+{
+ BseMidiReceiver *midi_receiver;
+ guint midi_channel;
+ BseModule *module;
+} EventHandlerSetup;
+
+static void
+event_handler_setup_func (BseModule *module,
+ void *ehs_data)
+{
+ EventHandlerSetup *ehs = (EventHandlerSetup *)ehs_data;
+ bse_midi_receiver_add_event_handler (ehs->midi_receiver,
+ ehs->midi_channel,
+ sound_font_osc_process_midi,
+ NULL,
+ ehs->module);
+
+ /* setup program before first midi event */
+ SoundFontOscModule *flmod = module->user_data;
+
+ BseFluidEvent *fluid_event = g_new0 (BseFluidEvent, 1);
+ fluid_event->command = BSE_FLUID_SYNTH_PROGRAM_SELECT;
+ fluid_event->channel = flmod->config.sfrepo->channel_map[flmod->config.osc_id];
+ fluid_event->arg1 = flmod->config.bank;
+ fluid_event->arg2 = flmod->config.program;
+ fluid_event->sfont_id = flmod->config.sfont_id;
+ fluid_event->tick_stamp = 0; /* now */
+ flmod->config.sfrepo->fluid_events = sfi_ring_insert_sorted (flmod->config.sfrepo->fluid_events,
fluid_event, event_cmp, NULL);
+}
+
+static void
+bse_sound_font_osc_context_create (BseSource *source,
+ guint context_handle,
+ BseTrans *trans)
+{
+ static const BseModuleClass sound_font_osc_class = {
+ 0, /* n_istreams */
+ 0, /* n_jstreams */
+ BSE_SOUND_FONT_OSC_N_OCHANNELS, /* n_ostreams */
+ sound_font_osc_process, /* process */
+ NULL, /* process_defer */
+ sound_font_osc_reset, /* reset */
+ (BseModuleFreeFunc) g_free, /* free */
+ BSE_COST_CHEAP, /* flags */
+ };
+ SoundFontOscModule *sound_font_osc = g_new0 (SoundFontOscModule, 1);
+ BseModule *module;
+
+ module = bse_module_new (&sound_font_osc_class, sound_font_osc);
+
+ /* setup module i/o streams with BseSource i/o channels */
+ bse_source_set_context_module (source, context_handle, module);
+
+ /* commit module to engine */
+ bse_trans_add (trans, bse_job_integrate (module));
+
+ /* chain parent class' handler */
+ BSE_SOURCE_CLASS (parent_class)->context_create (source, context_handle, trans);
+
+ /* update (initialize) module data */
+ bse_sound_font_osc_update_modules (BSE_SOUND_FONT_OSC (source), trans);
+
+ /* setup midi event handler */
+ EventHandlerSetup *ehs = g_new0 (EventHandlerSetup, 1);
+ BseMidiContext mc = bse_snet_get_midi_context (bse_item_get_snet (BSE_ITEM (source)), context_handle);
+ ehs->midi_receiver = mc.midi_receiver;
+ ehs->midi_channel = mc.midi_channel;
+ ehs->module = module;
+ bse_trans_add (trans, bse_job_access (module, event_handler_setup_func, ehs, g_free));
+
+ /* reset fluid synth if necessary */
+ BseSoundFontOsc *self = BSE_SOUND_FONT_OSC (source);
+ fluid_synth_t *fluid_synth = bse_sound_font_repo_lock_fluid_synth (self->config.sfrepo);
+ if (self->config.sfrepo->n_channel_oscs_active == 0)
+ fluid_synth_system_reset (fluid_synth);
+ self->config.sfrepo->n_channel_oscs_active++;
+ bse_sound_font_repo_unlock_fluid_synth (self->config.sfrepo);
+}
+
+static void
+bse_sound_font_osc_context_dismiss (BseSource *source,
+ guint context_handle,
+ BseTrans *trans)
+{
+ BseSoundFontOsc *self = BSE_SOUND_FONT_OSC (source);
+ BseModule *module = bse_source_get_context_omodule (source, context_handle);
+ BseMidiContext mc = bse_snet_get_midi_context (bse_item_get_snet (BSE_ITEM (source)), context_handle);
+ bse_midi_receiver_remove_event_handler (mc.midi_receiver,
+ mc.midi_channel,
+ sound_font_osc_process_midi,
+ NULL,
+ module);
+ /* remove old events from the event queue */
+ bse_sound_font_repo_lock_fluid_synth (self->config.sfrepo);
+ SfiRing *fluid_events = self->config.sfrepo->fluid_events;
+ SfiRing *node = fluid_events;
+ while (node)
+ {
+ SfiRing *next_node = sfi_ring_walk (node, fluid_events);
+ BseFluidEvent *event = node->data;
+ if (event->channel == self->config.sfrepo->channel_map[self->config.osc_id])
+ {
+ g_free (event);
+ fluid_events = sfi_ring_remove_node (fluid_events, node);
+ }
+ node = next_node;
+ }
+ self->config.sfrepo->n_channel_oscs_active--;
+ self->config.sfrepo->fluid_events = fluid_events;
+ bse_sound_font_repo_unlock_fluid_synth (self->config.sfrepo);
+ /* chain parent class' handler */
+ BSE_SOURCE_CLASS (parent_class)->context_dismiss (source, context_handle, trans);
+}
diff --git a/bse/bsesoundfontosc.h b/bse/bsesoundfontosc.h
new file mode 100644
index 0000000..395e217
--- /dev/null
+++ b/bse/bsesoundfontosc.h
@@ -0,0 +1,78 @@
+/* BseSoundFontOsc - BSE Fluid Synth sound font player
+ * Copyright (C) 1999-2002 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_OSC_H__
+#define __BSE_SOUND_FONT_OSC_H__
+
+#include <bse/bsesource.h>
+#include <bse/bsesoundfontpreset.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+
+
+/* --- object type macros --- */
+#define BSE_TYPE_SOUND_FONT_OSC (BSE_TYPE_ID (BseSoundFontOsc))
+#define BSE_SOUND_FONT_OSC(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), BSE_TYPE_SOUND_FONT_OSC,
BseSoundFontOsc))
+#define BSE_SOUND_FONT_OSC_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class),
BSE_TYPE_SOUND_FONT_OSC, BseSoundFontOscClass))
+#define BSE_IS_SOUND_FONT_OSC(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), BSE_TYPE_SOUND_FONT_OSC))
+#define BSE_IS_SOUND_FONT_OSC_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), BSE_TYPE_SOUND_FONT_OSC))
+#define BSE_SOUND_FONT_OSC_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), BSE_TYPE_SOUND_FONT_OSC,
BseSoundFontOscClass))
+
+enum
+{
+ BSE_SOUND_FONT_OSC_OCHANNEL_LEFT_OUT,
+ BSE_SOUND_FONT_OSC_OCHANNEL_RIGHT_OUT,
+ BSE_SOUND_FONT_OSC_OCHANNEL_DONE_OUT,
+ BSE_SOUND_FONT_OSC_N_OCHANNELS
+};
+
+/* --- BseSoundFontOsc source --- */
+typedef struct _BseSoundFontOsc BseSoundFontOsc;
+typedef struct _BseSoundFontOscClass BseSoundFontOscClass;
+typedef struct _BseSoundFontOscConfig BseSoundFontOscConfig;
+struct _BseSoundFontOscConfig
+{
+ int osc_id;
+ int sfont_id;
+ int bank;
+ int program;
+ BseSoundFontRepo *sfrepo;
+
+ int update_preset; /* preset changed indicator */
+};
+struct _BseSoundFontOsc
+{
+ BseSource parent_object;
+ BseSoundFontPreset *preset;
+ BseSoundFontOscConfig config;
+};
+struct _BseSoundFontOscClass
+{
+ BseSourceClass parent_class;
+};
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __BSE_SOUND_FONT_OSC_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]