[beast: 38/95] BSE: fully port Sequencer to C++ and std::thread
- From: Tim Janik <timj src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [beast: 38/95] BSE: fully port Sequencer to C++ and std::thread
- Date: Mon, 25 Mar 2013 00:39:42 +0000 (UTC)
commit 53fc0a29b84d2a23c8a1be02c373565b617ac57b
Author: Tim Janik <timj gnu org>
Date: Sat Mar 16 22:19:07 2013 +0100
BSE: fully port Sequencer to C++ and std::thread
bse/bsemain.cc | 5 +-
bse/bsemain.hh | 3 -
bse/bsemididevice-oss.cc | 4 +-
bse/bsepart.cc | 2 +-
bse/bsepcmdevice-null.cc | 6 +-
bse/bseproject.cc | 4 +-
bse/bsesequencer.cc | 342 +++++++++++++++++++----------------------
bse/bsesequencer.hh | 67 ++++++---
bse/bsesong.cc | 4 +-
bse/bsetrack.cc | 2 +-
drivers/bsemididevice-alsa.cc | 4 +-
11 files changed, 219 insertions(+), 224 deletions(-)
---
diff --git a/bse/bsemain.cc b/bse/bsemain.cc
index 6e72337..fd24a75 100644
--- a/bse/bsemain.cc
+++ b/bse/bsemain.cc
@@ -35,7 +35,6 @@ const guint bse_interface_age = BSE_INTERFACE_AGE;
const guint bse_binary_age = BSE_BINARY_AGE;
const gchar *bse_version = BSE_VERSION;
GMainContext *bse_main_context = NULL;
-BirnetMutex bse_main_sequencer_mutex = { 0, };
static volatile gboolean bse_initialization_stage = 0;
static gboolean textdomain_setup = FALSE;
static BseMainArgs default_main_args = {
@@ -180,7 +179,6 @@ static void
bse_init_core (void)
{
/* global threading things */
- sfi_mutex_init (&bse_main_sequencer_mutex);
bse_main_context = g_main_context_new ();
sfi_thread_set_wakeup ((BirnetThreadWakeup) g_main_context_wakeup,
bse_main_context, NULL);
@@ -334,7 +332,8 @@ bse_main_loop (Rapicorn::AsyncBlockingQueue<int> *init_queue)
Bse::TaskRegistry::add ("BSE Core", Rapicorn::ThisThread::process_pid(),
Rapicorn::ThisThread::thread_pid());
bse_init_core ();
// start other threads
- bse_sequencer_init_thread ();
+ struct Internal : Bse::Sequencer { using Bse::Sequencer::_init_threaded; };
+ Internal::_init_threaded();
// complete initialization
bse_initialization_stage++; // = 2
init_queue->push ('B'); // signal completion to caller
diff --git a/bse/bsemain.hh b/bse/bsemain.hh
index 2a20be0..8b6c993 100644
--- a/bse/bsemain.hh
+++ b/bse/bsemain.hh
@@ -32,8 +32,6 @@ void bse_message_to_default_handler (const BseMessage *msg);
/* --- global macros --- */
#define BSE_THREADS_ENTER() // bse_main_global_lock ()
#define BSE_THREADS_LEAVE() // bse_main_global_unlock ()
-#define BSE_SEQUENCER_LOCK() sfi_mutex_lock (&bse_main_sequencer_mutex)
-#define BSE_SEQUENCER_UNLOCK() sfi_mutex_unlock (&bse_main_sequencer_mutex)
#define BSE_DBG_EXT (bse_main_args->debug_extensions != FALSE)
#define BSE_CONFIG(field) (bse_main_args->field)
/* --- argc/argv overide settings --- */
@@ -79,7 +77,6 @@ void _bse_init_c_wrappers ();
extern BseMainArgs *bse_main_args;
extern BseTraceArgs bse_trace_args;
extern GMainContext *bse_main_context;
-extern BirnetMutex bse_main_sequencer_mutex;
G_END_DECLS
diff --git a/bse/bsemididevice-oss.cc b/bse/bsemididevice-oss.cc
index c178d9c..7bc9dae 100644
--- a/bse/bsemididevice-oss.cc
+++ b/bse/bsemididevice-oss.cc
@@ -152,7 +152,7 @@ bse_midi_device_oss_open (BseDevice *device,
GPollFD pfd = { 0, };
pfd.fd = oss->fd;
pfd.events = G_IO_IN;
- bse_sequencer_add_io_watch (1, &pfd, oss_midi_io_handler, oss);
+ Bse::Sequencer::instance().add_io_watch (1, &pfd, oss_midi_io_handler, oss);
}
else
{
@@ -171,7 +171,7 @@ bse_midi_device_oss_close (BseDevice *device)
BSE_MIDI_DEVICE (device)->handle = NULL;
g_assert (handle->running_thread == FALSE);
/* midi_handle_abort_wait (handle); */
- bse_sequencer_remove_io_watch (oss_midi_io_handler, oss);
+ Bse::Sequencer::instance().remove_io_watch (oss_midi_io_handler, oss);
(void) close (oss->fd);
g_free (oss);
}
diff --git a/bse/bsepart.cc b/bse/bsepart.cc
index d6951be..e01d2b9 100644
--- a/bse/bsepart.cc
+++ b/bse/bsepart.cc
@@ -1,6 +1,6 @@
// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#include "bsepart.hh"
-#include "bsemain.hh"
+#include "bsesequencer.hh"
#include "bsestorage.hh"
#include "bsesong.hh"
#include "bsetrack.hh"
diff --git a/bse/bsepcmdevice-null.cc b/bse/bsepcmdevice-null.cc
index 088b41a..b8f13cb 100644
--- a/bse/bsepcmdevice-null.cc
+++ b/bse/bsepcmdevice-null.cc
@@ -66,16 +66,18 @@ bse_pcm_device_null_close (BseDevice *device)
BSE_PCM_DEVICE (device)->handle = NULL;
g_free (null);
}
+
static gboolean
null_device_check_io (BsePcmHandle *handle,
glong *timeoutp)
{
/* keep the sequencer busy or we will constantly timeout */
- bse_sequencer_wakeup();
+ Bse::Sequencer::instance().wakeup();
*timeoutp = 1;
/* ensure sequencer fairness */
- return !bse_sequencer_thread_lagging (2);
+ return !Bse::Sequencer::instance().thread_lagging (2);
}
+
static guint
null_device_latency (BsePcmHandle *handle)
{
diff --git a/bse/bseproject.cc b/bse/bseproject.cc
index ff9a314..7316736 100644
--- a/bse/bseproject.cc
+++ b/bse/bseproject.cc
@@ -749,7 +749,7 @@ bse_project_start_playback (BseProject *self)
bse_project_state_changed (self, BSE_PROJECT_PLAYING);
/* then, start the sequencer */
while (songs)
- bse_sequencer_start_song ((BseSong*) sfi_ring_pop_head (&songs), 0);
+ Bse::Sequencer::instance().start_song ((BseSong*) sfi_ring_pop_head (&songs), 0);
}
void
bse_project_stop_playback (BseProject *self)
@@ -765,7 +765,7 @@ bse_project_stop_playback (BseProject *self)
{
BseSuper *super = BSE_SUPER (slist->data);
if (BSE_IS_SONG (super))
- bse_sequencer_remove_song (BSE_SONG (super));
+ Bse::Sequencer::instance().remove_song (BSE_SONG (super));
if (super->context_handle != ~uint (0) && BSE_SUPER_NEEDS_CONTEXT (super))
{
BseSource *source = BSE_SOURCE (super);
diff --git a/bse/bsesequencer.cc b/bse/bsesequencer.cc
index 9719aeb..d8bc498 100644
--- a/bse/bsesequencer.cc
+++ b/bse/bsesequencer.cc
@@ -15,61 +15,31 @@
#include <errno.h>
#include <string.h>
#include <vector>
-using namespace std; // FIXME
-
-/* due to a linker/compiler bug on SuSE 9.2, we need to
- * define extern "C" symbols outside of any C++ namespace,
- * in order for C code to link against it.
- */
-extern "C" { BirnetThread *bse_sequencer_thread = NULL; }
#define CHECKTRACE() UNLIKELY (bse_trace_args.sequencer)
#define SEQTRACE(...) do { if (CHECKTRACE()) sfi_debug_channel_printf (bse_trace_args.sequencer, NULL,
__VA_ARGS__); } while (0)
#define BSE_SEQUENCER_FUTURE_BLOCKS (7)
-/* --- prototypes --- */
-static void bse_sequencer_thread_main (gpointer data);
-static void bse_sequencer_process_song_SL (BseSong *song,
- guint n_ticks);
-/* --- variables --- */
-static BseSequencer *global_sequencer = NULL;
-static BirnetCond current_watch_cond = { 0, };
-static gint sequencer_wake_up_pipe[2] = { -1, -1 };
+namespace Bse {
-/* --- functions --- */
-extern "C" void
-bse_sequencer_init_thread (void)
-{
- g_assert (bse_sequencer_thread == NULL);
- sfi_cond_init (¤t_watch_cond);
- if (pipe (sequencer_wake_up_pipe) < 0)
- g_error ("failed to create sequencer wake-up pipe: %s", strerror (errno));
- glong flags = fcntl (sequencer_wake_up_pipe[0], F_GETFL, 0);
- fcntl (sequencer_wake_up_pipe[0], F_SETFL, O_NONBLOCK | flags);
- flags = fcntl (sequencer_wake_up_pipe[1], F_GETFL, 0);
- fcntl (sequencer_wake_up_pipe[1], F_SETFL, O_NONBLOCK | flags);
- /* initialize BseSequencer */
- static BseSequencer sseq = { 0, };
- sseq.stamp = Bse::TickStamp::current();
- g_assert (sseq.stamp > 0);
- global_sequencer = &sseq;
- bse_sequencer_thread = sfi_thread_run ("Sequencer", bse_sequencer_thread_main, NULL);
- if (!bse_sequencer_thread)
- g_error ("failed to create sequencer thread");
-}
+using Rapicorn::ThreadInfo; // FIXME
+
+Sequencer *Sequencer::singleton_ = NULL;
+Mutex Sequencer::sequencer_mutex_;
+static int sequencer_wake_up_pipe[2] = { -1, -1 };
+static ThreadInfo *sequencer_thread_self = NULL;
void
-bse_sequencer_wakeup ()
+Sequencer::wakeup ()
{
- guint8 wake_up_message = 'W';
- gint err;
+ uint8 wake_up_message = 'W';
+ int err;
do
err = write (sequencer_wake_up_pipe[1], &wake_up_message, 1);
while (err < 0 && errno == EINTR);
}
-namespace { // Anon
-class PollPool {
+class Sequencer::PollPool {
public:
struct IOWatch {
BseIOWatch watch_func;
@@ -170,32 +140,29 @@ public:
BIRNET_STATIC_ASSERT (offsetof (GPollFD, revents) == offsetof (struct pollfd, revents));
BIRNET_STATIC_ASSERT (sizeof (((GPollFD*) 0)->revents) == sizeof (((struct pollfd*) 0)->revents));
};
-} // Anon
-static PollPool sequencer_poll_pool;
-extern "C" void
-bse_sequencer_add_io_watch (guint n_pfds,
- const GPollFD *pfds,
- BseIOWatch watch_func,
- gpointer data)
+
+void
+Sequencer::add_io_watch (uint n_pfds, const GPollFD *pfds, BseIOWatch watch_func, void *watch_data)
{
g_return_if_fail (watch_func != NULL);
- BSE_SEQUENCER_LOCK ();
- sequencer_poll_pool.add_watch (n_pfds, pfds, watch_func, data);
- BSE_SEQUENCER_UNLOCK ();
+ BSE_SEQUENCER_LOCK();
+ poll_pool_->add_watch (n_pfds, pfds, watch_func, watch_data);
+ BSE_SEQUENCER_UNLOCK();
}
-static BseIOWatch current_watch_func = NULL;
+
+static BseIOWatch current_watch_func = NULL; // global guards allow removal of watch function while it's
in use
static gpointer current_watch_data = NULL;
static bool current_watch_needs_remove1 = false;
static bool current_watch_needs_remove2 = false;
-extern "C" void
-bse_sequencer_remove_io_watch (BseIOWatch watch_func,
- gpointer watch_data)
+
+void
+Sequencer::remove_io_watch (BseIOWatch watch_func, void *watch_data)
{
g_return_if_fail (watch_func != NULL);
/* removal requirements:
* - any thread should be able to remove an io watch (once)
* - a watch_func() should be able to remove its own io watch
- * - a watch_func() may not get called after bse_sequencer_remove_io_watch()
+ * - a watch_func() may not get called after remove_io_watch()
* finished in any thread
* - concurrent removal of an io watch from within its watch_func() (executed
* within the sequencer thread) and from an external thread at the same
@@ -204,10 +171,10 @@ bse_sequencer_remove_io_watch (BseIOWatch watch_func,
* least conceptually) or has never been installed
*/
bool removal_success;
- BSE_SEQUENCER_LOCK ();
+ BSE_SEQUENCER_LOCK();
if (current_watch_func == watch_func && current_watch_data == watch_data)
{ /* watch_func() to be removed is currently in call */
- if (bse_sequencer_thread == sfi_thread_self())
+ if (&ThreadInfo::self() == sequencer_thread_self)
{
/* allow removal calls from within a watch_func() */
removal_success = !current_watch_needs_remove1; /* catch multiple calls */
@@ -220,37 +187,39 @@ bse_sequencer_remove_io_watch (BseIOWatch watch_func,
current_watch_needs_remove2 = true;
/* wait until watch_func() call has finished */
while (current_watch_func == watch_func && current_watch_data == watch_data)
- sfi_cond_wait (¤t_watch_cond, &bse_main_sequencer_mutex);
+ watch_cond_.wait (sequencer_mutex_);
}
}
else /* can remove (watch_func(watch_data) not in call) */
{
- removal_success = sequencer_poll_pool.remove_watch (watch_func, watch_data);
+ removal_success = poll_pool_->remove_watch (watch_func, watch_data);
/* wake up sequencer thread, so it stops polling on fds it doesn't own anymore */
- bse_sequencer_wakeup();
+ wakeup();
}
- BSE_SEQUENCER_UNLOCK ();
+ BSE_SEQUENCER_UNLOCK();
if (!removal_success)
g_warning ("%s: failed to remove %p(%p)", G_STRFUNC, watch_func, watch_data);
}
-static bool
-bse_sequencer_poll_Lm (gint timeout_ms)
+
+bool
+Sequencer::pool_poll_Lm (gint timeout_ms)
{
- guint n_pfds = sequencer_poll_pool.get_n_pfds() + 1; /* one for the wake-up pipe */
+ guint n_pfds = poll_pool_->get_n_pfds() + 1; /* one for the wake-up pipe */
GPollFD *pfds = g_newa (GPollFD, n_pfds);
pfds[0].fd = sequencer_wake_up_pipe[0];
pfds[0].events = G_IO_IN;
pfds[0].revents = 0;
- sequencer_poll_pool.fill_pfds (n_pfds - 1, pfds + 1); /* rest used for io watch array */
- BSE_SEQUENCER_UNLOCK ();
- gint result = poll ((struct pollfd*) pfds, n_pfds, timeout_ms);
+ poll_pool_->fill_pfds (n_pfds - 1, pfds + 1); /* rest used for io watch array */
+ BSE_SEQUENCER_UNLOCK();
+ int result = poll ((struct pollfd*) pfds, n_pfds, timeout_ms);
if (result < 0 && errno != EINTR)
g_printerr ("%s: poll() error: %s\n", G_STRFUNC, g_strerror (errno));
- BSE_SEQUENCER_LOCK ();
+ BSE_SEQUENCER_LOCK();
if (result > 0 && pfds[0].revents)
{
guint8 buffer[256];
- read (sequencer_wake_up_pipe[0], buffer, 256); /* eat wake up message */
+ const size_t unused = read (sequencer_wake_up_pipe[0], buffer, 256); // eat wake up message
+ (void) unused;
result -= 1;
}
if (result > 0)
@@ -258,39 +227,38 @@ bse_sequencer_poll_Lm (gint timeout_ms)
/* dispatch io watches */
guint watch_n_pfds;
GPollFD *watch_pfds;
- while (sequencer_poll_pool.fetch_notify_watch (current_watch_func, current_watch_data, watch_n_pfds,
watch_pfds))
+ while (poll_pool_->fetch_notify_watch (current_watch_func, current_watch_data, watch_n_pfds,
watch_pfds))
{
g_assert (!current_watch_needs_remove1 && !current_watch_needs_remove2);
- BSE_SEQUENCER_UNLOCK ();
+ BSE_SEQUENCER_UNLOCK();
bool current_watch_stays_alive = current_watch_func (current_watch_data, watch_n_pfds, watch_pfds);
- BSE_SEQUENCER_LOCK ();
- if (current_watch_needs_remove1 || /* removal queued from within io handler */
- current_watch_needs_remove2 || /* removal queued from other thread */
- !current_watch_stays_alive) /* removal requested by io handler return value */
- sequencer_poll_pool.remove_watch (current_watch_func, current_watch_data);
+ BSE_SEQUENCER_LOCK();
+ if (current_watch_needs_remove1 || // removal queued from within io handler
+ current_watch_needs_remove2 || // removal queued from other thread
+ !current_watch_stays_alive) // removal requested by io handler return value
+ poll_pool_->remove_watch (current_watch_func, current_watch_data);
current_watch_needs_remove1 = false;
current_watch_needs_remove2 = false;
current_watch_func = NULL;
current_watch_data = NULL;
- sfi_cond_broadcast (¤t_watch_cond); /* wake up threads in
bse_sequencer_remove_io_watch() */
+ watch_cond_.broadcast(); // wake up threads in remove_io_watch()
}
}
- return !sfi_thread_aborted();
+ return true;
}
-extern "C" void
-bse_sequencer_start_song (BseSong *song,
- guint64 start_stamp)
+
+void
+Sequencer::start_song (BseSong *song, uint64 start_stamp)
{
- g_assert (bse_sequencer_thread != NULL);
g_return_if_fail (BSE_IS_SONG (song));
g_return_if_fail (BSE_SOURCE_PREPARED (song));
g_return_if_fail (song->sequencer_start_request_SL == 0);
- g_assert (song->sequencer_owns_refcount_SL == FALSE);
+ g_assert (song->sequencer_owns_refcount_SL == false);
start_stamp = MAX (start_stamp, 1);
g_object_ref (song);
- BSE_SEQUENCER_LOCK ();
- song->sequencer_owns_refcount_SL = TRUE;
- song->sequencer_start_request_SL = start_stamp <= 1 ? global_sequencer->stamp : start_stamp;
+ BSE_SEQUENCER_LOCK();
+ song->sequencer_owns_refcount_SL = true;
+ song->sequencer_start_request_SL = start_stamp <= 1 ? stamp_ : start_stamp;
song->sequencer_start_SL = 0;
song->sequencer_done_SL = 0;
song->delta_stamp_SL = 0;
@@ -301,83 +269,89 @@ bse_sequencer_start_song (BseSong *song,
BseTrack *track = (BseTrack*) ring->data;
track->track_done_SL = FALSE;
}
- global_sequencer->songs = sfi_ring_append (global_sequencer->songs, song);
- BSE_SEQUENCER_UNLOCK ();
- bse_sequencer_wakeup();
+ songs_ = sfi_ring_append (songs_, song);
+ BSE_SEQUENCER_UNLOCK();
+ wakeup();
}
-extern "C" void
-bse_sequencer_remove_song (BseSong *song)
+
+void
+Sequencer::remove_song (BseSong *song)
{
g_return_if_fail (BSE_IS_SONG (song));
g_return_if_fail (BSE_SOURCE_PREPARED (song));
if (song->sequencer_start_request_SL == 0)
{
- g_assert (song->sequencer_owns_refcount_SL == FALSE);
- return; /* uncontained */
+ g_assert (song->sequencer_owns_refcount_SL == false);
+ return; // uncontained
}
- BSE_SEQUENCER_LOCK ();
- SfiRing *ring = sfi_ring_find (global_sequencer->songs, song);
- global_sequencer->songs = sfi_ring_remove_node (global_sequencer->songs, ring);
+ BSE_SEQUENCER_LOCK();
+ SfiRing *ring = sfi_ring_find (songs_, song);
+ songs_ = sfi_ring_remove_node (songs_, ring);
song->sequencer_start_request_SL = 0;
if (!song->sequencer_done_SL)
- song->sequencer_done_SL = global_sequencer->stamp;
+ song->sequencer_done_SL = stamp_;
if (!song->sequencer_start_SL)
song->sequencer_start_SL = song->sequencer_done_SL;
- gboolean need_unref = song->sequencer_owns_refcount_SL;
- song->sequencer_owns_refcount_SL = FALSE;
- BSE_SEQUENCER_UNLOCK ();
+ bool need_unref = song->sequencer_owns_refcount_SL;
+ song->sequencer_owns_refcount_SL = false;
+ BSE_SEQUENCER_UNLOCK();
if (!ring)
g_warning ("%s: failed to find %s in sequencer", G_STRLOC, bse_object_debug_name (song));
if (need_unref)
g_object_unref (song);
}
-static gboolean
-bse_sequencer_remove_song_async (gpointer data) /* UserThread */
+
+static int
+sequencer_remove_song_async (gpointer data) /* UserThread */
{
BseSong *song = BSE_SONG (data);
- if (BSE_SOURCE_PREPARED (song) && /* project might be deactivated already */
- song->sequencer_done_SL) /* song might have been removed and re-added */
+ if (BSE_SOURCE_PREPARED (song) && // project might be deactivated already
+ song->sequencer_done_SL) // song might have been removed and re-added
{
- bse_sequencer_remove_song (song);
+ Sequencer::instance().remove_song (song);
BseProject *project = bse_item_get_project (BSE_ITEM (song));
bse_project_check_auto_stop (project);
}
- g_object_unref (song); /* sequencer_owns_refcount_SL = FALSE from
bse_sequencer_queue_remove_song_SL() */
- return FALSE;
+ g_object_unref (song); // sequencer_owns_refcount_SL = false; from
sequencer_queue_remove_song_SL()
+ return false;
}
+
static void
-bse_sequencer_queue_remove_song_SL (BseSong *song)
+sequencer_queue_remove_song_SL (BseSong *song)
{
- g_return_if_fail (song->sequencer_owns_refcount_SL == TRUE);
- song->sequencer_owns_refcount_SL = FALSE; /* g_object_unref() in bse_sequencer_remove_song_async() */
- /* queue a job into the BSE core for immediate execution */
- bse_idle_now (bse_sequencer_remove_song_async, song);
+ g_return_if_fail (song->sequencer_owns_refcount_SL == true);
+ song->sequencer_owns_refcount_SL = false; // g_object_unref() in sequencer_remove_song_async()
+ // queue a job into the BSE core for immediate execution
+ bse_idle_now (sequencer_remove_song_async, song);
}
-extern "C" gboolean
-bse_sequencer_thread_lagging (guint n_blocks)
+
+bool
+Sequencer::thread_lagging (uint n_blocks)
{
- /* return whether the sequencer lags for n_blocks future stamps */
- const guint64 cur_stamp = Bse::TickStamp::current();
- guint64 next_stamp = cur_stamp + n_blocks * bse_engine_block_size();
- BSE_SEQUENCER_LOCK ();
- gboolean lagging = global_sequencer->stamp < next_stamp;
- BSE_SEQUENCER_UNLOCK ();
+ // return whether the sequencer lags for n_blocks future stamps
+ const uint64 cur_stamp = Bse::TickStamp::current();
+ uint64 next_stamp = cur_stamp + n_blocks * bse_engine_block_size();
+ BSE_SEQUENCER_LOCK();
+ bool lagging = stamp_ < next_stamp;
+ BSE_SEQUENCER_UNLOCK();
return lagging;
}
-static void
-bse_sequencer_thread_main (gpointer data)
+
+void
+Sequencer::sequencer_thread ()
{
Bse::TaskRegistry::add ("Sequencer", Rapicorn::ThisThread::process_pid(),
Rapicorn::ThisThread::thread_pid());
+ sequencer_thread_self = &ThreadInfo::self();
SEQTRACE ("SEQ:thrdstrt: now=%llu", Bse::TickStamp::current());
- Bse::TickStampWakeupP wakeup = Bse::TickStamp::create_wakeup (bse_sequencer_wakeup);
+ Bse::TickStampWakeupP wakeup = Bse::TickStamp::create_wakeup ([&]() { this->wakeup(); });
bse_message_setup_thread_handler();
- BSE_SEQUENCER_LOCK ();
+ BSE_SEQUENCER_LOCK();
do
{
const guint64 cur_stamp = Bse::TickStamp::current();
guint64 next_stamp = cur_stamp + BSE_SEQUENCER_FUTURE_BLOCKS * bse_engine_block_size();
SfiRing *ring;
- for (ring = global_sequencer->songs; ring; ring = sfi_ring_walk (ring, global_sequencer->songs))
+ for (ring = songs_; ring; ring = sfi_ring_walk (ring, songs_))
{
BseSong *song = BSE_SONG (ring->data);
bool forced_ticks = 0;
@@ -403,7 +377,7 @@ bse_sequencer_thread_main (gpointer data)
}
if (n_ticks < 1)
break;
- bse_sequencer_process_song_SL (song, n_ticks);
+ process_song_SL (song, n_ticks);
stamp_diff = (next_stamp - song->sequencer_start_SL) - song->delta_stamp_SL;
}
if (old_song_pos <= cur_stamp && !song_starting) /* detect underrun after song start */
@@ -411,32 +385,24 @@ bse_sequencer_thread_main (gpointer data)
gchar *dh = bse_object_strdup_debug_handle (song); /* thread safe */
/* if (!song->sequencer_underrun_detected_SL) */
g_printerr ("BseSequencer: underrun by %lld blocks for song: %s\n",
- (cur_stamp - old_song_pos) / bse_engine_block_size() + 1,
+ uint64 ((cur_stamp - old_song_pos) / bse_engine_block_size() + 1),
dh);
song->sequencer_underrun_detected_SL = TRUE;
g_free (dh);
}
}
}
- global_sequencer->stamp = next_stamp;
+ stamp_ = next_stamp;
wakeup->awake_after (cur_stamp + bse_engine_block_size ());
}
- while (bse_sequencer_poll_Lm (-1));
- BSE_SEQUENCER_UNLOCK ();
+ while (pool_poll_Lm (-1));
+ BSE_SEQUENCER_UNLOCK();
SEQTRACE ("SEQ:thrdstop: now=%llu", Bse::TickStamp::current());
Bse::TaskRegistry::remove (Rapicorn::ThisThread::thread_pid());
}
-static void
-bse_sequencer_process_track_SL (BseTrack *track,
- gdouble start_stamp,
- guint start_tick,
- guint n_ticks,
- gdouble stamps_per_tick,
- BseMidiReceiver *midi_receiver);
-static gboolean
-bse_sequencer_process_song_unlooped_SL (BseSong *song,
- guint n_ticks,
- gboolean force_active_tracks)
+
+bool
+Sequencer::process_song_unlooped_SL (BseSong *song, uint n_ticks, bool force_active_tracks)
{
BseMidiReceiver *midi_receiver = song->midi_receiver_SL;
gdouble current_stamp = song->sequencer_start_SL + song->delta_stamp_SL;
@@ -452,10 +418,7 @@ bse_sequencer_process_song_unlooped_SL (BseSong *song,
if (!track->track_done_SL || force_active_tracks)
{
track->track_done_SL = FALSE;
- bse_sequencer_process_track_SL (track, current_stamp,
- song->tick_SL, tick_bound,
- stamps_per_tick,
- midi_receiver);
+ process_track_SL (track, current_stamp, song->tick_SL, tick_bound, stamps_per_tick, midi_receiver);
}
if (track->track_done_SL)
n_done_tracks++;
@@ -465,9 +428,9 @@ bse_sequencer_process_song_unlooped_SL (BseSong *song,
song->delta_stamp_SL += n_ticks * stamps_per_tick;
return n_done_tracks != n_tracks;
}
-static void
-bse_sequencer_process_song_SL (BseSong *song,
- guint n_ticks)
+
+void
+Sequencer::process_song_SL (BseSong *song, uint n_ticks)
{
gboolean tracks_active = TRUE;
if (song->loop_enabled_SL && (gint64) song->tick_SL <= song->loop_right_SL)
@@ -476,7 +439,7 @@ bse_sequencer_process_song_SL (BseSong *song,
guint tdiff = song->loop_right_SL - song->tick_SL;
tdiff = MIN (tdiff, n_ticks);
if (tdiff)
- bse_sequencer_process_song_unlooped_SL (song, tdiff, TRUE);
+ process_song_unlooped_SL (song, tdiff, true);
n_ticks -= tdiff;
if ((gint64) song->tick_SL >= song->loop_right_SL)
{
@@ -485,30 +448,20 @@ bse_sequencer_process_song_SL (BseSong *song,
}
while (n_ticks);
else
- tracks_active = bse_sequencer_process_song_unlooped_SL (song, n_ticks, FALSE);
+ tracks_active = process_song_unlooped_SL (song, n_ticks, false);
if (!song->sequencer_done_SL && !tracks_active)
{
- song->sequencer_done_SL = global_sequencer->stamp;
- bse_sequencer_queue_remove_song_SL (song);
+ song->sequencer_done_SL = stamp_;
+ sequencer_queue_remove_song_SL (song);
}
}
-static void
-bse_sequencer_process_part_SL (BsePart *part,
- gdouble start_stamp,
- guint start_tick,
- guint bound, /* start_tick + n_ticks */
- gdouble stamps_per_tick,
- BseMidiReceiver *midi_receiver,
- guint midi_channel);
-static void
-bse_sequencer_process_track_SL (BseTrack *track,
- gdouble start_stamp,
- guint start_tick,
- guint bound, /* start_tick + n_ticks */
- gdouble stamps_per_tick,
- BseMidiReceiver *midi_receiver)
+
+void
+Sequencer::process_track_SL (BseTrack *track, double start_stamp, uint start_tick,
+ uint bound, /* start_tick + n_ticks */
+ double stamps_per_tick, BseMidiReceiver *midi_receiver)
{
- guint start, next;
+ uint start, next;
BsePart *part = bse_track_get_part_SL (track, start_tick, &start, &next);
/* advance to first part */
if (!part && next)
@@ -535,23 +488,18 @@ bse_sequencer_process_track_SL (BseTrack *track,
part_bound = next ? MIN (bound, next) : bound;
part_bound -= start;
if (!track->muted_SL)
- bse_sequencer_process_part_SL (part, part_stamp,
- part_start, part_bound, stamps_per_tick,
- midi_receiver, track->midi_channel_SL);
+ process_part_SL (part, part_stamp, part_start, part_bound, stamps_per_tick, midi_receiver,
track->midi_channel_SL);
part = next ? bse_track_get_part_SL (track, next, &start, &next) : NULL;
}
}
-static void
-bse_sequencer_process_part_SL (BsePart *part,
- gdouble start_stamp,
- guint start_tick,
- guint tick_bound, /* start_tick + n_ticks */
- gdouble stamps_per_tick,
- BseMidiReceiver *midi_receiver,
- guint midi_channel)
+
+void
+Sequencer::process_part_SL (BsePart *part, double start_stamp, uint start_tick,
+ uint tick_bound, /* start_tick + n_ticks */
+ double stamps_per_tick, BseMidiReceiver *midi_receiver, uint midi_channel)
{
BsePartTickNode *node, *last;
- guint channel;
+ uint channel;
for (channel = 0; channel < part->n_channels; channel++)
{
BsePartEventNote *note = bse_part_note_channel_lookup_ge (&part->channels[channel], start_tick);
@@ -571,9 +519,9 @@ bse_sequencer_process_part_SL (BsePart *part,
if (CHECKTRACE())
{
SEQTRACE ("SEQ:note-on: tick=%llu midinote=%-3d velocity=%02x freq=% 10f now=%llu",
- eon->delta_time, note->note, bse_ftoi (note->velocity * 128), freq,
Bse::TickStamp::current());
+ uint64 (eon->delta_time), note->note, bse_ftoi (note->velocity * 128), freq,
Bse::TickStamp::current());
SEQTRACE ("SEQ:note-off: tick=%llu midinote=%-3d velocity=%02x freq=% 10f now=%llu",
- eoff->delta_time, note->note, bse_ftoi (note->velocity * 128), freq,
Bse::TickStamp::current());
+ uint64 (eoff->delta_time), note->note, bse_ftoi (note->velocity * 128), freq,
Bse::TickStamp::current());
}
note++;
}
@@ -590,8 +538,34 @@ bse_sequencer_process_part_SL (BsePart *part,
BseMidiSignalType (cev->ctype), cev->value);
bse_midi_receiver_push_event (midi_receiver, event);
SEQTRACE ("SEQ:control: tick=%llu midisignal=%-3d value=%f now=%llu",
- event->delta_time, cev->ctype, cev->value, Bse::TickStamp::current());
+ uint64 (event->delta_time), cev->ctype, cev->value, Bse::TickStamp::current());
}
node++;
}
}
+
+Sequencer::Sequencer() :
+ stamp_ (0), songs_ (NULL)
+{
+ stamp_ = Bse::TickStamp::current();
+ assert (stamp_ > 0);
+
+ if (pipe (sequencer_wake_up_pipe) < 0)
+ g_error ("failed to create sequencer wake-up pipe: %s", strerror (errno));
+ long flags = fcntl (sequencer_wake_up_pipe[0], F_GETFL, 0);
+ fcntl (sequencer_wake_up_pipe[0], F_SETFL, O_NONBLOCK | flags);
+ flags = fcntl (sequencer_wake_up_pipe[1], F_GETFL, 0);
+ fcntl (sequencer_wake_up_pipe[1], F_SETFL, O_NONBLOCK | flags);
+
+ poll_pool_ = new PollPool;
+}
+
+void
+Sequencer::_init_threaded ()
+{
+ assert (singleton_ == NULL);
+ singleton_ = new Sequencer();
+ singleton_->thread_ = std::thread (&Sequencer::sequencer_thread, singleton_); // FIXME: join on exit
+}
+
+} // Bse
diff --git a/bse/bsesequencer.hh b/bse/bsesequencer.hh
index b2b7ef7..52d8bd2 100644
--- a/bse/bsesequencer.hh
+++ b/bse/bsesequencer.hh
@@ -1,30 +1,53 @@
// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
-#ifndef __BSE_SSEQUENCER_H__
-#define __BSE_SSEQUENCER_H__
+#ifndef __BSE_SSEQUENCER_HH__
+#define __BSE_SSEQUENCER_HH__
#include <bse/bsesong.hh>
-G_BEGIN_DECLS
+namespace Bse {
-typedef struct {
- guint64 stamp; /* sequencer time (ahead of real time) */
- SfiRing *songs;
-} BseSequencer;
+using Rapicorn::Mutex; // FIXME
+using Rapicorn::Cond; // FIXME
-extern BirnetThread* bse_sequencer_thread; // FIXME
+/** Note and MIDI sequencer.
+ * The sequencer processes notes from parts and MIDI input and generates events for the synthesis engine.
+ */
+class Sequencer {
+ static Sequencer *singleton_;
+ static Mutex sequencer_mutex_;
+ struct PollPool;
+ uint64 stamp_; // sequencer time (ahead of real time)
+ SfiRing *songs_;
+ Cond watch_cond_;
+ PollPool *poll_pool_;
+ std::thread thread_;
+private:
+ void sequencer_thread ();
+ bool pool_poll_Lm (int timeout_ms);
+ void process_part_SL (BsePart *part, double start_stamp, uint start_tick,
+ uint tick_bound, /* start_tick + n_ticks */
+ double stamps_per_tick, BseMidiReceiver *midi_receiver, uint midi_channel);
+ void process_track_SL (BseTrack *track, double start_stamp, uint start_tick,
+ uint bound, /* start_tick + n_ticks */
+ double stamps_per_tick, BseMidiReceiver *midi_receiver);
+ void process_song_SL (BseSong *song, uint n_ticks);
+ bool process_song_unlooped_SL (BseSong *song, uint n_ticks, bool force_active_tracks);
+ explicit Sequencer ();
+protected:
+ static void _init_threaded ();
+public:
+ void wakeup ();
+ void add_io_watch (uint n_pfds, const GPollFD *pfds, BseIOWatch watch_func, void *watch_data);
+ void remove_io_watch (BseIOWatch watch_func, void *watch_data);
+ void start_song (BseSong *song, uint64 start_stamp);
+ void remove_song (BseSong *song);
+ bool thread_lagging (uint n_blocks);
+ static Mutex& sequencer_mutex () { return sequencer_mutex_; }
+ static Sequencer& instance () { return *singleton_; }
+};
-void bse_sequencer_wakeup ();
-void bse_sequencer_init_thread (void);
-void bse_sequencer_add_io_watch (guint n_pfds,
- const GPollFD *pfds,
- BseIOWatch watch_func,
- gpointer data);
-void bse_sequencer_remove_io_watch (BseIOWatch watch_func,
- gpointer data);
-void bse_sequencer_start_song (BseSong *song,
- guint64 start_stamp);
-void bse_sequencer_remove_song (BseSong *song);
-gboolean bse_sequencer_thread_lagging (guint n_blocks);
+#define BSE_SEQUENCER_LOCK() (Bse::Sequencer::sequencer_mutex().lock())
+#define BSE_SEQUENCER_UNLOCK() (Bse::Sequencer::sequencer_mutex().unlock())
-G_END_DECLS
+} // Bse
-#endif /* __BSE_SSEQUENCER_H__ */
+#endif // __BSE_SSEQUENCER_HH__
diff --git a/bse/bsesong.cc b/bse/bsesong.cc
index d10f9ae..d4e07cd 100644
--- a/bse/bsesong.cc
+++ b/bse/bsesong.cc
@@ -463,8 +463,8 @@ static void
bse_song_reset (BseSource *source)
{
BseSong *self = BSE_SONG (source);
- bse_sequencer_remove_song (self),
- /* chain parent class' handler */
+ Bse::Sequencer::instance().remove_song (self);
+ // chain parent class' handler
BSE_SOURCE_CLASS (parent_class)->reset (source);
g_assert (self->sequencer_start_request_SL == 0);
/* outside of sequencer reach, so no locks needed */
diff --git a/bse/bsetrack.cc b/bse/bsetrack.cc
index 9238023..5b1a1cc 100644
--- a/bse/bsetrack.cc
+++ b/bse/bsetrack.cc
@@ -6,7 +6,7 @@
#include "bsewave.hh"
#include "bsepart.hh"
#include "bsebus.hh"
-#include "bsemain.hh"
+#include "bsesequencer.hh"
#include "gslcommon.hh"
#include "bsesubsynth.hh"
#include "bseproject.hh"
diff --git a/drivers/bsemididevice-alsa.cc b/drivers/bsemididevice-alsa.cc
index 55febb9..eeafa39 100644
--- a/drivers/bsemididevice-alsa.cc
+++ b/drivers/bsemididevice-alsa.cc
@@ -242,7 +242,7 @@ bse_midi_device_alsa_open (BseDevice *device,
if (wn && snd_rawmidi_poll_descriptors (alsa->write_handle, pfds + alsa->total_pfds, wn) >= 0)
alsa->total_pfds += wn;
if (alsa->total_pfds)
- bse_sequencer_add_io_watch (alsa->total_pfds, (GPollFD*) pfds, alsa_midi_io_handler, alsa);
+ Bse::Sequencer::instance().add_io_watch (alsa->total_pfds, (GPollFD*) pfds,
alsa_midi_io_handler, alsa);
}
}
}
@@ -264,7 +264,7 @@ bse_midi_device_alsa_close (BseDevice *device)
AlsaMidiHandle *alsa = (AlsaMidiHandle*) BSE_MIDI_DEVICE (device)->handle;
BSE_MIDI_DEVICE (device)->handle = NULL;
if (alsa->total_pfds)
- bse_sequencer_remove_io_watch (alsa_midi_io_handler, alsa);
+ Bse::Sequencer::instance().remove_io_watch (alsa_midi_io_handler, alsa);
if (alsa->read_handle)
snd_rawmidi_close (alsa->read_handle);
if (alsa->write_handle)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]