substantive change: use the JACK wait API and provide "thread buffers" separately...
authorPaul Davis <paul@linuxaudiosystems.com>
Tue, 13 Apr 2010 20:48:33 +0000 (20:48 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 13 Apr 2010 20:48:33 +0000 (20:48 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@6888 d708f5d6-7413-0410-9779-e7cbd77b26cf

15 files changed:
libs/ardour/ardour/audioengine.h
libs/ardour/ardour/buffer_manager.h [new file with mode: 0644]
libs/ardour/ardour/process_thread.h [new file with mode: 0644]
libs/ardour/ardour/session.h
libs/ardour/ardour/thread_buffers.h [new file with mode: 0644]
libs/ardour/audioengine.cc
libs/ardour/buffer_manager.cc [new file with mode: 0644]
libs/ardour/globals.cc
libs/ardour/process_thread.cc [new file with mode: 0644]
libs/ardour/session.cc
libs/ardour/session_process.cc
libs/ardour/session_state.cc
libs/ardour/thread_buffers.cc [new file with mode: 0644]
libs/ardour/wscript
libs/pbd/pbd/ringbufferNPT.h

index e630e1a95e87d8fb3a2d2d1f3ea1a4928f580082..63f9afeb2bb1a0f051821d2e189fad817bd00d88 100644 (file)
@@ -55,6 +55,7 @@ class InternalPort;
 class MidiPort;
 class Port;
 class Session;
+class ProcessThread;
 
 class AudioEngine : public SessionHandlePtr
 {
@@ -69,6 +70,8 @@ class AudioEngine : public SessionHandlePtr
 
        bool is_realtime () const;
 
+        ProcessThread* main_thread() const { return _main_thread; }
+
        std::string client_name() const { return jack_client_name; }
 
        int reconnect_to_jack ();
@@ -272,6 +275,8 @@ _      the regular process() call to session->process() is not made.
        Port *register_port (DataType type, const std::string& portname, bool input);
 
        int    process_callback (nframes_t nframes);
+       void*  process_thread ();
+        void   finish_process_cycle (int status);
        void   remove_all_ports ();
 
        std::string get_nth_physical (DataType type, uint32_t n, int flags);
@@ -284,6 +289,7 @@ _      the regular process() call to session->process() is not made.
 #endif
        static int  _graph_order_callback (void *arg);
        static int  _process_callback (nframes_t nframes, void *arg);
+       static void* _process_thread (void *arg);
        static int  _sample_rate_callback (nframes_t nframes, void *arg);
        static int  _bufsize_callback (nframes_t nframes, void *arg);
        static void _jack_timebase_callback (jack_transport_state_t, nframes_t, jack_position_t*, int, void*);
@@ -307,6 +313,8 @@ _      the regular process() call to session->process() is not made.
 
        Glib::Thread*    m_meter_thread;
        static gint      m_meter_exit;
+
+        ProcessThread* _main_thread;
 };
 
 } // namespace ARDOUR
diff --git a/libs/ardour/ardour/buffer_manager.h b/libs/ardour/ardour/buffer_manager.h
new file mode 100644 (file)
index 0000000..4da8d06
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __libardour_buffer_manager__ 
+#define __libardour_buffer_manager__
+
+#include <stdint.h>
+
+#include "pbd/ringbufferNPT.h"
+
+#include "ardour/chan_count.h"
+
+namespace ARDOUR {
+
+class ThreadBuffers;
+
+class BufferManager
+{
+  public:
+        static void init (uint32_t);
+        
+        static ThreadBuffers* get_thread_buffers ();
+        static void           put_thread_buffers (ThreadBuffers*);
+
+        static void ensure_buffers (ChanCount howmany = ChanCount::ZERO);
+
+  private:
+        typedef RingBufferNPT<ThreadBuffers*> ThreadBufferFIFO;
+        static ThreadBufferFIFO* thread_buffers;
+};
+
+}
+
+#endif /* __libardour_buffer_manager__ */
diff --git a/libs/ardour/ardour/process_thread.h b/libs/ardour/ardour/process_thread.h
new file mode 100644 (file)
index 0000000..d6bbbfc
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __libardour_process_thread__
+#define __libardour_process_thread__
+
+#include <glibmm/thread.h>
+
+#include "ardour/chan_count.h"
+#include "ardour/types.h"
+
+namespace ARDOUR {
+
+class ThreadBuffers;
+
+class ProcessThread
+{
+  public:
+    ProcessThread ();
+    ~ProcessThread ();
+
+    static void init();
+
+    void get_buffers ();
+    void drop_buffers ();
+
+    /* these MUST be called by a process thread's thread, nothing else
+     */
+
+    static BufferSet& get_silent_buffers (ChanCount count = ChanCount::ZERO);
+    static BufferSet& get_scratch_buffers (ChanCount count = ChanCount::ZERO);
+    static BufferSet& get_mix_buffers (ChanCount count = ChanCount::ZERO);
+    static gain_t* gain_automation_buffer ();
+    static pan_t** pan_automation_buffer ();
+
+  protected:
+    void session_going_away ();
+
+  private:
+    Glib::Thread* _thread;
+
+    static Glib::Private<ThreadBuffers>* _private_thread_buffers;
+};
+
+} // namespace
+
+#endif /* __libardour_process_thread__ */
index 2b51e3f8ecb700cc96f2e8872f84f068b1979fdc..b5c818e6a25dea5a19b5febc554c4d4b17f127e5 100644 (file)
@@ -106,6 +106,7 @@ class Playlist;
 class PluginInsert;
 class Port;
 class PortInsert;
+class ProcessThread;
 class Processor;
 class Region;
 class Return;
@@ -736,8 +737,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 
        /* buffers for gain and pan */
 
-       gain_t* gain_automation_buffer () const { return _gain_automation_buffer; }
-       pan_t** pan_automation_buffer () const  { return _pan_automation_buffer; }
+       gain_t* gain_automation_buffer () const;
+       pan_t** pan_automation_buffer () const;
 
        void ensure_buffer_set (BufferSet& buffers, const ChanCount& howmany);
 
@@ -859,9 +860,6 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
        nframes64_t             _last_slave_transport_frame;
        nframes_t                maximum_output_latency;
        volatile nframes64_t    _requested_return_frame;
-       BufferSet*              _scratch_buffers;
-       BufferSet*              _silent_buffers;
-       BufferSet*              _mix_buffers;
        nframes_t                current_block_size;
        nframes_t               _worst_output_latency;
        nframes_t               _worst_input_latency;
@@ -881,7 +879,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 
        void update_latency_compensation_proxy (void* ignored);
 
-       void ensure_buffers (ChanCount howmany);
+       void ensure_buffers (ChanCount howmany = ChanCount::ZERO);
 
        void process_scrub          (nframes_t);
        void process_without_events (nframes_t);
@@ -894,6 +892,9 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
        void unblock_processing() { g_atomic_int_set (&processing_prohibited, 0); }
        bool processing_blocked() const { return g_atomic_int_get (&processing_prohibited); }
 
+        Glib::Mutex                process_thread_lock;
+        std::list<ProcessThread*>  process_threads;
+
        /* slave tracking */
 
        static const int delta_accumulator_size = 25;
@@ -1389,11 +1390,6 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
        boost::shared_ptr<Route> _master_out;
        boost::shared_ptr<Route> _monitor_out;
 
-       gain_t* _gain_automation_buffer;
-       pan_t** _pan_automation_buffer;
-       void allocate_pan_automation_buffers (nframes_t nframes, uint32_t howmany, bool force);
-       uint32_t _npan_buffers;
-
        /* VST support */
 
        long _vst_callback (VSTPlugin*,
diff --git a/libs/ardour/ardour/thread_buffers.h b/libs/ardour/ardour/thread_buffers.h
new file mode 100644 (file)
index 0000000..3c31217
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __libardour_thread_buffers__
+#define __libardour_thread_buffers__
+
+#include <glibmm/thread.h>
+
+#include "ardour/chan_count.h"
+#include "ardour/types.h"
+
+namespace ARDOUR {
+
+class BufferSet;
+
+class ThreadBuffers {
+  public:  
+        ThreadBuffers ();
+        ~ThreadBuffers ();
+
+        void ensure_buffers (ChanCount howmany = ChanCount::ZERO);
+
+        BufferSet* silent_buffers;
+        BufferSet* scratch_buffers;
+        BufferSet* mix_buffers;
+        gain_t*    gain_automation_buffer;
+        pan_t**    pan_automation_buffer;
+        uint32_t   npan_buffers;
+
+  private:
+        void allocate_pan_automation_buffers (nframes_t nframes, uint32_t howmany, bool force);
+};
+
+} // namespace
+
+#endif /* __libardour_thread_buffers__ */
index db1c4f2ef5e07e55107517e0c8062e9771ceafed..196482f143d99c00a7ac9ea2fee58527fd2b4efd 100644 (file)
@@ -43,6 +43,7 @@
 #include "ardour/io.h"
 #include "ardour/meter.h"
 #include "ardour/midi_port.h"
+#include "ardour/process_thread.h"
 #include "ardour/port.h"
 #include "ardour/port_set.h"
 #include "ardour/session.h"
@@ -77,6 +78,7 @@ AudioEngine::AudioEngine (string client_name, string session_uuid)
        _frame_rate = 0;
        _buffer_size = 0;
        _freewheeling = false;
+        _main_thread = 0;
 
        m_meter_thread = 0;
        g_atomic_int_set (&m_meter_exit, 0);
@@ -184,7 +186,8 @@ AudioEngine::start ()
                jack_on_shutdown (_priv_jack, halted, this);
                jack_set_graph_order_callback (_priv_jack, _graph_order_callback, this);
                jack_set_thread_init_callback (_priv_jack, _thread_init_callback, this);
-               jack_set_process_callback (_priv_jack, _process_callback, this);
+               // jack_set_process_callback (_priv_jack, _process_callback, this);
+               jack_set_process_thread (_priv_jack, _process_thread, this);
                jack_set_sample_rate_callback (_priv_jack, _sample_rate_callback, this);
                jack_set_buffer_size_callback (_priv_jack, _bufsize_callback, this);
                jack_set_xrun_callback (_priv_jack, _xrun_callback, this);
@@ -336,6 +339,12 @@ AudioEngine::_process_callback (nframes_t nframes, void *arg)
        return static_cast<AudioEngine *> (arg)->process_callback (nframes);
 }
 
+void*
+AudioEngine::_process_thread (void *arg)
+{
+       return static_cast<AudioEngine *> (arg)->process_thread ();
+}
+
 void
 AudioEngine::_freewheel_callback (int onoff, void *arg)
 {
@@ -372,6 +381,47 @@ AudioEngine::split_cycle (nframes_t offset)
        }
 }
 
+void
+AudioEngine::finish_process_cycle (int status)
+{
+        GET_PRIVATE_JACK_POINTER(_jack);
+        cerr << "signal process cycle end\n";
+        jack_cycle_signal (_jack, 0);
+}
+
+void*
+AudioEngine::process_thread ()
+{
+        /* JACK doesn't do this for us when we use the wait API 
+         */
+
+        cerr << "JACK process thread is here\n";
+
+        _thread_init_callback (0);
+
+        cerr << " its initialized\n";
+
+        _main_thread = new ProcessThread;
+
+        cerr << " we have ProcThread\n";
+
+        while (1) {
+                cerr << "getting client ptr from " << _jack << endl;
+                GET_PRIVATE_JACK_POINTER_RET(_jack,0);
+                cerr << "Wait for JACK\n";
+                jack_nframes_t nframes = jack_cycle_wait (_jack);
+                cerr << "run process\n";
+
+                if (process_callback (nframes)) {
+                        return 0;
+                }
+
+                finish_process_cycle (0);
+        }
+
+        return 0;
+}
+
 /** Method called by JACK (via _process_callback) which says that there
  * is work to be done.
  * @param nframes Number of frames to process.
@@ -379,7 +429,7 @@ AudioEngine::split_cycle (nframes_t offset)
 int
 AudioEngine::process_callback (nframes_t nframes)
 {
-       GET_PRIVATE_JACK_POINTER_RET(_jack,0)
+       GET_PRIVATE_JACK_POINTER_RET(_jack,0);
        // CycleTimer ct ("AudioEngine::process");
        Glib::Mutex::Lock tm (_process_lock, Glib::TRY_LOCK);
 
@@ -434,6 +484,7 @@ AudioEngine::process_callback (nframes_t nframes)
        } else {
                if (_session) {
                        _session->process (nframes);
+
                }
        }
 
@@ -930,6 +981,8 @@ AudioEngine::get_ports (const string& port_name_pattern, const string& type_name
 void
 AudioEngine::halted (void *arg)
 {
+        cerr << "HALTED by JACK\n";
+
         /* called from jack shutdown handler  */
 
        AudioEngine* ae = static_cast<AudioEngine *> (arg);
@@ -1246,13 +1299,8 @@ AudioEngine::reconnect_to_jack ()
 
        if (_session) {
                _session->reset_jack_connection (_priv_jack);
-               nframes_t blocksize = jack_get_buffer_size (_priv_jack);
-               _session->set_block_size (blocksize);
+                jack_bufsize_callback (jack_get_buffer_size (_priv_jack));
                _session->set_frame_rate (jack_get_sample_rate (_priv_jack));
-
-               _raw_buffer_sizes[DataType::AUDIO] = blocksize * sizeof(float);
-               cout << "FIXME: Assuming maximum MIDI buffer size " << blocksize * 4 << "bytes" << endl;
-               _raw_buffer_sizes[DataType::MIDI] = blocksize * 4;
        }
 
        last_monitor_check = 0;
@@ -1260,7 +1308,8 @@ AudioEngine::reconnect_to_jack ()
        jack_on_shutdown (_priv_jack, halted, this);
        jack_set_graph_order_callback (_priv_jack, _graph_order_callback, this);
        jack_set_thread_init_callback (_priv_jack, _thread_init_callback, this);
-       jack_set_process_callback (_priv_jack, _process_callback, this);
+       // jack_set_process_callback (_priv_jack, _process_callback, this);
+       jack_set_process_thread (_priv_jack, _process_thread, this);
        jack_set_sample_rate_callback (_priv_jack, _sample_rate_callback, this);
        jack_set_buffer_size_callback (_priv_jack, _bufsize_callback, this);
        jack_set_xrun_callback (_priv_jack, _xrun_callback, this);
diff --git a/libs/ardour/buffer_manager.cc b/libs/ardour/buffer_manager.cc
new file mode 100644 (file)
index 0000000..3436dac
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+    Copyright (C) 2010 Paul Davis
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+#include "ardour/buffer_manager.h"
+#include "ardour/thread_buffers.h"
+
+using namespace ARDOUR;
+using namespace PBD;
+
+RingBufferNPT<ThreadBuffers*>* BufferManager::thread_buffers = 0;
+
+void
+BufferManager::init (uint32_t size)
+{
+        thread_buffers = new ThreadBufferFIFO (size+1); // must be one larger than requested
+
+        /* and populate with actual ThreadBuffers 
+         */
+
+        std::cerr << "BM: initial read space: " << thread_buffers->read_space() << std::endl;
+        
+        for (uint32_t n = 0; n < size; ++n) {        
+                ThreadBuffers* ts = new ThreadBuffers;
+                thread_buffers->write (&ts, 1);
+                std::cerr << "BM: added one, read =  " << thread_buffers->read_space() 
+                          << " write = " << thread_buffers->write_space() 
+                          << std::endl;
+        }
+
+        std::cerr << "BM: final, read =  " << thread_buffers->read_space() 
+                  << " write = " << thread_buffers->write_space() 
+                  << std::endl;
+
+        std::cerr << "BUFFER MANAGER INITIALIZED WITH " << size << " BUFFERs\n";
+}
+
+ThreadBuffers*
+BufferManager::get_thread_buffers ()
+{
+        ThreadBuffers* tbp;
+
+        if (thread_buffers->read (&tbp, 1) == 1) {
+                return tbp;
+        }
+
+        return 0;
+}
+
+void
+BufferManager::put_thread_buffers (ThreadBuffers* tbp)
+{
+        thread_buffers->write (&tbp, 1);
+}
+
+void
+BufferManager::ensure_buffers (ChanCount howmany)
+{
+        /* this is protected by the audioengine's process lock: we do not  */
+
+        std::cerr << "BufMgr: ensure " << thread_buffers->bufsize() - 1 << " buffers match " << howmany << std::endl;
+
+        for (uint32_t n = 0; n < thread_buffers->bufsize() - 1; ++n) {
+                thread_buffers->buffer()[n]->ensure_buffers (howmany);
+        }
+}
index 9f3d99ead4e0edbee50b7a64072243dacc697205..b78edc11d2e649a6bceff03a8116928804ec7cda 100644 (file)
 #include "ardour/audioengine.h"
 #include "ardour/audioregion.h"
 #include "ardour/audiosource.h"
+#include "ardour/buffer_manager.h"
 #include "ardour/control_protocol_manager.h"
 #include "ardour/debug.h"
 #include "ardour/filesystem_paths.h"
 #include "ardour/mix.h"
 #include "ardour/playlist.h"
 #include "ardour/plugin_manager.h"
+#include "ardour/process_thread.h"
 #include "ardour/profile.h"
 #include "ardour/region.h"
 #include "ardour/rc_configuration.h"
@@ -405,6 +407,9 @@ ARDOUR::init (bool use_vst, bool try_optimization)
        /* singleton - first object is "it" */
        new PluginManager ();
 
+        ProcessThread::init ();
+        BufferManager::init (2); // XX should be num_processors_for_dsp
+
        return 0;
 }
 
diff --git a/libs/ardour/process_thread.cc b/libs/ardour/process_thread.cc
new file mode 100644 (file)
index 0000000..e36639a
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+    Copyright (C) 2010 Paul Davis
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+#include "ardour/audioengine.h"
+#include "ardour/buffer.h"
+#include "ardour/buffer_manager.h"
+#include "ardour/buffer_set.h"
+#include "ardour/process_thread.h"
+#include "ardour/thread_buffers.h"
+
+using namespace ARDOUR;
+using namespace Glib;
+using namespace std;
+
+Private<ThreadBuffers>* ProcessThread::_private_thread_buffers = 0;
+
+static void 
+release_thread_buffer (void* arg)
+{
+        BufferManager::put_thread_buffers ((ThreadBuffers*) arg);
+}
+
+void
+ProcessThread::init ()
+{
+        _private_thread_buffers = new Private<ThreadBuffers> (release_thread_buffer);
+}
+
+ProcessThread::ProcessThread ()
+        : _thread (0)
+{
+}
+
+ProcessThread::~ProcessThread ()
+{
+}
+
+void
+ProcessThread::get_buffers ()
+{
+        ThreadBuffers* tb = BufferManager::get_thread_buffers ();
+
+        assert (tb);
+        _private_thread_buffers->set (tb);
+        cerr << "ProcThread " << this << " using TBs at " << tb << " (aka. " << _private_thread_buffers->get() << endl;
+}
+
+void
+ProcessThread::drop_buffers ()
+{
+        ThreadBuffers* tb = _private_thread_buffers->get();
+        assert (tb);
+        BufferManager::put_thread_buffers (tb);
+        _private_thread_buffers->set (0);
+        cerr << "ProcThread " << this << " dropped TBs\n";
+}
+
+BufferSet&
+ProcessThread::get_silent_buffers (ChanCount count)
+{
+        ThreadBuffers* tb = _private_thread_buffers->get();
+        assert (tb);
+
+        BufferSet* sb = tb->silent_buffers;
+        assert (sb);
+
+       assert(sb->available() >= count);
+       sb->set_count(count);
+
+       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+               for (size_t i= 0; i < count.get(*t); ++i) {
+                       sb->get(*t, i).clear();
+               }
+       }
+
+       return *sb;
+}
+
+BufferSet&
+ProcessThread::get_scratch_buffers (ChanCount count)
+{
+        ThreadBuffers* tb = _private_thread_buffers->get();
+        assert (tb);
+
+        BufferSet* sb = tb->scratch_buffers;
+        assert (sb);
+
+       if (count != ChanCount::ZERO) {
+               assert(sb->available() >= count);
+               sb->set_count (count);
+       } else {
+               sb->set_count (sb->available());
+       }
+
+       return *sb;
+}
+
+BufferSet&
+ProcessThread::get_mix_buffers (ChanCount count)
+{
+        ThreadBuffers* tb = _private_thread_buffers->get();
+        assert (tb);
+
+        BufferSet* mb = tb->mix_buffers;
+
+        assert (mb);
+       assert (mb->available() >= count);
+       mb->set_count(count);
+       return *mb;
+}
+
+gain_t*
+ProcessThread::gain_automation_buffer()
+{
+        ThreadBuffers* tb = _private_thread_buffers->get();
+        assert (tb);
+
+        gain_t *g =  tb->gain_automation_buffer;
+        assert (g);
+        return g;
+}
+
+pan_t**
+ProcessThread::pan_automation_buffer()
+{
+        ThreadBuffers* tb = _private_thread_buffers->get();
+        assert (tb);
+
+        pan_t** p = tb->pan_automation_buffer;
+        assert (p);
+        return p;
+}
index 21ed454c2968b96f0e16c2bc8be37e13d320fc6a..ac8d5d030fe11e4fc81da3f185c728bb2b446850 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 1999-2004 Paul Davis
+    Copyright (C) 1999-2010 Paul Davis
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -52,6 +52,7 @@
 #include "ardour/audioplaylist.h"
 #include "ardour/audioregion.h"
 #include "ardour/auditioner.h"
+#include "ardour/buffer_manager.h"
 #include "ardour/buffer_set.h"
 #include "ardour/bundle.h"
 #include "ardour/butler.h"
@@ -70,6 +71,7 @@
 #include "ardour/midi_track.h"
 #include "ardour/midi_ui.h"
 #include "ardour/named_selection.h"
+#include "ardour/process_thread.h"
 #include "ardour/playlist.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/port_insert.h"
@@ -129,9 +131,6 @@ Session::Session (AudioEngine &eng,
        : _engine (eng),
          _target_transport_speed (0.0),
          _requested_return_frame (-1),
-         _scratch_buffers(new BufferSet()),
-         _silent_buffers(new BufferSet()),
-         _mix_buffers(new BufferSet()),
          mmc (0),
          _mmc_port (default_mmc_port),
          _mtc_port (default_mtc_port),
@@ -243,10 +242,6 @@ Session::destroy ()
 
        clear_clicks ();
 
-       delete _scratch_buffers;
-       delete _silent_buffers;
-       delete _mix_buffers;
-
        /* clear out any pending dead wood from RCU managed objects */
 
        routes.flush ();
@@ -1193,12 +1188,7 @@ Session::set_block_size (nframes_t nframes)
        {
                current_block_size = nframes;
 
-               ensure_buffers(_scratch_buffers->available());
-
-               delete [] _gain_automation_buffer;
-               _gain_automation_buffer = new gain_t[nframes];
-
-               allocate_pan_automation_buffers (nframes, _npan_buffers, true);
+               ensure_buffers ();
 
                boost::shared_ptr<RouteList> r = routes.reader ();
 
@@ -3209,18 +3199,7 @@ Session::tempo_map_changed (const PropertyChange&)
 void
 Session::ensure_buffers (ChanCount howmany)
 {
-       if (current_block_size == 0) {
-               return; // too early? (is this ok?)
-       }
-
-       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
-               size_t count = std::max(_scratch_buffers->available().get(*t), howmany.get(*t));
-               _scratch_buffers->ensure_buffers (*t, count, _engine.raw_buffer_size(*t));
-               _mix_buffers->ensure_buffers (*t, count, _engine.raw_buffer_size(*t));
-               _silent_buffers->ensure_buffers (*t, count, _engine.raw_buffer_size(*t));
-       }
-
-       allocate_pan_automation_buffers (current_block_size, howmany.n_audio(), false);
+        BufferManager::ensure_buffers (howmany);
 }
 
 void
@@ -3439,31 +3418,6 @@ Session::route_name_internal (string n) const
        return false;
 }
 
-void
-Session::allocate_pan_automation_buffers (nframes_t nframes, uint32_t howmany, bool force)
-{
-       if (!force && howmany <= _npan_buffers) {
-               return;
-       }
-
-       if (_pan_automation_buffer) {
-
-               for (uint32_t i = 0; i < _npan_buffers; ++i) {
-                       delete [] _pan_automation_buffer[i];
-               }
-
-               delete [] _pan_automation_buffer;
-       }
-
-       _pan_automation_buffer = new pan_t*[howmany];
-
-       for (uint32_t i = 0; i < howmany; ++i) {
-               _pan_automation_buffer[i] = new pan_t[nframes];
-       }
-
-       _npan_buffers = howmany;
-}
-
 int
 Session::freeze_all (InterThreadInfo& itt)
 {
@@ -3649,9 +3603,23 @@ Session::write_one_track (AudioTrack& track, nframes_t start, nframes_t end,
        return result;
 }
 
+gain_t*
+Session::gain_automation_buffer() const
+{
+        return ProcessThread::gain_automation_buffer ();
+}
+
+pan_t**
+Session::pan_automation_buffer() const
+{
+        return ProcessThread::pan_automation_buffer ();
+}
+
 BufferSet&
 Session::get_silent_buffers (ChanCount count)
 {
+        return ProcessThread::get_silent_buffers (count);
+#if 0
        assert(_silent_buffers->available() >= count);
        _silent_buffers->set_count(count);
 
@@ -3662,11 +3630,14 @@ Session::get_silent_buffers (ChanCount count)
        }
 
        return *_silent_buffers;
+#endif
 }
 
 BufferSet&
 Session::get_scratch_buffers (ChanCount count)
 {
+        return ProcessThread::get_scratch_buffers (count);
+#if 0
        if (count != ChanCount::ZERO) {
                assert(_scratch_buffers->available() >= count);
                _scratch_buffers->set_count(count);
@@ -3675,14 +3646,18 @@ Session::get_scratch_buffers (ChanCount count)
        }
 
        return *_scratch_buffers;
+#endif
 }
 
 BufferSet&
 Session::get_mix_buffers (ChanCount count)
 {
+        return ProcessThread::get_mix_buffers (count);
+#if 0
        assert(_mix_buffers->available() >= count);
        _mix_buffers->set_count(count);
        return *_mix_buffers;
+#endif
 }
 
 uint32_t
index 834280de917c34bfea38918bb76cfff4ea30a8c6..85c424e40cd8498464ab13f6c19fc0b0068428a5 100644 (file)
@@ -33,6 +33,7 @@
 #include "ardour/auditioner.h"
 #include "ardour/butler.h"
 #include "ardour/debug.h"
+#include "ardour/process_thread.h"
 #include "ardour/session.h"
 #include "ardour/slave.h"
 #include "ardour/timestamps.h"
@@ -65,9 +66,13 @@ Session::process (nframes_t nframes)
                        post_transport ();
                }
        }
+        
+        _engine.main_thread()->get_buffers ();
 
        (this->*process_function) (nframes);
 
+        _engine.main_thread()->drop_buffers ();
+
        // the ticker is for sending time information like MidiClock
        nframes_t transport_frames = transport_frame();
        BBT_Time  transport_bbt;
index f67714401f8d7d19e61ebe04a297c07ec702b71e..1f116d82bca98bb6c48ace34dfb2e9c5d6008898 100644 (file)
@@ -210,9 +210,6 @@ Session::first_stage_init (string fullpath, string snapshot_name)
        g_atomic_int_set (&_capture_load_min, 100);
        _play_range = false;
        _exporting = false;
-       _gain_automation_buffer = 0;
-       _pan_automation_buffer = 0;
-       _npan_buffers = 0;
        pending_abort = false;
        destructive_index = 0;
        first_file_data_format_reset = true;
diff --git a/libs/ardour/thread_buffers.cc b/libs/ardour/thread_buffers.cc
new file mode 100644 (file)
index 0000000..e319acc
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+    Copyright (C) 2010 Paul Davis
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <iostream>
+
+#include "ardour/audioengine.h"
+#include "ardour/buffer_set.h"
+#include "ardour/thread_buffers.h"
+
+using namespace ARDOUR;
+using namespace std;
+
+ThreadBuffers::ThreadBuffers ()
+        : silent_buffers (new BufferSet)
+        , scratch_buffers (new BufferSet)
+        , mix_buffers (new BufferSet)
+        , gain_automation_buffer (0)
+        , pan_automation_buffer (0)
+        , npan_buffers (0)
+{
+}
+
+void
+ThreadBuffers::ensure_buffers (ChanCount howmany)
+{
+        // std::cerr << "ThreadBuffers " << this << " resize buffers with count = " << howmany << std::endl;
+
+        /* this is all protected by the process lock in the Session
+         */
+
+        if (howmany.n_total() == 0) {
+                return;
+        }
+
+        AudioEngine* _engine = AudioEngine::instance ();
+
+       for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+               size_t count = std::max (scratch_buffers->available().get(*t), howmany.get(*t));
+                size_t size = _engine->raw_buffer_size (*t);
+
+               scratch_buffers->ensure_buffers (*t, count, size);
+               mix_buffers->ensure_buffers (*t, count, size);
+                silent_buffers->ensure_buffers (*t, count, size);
+       }
+
+        delete [] gain_automation_buffer;
+        gain_automation_buffer = new gain_t[_engine->raw_buffer_size (DataType::AUDIO)];
+
+       allocate_pan_automation_buffers (_engine->raw_buffer_size (DataType::AUDIO), howmany.n_audio(), false);
+}
+
+void
+ThreadBuffers::allocate_pan_automation_buffers (nframes_t nframes, uint32_t howmany, bool force)
+{
+       if (!force && howmany <= npan_buffers) {
+               return;
+       }
+
+       if (pan_automation_buffer) {
+
+               for (uint32_t i = 0; i < npan_buffers; ++i) {
+                       delete [] pan_automation_buffer[i];
+               }
+
+               delete [] pan_automation_buffer;
+       }
+
+       pan_automation_buffer = new pan_t*[howmany];
+
+       for (uint32_t i = 0; i < howmany; ++i) {
+               pan_automation_buffer[i] = new pan_t[nframes];
+       }
+
+       npan_buffers = howmany;
+}
index ce9d41d7957ad82d829bfa483c4252c6900ab0a3..32127b6f7fcd5b876f95d65ab44e03f8ab78888d 100644 (file)
@@ -57,6 +57,7 @@ libardour_sources = [
        'beats_frames_converter.cc',
        'broadcast_info.cc',
        'buffer.cc',
+       'buffer_manager.cc',
        'buffer_set.cc',
        'bundle.cc',
        'butler.cc',
@@ -140,6 +141,7 @@ libardour_sources = [
        'port.cc',
        'port_insert.cc',
        'port_set.cc',
+       'process_thread.cc',
        'processor.cc',
        'quantize.cc',
        'rc_configuration.cc',
@@ -187,6 +189,7 @@ libardour_sources = [
        'template_utils.cc',
        'tempo.cc',
        'tempo_map_importer.cc',
+        'thread_buffers.cc',
        'ticker.cc',
        'track.cc',
        'transient_detector.cc',
@@ -218,7 +221,7 @@ def configure(conf):
        autowaf.configure(conf)
        conf.check_tool('compiler_cxx gas')
        autowaf.check_pkg(conf, 'aubio', uselib_store='AUBIO', atleast_version='0.3.2')
-       autowaf.check_pkg(conf, 'jack', uselib_store='JACK', atleast_version='0.109.0')
+       autowaf.check_pkg(conf, 'jack', uselib_store='JACK', atleast_version='0.119.0')
        autowaf.check_pkg(conf, 'libxml-2.0', uselib_store='XML')
        autowaf.check_pkg(conf, 'lrdf', uselib_store='LRDF', atleast_version='0.4.0')
        autowaf.check_pkg(conf, 'samplerate', uselib_store='SAMPLERATE', atleast_version='0.1.0')
index 30c71a8b1ab368181b58bf573b844263a5f67726..2b6aa03d626dc333ad35926551b7f56e34066647 100644 (file)
@@ -22,6 +22,7 @@
 
 //#include <sys/mman.h>
 
+#include <cstring>
 #include <glib.h>
 
 /* ringbuffer class where the element size is not required to be a power of two */