more miscellaneous changes for audioengine, all of this is still far from actually...
authorPaul Davis <paul@linuxaudiosystems.com>
Wed, 24 Jul 2013 12:36:04 +0000 (08:36 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Wed, 24 Jul 2013 12:36:04 +0000 (08:36 -0400)
gtk2_ardour/ardour_ui.cc
gtk2_ardour/main.cc
gtk2_ardour/opts.cc
gtk2_ardour/opts.h
libs/ardour/ardour/audio_backend.h
libs/ardour/ardour/audioengine.h
libs/ardour/ardour/port.h
libs/ardour/ardour/port_manager.h
libs/ardour/audioengine.cc
libs/ardour/jack_audiobackend.cc
libs/ardour/port.cc

index 556dee99feaa4d3d0e0237341b6db8a2b7bb7607..aa71040f462547ce304e476f3d62d8cbf541a7f6 100644 (file)
@@ -396,7 +396,7 @@ ARDOUR_UI::create_engine ()
        loading_message (_("Starting audio engine"));
 
        try {
-               engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid);
+               engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::backend_client_name, ARDOUR_COMMAND_LINE::backend_session_uuid);
 
        } catch (...) {
 
index 21e534397976b39930a1e02fd8c7f3fb2dc21a55..e5a7e8d5804165d2996f5b9f46c02cfc26a7fd53 100644 (file)
@@ -372,33 +372,29 @@ static void load_custom_fonts() {
 #endif
 
 static gboolean
-tell_about_jack_death (void* /* ignored */)
+tell_about_backend_death (void* /* ignored */)
 {
        if (AudioEngine::instance()->processed_frames() == 0) {
                /* died during startup */
-               MessageDialog msg (_("JACK exited"), false);
+               MessageDialog msg (string_compose (_("The audio backend (%1) has failed, or terminated"), AudioEngine::instance()->current_backend_name()), false);
                msg.set_position (Gtk::WIN_POS_CENTER);
                msg.set_secondary_text (string_compose (_(
-"JACK exited unexpectedly, and without notifying %1.\n\
+"%2 exited unexpectedly, and without notifying %1.\n\
 \n\
-This could be due to misconfiguration or to an error inside JACK.\n\
+This could be due to misconfiguration or to an error inside %2.\n\
 \n\
-Click OK to exit %1."), PROGRAM_NAME));
+Click OK to exit %1."), PROGRAM_NAME, AudioEngine::instance()->current_backend_name()));
 
                msg.run ();
                _exit (0);
 
        } else {
 
-               /* engine has already run, so this is a mid-session JACK death */
-
-               MessageDialog* msg = manage (new MessageDialog (_("JACK exited"), false));
-               msg->set_secondary_text (string_compose (_(
-"JACK exited unexpectedly, and without notifying %1.\n\
-\n\
-This is probably due to an error inside JACK. You should restart JACK\n\
-and reconnect %1 to it, or exit %1 now. You cannot save your\n\
-session at this time, because we would lose your connection information.\n"), PROGRAM_NAME));
+               /* engine has already run, so this is a mid-session backend death */
+                       
+               MessageDialog msg (string_compose (_("The audio backend (%1) has failed, or terminated"), AudioEngine::instance()->current_backend_name()), false);
+               msg->set_secondary_text (string_compose (_("%2 exited unexpectedly, and without notifying %1."),
+                                                        PROGRAM_NAME, AudioEngine::instance()->current_backend_name()));
                msg->present ();
        }
        return false; /* do not call again */
@@ -407,15 +403,15 @@ session at this time, because we would lose your connection information.\n"), PR
 static void
 sigpipe_handler (int /*signal*/)
 {
-       /* XXX fix this so that we do this again after a reconnect to JACK
+       /* XXX fix this so that we do this again after a reconnect to the backend
         */
 
-       static bool done_the_jack_thing = false;
+       static bool done_the_backend_thing = false;
 
-       if (!done_the_jack_thing) {
+       if (!done_the_backend_thing) {
                AudioEngine::instance()->died ();
-               g_idle_add (tell_about_jack_death, 0);
-               done_the_jack_thing =  true;
+               g_idle_add (tell_about_backend_death, 0);
+               done_the_backend_thing =  true;
        }
 }
 
index b29f106bfeedfdfa104c90aadbf91dd406928fd4..90d753af4c604ed06caa750e9cb3a934fbd6372c 100644 (file)
@@ -32,7 +32,8 @@
 using namespace std;
 
 string ARDOUR_COMMAND_LINE::session_name = "";
-string ARDOUR_COMMAND_LINE::jack_client_name = "ardour";
+string ARDOUR_COMMAND_LINE::backend_client_name = "ardour";
+string ARDOUR_COMMAND_LINE::backend_session_uuid;
 bool  ARDOUR_COMMAND_LINE::show_key_actions = false;
 bool ARDOUR_COMMAND_LINE::no_splash = false;
 bool ARDOUR_COMMAND_LINE::just_version = false;
@@ -45,7 +46,6 @@ string ARDOUR_COMMAND_LINE::keybindings_path = ""; /* empty means use builtin de
 std::string ARDOUR_COMMAND_LINE::menus_file = "ardour.menus";
 bool ARDOUR_COMMAND_LINE::finder_invoked_ardour = false;
 string ARDOUR_COMMAND_LINE::immediate_save;
-string ARDOUR_COMMAND_LINE::jack_session_uuid;
 string ARDOUR_COMMAND_LINE::load_template;
 bool ARDOUR_COMMAND_LINE::check_announcements = true;
 
@@ -60,7 +60,7 @@ print_help (const char *execname)
             << _("  -h, --help                  Print this message\n")
             << _("  -a, --no-announcements      Do not contact website for announcements\n")
             << _("  -b, --bindings              Print all possible keyboard binding names\n")
-            << _("  -c, --name <name>           Use a specific jack client name, default is ardour\n")
+            << _("  -c, --name <name>           Use a specific backend client name, default is ardour\n")
             << _("  -d, --disable-plugins       Disable all plugins in an existing session\n")
             << _("  -D, --debug <options>       Set debug flags. Use \"-D list\" to see available options\n")
             << _("  -n, --no-splash             Do not show splash screen\n")
@@ -199,7 +199,7 @@ ARDOUR_COMMAND_LINE::parse_opts (int argc, char *argv[])
                        break;
 
                case 'c':
-                       jack_client_name = optarg;
+                       backend_client_name = optarg;
                        break;
 
                case 'C':
@@ -215,7 +215,7 @@ ARDOUR_COMMAND_LINE::parse_opts (int argc, char *argv[])
                        break;
 
                case 'U':
-                       jack_session_uuid = optarg;
+                       backend_session_uuid = optarg;
                         break;
 
                default:
index b9faa36d7216c523303330055d537b08aeb03e70..fdf29157d2d17ffdbecca8d33e3589570ad7f33d 100644 (file)
@@ -28,7 +28,8 @@ extern std::string session_name;
 extern bool   show_key_actions;
 extern bool   no_splash;
 extern bool   just_version;
-extern std::string jack_client_name;
+extern std::string backend_client_name;
+extern std::string backend_session_uuid;
 extern bool   use_vst;
 extern bool   new_session;
 extern char*  curvetest_file;
@@ -39,7 +40,6 @@ extern std::string keybindings_path;
 extern std::string menus_file;
 extern bool   finder_invoked_ardour;
 extern std::string immediate_save;
-extern std::string jack_session_uuid;
 extern std::string load_template;
 extern bool        check_announcements;
 
index d286fbd9c2f92e4f9e32a505d604f89c0ecb7deb..98f6c4d8a7782f054aa4d1517bbdc0a4df72d8bd 100644 (file)
@@ -80,24 +80,102 @@ class AudioBackend {
      */
     virtual std::vector<uint32_t> available_buffer_sizes (const std::string& device) const = 0;
 
-    struct Parameters {
-       std::string device_name;
-       float       sample_rate;
-       uint32_t    buffer_size;
-       uint32_t    systemic_input_latency;
-       uint32_t    systemic_output_latency;
-       uint32_t    input_channels;
-       uint32_t    output_channels;
+    /** Returns the maximum number of input channels that are potentially
+     * usable with the hardware identified by @param device.  Any number from 1
+     * to the value returned may be supplied in other calls to this backend as
+     * the input channel count to use with the name device, but the requested
+     * count may turn out to be unavailable, or become invalid at any time.
+     */
+    virtual uint32_t available_input_channel_count (const std::string& device) const = 0;
+
+    /** Returns the maximum number of output channels that are potentially
+     * usable with the hardware identified by @param device.  Any number from 1
+     * to the value returned may be supplied in other calls to this backend as
+     * the output channel count to use with the name device, but the requested
+     * count may turn out to be unavailable, or become invalid at any time.
+     */
+    virtual uint32_t available_output_channel_count (const std::string& device) const = 0;
+
+    enum SampleFormat {
+           Signed16bitInteger,
+           Signed24bitInteger,
+           Signed32bitInteger,
+           FloatingPoint
     };
 
-    virtual int set_parameters (const Parameters&) = 0;
-    virtual int get_parameters (Parameters&) const = 0;
+    /* Set the hardware parameters.
+     * 
+     * If called when the current state is stopped or paused,
+     * the changes will not take effect until the state changes to running.
+     *
+     * If called while running, the state will change as fast as the
+     * implementation allows.
+     *
+     * All set_*() methods return zero on success, non-zero otherwise.
+     */
+
+    /** Set the name of the device to be used
+     */
+    virtual int set_device_name (const std::string&) = 0;
+    /** Set the sample rate to be used
+     */
+    virtual int set_sample_rate (float) = 0;
+    /** Set the buffer size to be used.
+     *
+     * The device is assumed to use a double buffering scheme, so that one
+     * buffer's worth of data can be processed by hardware while software works
+     * on the other buffer. All known suitable audio APIs support this model
+     * (though ALSA allows for alternate numbers of buffers, and CoreAudio
+     * doesn't directly expose the concept).
+     */
+    virtual int set_buffer_size (uint32_t) = 0;
+    /** Set the preferred underlying hardware sample format
+     *
+     * This does not change the sample format (32 bit float) read and
+     * written to the device via the Port API.
+     */
+    virtual int set_sample_format (SampleFormat) = 0;
+    /** Set the preferred underlying hardware data layout.
+     * If @param yn is true, then the hardware will interleave
+     * samples for successive channels; otherwise, the hardware will store
+     * samples for a single channel contiguously.
+     * 
+     * Setting this does not change the fact that all data streams
+     * to and from Ports are mono (essentially, non-interleaved)
+     */
+    virtual int set_interleaved (bool yn) = 0;
+    /** Set the number of input channels that should be used
+     */
+    virtual int set_input_channels (uint32_t) = 0;
+    /** Set the number of output channels that should be used
+     */
+    virtual int set_output_channels (uint32_t) = 0;
+    /** Set the (additional) input latency that cannot be determined via 
+     * the implementation's underlying code (e.g. latency from
+     * external D-A/D-A converters. Units are samples.
+     */
+    virtual int set_systemic_input_latency (uint32_t) = 0;
+    /** Set the (additional) output latency that cannot be determined via 
+     * the implementation's underlying code (e.g. latency from
+     * external D-A/D-A converters. Units are samples.
+     */
+    virtual int set_systemic_output_latency (uint32_t) = 0;
+
+    virtual std::string  get_device_name () const = 0;
+    virtual float        get_sample_rate () const = 0;
+    virtual uint32_t     get_buffer_size () const = 0;
+    virtual SampleFormat get_sample_format () const = 0;
+    virtual bool         get_interleaved () const = 0;
+    virtual uint32_t     get_input_channels () const = 0;
+    virtual uint32_t     get_output_channels () const = 0;
+    virtual uint32_t     get_systemic_input_latency () const = 0;
+    virtual uint32_t     get_systemic_output_latency () const = 0;
 
     /* Basic state control */
 
     /** Start using the device named in the most recent call
-     * to set_parameters(), with the parameters also provided
-     * to that call.
+     * to set_device(), with the parameters set by various
+     * the most recent calls to set_sample_rate() etc. etc.
      * 
      * At some undetermined time after this function is successfully called,
      * the backend will start calling the ::process_callback() method of
@@ -108,14 +186,14 @@ class AudioBackend {
      */
     virtual int start () = 0;
 
-    /** Stop using the device named in the most recent call to set_parameters().
+    /** Stop using the device currently in use. 
      *
      * If the function is successfully called, no subsequent calls to the
      * process_callback() of @param engine will be made after the function
-     * returns, until set_parameters() and start() are called again.
+     * returns, until parameters are reset and start() are called again.
      * 
      * The backend is considered to be un-configured after a successful
-     * return, and requires a call to set_parameters() before it can be
+     * return, and requires calls to set hardware parameters before it can be
      * start()-ed again. See pause() for a way to avoid this. stop() should
      * only be used when reconfiguration is required OR when there are no 
      * plans to use the backend in the future with a reconfiguration.
@@ -131,10 +209,8 @@ class AudioBackend {
      * returns, until start() is called again.
      * 
      * The backend will retain its existing parameter configuration after a successful
-     * return, and requires a call to set_parameters() before it can be
-     * start()-ed again. See pause() for a way to avoid this. stop() should
-     * only be used when reconfiguration is required OR when there are no 
-     * plans to use the backend in the future with a reconfiguration.
+     * return, and does NOT require any calls to set hardware parameters before it can be
+     * start()-ed again. 
      *
      * Return zero if successful, 1 if the device is not in use, negative values on error
      */
@@ -142,9 +218,15 @@ class AudioBackend {
 
     /** While remaining connected to the device, and without changing its
      * configuration, start (or stop) calling the process_callback() of @param engine
-     * without waiting for the device. 
+     * without waiting for the device. Once process_callback() has returned, it
+     * will be called again immediately, thus allowing for faster-than-realtime
+     * processing.
+     *
+     * All registered ports remain in existence and all connections remain
+     * unaltered. However, any physical ports should NOT be used by the
+     * process_callback() during freewheeling - the data behaviour is undefined.
      *
-     * If @param start_stop is true, begin this behaviour, otherwise cease this
+     * If @param start_stop is true, begin this behaviour; otherwise cease this
      * behaviour if it currently occuring, and return to calling
      * process_callback() of @param engine by waiting for the device.
      *
@@ -155,7 +237,13 @@ class AudioBackend {
     /** return the fraction of the time represented by the current buffer
      * size that is being used for each buffer process cycle, as a value
      * from 0.0 to 1.0
-    */
+     *
+     * E.g. if the buffer size represents 5msec and current processing
+     * takes 1msec, the returned value should be 0.2. 
+     * 
+     * Implementations can feel free to smooth the values returned over
+     * time (e.g. high pass filtering, or its equivalent).
+     */
     virtual float get_cpu_load() const  = 0;
 
     /* Transport Control (JACK is the only audio API that currently offers
@@ -179,6 +267,16 @@ class AudioBackend {
      */
     virtual framepos_t transport_frame() { return 0; }
 
+    /** If @param yn is true, become the time master for any inter-application transport
+     * timebase, otherwise cease to be the time master for the same.
+     *
+     * Return zero on success, non-zero otherwise
+     * 
+     * JACK is the only currently known audio API with the concept of a shared
+     * transport timebase.
+     */
+    virtual int set_time_master (bool yn) { return 0; }
+
     virtual framecnt_t sample_rate () const;
     virtual pframes_t  samples_per_cycle () const;
     virtual int        usecs_per_cycle () const { return _usecs_per_cycle; }
@@ -229,11 +327,28 @@ class AudioBackend {
      * that it can only be called by a process thread)
      */
     virtual bool get_sync_offset (pframes_t& offset) const { return 0; }
+
+    /** Create a new thread suitable for running part of the buffer process
+     * cycle (i.e. Realtime scheduling, memory allocation, etc. etc are all
+     * correctly setup), with a stack size given in bytes by specified @param
+     * stacksize. The thread will begin executing @param func, and will exit
+     * when that function returns.
+     */
+    virtual int create_process_thread (boost::function<void()> func, pthread_t*, size_t stacksize) = 0;
     
   private:
     AudioEngine&          engine;
-    Parameters           _last_requested_parameters;
     State                _state;
+
+    std::string  _target_device;
+    float        _target_sample_rate;
+    uint32_t     _target_buffer_size;
+    SampleFormat _target_sample_format;
+    bool         _target_interleaved;
+    uint32_t     _target_input_channels;
+    uint32_t     _target_output_channels;
+    uin32_t      _target_systemic_input_latency;
+    uin32_t      _target_systemic_input_latency;
 };
 
 }
index 5a064f51833be6cfb9e1d8aac3f6950943907ee3..a3f16ff376eb1dbeeb2610f6c7a7300f162b244d 100644 (file)
@@ -33,7 +33,6 @@
 
 #include <glibmm/threads.h>
 
-#include "pbd/rcu.h"
 #include "pbd/signals.h"
 #include "pbd/stacktrace.h"
 
@@ -60,163 +59,145 @@ class MidiPort;
 class Port;
 class Session;
 class ProcessThread;
+class AudioBackend;
 
 class AudioEngine : public SessionHandlePtr
 {
 public:
-       typedef std::map<std::string,boost::shared_ptr<Port> > Ports;
-
-       AudioEngine (std::string client_name, std::string session_uuid);
-       virtual ~AudioEngine ();
-
-        static int discover_backends();
-        std::vector<std::string> available_backends() const;
-
-       ProcessThread* main_thread() const { return _main_thread; }
-
-       std::string client_name() const { return jack_client_name; }
-
-       int stop (bool forever = false);
-       int start ();
-        int pause ();
-        int freewheel (bool);
+    typedef std::map<std::string,boost::shared_ptr<Port> > Ports;
     
-       bool running() const { return _running; }
-
-       Glib::Threads::Mutex& process_lock() { return _process_lock; }
-
-
-       int request_buffer_size (pframes_t);
-
-       framecnt_t processed_frames() const { return _processed_frames; }
-
-       float get_cpu_load() {
-               jack_client_t* _priv_jack = _jack;
-               if (!_running || !_priv_jack) {
-                       return 0;
-               }
-               return jack_cpu_load (_priv_jack);
-       }
-
-       void set_session (Session *);
-       void remove_session (); // not a replacement for SessionHandle::session_going_away()
-
-       class NoBackendAvailable : public std::exception {
-       public:
-               virtual const char *what() const throw() { return "could not connect to engine backend"; }
-       };
-
-       void split_cycle (pframes_t offset);
-
-       int  reset_timebase ();
-
-        void update_latencies ();
-
-       /* start/stop freewheeling */
-
-       int freewheel (bool onoff);
-       bool freewheeling() const { return _freewheeling; }
-
-       /* this signal is sent for every process() cycle while freewheeling.
-_         the regular process() call to session->process() is not made.
-       */
-
-       PBD::Signal1<int, pframes_t> Freewheel;
-
-       PBD::Signal0<void> Xrun;
-
-       /* this signal is if JACK notifies us of a graph order event */
+    AudioEngine (std::string client_name, std::string session_uuid);
+    virtual ~AudioEngine ();
+    
+    static int discover_backends();
+    std::vector<std::string> available_backends() const;
+    std::string current_backend_name () const;
 
-       PBD::Signal0<void> GraphReordered;
+    ProcessThread* main_thread() const { return _main_thread; }
+    
+    std::string client_name() const { return backend_client_name; }
+    
+    int stop (bool forever = false);
+    int start ();
+    int pause ();
+    int freewheel (bool onoff);
+    bool freewheeling() const { return _freewheeling; }
+   
+    bool running() const { return _running; }
+    Glib::Threads::Mutex& process_lock() { return _process_lock; }
+
+    int request_buffer_size (pframes_t);
+
+    framecnt_t processed_frames() const { return _processed_frames; }
+    
+    float get_cpu_load();
+    
+    void set_session (Session *);
+    void remove_session (); // not a replacement for SessionHandle::session_going_away()
+    
+    class NoBackendAvailable : public std::exception {
+      public:
+       virtual const char *what() const throw() { return "could not connect to engine backend"; }
+    };
+    
+    void split_cycle (pframes_t offset);
+    
+    int  reset_timebase ();
+    
+    void update_latencies ();
 
+    
+    /* this signal is sent for every process() cycle while freewheeling.
+       (the regular process() call to session->process() is not made)
+    */
+    
+    PBD::Signal1<int, pframes_t> Freewheel;
+    
+    PBD::Signal0<void> Xrun;
+    
+    /* this signal is if the backend notifies us of a graph order event */
+    
+    PBD::Signal0<void> GraphReordered;
+    
 #ifdef HAVE_JACK_SESSION
-       PBD::Signal1<void,jack_session_event_t *> JackSessionEvent;
+    PBD::Signal1<void,jack_session_event_t *> JackSessionEvent;
 #endif
-
-
-       /* this signal is emitted if the sample rate changes */
-
-       PBD::Signal1<void, framecnt_t> SampleRateChanged;
-
-       /* this signal is sent if JACK ever disconnects us */
-
-       PBD::Signal1<void,const char*> Halted;
-
-       /* these two are emitted when the engine itself is
-          started and stopped
-       */
-
-       PBD::Signal0<void> Running;
-       PBD::Signal0<void> Stopped;
-
-       /** Emitted if a JACK port is registered or unregistered */
-       PBD::Signal0<void> PortRegisteredOrUnregistered;
-
-       /** Emitted if a JACK port is connected or disconnected.
-        *  The Port parameters are the ports being connected / disconnected, or 0 if they are not known to Ardour.
-        *  The std::string parameters are the (long) port names.
-        *  The bool parameter is true if ports were connected, or false for disconnected.
-        */
-       PBD::Signal5<void, boost::weak_ptr<Port>, std::string, boost::weak_ptr<Port>, std::string, bool> PortConnectedOrDisconnected;
-
-       std::string make_port_name_relative (std::string) const;
-       std::string make_port_name_non_relative (std::string) const;
-       bool port_is_mine (const std::string&) const;
-
-       static AudioEngine* instance() { return _instance; }
-       static void destroy();
-       void died ();
-
-       int create_process_thread (boost::function<void()>, pthread_t*, size_t stacksize);
-
-private:
-       static AudioEngine*       _instance;
-
-       Glib::Threads::Mutex      _process_lock;
-        Glib::Threads::Cond        session_removed;
-       bool                       session_remove_pending;
-        frameoffset_t              session_removal_countdown;
-        gain_t                     session_removal_gain;
-        gain_t                     session_removal_gain_step;
-       bool                      _running;
-       bool                      _has_run;
-       mutable framecnt_t        _buffer_size;
-       std::map<DataType,size_t> _raw_buffer_sizes;
-       mutable framecnt_t        _frame_rate;
-       /// number of frames between each check for changes in monitor input
-       framecnt_t                 monitor_check_interval;
-       /// time of the last monitor check in frames
-       framecnt_t                 last_monitor_check;
-       /// the number of frames processed since start() was called
-       framecnt_t                _processed_frames;
-       bool                      _freewheeling;
-       bool                      _pre_freewheel_mmc_enabled;
-       int                       _usecs_per_cycle;
-       bool                       port_remove_in_progress;
-        Glib::Threads::Thread*     m_meter_thread;
-       ProcessThread*            _main_thread;
-
-
-       SerializedRCUManager<Ports> ports;
-
-       boost::shared_ptr<Port> register_port (DataType type, const std::string& portname, bool input);
-
-       int    process_callback (pframes_t nframes);
-       void*  process_thread ();
-       void   remove_all_ports ();
-
-       void port_registration_failure (const std::string& portname);
-
-       void meter_thread ();
-       void start_metering_thread ();
-       void stop_metering_thread ();
-
-       static gint      m_meter_exit;
-
-        void parameter_changed (const std::string&);
-        PBD::ScopedConnection config_connection;
+    
+    /* this signal is emitted if the sample rate changes */
+    
+    PBD::Signal1<void, framecnt_t> SampleRateChanged;
+    
+    /* this signal is sent if the backend ever disconnects us */
+    
+    PBD::Signal1<void,const char*> Halted;
+    
+    /* these two are emitted when the engine itself is
+       started and stopped
+    */
+    
+    PBD::Signal0<void> Running;
+    PBD::Signal0<void> Stopped;
+    
+    /** Emitted if a Port is registered or unregistered */
+    PBD::Signal0<void> PortRegisteredOrUnregistered;
+    
+    /** Emitted if a Port is connected or disconnected.
+     *  The Port parameters are the ports being connected / disconnected, or 0 if they are not known to Ardour.
+     *  The std::string parameters are the (long) port names.
+     *  The bool parameter is true if ports were connected, or false for disconnected.
+     */
+    PBD::Signal5<void, boost::weak_ptr<Port>, std::string, boost::weak_ptr<Port>, std::string, bool> PortConnectedOrDisconnected;
+    
+    std::string make_port_name_relative (std::string) const;
+    std::string make_port_name_non_relative (std::string) const;
+    bool port_is_mine (const std::string&) const;
+    
+    static AudioEngine* instance() { return _instance; }
+    static void destroy();
+    void died ();
+    
+    /* The backend will cause this at the appropriate time(s)
+     */
+    int    process_callback (pframes_t nframes);
+    
+  private:
+    static AudioEngine*       _instance;
+    
+    Glib::Threads::Mutex      _process_lock;
+    Glib::Threads::Cond        session_removed;
+    bool                       session_remove_pending;
+    frameoffset_t              session_removal_countdown;
+    gain_t                     session_removal_gain;
+    gain_t                     session_removal_gain_step;
+    bool                      _running;
+    bool                      _has_run;
+    mutable framecnt_t        _buffer_size;
+    std::map<DataType,size_t> _raw_buffer_sizes;
+    mutable framecnt_t        _frame_rate;
+    /// number of frames between each check for changes in monitor input
+    framecnt_t                 monitor_check_interval;
+    /// time of the last monitor check in frames
+    framecnt_t                 last_monitor_check;
+    /// the number of frames processed since start() was called
+    framecnt_t                _processed_frames;
+    bool                      _freewheeling;
+    bool                      _pre_freewheel_mmc_enabled;
+    int                       _usecs_per_cycle;
+    bool                       port_remove_in_progress;
+    Glib::Threads::Thread*     m_meter_thread;
+    ProcessThread*            _main_thread;
+    
+    
+    void meter_thread ();
+    void start_metering_thread ();
+    void stop_metering_thread ();
+    
+    static gint      m_meter_exit;
+    
+    void parameter_changed (const std::string&);
+    PBD::ScopedConnection config_connection;
 };
-
+       
 } // namespace ARDOUR
 
 #endif /* __ardour_audioengine_h__ */
index e225117d940a90adde0d8e4c7bb19b134182ffce..5afe8e28068bc59a7d531c0665ce37d9773bcf08 100644 (file)
@@ -90,11 +90,11 @@ public:
        virtual int connect (Port *);
        int disconnect (Port *);
 
-       void ensure_jack_monitors_input (bool);
-       bool jack_monitoring_input () const;
+       void request_monitor_input (bool);
+       void ensure_monitor_input (bool);
+       bool monitoring_input () const;
        int reestablish ();
        int reconnect ();
-       void request_jack_monitors_input (bool);
 
        bool last_monitor() const { return _last_monitor; }
        void set_last_monitor (bool yn) { _last_monitor = yn; }
index 8a363899ea4972ea3c478a8e3b86a95e0c3f6b24..f6aedc02a17fad709a41e51aa210f9df7f9f41b0 100644 (file)
-namespace ARDOUR
+/*
+    Copyright (C) 2013 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.
+
+*/
+
+#ifndef __libardour_port_manager_h__
+#define __libardour_port_manager_h__
+
+#include <vector>
+#include <string>
+#include <exception>
+#include <map>
+
+#include <stdint.h>
+
+#include <boost/shared_ptr.hpp>
+
+#include "pbd/rcu.h"
+
+#include "ardour/chan_count.h"
+
+namespace ARDOUR {
+
+class Port;
 
 class PortManager 
 {
   public:
-       PortManager() {}
-       virtual ~PortManager() {}
-
-       /* Port registration */
-       
-       virtual boost::shared_ptr<Port> register_input_port (DataType, const std::string& portname) = 0;
-       virtual boost::shared_ptr<Port> register_output_port (DataType, const std::string& portname) = 0;
-       virtual int unregister_port (boost::shared_ptr<Port>) = 0;
-       
-       /* Port connectivity */
-       
-       virtual int connect (const std::string& source, const std::string& destination) = 0;
-       virtual int disconnect (const std::string& source, const std::string& destination) = 0;
-       virtual int disconnect (boost::shared_ptr<Port>) = 0;
+    typedef std::map<std::string,boost::shared_ptr<Port> > Ports;
+    
+    PortManager();
+    virtual ~PortManager() {}
+    
+    /* Port registration */
+    
+    virtual boost::shared_ptr<Port> register_input_port (DataType, const std::string& portname) = 0;
+    virtual boost::shared_ptr<Port> register_output_port (DataType, const std::string& portname) = 0;
+    virtual int unregister_port (boost::shared_ptr<Port>) = 0;
+    
+    /* Port connectivity */
+    
+    virtual int connect (const std::string& source, const std::string& destination) = 0;
+    virtual int disconnect (const std::string& source, const std::string& destination) = 0;
+    virtual int disconnect (boost::shared_ptr<Port>) = 0;
+    
+    /* other Port management */
+    
+    virtual bool port_is_physical (const std::string&) const = 0;
+    virtual void get_physical_outputs (DataType type, std::vector<std::string>&) = 0;
+    virtual void get_physical_inputs (DataType type, std::vector<std::string>&) = 0;
+    virtual boost::shared_ptr<Port> get_port_by_name (const std::string &) = 0;
+    virtual void port_renamed (const std::string&, const std::string&) = 0;
+    virtual ChanCount n_physical_outputs () const = 0;
+    virtual ChanCount n_physical_inputs () const = 0;
+    virtual const char ** get_ports (const std::string& port_name_pattern, const std::string& type_name_pattern, uint32_t flags) = 0;
+    
+    void remove_all_ports ();
+    
+    /* per-Port monitoring */
+    
+    virtual bool can_request_input_monitoring () const = 0;
+    virtual void request_input_monitoring (const std::string&, bool) const = 0;
+    
+    class PortRegistrationFailure : public std::exception {
+      public:
+       PortRegistrationFailure (std::string const & why = "")
+               : reason (why) {}
        
-       /* other Port management */
+       ~PortRegistrationFailure () throw () {}
        
-       virtual bool port_is_physical (const std::string&) const = 0;
-       virtual void get_physical_outputs (DataType type, std::vector<std::string>&) = 0;
-       virtual void get_physical_inputs (DataType type, std::vector<std::string>&) = 0;
-       virtual boost::shared_ptr<Port> get_port_by_name (const std::string &) = 0;
-       virtual void port_renamed (const std::string&, const std::string&) = 0;
-       virtual ChanCount n_physical_outputs () const = 0;
-       virtual ChanCount n_physical_inputs () const = 0;
-       virtual const char ** get_ports (const std::string& port_name_pattern, const std::string& type_name_pattern, uint32_t flags) = 0;
-
-       /* per-Port monitoring */
+       virtual const char *what() const throw () { return reason.c_str(); }
        
-       virtual bool can_request_input_monitoring () const = 0;
-       virtual void request_input_monitoring (const std::string&, bool) const = 0;
+      private:
+       std::string reason;
+    };
 
-       class PortRegistrationFailure : public std::exception {
-       public:
-               PortRegistrationFailure (std::string const & why = "")
-                       : reason (why) {}
-
-               ~PortRegistrationFailure () throw () {}
-
-               virtual const char *what() const throw () { return reason.c_str(); }
-
-       private:
-               std::string reason;
-       };
+  protected:
+    typedef void* PortHandle;
+    PortHandle register (const std::string&, DataType type, Port::Flags);
+    void  unregister (PortHandle);
+    bool  connected (PortHandle);
+    int   disconnect_all (PortHandle);
+    bool  connected_to (PortHandle, const std::string);
+    int   get_connections (PortHandle, std::vector<std::string>&);
 
+  private:
+    SerializedRCUManager<Ports> ports;
+    boost::shared_ptr<Port> register_port (DataType type, const std::string& portname, bool input);
+    void port_registration_failure (const std::string& portname);
 };
+       
+}
+
+#endif /* __libardour_port_manager_h__ */
index 1166b906f893713cb7d867895ad551c112860923..25a55b5aaf01bb19cc9adb9ecc15891ace852be4 100644 (file)
@@ -70,7 +70,6 @@ AudioEngine::AudioEngine ()
        , port_remove_in_progress (false)
        , m_meter_thread (0)
        , _main_thread (0)
-       , ports (new Ports)
 {
        g_atomic_int_set (&m_meter_exit, 0);
 
@@ -330,7 +329,7 @@ AudioEngine::process_callback (pframes_t nframes)
 
                        bool x;
 
-                       if (i->second->last_monitor() != (x = i->second->jack_monitoring_input ())) {
+                       if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
                                i->second->set_last_monitor (x);
                                /* XXX I think this is dangerous, due to
                                   a likely mutex in the signal handlers ...
@@ -878,9 +877,9 @@ AudioEngine::reset_timebase ()
        GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
        if (_session) {
                if (_session->config.get_jack_time_master()) {
-                       return jack_set_timebase_callback (_priv_jack, 0, _jack_timebase_callback, this);
+                       _backend->set_time_master (true);
                } else {
-                       return jack_release_timebase (_jack);
+                       _backend->set_time_master (false);
                }
        }
        return 0;
index b5e21b8207988908d50690d779215f53213bb60d..2d614a80a04549c9e8763570be437019ecd14295 100644 (file)
@@ -114,7 +114,7 @@ JACKAudioBackend::disconnect_from_jack ()
 {
 
 int
-AudioEngine::reconnect_to_jack ()
+JACKAudioBackend::reconnect_to_jack ()
 {
        if (_running) {
                disconnect_from_jack ();
@@ -194,41 +194,116 @@ JACKAudioBackend::request_buffer_size (pframes_t nframes)
 /* --- TRANSPORT STATE MANAGEMENT --- */
 
 void
-AudioEngine::transport_stop ()
+JACKAudioBackend::transport_stop ()
 {
        GET_PRIVATE_JACK_POINTER (_jack);
        jack_transport_stop (_priv_jack);
 }
 
 void
-AudioEngine::transport_start ()
+JACKAudioBackend::transport_start ()
 {
        GET_PRIVATE_JACK_POINTER (_jack);
        jack_transport_start (_priv_jack);
 }
 
 void
-AudioEngine::transport_locate (framepos_t where)
+JACKAudioBackend::transport_locate (framepos_t where)
 {
        GET_PRIVATE_JACK_POINTER (_jack);
        jack_transport_locate (_priv_jack, where);
 }
 
 framepos_t 
-AudioEngine::transport_frame () const 
+JACKAudioBackend::transport_frame () const 
 {
        GET_PRIVATE_JACK_POINTER_RET (_jack, 0);
        return jack_get_current_transport_frame (_priv_jack);
 }
 
-AudioEngine::TransportState
-AudioEngine::transport_state ()
+JACKAudioBackend::TransportState
+JACKAudioBackend::transport_state ()
 {
        GET_PRIVATE_JACK_POINTER_RET (_jack, ((TransportState) JackTransportStopped));
        jack_position_t pos;
        return (TransportState) jack_transport_query (_priv_jack, &pos);
 }
 
+int
+JACKAudioBackend::set_time_master (bool yn)
+{
+       GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
+       if (yn) {
+               return jack_set_timebase_callback (_priv_jack, 0, _jack_timebase_callback, this);
+       } else {
+               return jack_release_timebase (_jack);
+       }
+}
+
+/* process-time */
+
+framecnt_t frame_rate () const;
+pframes_t frames_per_cycle () const;
+
+size_t raw_buffer_size(DataType t);
+
+int usecs_per_cycle () const { return _usecs_per_cycle; }
+
+bool
+JACKAudioBackend::get_sync_offset (pframes_t& offset) const
+{
+
+#ifdef HAVE_JACK_VIDEO_SUPPORT
+
+       GET_PRIVATE_JACK_POINTER_RET (_jack, false);
+
+       jack_position_t pos;
+
+       if (_priv_jack) {
+               (void) jack_transport_query (_priv_jack, &pos);
+
+               if (pos.valid & JackVideoFrameOffset) {
+                       offset = pos.video_offset;
+                       return true;
+               }
+       }
+#else
+       /* keep gcc happy */
+       offset = 0;
+#endif
+
+       return false;
+}
+
+pframes_t
+JACKAudioBackend::frames_since_cycle_start ()
+{
+       jack_client_t* _priv_jack = _jack;
+       if (!_running || !_priv_jack) {
+               return 0;
+       }
+       return jack_frames_since_cycle_start (_priv_jack);
+}
+
+pframes_t
+JACKAudioBackend::frame_time ()
+{
+       jack_client_t* _priv_jack = _jack;
+       if (!_running || !_priv_jack) {
+               return 0;
+       }
+       return jack_frame_time (_priv_jack);
+}
+
+pframes_t
+JACKAudioBackend::frame_time_at_cycle_start ()
+{
+       jack_client_t* _priv_jack = _jack;
+       if (!_running || !_priv_jack) {
+               return 0;
+       }
+       return jack_last_frame_time (_priv_jack);
+}
 
 /* JACK Callbacks */
 
@@ -418,6 +493,32 @@ JACKAudioBackend::connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, in
                ); /* EMIT SIGNAL */
 }
 
+int
+JACKAudioBackend::create_process_thread (boost::function<void()> f, pthread_t* thread, size_t stacksize)
+{
+        GET_PRIVATE_JACK_POINTER_RET (_jack, 0);
+        ThreadData* td = new ThreadData (this, f, stacksize);
+
+        if (jack_client_create_thread (_priv_jack, thread, jack_client_real_time_priority (_priv_jack),
+                                       jack_is_realtime (_priv_jack), _start_process_thread, td)) {
+                return -1;
+        }
+
+        return 0;
+}
+
+void*
+JACKAudioBackend::_start_process_thread (void* arg)
+{
+        ThreadData* td = reinterpret_cast<ThreadData*> (arg);
+        boost::function<void()> f = td->f;
+        delete td;
+
+        f ();
+
+        return 0;
+}
+
 void*
 JACKAudioBackend::_process_thread (void *arg)
 {
index 3473b73617a84226bb442a1bc421bc717fc1ce57..859f1ff8ab3f45a6e805b7d6dd884496825c0d21 100644 (file)
@@ -242,13 +242,19 @@ Port::set_engine (AudioEngine* e)
 }
 
 void
-Port::ensure_jack_monitors_input (bool yn)
+Port::request_monitor_input (bool yn)
+{
+       jack_port_request_monitor (_jack_port, yn);
+}
+
+void
+Port::ensure_monitor_input (bool yn)
 {
        jack_port_ensure_monitor (_jack_port, yn);
 }
 
 bool
-Port::jack_monitoring_input () const
+Port::monitoring_input () const
 {
        return jack_port_monitoring_input (_jack_port);
 }
@@ -490,12 +496,6 @@ Port::set_name (std::string const & n)
        return r;
 }
 
-void
-Port::request_jack_monitors_input (bool yn)
-{
-       jack_port_request_monitor (_jack_port, yn);
-}
-
 bool
 Port::physically_connected () const
 {