libpsynth 0.2.1
/home/raskolnikov/dev/psynth/trunk/src/psynth/new_graph/processor.hpp
Go to the documentation of this file.
00001 
00011 /*
00012  *  Copyright (C) 2011 Juan Pedro BolĂ­var Puente
00013  *
00014  *  This file is part of Psychosynth.
00015  *   
00016  *  Psychosynth is free software: you can redistribute it and/or modify
00017  *  it under the terms of the GNU General Public License as published by
00018  *  the Free Software Foundation, either version 3 of the License, or
00019  *  (at your option) any later version.
00020  *
00021  *  Psychosynth is distributed in the hope that it will be useful,
00022  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024  *  GNU General Public License for more details.
00025  *
00026  *  You should have received a copy of the GNU General Public License
00027  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00028  *
00029  */
00030 
00031 #ifndef PSYNTH_GRAPH_PROCESSOR_HPP_
00032 #define PSYNTH_GRAPH_PROCESSOR_HPP_
00033 
00034 #include <thread>
00035 #include <atomic>
00036 #include <list>
00037 
00038 #include <psynth/new_graph/core/patch_fwd.hpp>
00039 #include <psynth/new_graph/node_fwd.hpp>
00040 #include <psynth/new_graph/port_fwd.hpp>
00041 #include <psynth/new_graph/sink_node_fwd.hpp>
00042 #include <psynth/new_graph/process_node_fwd.hpp>
00043 
00044 #include <psynth/new_graph/exception.hpp>
00045 #include <psynth/new_graph/event.hpp>
00046 #include <psynth/new_graph/triple_buffer.hpp>
00047 
00048 #include <psynth/base/hetero_deque.hpp>
00049 #include <psynth/base/threads.hpp>
00050 
00051 namespace psynth
00052 {
00053 namespace graph
00054 {
00055 
00056 PSYNTH_DECLARE_ERROR (error, processor_error);
00057 PSYNTH_DECLARE_ERROR (processor_error, processor_not_running_error);
00058 PSYNTH_DECLARE_ERROR (processor_error, processor_not_idle_error);
00059 
00060 constexpr std::size_t default_queue_size = 1 << 20;
00061 constexpr std::size_t default_block_size = 1 << 6;
00062 constexpr std::size_t default_frame_rate = 44100;
00063 
00064 class processor;
00065 
00066 typedef base::hetero_deque<rt_event>    rt_event_deque;
00067 typedef base::hetero_deque<async_event> async_event_deque;
00068 
00069 typedef triple_buffer<
00070     rt_event_deque,
00071     base::try_lock_guard<>,
00072     base::no_lock_guard<> >
00073 rt_triple_buffer;
00074 
00075 typedef triple_buffer<
00076     async_event_deque,
00077     base::no_lock_guard<>, // We handle locking ourselves in the
00078                            // processor class because it is not so simple.
00079     base::lock_guard<> >
00080 async_triple_buffer;
00081 
00082 class basic_process_context : private boost::noncopyable
00083 {
00084 public:    
00085     std::size_t block_size () const
00086     { return _block_size; }
00087 
00088     std::size_t frame_rate () const
00089     { return _frame_rate; }
00090 
00091 protected:
00093     basic_process_context (std::size_t block_size,
00094                            std::size_t frame_rate,
00095                            std::size_t queue_size);
00096     
00097     rt_triple_buffer    _rt_buffers;
00098     async_triple_buffer _async_buffers;
00099     
00100     std::size_t _block_size;
00101     std::size_t _frame_rate;
00102     
00103     // FIXME: Factor the related functions a bit
00104     std::thread             _async_thread;
00105     std::condition_variable _async_cond;
00106     std::mutex              _async_mutex;
00107     bool                    _async_request_flip;
00108 
00109     friend class processor;
00110 };
00111 
00112 class rt_process_context : public virtual basic_process_context
00113 {
00114 public:
00115     template <class Event, typename... Args>
00116     bool push_rt_event (Args&&... args);
00117 
00118     template <class Event, typename... Args>
00119     bool push_async_event (Args&&... args);
00120 
00121     template <class Concrete>
00122     bool push_rt_event (Concrete&& arg)
00123     {
00124         return this->push_rt_event<
00125             typename std::decay<Concrete>::type,
00126             decltype (std::forward<Concrete> (arg))> (
00127                 std::forward<Concrete> (arg));
00128     }
00129 
00130     template <class Concrete>
00131     bool push_async_event (Concrete&& arg)
00132     {
00133         return this->push_async_event<
00134             typename std::decay<Concrete>::type,
00135             decltype (std::forward<Concrete> (arg))> (
00136                 std::forward<Concrete> (arg));
00137     }
00138 
00139 protected:
00140     friend class processor;
00141     
00142     rt_process_context (std::size_t block_size,
00143                            std::size_t frame_rate,
00144                            std::size_t queue_size)
00145         : basic_process_context (block_size, frame_rate, queue_size)
00146     {}
00147     
00148     node_ptr        _curr_node;
00149     node_ptr        _request_node;
00150     out_port_base*  _request_output;
00151 };
00152 
00153 class async_process_context : public virtual basic_process_context
00154 {
00155 public:    
00156     template <class Event, typename... Args>
00157     bool push_rt_event (Args&&... args);
00158 
00159     template <class Event, typename... Args>
00160     bool push_async_event (Args&&... args);
00161 
00162     template <class Concrete>
00163     bool push_rt_event (Concrete&& arg)
00164     {
00165         return this->push_rt_event<
00166             typename std::decay<Concrete>::type,
00167             decltype (std::forward<Concrete> (arg))> (
00168                 std::forward<Concrete> (arg));
00169     }
00170 
00171     template <class Concrete>
00172     bool push_async_event (Concrete&& arg)
00173     {
00174         return this->push_async_event<
00175             typename std::decay<Concrete>::type,
00176             decltype (std::forward<Concrete> (arg))> (
00177                 std::forward<Concrete> (arg));
00178     }
00179 
00180 protected:
00181     friend class processor;
00182 
00183     async_process_context (std::size_t block_size,
00184                            std::size_t frame_rate,
00185                            std::size_t queue_size)
00186         : basic_process_context (block_size, frame_rate, queue_size) {}
00187     
00188 };
00189 
00190 class user_process_context : public virtual basic_process_context
00191 {
00192 public:
00193     template <class Event, typename... Args>
00194     bool push_rt_event (Args&&... args);
00195 
00196     template <class Event, typename... Args>
00197     bool push_async_event (Args&&... args);
00198 
00199     template <class Concrete>
00200     bool push_rt_event (Concrete&& arg)
00201     {
00202         return this->push_rt_event<
00203             typename std::decay<Concrete>::type,
00204             decltype (std::forward<Concrete> (arg))> (
00205                 std::forward<Concrete> (arg));
00206     }
00207 
00208     template <class Concrete>
00209     bool push_async_event (Concrete&& arg)
00210     {
00211         return this->push_async_event<
00212             typename std::decay<Concrete>::type,
00213             decltype (std::forward<Concrete> (arg))> (
00214                 std::forward<Concrete> (arg));
00215     }
00216 
00217 protected:
00218     friend class processor;
00219 
00220     user_process_context (std::size_t block_size,
00221                              std::size_t frame_rate,
00222                              std::size_t queue_size)
00223         : basic_process_context (block_size, frame_rate, queue_size) {}
00224 };
00225 
00226 class full_process_context : public rt_process_context
00227                            , public async_process_context
00228                            , public user_process_context
00229 {
00230 // private:
00231 public: // Eases unit testing!
00232     friend class processor;
00233     
00234     full_process_context (std::size_t block_size = 1 << 6,
00235                           std::size_t frame_rate = 44100,
00236                           std::size_t queue_size = 1 << 10)
00237         : basic_process_context (block_size, frame_rate, queue_size)
00238         , rt_process_context (block_size, frame_rate, queue_size)
00239         , async_process_context (block_size, frame_rate, queue_size)
00240         , user_process_context (block_size, frame_rate, queue_size)
00241     {}
00242 };
00243 
00244 
00245 class processor : private boost::noncopyable
00246 {
00247 public:
00248     processor (core::patch_ptr root   = 0,
00249                std::size_t block_size = default_block_size,
00250                std::size_t frame_rate = default_frame_rate,
00251                std::size_t queue_size = default_queue_size);
00252 
00253     ~processor ();
00254     
00255     void start ();
00256     void stop ();
00257 
00258     core::patch_ptr root ()
00259     { return _root; }
00260 
00261     user_process_context& context ()
00262     { return _ctx; }
00263     
00264     const user_process_context& context () const
00265     { return _ctx; }
00266     
00267     void set_block_size (std::size_t new_size);
00268     void set_frame_rate (std::size_t new_frame_rate);
00269     
00270     void rt_request_process (std::ptrdiff_t iterations);
00271     void rt_request_process ();
00272 
00273     bool is_running () const
00274     { return _is_running; }
00275 
00277     void notify_add_node (node_ptr node)
00278     { _explore_node_add (node); }
00279 
00281     void notify_remove_node (node_ptr node)
00282     { _explore_node_remove (node); }
00283     
00284 private:
00285     void _explore_node_add (node_ptr node);
00286     void _explore_node_remove (node_ptr node);
00287     
00288     void _async_loop ();
00289     void _rt_process_once ();
00290 
00291     typedef std::list<sink_node_ptr> sink_node_list;
00292     typedef std::list<process_node_ptr> process_node_list;
00293 
00294     core::patch_ptr         _root;
00295     
00296     process_node_list       _procs; // Not readed from rt-threads.
00297     sink_node_list          _sinks; // Readed from rt-threads.
00298     
00299     full_process_context    _ctx;
00300 
00301     std::mutex              _rt_mutex;
00302     
00303     std::atomic<bool>       _is_running;
00304 };
00305 
00306 } /* namespace graph */
00307 } /* namespace psynth */
00308 
00309 #include <psynth/new_graph/processor.tpp>
00310 
00311 #endif /* PSYNTH_GRAPH_PROCESSOR_HPP_ */