[beast: 1/8] BSE: synchronize PcmWriter output with song start



commit 61696c4642f855390b877dc890762dd81a1b3c59
Author: Tim Janik <timj gnu org>
Date:   Wed Mar 15 01:34:22 2017 +0100

    BSE: synchronize PcmWriter output with song start
    
    Currently, PcmWriterImpl::trigger_tick() only works correctly for a scenario
    where one project with one song is played back. A comment outlines the short
    commings.
    
    Signed-off-by: Tim Janik <timj gnu org>

 bse/bsepcmmodule.cc |    3 ++-
 bse/bsepcmwriter.cc |   48 ++++++++++++++++++++++++++++++++++++++----------
 bse/bsepcmwriter.hh |   20 +++++++++-----------
 bse/bseproject.cc   |    5 ++++-
 bse/bsesequencer.cc |    4 ++++
 5 files changed, 57 insertions(+), 23 deletions(-)
---
diff --git a/bse/bsepcmmodule.cc b/bse/bsepcmmodule.cc
index a319ba6..0af927b 100644
--- a/bse/bsepcmmodule.cc
+++ b/bse/bsepcmmodule.cc
@@ -93,7 +93,8 @@ bse_pcm_omodule_process (BseModule *module,
 
   bse_pcm_handle_write (mdata->handle, mdata->n_values, mdata->buffer);
   if (mdata->pcm_writer)
-    bse_pcm_writer_write (mdata->pcm_writer, mdata->n_values, mdata->buffer);
+    bse_pcm_writer_write (mdata->pcm_writer, mdata->n_values, mdata->buffer,
+                          bse_module_tick_stamp (module));
 }
 
 static void
diff --git a/bse/bsepcmwriter.cc b/bse/bsepcmwriter.cc
index 58b57c2..e95f902 100644
--- a/bse/bsepcmwriter.cc
+++ b/bse/bsepcmwriter.cc
@@ -7,13 +7,17 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-/* --- prototypes --- */
+
+// == prototypes ==
 static void       bse_pcm_writer_init                  (BsePcmWriter      *pdev);
 static void       bse_pcm_writer_class_init            (BsePcmWriterClass *klass);
 static void       bse_pcm_writer_finalize              (GObject           *object);
-/* --- variables --- */
+
+// == variables ==
+static std::atomic<uint64> atomic_trigger_tick {-uint64 (1)};
 static gpointer parent_class = NULL;
-/* --- functions --- */
+
+// == functions ==
 BSE_BUILTIN_TYPE (BsePcmWriter)
 {
   static const GTypeInfo pcm_writer_info = {
@@ -77,6 +81,7 @@ bse_pcm_writer_open (BsePcmWriter *self,
   self->mutex.lock();
   self->n_bytes = 0;
   self->recorded_maximum = recorded_maximum;
+  self->start_tick = atomic_trigger_tick;
   fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
   if (fd < 0)
     {
@@ -119,16 +124,27 @@ bsethread_halt_recording (gpointer data)
 }
 
 void
-bse_pcm_writer_write (BsePcmWriter *self,
-                     gsize         n_values,
-                     const gfloat *values)
+bse_pcm_writer_write (BsePcmWriter *self, size_t n_values, const float *values, uint64 start_stamp)
 {
   assert_return (BSE_IS_PCM_WRITER (self));
   assert_return (self->open);
-  if (n_values)
-    assert_return (values != NULL);
-  else
-    return;
+  return_unless (n_values);
+  assert_return (values != NULL);
+  if (UNLIKELY (start_stamp + n_values <= self->start_tick))
+    {
+      self->mutex.lock();
+      self->start_tick = atomic_trigger_tick;
+      self->mutex.unlock();
+      if (start_stamp + n_values <= self->start_tick)
+        return; // writer not yet activated
+    }
+  if (self->start_tick > start_stamp)
+    {
+      const uint64 delta = self->start_tick - start_stamp;
+      n_values -= delta;
+      values += delta;
+      start_stamp += delta;
+    }
   self->mutex.lock();
   const uint bw = 2; /* 16bit */
   if (!self->broken && (!self->recorded_maximum || self->n_bytes < bw * self->recorded_maximum))
@@ -170,4 +186,16 @@ PcmWriterImpl::PcmWriterImpl (BseObject *bobj) :
 PcmWriterImpl::~PcmWriterImpl ()
 {}
 
+void
+PcmWriterImpl::trigger_tick (uint64 start_tick)
+{
+  /* FIXME: workaround for the lack of per-project engine instantiations.
+   * There really should be a single engine instance per-project, and a
+   * single pcm-writer instance per engine (if any). Then trigger_tick()
+   * becomes a method on the per-project pcm-writer instead of a static
+   * function that only works for WAV capturing of a single instance.
+   */
+  atomic_trigger_tick = start_tick;
+}
+
 } // Bse
diff --git a/bse/bsepcmwriter.hh b/bse/bsepcmwriter.hh
index 0d66618..f723cf5 100644
--- a/bse/bsepcmwriter.hh
+++ b/bse/bsepcmwriter.hh
@@ -21,28 +21,26 @@ struct BsePcmWriter : BseItem {
   gint         fd;
   uint64       n_bytes;
   uint64        recorded_maximum;
+  uint64        start_tick;
 };
 struct BsePcmWriterClass : BseItemClass
 {};
 
-Bse::Error     bse_pcm_writer_open             (BsePcmWriter           *pdev,
-                                                const gchar            *file,
-                                                guint                   n_channels,
-                                                guint                   sample_freq,
-                                                 uint64                  recorded_maximum);
-void           bse_pcm_writer_close            (BsePcmWriter           *pdev);
+Bse::Error bse_pcm_writer_open (BsePcmWriter *pdev, const gchar *file, guint n_channels,
+                                 guint sample_freq, uint64 recorded_maximum);
+void      bse_pcm_writer_close (BsePcmWriter *pdev);
 /* writing is lock protected */
-void           bse_pcm_writer_write            (BsePcmWriter           *pdev,
-                                                gsize                   n_values,
-                                                const gfloat           *values);
+void      bse_pcm_writer_write (BsePcmWriter *pdev, size_t n_values,
+                                 const float *values, uint64 start_stamp);
 
 namespace Bse {
 
 class PcmWriterImpl : public ItemImpl, public virtual PcmWriterIface {
 protected:
-  virtual  ~PcmWriterImpl ();
+  virtual    ~PcmWriterImpl ();
 public:
-  explicit  PcmWriterImpl (BseObject*);
+  explicit    PcmWriterImpl (BseObject*);
+  static void trigger_tick  (uint64 start_tick);
 };
 
 } // Bse
diff --git a/bse/bseproject.cc b/bse/bseproject.cc
index 52c1b43..ba56f7d 100644
--- a/bse/bseproject.cc
+++ b/bse/bseproject.cc
@@ -16,6 +16,7 @@
 #include "bsemidinotifier.hh"
 #include "gslcommon.hh"
 #include "bseengine.hh"
+#include "bsepcmwriter.hh"
 #include "bsemidifile.hh"
 #include <string.h>
 #include <stdlib.h>
@@ -817,6 +818,8 @@ bse_project_start_playback (BseProject *self)
       if (BSE_IS_SONG (super))
        songs = sfi_ring_append (songs, super);
     }
+  if (!songs) // start pcm-writer ASAP if no songs are present
+    Bse::PcmWriterImpl::trigger_tick (Bse::TickStamp::current());
   /* enfore MasterThread roundtrip */
   bse_trans_add (trans, bse_job_nop());
   bse_trans_commit (trans);
@@ -826,7 +829,7 @@ bse_project_start_playback (BseProject *self)
   if (seen_synth || songs)
     bse_project_state_changed (self, Bse::ProjectState::PLAYING);
   /* then, start the sequencer */
-  while (songs)
+  while (songs) // start_song will synchronize PcmWriterImpl::trigger_tick
     Bse::Sequencer::instance().start_song ((BseSong*) sfi_ring_pop_head (&songs), 0);
 }
 
diff --git a/bse/bsesequencer.cc b/bse/bsesequencer.cc
index 02ade33..7d416b4 100644
--- a/bse/bsesequencer.cc
+++ b/bse/bsesequencer.cc
@@ -8,6 +8,7 @@
 #include "bseproject.hh"
 #include "bsemidireceiver.hh"
 #include "bsemain.hh"
+#include "bsepcmwriter.hh"
 #include "bseieee754.hh"
 #include "bsestartup.hh"        // for TaskRegistry
 #include <sys/poll.h>
@@ -242,6 +243,9 @@ Sequencer::start_song (BseSong *song, uint64 start_stamp)
   assert (song->sequencer_owns_refcount_SL == false);
   start_stamp = MAX (start_stamp, 1);
 
+  // synchornize pcm-writer output with song start
+  PcmWriterImpl::trigger_tick (start_stamp);
+
   g_object_ref (song);
   BSE_SEQUENCER_LOCK();
   song->sequencer_owns_refcount_SL = true;


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