summaryrefslogtreecommitdiff
path: root/libs/ardour/ardour
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ardour/ardour')
-rw-r--r--libs/ardour/ardour/ardour.h4
-rw-r--r--libs/ardour/ardour/async_midi_port.h99
-rw-r--r--libs/ardour/ardour/audio_backend.h432
-rw-r--r--libs/ardour/ardour/audio_diskstream.h4
-rw-r--r--libs/ardour/ardour/audio_port.h6
-rw-r--r--libs/ardour/ardour/audioengine.h481
-rw-r--r--libs/ardour/ardour/backend_search_path.h39
-rw-r--r--libs/ardour/ardour/buffer_set.h2
-rw-r--r--libs/ardour/ardour/data_type.h27
-rw-r--r--libs/ardour/ardour/debug.h1
-rw-r--r--libs/ardour/ardour/directory_names.h1
-rw-r--r--libs/ardour/ardour/diskstream.h4
-rw-r--r--libs/ardour/ardour/graph.h2
-rw-r--r--libs/ardour/ardour/midi_buffer.h1
-rw-r--r--libs/ardour/ardour/midi_diskstream.h2
-rw-r--r--libs/ardour/ardour/midi_port.h27
-rw-r--r--libs/ardour/ardour/midi_ui.h6
-rw-r--r--libs/ardour/ardour/midiport_manager.h99
-rw-r--r--libs/ardour/ardour/port.h47
-rw-r--r--libs/ardour/ardour/port_engine.h345
-rw-r--r--libs/ardour/ardour/port_manager.h169
-rw-r--r--libs/ardour/ardour/public_diskstream.h4
-rw-r--r--libs/ardour/ardour/rc_configuration.h6
-rw-r--r--libs/ardour/ardour/session.h63
-rw-r--r--libs/ardour/ardour/slave.h26
-rw-r--r--libs/ardour/ardour/ticker.h53
-rw-r--r--libs/ardour/ardour/track.h4
-rw-r--r--libs/ardour/ardour/types.h40
28 files changed, 1556 insertions, 438 deletions
diff --git a/libs/ardour/ardour/ardour.h b/libs/ardour/ardour/ardour.h
index eaf6b572fd..311611997f 100644
--- a/libs/ardour/ardour/ardour.h
+++ b/libs/ardour/ardour/ardour.h
@@ -75,9 +75,7 @@ namespace ARDOUR {
bool translations_are_enabled ();
bool set_translations_enabled (bool);
- static inline microseconds_t get_microseconds () {
- return (microseconds_t) jack_get_time();
- }
+ microseconds_t get_microseconds ();
void setup_fpu ();
std::vector<SyncSource> get_available_sync_options();
diff --git a/libs/ardour/ardour/async_midi_port.h b/libs/ardour/ardour/async_midi_port.h
new file mode 100644
index 0000000000..896301b398
--- /dev/null
+++ b/libs/ardour/ardour/async_midi_port.h
@@ -0,0 +1,99 @@
+/*
+ Copyright (C) 1998-2010 Paul Barton-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_async_midiport_h__
+#define __libardour_async_midiport_h__
+
+#include <string>
+#include <iostream>
+
+#include "pbd/xml++.h"
+#include "pbd/crossthread.h"
+#include "pbd/signals.h"
+#include "pbd/ringbuffer.h"
+
+#include "evoral/Event.hpp"
+#include "evoral/EventRingBuffer.hpp"
+
+#include "midi++/types.h"
+#include "midi++/parser.h"
+#include "midi++/port.h"
+
+#include "ardour/midi_port.h"
+
+namespace ARDOUR {
+
+ class AsyncMIDIPort : public ARDOUR::MidiPort, public MIDI::Port {
+
+ public:
+ AsyncMIDIPort (std::string const &, PortFlags);
+ ~AsyncMIDIPort ();
+
+ /* called from an RT context */
+
+ void cycle_start (pframes_t nframes);
+ void cycle_end (pframes_t nframes);
+
+ /* called from non-RT context */
+
+ void parse (framecnt_t timestamp);
+ int write (const MIDI::byte *msg, size_t msglen, MIDI::timestamp_t timestamp);
+ int read (MIDI::byte *buf, size_t bufsize);
+ void drain (int check_interval_usecs);
+ int selectable () const {
+#ifdef PLATFORM_WINDOWS
+ return false;
+#else
+ return xthread.selectable();
+#endif
+ }
+
+ static void set_process_thread (pthread_t);
+ static pthread_t get_process_thread () { return _process_thread; }
+ static bool is_process_thread();
+
+ private:
+ bool _currently_in_cycle;
+ MIDI::timestamp_t _last_write_timestamp;
+ RingBuffer< Evoral::Event<double> > output_fifo;
+ Evoral::EventRingBuffer<MIDI::timestamp_t> input_fifo;
+ Glib::Threads::Mutex output_fifo_lock;
+#ifndef PLATFORM_WINDOWS
+ CrossThreadChannel xthread;
+#endif
+
+ int create_port ();
+
+ /** Channel used to signal to the MidiControlUI that input has arrived */
+
+ std::string _connections;
+ PBD::ScopedConnection connect_connection;
+ PBD::ScopedConnection halt_connection;
+ void flush (void* jack_port_buffer);
+ void jack_halted ();
+ void make_connections ();
+ void init (std::string const &, Flags);
+
+ void flush_output_fifo (pframes_t);
+
+ static pthread_t _process_thread;
+};
+
+} // namespace ARDOUR
+
+#endif /* __libardour_async_midiport_h__ */
diff --git a/libs/ardour/ardour/audio_backend.h b/libs/ardour/ardour/audio_backend.h
new file mode 100644
index 0000000000..ab37bea526
--- /dev/null
+++ b/libs/ardour/ardour/audio_backend.h
@@ -0,0 +1,432 @@
+/*
+ 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_audiobackend_h__
+#define __libardour_audiobackend_h__
+
+#include <string>
+#include <vector>
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <boost/function.hpp>
+
+#include "ardour/types.h"
+
+namespace ARDOUR {
+
+class AudioEngine;
+class PortEngine;
+class PortManager;
+
+class AudioBackend {
+ public:
+
+ AudioBackend (AudioEngine& e) : engine (e){}
+ virtual ~AudioBackend () {}
+
+ /** Return the name of this backend.
+ *
+ * Should use a well-known, unique term. Expected examples
+ * might include "JACK", "CoreAudio", "ASIO" etc.
+ */
+ virtual std::string name() const = 0;
+
+ /** Return a private, type-free pointer to any data
+ * that might be useful to a concrete implementation
+ */
+ virtual void* private_handle() const = 0;
+
+ /** Return true if the underlying mechanism/API is still available
+ * for us to utilize. return false if some or all of the AudioBackend
+ * API can no longer be effectively used.
+ */
+ virtual bool connected() const = 0;
+
+ /** Return true if the callback from the underlying mechanism/API
+ * (CoreAudio, JACK, ASIO etc.) occurs in a thread subject to realtime
+ * constraints. Return false otherwise.
+ */
+ virtual bool is_realtime () const = 0;
+
+ /* Discovering devices and parameters */
+
+ /** Return true if this backend requires the selection of a "driver"
+ * before any device can be selected. Return false otherwise.
+ *
+ * Intended mainly to differentiate between meta-APIs like JACK
+ * which can still expose different backends (such as ALSA or CoreAudio
+ * or FFADO or netjack) and those like ASIO or CoreAudio which
+ * do not.
+ */
+ virtual bool requires_driver_selection() const { return false; }
+
+ /** If the return value of requires_driver_selection() is true,
+ * then this function can return the list of known driver names.
+ *
+ * If the return value of requires_driver_selection() is false,
+ * then this function should not be called. If it is called
+ * its return value is an empty vector of strings.
+ */
+ virtual std::vector<std::string> enumerate_drivers() const { return std::vector<std::string>(); }
+
+ /** Returns zero if the backend can successfully use @param name as the
+ * driver, non-zero otherwise.
+ *
+ * Should not be used unless the backend returns true from
+ * requires_driver_selection()
+ */
+ virtual int set_driver (const std::string& /*drivername*/) { return 0; }
+
+ /** used to list device names along with whether or not they are currently
+ * available.
+ */
+ struct DeviceStatus {
+ std::string name;
+ bool available;
+
+ DeviceStatus (const std::string& s, bool avail) : name (s), available (avail) {}
+ };
+
+ /** Returns a collection of DeviceStatuses identifying devices discovered
+ * by this backend since the start of the process.
+ *
+ * Any of the names in each DeviceStatus may be used to identify a
+ * device in other calls to the backend, though any of them may become
+ * invalid at any time.
+ */
+ virtual std::vector<DeviceStatus> enumerate_devices () const = 0;
+
+ /** Returns a collection of float identifying sample rates that are
+ * potentially usable with the hardware identified by @param device.
+ * Any of these values may be supplied in other calls to this backend
+ * as the desired sample rate to use with the name device, but the
+ * requested sample rate may turn out to be unavailable, or become invalid
+ * at any time.
+ */
+ virtual std::vector<float> available_sample_rates (const std::string& device) const = 0;
+ /** Returns a collection of uint32 identifying buffer sizes that are
+ * potentially usable with the hardware identified by @param device.
+ * Any of these values may be supplied in other calls to this backend
+ * as the desired buffer size to use with the name device, but the
+ * requested buffer size may turn out to be unavailable, or become invalid
+ * at any time.
+ */
+ virtual std::vector<uint32_t> available_buffer_sizes (const std::string& device) const = 0;
+
+ /** 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;
+
+ /* Return true if the derived class can change the sample rate of the
+ * device in use while the device is already being used. Return false
+ * otherwise. (example: JACK cannot do this as of September 2013)
+ */
+ virtual bool can_change_sample_rate_when_running () const = 0;
+ /* Return true if the derived class can change the buffer size of the
+ * device in use while the device is already being used. Return false
+ * otherwise.
+ */
+ virtual bool can_change_buffer_size_when_running () 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;
+
+ /* Retrieving parameters */
+
+ virtual std::string device_name () const = 0;
+ virtual float sample_rate () const = 0;
+ virtual uint32_t buffer_size () const = 0;
+ virtual SampleFormat sample_format () const = 0;
+ virtual bool interleaved () const = 0;
+ virtual uint32_t input_channels () const = 0;
+ virtual uint32_t output_channels () const = 0;
+ virtual uint32_t systemic_input_latency () const = 0;
+ virtual uint32_t systemic_output_latency () const = 0;
+
+ /** Return the name of a control application for the
+ * selected/in-use device. If no such application exists,
+ * or if no device has been selected or is in-use,
+ * return an empty string.
+ */
+ virtual std::string control_app_name() const = 0;
+ /** Launch the control app for the currently in-use or
+ * selected device. May do nothing if the control
+ * app is undefined or cannot be launched.
+ */
+ virtual void launch_control_app () = 0;
+ /* Basic state control */
+
+ /** Start using the device named in the most recent 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
+ * the AudioEngine referenced by @param engine. These calls will
+ * occur in a thread created by and/or under the control of the backend.
+ *
+ * Return zero if successful, negative values otherwise.
+ */
+ virtual int start () = 0;
+
+ /** 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 parameters are reset and start() are called again.
+ *
+ * The backend is considered to be un-configured after a successful
+ * 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.
+ *
+ * Return zero if successful, 1 if the device is not in use, negative values on error
+ */
+ virtual int stop () = 0;
+
+ /** Temporarily cease using the device named in the most recent call to set_parameters().
+ *
+ * If the function is successfully called, no subsequent calls to the
+ * process_callback() of @param engine will be made after the function
+ * returns, until start() is called again.
+ *
+ * The backend will retain its existing parameter configuration after a successful
+ * 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
+ */
+ virtual int pause () = 0;
+
+ /** 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. 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
+ * behaviour if it currently occuring, and return to calling
+ * process_callback() of @param engine by waiting for the device.
+ *
+ * Return zero on success, non-zero otherwise.
+ */
+ virtual int freewheel (bool start_stop) = 0;
+
+ /** 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 cpu_load() const = 0;
+
+ /* Transport Control (JACK is the only audio API that currently offers
+ the concept of shared transport control)
+ */
+
+ /** Attempt to change the transport state to TransportRolling.
+ */
+ virtual void transport_start () {}
+ /** Attempt to change the transport state to TransportStopped.
+ */
+ virtual void transport_stop () {}
+ /** return the current transport state
+ */
+ virtual TransportState transport_state () const { return TransportStopped; }
+ /** Attempt to locate the transport to @param pos
+ */
+ virtual void transport_locate (framepos_t /*pos*/) {}
+ /** Return the current transport location, in samples measured
+ * from the origin (defined by the transport time master)
+ */
+ virtual framepos_t transport_frame() const { 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 int usecs_per_cycle () const { return 1000000 * (buffer_size() / sample_rate()); }
+ virtual size_t raw_buffer_size (DataType t) = 0;
+
+ /* Process time */
+
+ /** return the time according to the sample clock in use, measured in
+ * samples since an arbitrary zero time in the past. The value should
+ * increase monotonically and linearly, without interruption from any
+ * source (including CPU frequency scaling).
+ *
+ * It is extremely likely that any implementation will use a DLL, since
+ * this function can be called from any thread, at any time, and must be
+ * able to accurately determine the correct sample time.
+ *
+ * Can be called from any thread.
+ */
+ virtual pframes_t sample_time () = 0;
+
+ /** Return the time according to the sample clock in use when the most
+ * recent buffer process cycle began. Can be called from any thread.
+ */
+ virtual pframes_t sample_time_at_cycle_start () = 0;
+
+ /** Return the time since the current buffer process cycle started,
+ * in samples, according to the sample clock in use.
+ *
+ * Can ONLY be called from within a process() callback tree (which
+ * implies that it can only be called by a process thread)
+ */
+ virtual pframes_t samples_since_cycle_start () = 0;
+
+ /** Return true if it possible to determine the offset in samples of the
+ * first video frame that starts within the current buffer process cycle,
+ * measured from the first sample of the cycle. If returning true,
+ * set @param offset to that offset.
+ *
+ * Eg. if it can be determined that the first video frame within the cycle
+ * starts 28 samples after the first sample of the cycle, then this method
+ * should return true and set @param offset to 28.
+ *
+ * May be impossible to support outside of JACK, which has specific support
+ * (in some cases, hardware support) for this feature.
+ *
+ * Can ONLY be called from within a process() callback tree (which implies
+ * that it can only be called by a process thread)
+ */
+ virtual bool get_sync_offset (pframes_t& /*offset*/) const { return false; }
+
+ /** 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;
+
+ virtual void update_latencies () = 0;
+
+ protected:
+ AudioEngine& engine;
+};
+
+struct AudioBackendInfo {
+ const char* name;
+
+ int (*instantiate) (const std::string& arg1, const std::string& arg2);
+ int (*deinstantiate) (void);
+
+ boost::shared_ptr<AudioBackend> (*backend_factory) (AudioEngine&);
+ boost::shared_ptr<PortEngine> (*portengine_factory) (PortManager&);
+
+ /** Return true if the underlying mechanism/API has been
+ * configured and does not need (re)configuration in order
+ * to be usable. Return false otherwise.
+ *
+ * Note that this may return true if (re)configuration, even though
+ * not currently required, is still possible.
+ */
+ bool (*already_configured)();
+};
+
+} // namespace
+
+#endif /* __libardour_audiobackend_h__ */
+
diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h
index b636cb4734..5a856e9b36 100644
--- a/libs/ardour/ardour/audio_diskstream.h
+++ b/libs/ardour/ardour/audio_diskstream.h
@@ -114,7 +114,7 @@ class AudioDiskstream : public Diskstream
XMLNode& get_state(void);
int set_state(const XMLNode& node, int version);
- void request_jack_monitors_input (bool);
+ void request_input_monitoring (bool);
static void swap_by_ptr (Sample *first, Sample *last) {
while (first < last) {
@@ -160,7 +160,7 @@ class AudioDiskstream : public Diskstream
std::string name;
bool is_physical () const;
- void request_jack_monitors_input (bool) const;
+ void request_input_monitoring (bool) const;
};
/** Information about one of our channels */
diff --git a/libs/ardour/ardour/audio_port.h b/libs/ardour/ardour/audio_port.h
index 7f084a5c85..f87b134e9e 100644
--- a/libs/ardour/ardour/audio_port.h
+++ b/libs/ardour/ardour/audio_port.h
@@ -46,10 +46,10 @@ class AudioPort : public Port
AudioBuffer& get_audio_buffer (pframes_t nframes);
protected:
- friend class AudioEngine;
+ friend class PortManager;
+ AudioPort (std::string const &, PortFlags);
- AudioPort (std::string const &, Flags);
- /* special access for engine only */
+ /* special access for PortManager only (hah, C++) */
Sample* engine_get_whole_audio_buffer ();
private:
diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h
index ec31dd1ac2..cf4f91d4d0 100644
--- a/libs/ardour/ardour/audioengine.h
+++ b/libs/ardour/ardour/audioengine.h
@@ -33,29 +33,22 @@
#include <glibmm/threads.h>
-#include "pbd/rcu.h"
#include "pbd/signals.h"
#include "pbd/stacktrace.h"
-#ifndef PLATFORM_WINDOWS
-#include <jack/weakjack.h>
-#endif
-
-#include <jack/jack.h>
-#include <jack/transport.h>
-#include <jack/thread.h>
-
#include "ardour/ardour.h"
-
#include "ardour/data_type.h"
#include "ardour/session_handle.h"
#include "ardour/types.h"
#include "ardour/chan_count.h"
+#include "ardour/port_manager.h"
#ifdef HAVE_JACK_SESSION
#include <jack/session.h>
#endif
+class MTDM;
+
namespace ARDOUR {
class InternalPort;
@@ -63,300 +56,190 @@ class MidiPort;
class Port;
class Session;
class ProcessThread;
+class AudioBackend;
+class AudioBackendInfo;
-class AudioEngine : public SessionHandlePtr
+class AudioEngine : public SessionHandlePtr, public PortManager
{
public:
- typedef std::map<std::string,boost::shared_ptr<Port> > Ports;
-
- AudioEngine (std::string client_name, std::string session_uuid);
- virtual ~AudioEngine ();
-
- jack_client_t* jack() const;
- bool connected() const { return _jack != 0; }
-
- bool is_realtime () const;
-
- ProcessThread* main_thread() const { return _main_thread; }
-
- std::string client_name() const { return jack_client_name; }
-
- int reconnect_to_jack ();
- int disconnect_from_jack();
-
- int stop (bool forever = false);
- int start ();
- bool running() const { return _running; }
-
- Glib::Threads::Mutex& process_lock() { return _process_lock; }
-
- 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 get_sync_offset (pframes_t & offset) const;
-
- pframes_t 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 frame_time () {
- jack_client_t* _priv_jack = _jack;
- if (!_running || !_priv_jack) {
- return 0;
- }
- return jack_frame_time (_priv_jack);
- }
-
- pframes_t frame_time_at_cycle_start () {
- jack_client_t* _priv_jack = _jack;
- if (!_running || !_priv_jack) {
- return 0;
- }
- return jack_last_frame_time (_priv_jack);
- }
-
- pframes_t transport_frame () const {
- const jack_client_t* _priv_jack = _jack;
- if (!_running || !_priv_jack) {
- return 0;
- }
- return jack_get_current_transport_frame (_priv_jack);
- }
-
- 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 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;
- };
-
- class NoBackendAvailable : public std::exception {
- public:
- virtual const char *what() const throw() { return "could not connect to engine backend"; }
- };
-
- boost::shared_ptr<Port> register_input_port (DataType, const std::string& portname);
- boost::shared_ptr<Port> register_output_port (DataType, const std::string& portname);
- int unregister_port (boost::shared_ptr<Port>);
-
- bool port_is_physical (const std::string&) const;
- void request_jack_monitors_input (const std::string&, bool) const;
-
- void split_cycle (pframes_t offset);
-
- int connect (const std::string& source, const std::string& destination);
- int disconnect (const std::string& source, const std::string& destination);
- int disconnect (boost::shared_ptr<Port>);
-
- const char ** get_ports (const std::string& port_name_pattern, const std::string& type_name_pattern, uint32_t flags);
-
- bool can_request_hardware_monitoring ();
-
- ChanCount n_physical_outputs () const;
- ChanCount n_physical_inputs () const;
-
- void get_physical_outputs (DataType type, std::vector<std::string>&);
- void get_physical_inputs (DataType type, std::vector<std::string>&);
- boost::shared_ptr<Port> get_port_by_name (const std::string &);
- void port_renamed (const std::string&, const std::string&);
-
- enum TransportState {
- TransportStopped = JackTransportStopped,
- TransportRolling = JackTransportRolling,
- TransportLooping = JackTransportLooping,
- TransportStarting = JackTransportStarting
- };
-
- void transport_start ();
- void transport_stop ();
- void transport_locate (framepos_t);
- TransportState transport_state ();
-
- 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 */
-
- PBD::Signal0<void> GraphReordered;
-
-#ifdef HAVE_JACK_SESSION
- 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()>, jack_native_thread_t*, size_t stacksize);
- bool stop_process_thread (jack_native_thread_t);
-
-private:
- static AudioEngine* _instance;
-
- jack_client_t* volatile _jack; /* could be reset to null by SIGPIPE or another thread */
- std::string jack_client_name;
- 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 ();
-
- ChanCount n_physical (unsigned long) const;
- void get_physical (DataType, unsigned long, std::vector<std::string> &);
-
- void port_registration_failure (const std::string& portname);
-
- static int _xrun_callback (void *arg);
-#ifdef HAVE_JACK_SESSION
- static void _session_callback (jack_session_event_t *event, void *arg);
-#endif
- static int _graph_order_callback (void *arg);
- static void* _process_thread (void *arg);
- static int _sample_rate_callback (pframes_t nframes, void *arg);
- static int _bufsize_callback (pframes_t nframes, void *arg);
- static void _jack_timebase_callback (jack_transport_state_t, pframes_t, jack_position_t*, int, void*);
- static int _jack_sync_callback (jack_transport_state_t, jack_position_t*, void *arg);
- static void _freewheel_callback (int , void *arg);
- static void _registration_callback (jack_port_id_t, int, void *);
- static void _connect_callback (jack_port_id_t, jack_port_id_t, int, void *);
-
- void jack_timebase_callback (jack_transport_state_t, pframes_t, jack_position_t*, int);
- int jack_sync_callback (jack_transport_state_t, jack_position_t*);
- int jack_bufsize_callback (pframes_t);
- int jack_sample_rate_callback (pframes_t);
- void freewheel_callback (int);
- void connect_callback (jack_port_id_t, jack_port_id_t, int);
-
- void set_jack_callbacks ();
-
- static void _latency_callback (jack_latency_callback_mode_t, void*);
- void jack_latency_callback (jack_latency_callback_mode_t);
-
- int connect_to_jack (std::string client_name, std::string session_uuid);
-
- static void halted (void *);
- static void halted_info (jack_status_t,const char*,void *);
-
- void meter_thread ();
- void start_metering_thread ();
- void stop_metering_thread ();
-
- static gint m_meter_exit;
-
- struct ThreadData {
- AudioEngine* engine;
- boost::function<void()> f;
- size_t stacksize;
-
- ThreadData (AudioEngine* ae, boost::function<void()> fp, size_t stacksz)
- : engine (ae) , f (fp) , stacksize (stacksz) {}
- };
-
- static void* _start_process_thread (void*);
- void parameter_changed (const std::string&);
- PBD::ScopedConnection config_connection;
+ static AudioEngine* create ();
+
+ virtual ~AudioEngine ();
+
+ int discover_backends();
+ std::vector<const AudioBackendInfo*> available_backends() const;
+ std::string current_backend_name () const;
+ boost::shared_ptr<AudioBackend> set_backend (const std::string&, const std::string& arg1, const std::string& arg2);
+ boost::shared_ptr<AudioBackend> current_backend() const { return _backend; }
+ bool setup_required () const;
+
+ ProcessThread* main_thread() const { return _main_thread; }
+
+ /* START BACKEND PROXY API
+ *
+ * See audio_backend.h for full documentation and semantics. These wrappers
+ * just forward to a backend implementation.
+ */
+
+ int start ();
+ int stop ();
+ int pause ();
+ int freewheel (bool start_stop);
+ float get_cpu_load() const ;
+ void transport_start ();
+ void transport_stop ();
+ TransportState transport_state ();
+ void transport_locate (framepos_t pos);
+ framepos_t transport_frame();
+ framecnt_t sample_rate () const;
+ pframes_t samples_per_cycle () const;
+ int usecs_per_cycle () const;
+ size_t raw_buffer_size (DataType t);
+ pframes_t sample_time ();
+ pframes_t sample_time_at_cycle_start ();
+ pframes_t samples_since_cycle_start ();
+ bool get_sync_offset (pframes_t& offset) const;
+ int create_process_thread (boost::function<void()> func, pthread_t*, size_t stacksize);
+ bool is_realtime() const;
+ bool connected() const;
+
+ int set_device_name (const std::string&);
+ int set_sample_rate (float);
+ int set_buffer_size (uint32_t);
+ int set_sample_format (SampleFormat);
+ int set_interleaved (bool yn);
+ int set_input_channels (uint32_t);
+ int set_output_channels (uint32_t);
+ int set_systemic_input_latency (uint32_t);
+ int set_systemic_output_latency (uint32_t);
+
+ /* END BACKEND PROXY API */
+
+ bool freewheeling() const { return _freewheeling; }
+ bool running() const { return _running; }
+
+ Glib::Threads::Mutex& process_lock() { return _process_lock; }
+
+ int request_buffer_size (pframes_t samples) {
+ return set_buffer_size (samples);
+ }
+
+ framecnt_t processed_frames() const { return _processed_frames; }
+
+ void set_session (Session *);
+ void remove_session (); // not a replacement for SessionHandle::session_going_away()
+ Session* session() const { return _session; }
+
+ 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 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;
+
+ static AudioEngine* instance() { return _instance; }
+ static void destroy();
+ void died ();
+
+ /* The backend will cause these at the appropriate time(s)
+ */
+ int process_callback (pframes_t nframes);
+ int buffer_size_change (pframes_t nframes);
+ int sample_rate_change (pframes_t nframes);
+ void freewheel_callback (bool);
+ void timebase_callback (TransportState state, pframes_t nframes, framepos_t pos, int new_position);
+ int sync_callback (TransportState state, framepos_t position);
+ int port_registration_callback ();
+ void latency_callback (bool for_playback);
+ void halted_callback (const char* reason);
+
+ /* sets up the process callback thread */
+ static void thread_init_callback (void *);
+
+ /* latency measurement */
+
+ MTDM* mtdm();
+ void start_latency_detection ();
+ void stop_latency_detection ();
+ void set_latency_input_port (const std::string&);
+ void set_latency_output_port (const std::string&);
+ uint32_t latency_signal_delay () const { return _latency_signal_latency; }
+
+ private:
+ AudioEngine ();
+
+ static AudioEngine* _instance;
+
+ boost::shared_ptr<AudioBackend> _backend;
+
+ 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 _freewheeling;
+ /// 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;
+ Glib::Threads::Thread* m_meter_thread;
+ ProcessThread* _main_thread;
+ MTDM* _mtdm;
+ bool _measuring_latency;
+ PortEngine::PortHandle _latency_input_port;
+ PortEngine::PortHandle _latency_output_port;
+ framecnt_t _latency_flush_frames;
+ std::string _latency_input_name;
+ std::string _latency_output_name;
+ framecnt_t _latency_signal_latency;
+
+ 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;
+
+ typedef std::map<std::string,AudioBackendInfo*> BackendMap;
+ BackendMap _backends;
+ AudioBackendInfo* backend_discover (const std::string&);
+ void drop_backend ();
};
-
+
} // namespace ARDOUR
#endif /* __ardour_audioengine_h__ */
diff --git a/libs/ardour/ardour/backend_search_path.h b/libs/ardour/ardour/backend_search_path.h
new file mode 100644
index 0000000000..e8a5082c71
--- /dev/null
+++ b/libs/ardour/ardour/backend_search_path.h
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) 2011 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 __ardour_backend_search_path_h__
+#define __ardour_backend_search_path_h__
+
+#include "pbd/search_path.h"
+
+namespace ARDOUR {
+
+ /**
+ * return a SearchPath containing directories in which to look for
+ * backend plugins.
+ *
+ * If ARDOUR_BACKEND_PATH is defined then the SearchPath returned
+ * will contain only those directories specified in it, otherwise it will
+ * contain the user and system directories which may contain audio/MIDI
+ * backends.
+ */
+ PBD::Searchpath backend_search_path ();
+
+} // namespace ARDOUR
+
+#endif /* __ardour_backend_search_path_h__ */
diff --git a/libs/ardour/ardour/buffer_set.h b/libs/ardour/ardour/buffer_set.h
index 12e9dbc63b..26d47682af 100644
--- a/libs/ardour/ardour/buffer_set.h
+++ b/libs/ardour/ardour/buffer_set.h
@@ -70,7 +70,7 @@ public:
void clear();
void attach_buffers (PortSet& ports);
- void get_jack_port_addresses (PortSet &, framecnt_t);
+ void get_backend_port_addresses (PortSet &, framecnt_t);
/* the capacity here is a size_t and has a different interpretation depending
on the DataType of the buffers. for audio, its a frame count. for MIDI
diff --git a/libs/ardour/ardour/data_type.h b/libs/ardour/ardour/data_type.h
index 6a016ae75a..b4129e2629 100644
--- a/libs/ardour/ardour/data_type.h
+++ b/libs/ardour/ardour/data_type.h
@@ -21,11 +21,11 @@
#define __ardour_data_type_h__
#include <string>
-#include <jack/jack.h>
+#include <stdint.h>
+#include <glib.h>
namespace ARDOUR {
-
/** A type of Data Ardour is capable of processing.
*
* The majority of this class is dedicated to conversion to and from various
@@ -61,33 +61,25 @@ public:
/** Construct from a string (Used for loading from XML and Ports)
* The string can be as in an XML file (eg "audio" or "midi"), or a
- * Jack type string (from jack_port_type) */
+ */
DataType(const std::string& str)
: _symbol(NIL) {
- if (str == "audio" || str == JACK_DEFAULT_AUDIO_TYPE)
+ if (!g_ascii_strncasecmp(str.c_str(), "audio", str.length())) {
_symbol = AUDIO;
- else if (str == "midi" || str == JACK_DEFAULT_MIDI_TYPE)
+ } else if (!g_ascii_strncasecmp(str.c_str(), "midi", str.length())) {
_symbol = MIDI;
- }
-
- /** Get the Jack type this DataType corresponds to */
- const char* to_jack_type() const {
- switch (_symbol) {
- case AUDIO: return JACK_DEFAULT_AUDIO_TYPE;
- case MIDI: return JACK_DEFAULT_MIDI_TYPE;
- default: return "";
}
}
/** Inverse of the from-string constructor */
const char* to_string() const {
switch (_symbol) {
- case AUDIO: return "audio";
- case MIDI: return "midi";
- default: return "unknown"; // reeeally shouldn't ever happen
+ case AUDIO: return "audio";
+ case MIDI: return "midi";
+ default: return "unknown"; // reeeally shouldn't ever happen
}
}
-
+
const char* to_i18n_string () const;
inline operator uint32_t() const { return (uint32_t)_symbol; }
@@ -125,7 +117,6 @@ private:
};
-
} // namespace ARDOUR
#endif // __ardour_data_type_h__
diff --git a/libs/ardour/ardour/debug.h b/libs/ardour/ardour/debug.h
index ae18e59c04..47eee69df5 100644
--- a/libs/ardour/ardour/debug.h
+++ b/libs/ardour/ardour/debug.h
@@ -64,6 +64,7 @@ namespace PBD {
extern uint64_t OrderKeys;
extern uint64_t Automation;
extern uint64_t WiimoteControl;
+ extern uint64_t Ports;
}
}
diff --git a/libs/ardour/ardour/directory_names.h b/libs/ardour/ardour/directory_names.h
index cb4701d336..72a456efe6 100644
--- a/libs/ardour/ardour/directory_names.h
+++ b/libs/ardour/ardour/directory_names.h
@@ -39,6 +39,7 @@ extern const char* const surfaces_dir_name;
extern const char* const ladspa_dir_name;
extern const char* const user_config_dir_name;
extern const char* const panner_dir_name;
+extern const char* const backend_dir_name;
};
diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h
index 427b52b054..7a4bccbb46 100644
--- a/libs/ardour/ardour/diskstream.h
+++ b/libs/ardour/ardour/diskstream.h
@@ -133,8 +133,8 @@ class Diskstream : public SessionObject, public PublicDiskstream
virtual XMLNode& get_state(void);
virtual int set_state(const XMLNode&, int version);
- virtual void request_jack_monitors_input (bool) {}
- virtual void ensure_jack_monitors_input (bool) {}
+ virtual void request_input_monitoring (bool) {}
+ virtual void ensure_input_monitoring (bool) {}
framecnt_t capture_offset() const { return _capture_offset; }
virtual void set_capture_offset ();
diff --git a/libs/ardour/ardour/graph.h b/libs/ardour/ardour/graph.h
index 0a288d68d3..cac09d34af 100644
--- a/libs/ardour/ardour/graph.h
+++ b/libs/ardour/ardour/graph.h
@@ -92,7 +92,7 @@ protected:
virtual void session_going_away ();
private:
- std::list<jack_native_thread_t> _thread_list;
+ std::list<pthread_t> _thread_list;
volatile bool _quit_threads;
void reset_thread_list ();
diff --git a/libs/ardour/ardour/midi_buffer.h b/libs/ardour/ardour/midi_buffer.h
index 5ef5e4c845..781396a598 100644
--- a/libs/ardour/ardour/midi_buffer.h
+++ b/libs/ardour/ardour/midi_buffer.h
@@ -44,7 +44,6 @@ public:
void copy(const MidiBuffer& copy);
bool push_back(const Evoral::MIDIEvent<TimeType>& event);
- bool push_back(const jack_midi_event_t& event);
bool push_back(TimeType time, size_t size, const uint8_t* data);
uint8_t* reserve(TimeType time, size_t size);
diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h
index 34fa0ae79a..b1c126b339 100644
--- a/libs/ardour/ardour/midi_diskstream.h
+++ b/libs/ardour/ardour/midi_diskstream.h
@@ -81,7 +81,7 @@ class MidiDiskstream : public Diskstream
XMLNode& get_state(void);
int set_state(const XMLNode&, int version);
- void ensure_jack_monitors_input (bool);
+ void ensure_input_monitoring (bool);
boost::shared_ptr<SMFSource> write_source () { return _write_source; }
diff --git a/libs/ardour/ardour/midi_port.h b/libs/ardour/ardour/midi_port.h
index 5dc55398cb..00617d90ec 100644
--- a/libs/ardour/ardour/midi_port.h
+++ b/libs/ardour/ardour/midi_port.h
@@ -21,6 +21,8 @@
#ifndef __ardour_midi_port_h__
#define __ardour_midi_port_h__
+#include "midi++/parser.h"
+
#include "ardour/port.h"
#include "ardour/midi_buffer.h"
#include "ardour/midi_state_tracker.h"
@@ -56,18 +58,35 @@ class MidiPort : public Port {
MidiBuffer& get_midi_buffer (pframes_t nframes);
+ void set_always_parse (bool yn);
+ MIDI::Parser& self_parser() { return _self_parser; }
+
protected:
- friend class AudioEngine;
+ friend class PortManager;
- MidiPort (const std::string& name, Flags);
+ MidiPort (const std::string& name, PortFlags);
private:
MidiBuffer* _buffer;
bool _has_been_mixed_down;
bool _resolve_required;
bool _input_active;
-
- void resolve_notes (void* jack_buffer, MidiBuffer::TimeType when);
+ bool _always_parse;
+
+ /* Naming this is tricky. AsyncMIDIPort inherits (for now, aug 2013) from
+ * both MIDI::Port, which has _parser, and this (ARDOUR::MidiPort). We
+ * need parsing support in this object, independently of what the
+ * MIDI::Port/AsyncMIDIPort stuff does. Rather than risk errors coming
+ * from not explicitly naming which _parser we want, we will call this
+ * _self_parser for now.
+ *
+ * Ultimately, MIDI::Port should probably go away or be fully integrated
+ * into this object, somehow.
+ */
+
+ MIDI::Parser _self_parser;
+
+ void resolve_notes (void* buffer, MidiBuffer::TimeType when);
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/midi_ui.h b/libs/ardour/ardour/midi_ui.h
index 34e97494be..c15a530057 100644
--- a/libs/ardour/ardour/midi_ui.h
+++ b/libs/ardour/ardour/midi_ui.h
@@ -26,13 +26,11 @@
#include "pbd/signals.h"
#include "pbd/stacktrace.h"
-namespace MIDI {
- class Port;
-}
namespace ARDOUR {
class Session;
+class AsyncMIDIPort;
/* this is mostly a placeholder because I suspect that at some
point we will want to add more members to accomodate
@@ -67,7 +65,7 @@ class MidiControlUI : public AbstractUI<MidiUIRequest>
ARDOUR::Session& _session;
PBD::ScopedConnection rebind_connection;
- bool midi_input_handler (Glib::IOCondition, MIDI::Port*);
+ bool midi_input_handler (Glib::IOCondition, AsyncMIDIPort*);
void reset_ports ();
void clear_ports ();
diff --git a/libs/ardour/ardour/midiport_manager.h b/libs/ardour/ardour/midiport_manager.h
new file mode 100644
index 0000000000..9f93c43d5a
--- /dev/null
+++ b/libs/ardour/ardour/midiport_manager.h
@@ -0,0 +1,99 @@
+/*
+ Copyright (C) 1998 Paul Barton-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 __midiport_manager_h__
+#define __midiport_manager_h__
+
+#include <list>
+
+#include <string>
+
+#include "pbd/rcu.h"
+
+#include "midi++/types.h"
+#include "midi++/port.h"
+
+#include "ardour/types.h"
+
+namespace ARDOUR {
+
+class MidiPort;
+class Port;
+
+class MidiPortManager {
+ public:
+ MidiPortManager();
+ virtual ~MidiPortManager ();
+
+ /* Ports used for control. These are read/written to outside of the
+ * process callback (asynchronously with respect to when data
+ * actually arrives).
+ *
+ * More detail: we do actually read/write data for these ports
+ * inside the process callback, but incoming data is only parsed
+ * and outgoing data is only generated *outside* the process
+ * callback.
+ */
+
+ MIDI::Port* midi_input_port () const { return _midi_input_port; }
+ MIDI::Port* midi_output_port () const { return _midi_output_port; }
+ MIDI::Port* mmc_input_port () const { return _mmc_input_port; }
+ MIDI::Port* mmc_output_port () const { return _mmc_output_port; }
+
+ /* Ports used for synchronization. These have their I/O handled inside the
+ * process callback.
+ */
+
+ boost::shared_ptr<MidiPort> mtc_input_port() const { return _mtc_input_port; }
+ boost::shared_ptr<MidiPort> mtc_output_port() const { return _mtc_output_port; }
+ boost::shared_ptr<MidiPort> midi_clock_input_port() const { return _midi_clock_input_port; }
+ boost::shared_ptr<MidiPort> midi_clock_output_port() const { return _midi_clock_output_port; }
+
+ void set_midi_port_states (const XMLNodeList&);
+ std::list<XMLNode*> get_midi_port_states () const;
+
+ PBD::Signal0<void> PortsChanged;
+
+ protected:
+ /* asynchronously handled ports: MIDI::Port */
+ MIDI::Port* _midi_input_port;
+ MIDI::Port* _midi_output_port;
+ MIDI::Port* _mmc_input_port;
+ MIDI::Port* _mmc_output_port;
+ /* these point to the same objects as the 4 members above,
+ but cast to their ARDOUR::Port base class
+ */
+ boost::shared_ptr<Port> _midi_in;
+ boost::shared_ptr<Port> _midi_out;
+ boost::shared_ptr<Port> _mmc_in;
+ boost::shared_ptr<Port> _mmc_out;
+
+ /* synchronously handled ports: ARDOUR::MidiPort */
+ boost::shared_ptr<MidiPort> _mtc_input_port;
+ boost::shared_ptr<MidiPort> _mtc_output_port;
+ boost::shared_ptr<MidiPort> _midi_clock_input_port;
+ boost::shared_ptr<MidiPort> _midi_clock_output_port;
+
+ void create_ports ();
+
+};
+
+} // namespace MIDI
+
+#endif // __midi_port_manager_h__
diff --git a/libs/ardour/ardour/port.h b/libs/ardour/ardour/port.h
index e225117d94..77bf2b6f71 100644
--- a/libs/ardour/ardour/port.h
+++ b/libs/ardour/ardour/port.h
@@ -30,6 +30,7 @@
#include "pbd/signals.h"
#include "ardour/data_type.h"
+#include "ardour/port_engine.h"
#include "ardour/types.h"
namespace ARDOUR {
@@ -40,11 +41,6 @@ class Buffer;
class Port : public boost::noncopyable
{
public:
- enum Flags {
- IsInput = JackPortIsInput,
- IsOutput = JackPortIsOutput,
- };
-
virtual ~Port ();
static void set_connecting_blocked( bool yn ) {
@@ -62,7 +58,7 @@ public:
int set_name (std::string const &);
/** @return flags */
- Flags flags () const {
+ PortFlags flags () const {
return _flags;
}
@@ -90,24 +86,24 @@ public:
virtual int connect (Port *);
int disconnect (Port *);
- void ensure_jack_monitors_input (bool);
- bool jack_monitoring_input () const;
+ void request_input_monitoring (bool);
+ void ensure_input_monitoring (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; }
- jack_port_t* jack_port() const { return _jack_port; }
+ PortEngine::PortHandle port_handle() { return _port_handle; }
- void get_connected_latency_range (jack_latency_range_t& range, bool playback) const;
+ void get_connected_latency_range (LatencyRange& range, bool playback) const;
- void set_private_latency_range (jack_latency_range_t& range, bool playback);
- const jack_latency_range_t& private_latency_range (bool playback) const;
+ void set_private_latency_range (LatencyRange& range, bool playback);
+ const LatencyRange& private_latency_range (bool playback) const;
- void set_public_latency_range (jack_latency_range_t& range, bool playback) const;
- jack_latency_range_t public_latency_range (bool playback) const;
+ void set_public_latency_range (LatencyRange& range, bool playback) const;
+ LatencyRange public_latency_range (bool playback) const;
virtual void reset ();
@@ -122,8 +118,6 @@ public:
bool physically_connected () const;
- static void set_engine (AudioEngine *);
-
PBD::Signal1<void,bool> MonitorInputChanged;
static PBD::Signal2<void,boost::shared_ptr<Port>,boost::shared_ptr<Port> > PostDisconnect;
static PBD::Signal0<void> PortDrop;
@@ -141,11 +135,16 @@ public:
virtual void increment_port_buffer_offset (pframes_t n);
+ virtual XMLNode& get_state (void) const;
+ virtual int set_state (const XMLNode&, int version);
+
+ static std::string state_node_name;
+
protected:
- Port (std::string const &, DataType, Flags);
+ Port (std::string const &, DataType, PortFlags);
- jack_port_t* _jack_port; ///< JACK port
+ PortEngine::PortHandle _port_handle;
static bool _connecting_blocked;
static pframes_t _global_port_buffer_offset; /* access only from process() tree */
@@ -153,18 +152,16 @@ protected:
framecnt_t _port_buffer_offset; /* access only from process() tree */
- jack_latency_range_t _private_playback_latency;
- jack_latency_range_t _private_capture_latency;
-
- static AudioEngine* _engine; ///< the AudioEngine
+ LatencyRange _private_playback_latency;
+ LatencyRange _private_capture_latency;
private:
std::string _name; ///< port short name
- Flags _flags; ///< flags
+ PortFlags _flags; ///< flags
bool _last_monitor;
/** ports that we are connected to, kept so that we can
- reconnect to JACK when required
+ reconnect to the backend when required
*/
std::set<std::string> _connections;
diff --git a/libs/ardour/ardour/port_engine.h b/libs/ardour/ardour/port_engine.h
new file mode 100644
index 0000000000..71f93ea05e
--- /dev/null
+++ b/libs/ardour/ardour/port_engine.h
@@ -0,0 +1,345 @@
+/*
+ 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_engine_h__
+#define __libardour_port_engine_h__
+
+#include <vector>
+#include <string>
+
+#include <stdint.h>
+
+#include "ardour/data_type.h"
+#include "ardour/types.h"
+
+namespace ARDOUR {
+
+class PortManager;
+
+/** PortEngine is an abstract base class that defines the functionality
+ * required by Ardour.
+ *
+ * A Port is basically an endpoint for a datastream (which can either be
+ * continuous, like audio, or event-based, like MIDI). Ports have buffers
+ * associated with them into which data can be written (if they are output
+ * ports) and from which data can be read (if they input ports). Ports can be
+ * connected together so that data written to an output port can be read from
+ * an input port. These connections can be 1:1, 1:N OR N:1.
+ *
+ * Ports may be associated with software only, or with hardware. Hardware
+ * related ports are often referred to as physical, and correspond to some
+ * relevant physical entity on a hardware device, such as an audio jack or a
+ * MIDI connector. Physical ports may be potentially asked to monitor their
+ * inputs, though some implementations may not support this.
+ *
+ * Most physical ports will also be considered "terminal", which means that
+ * data delivered there or read from there will go to or comes from a system
+ * outside of the PortEngine implementation's control (e.g. the analog domain
+ * for audio, or external MIDI devices for MIDI). Non-physical ports can also
+ * be considered "terminal". For example, the output port of a software
+ * synthesizer is a terminal port, because the data contained in its buffer
+ * does not and cannot be considered to come from any other port - it is
+ * synthesized by its owner.
+ *
+ * Ports also have latency associated with them. Each port has a playback
+ * latency and a capture latency:
+ *
+ * <b>capture latency</b>: how long since the data read from the buffer of a
+ * port arrived at at a terminal port. The data will have
+ * come from the "outside world" if the terminal port is also
+ * physical, or will have been synthesized by the entity that
+ * owns the terminal port.
+ *
+ * <b>playback latency</b>: how long until the data written to the buffer of
+ * port will reach a terminal port.
+ *
+ *
+ * For more detailed questions about the PortEngine API, consult the JACK API
+ * documentation, on which this entire object is based.
+ */
+
+class PortEngine {
+ public:
+ PortEngine (PortManager& pm) : manager (pm) {}
+ virtual ~PortEngine() {}
+
+ /* We use void* here so that the API can be defined for any implementation.
+ *
+ * We could theoretically use a template (PortEngine<T>) and define
+ * PortHandle as T, but this complicates the desired inheritance
+ * pattern in which FooPortEngine handles things for the Foo API,
+ * rather than being a derivative of PortEngine<Foo>.
+ */
+
+ typedef void* PortHandle;
+
+ /** Return a typeless pointer to an object that may be of interest
+ * that understands the internals of a particular PortEngine
+ * implementation.
+ *
+ * XXX the existence of this method is a band-aid over some design
+ * issues and will it will be removed in the future
+ */
+ virtual void* private_handle() const = 0;
+
+ virtual bool connected() const = 0;
+
+ /** Return the name of this process as used by the port manager
+ * when naming ports.
+ */
+ virtual const std::string& my_name() const = 0;
+
+ /** Return the maximum size of a port name
+ */
+ virtual uint32_t port_name_size() const = 0;
+
+ /** Returns zero if the port referred to by @param port was set to @param
+ * name. Return non-zero otherwise.
+ */
+ virtual int set_port_name (PortHandle port, const std::string& name) = 0;
+ /** Return the name of the port referred to by @param port. If the port
+ * does not exist, return an empty string.
+ */
+ virtual std::string get_port_name (PortHandle) const = 0;
+ /** Return a reference to a port with the fullname @param name. Return
+ * a null pointer if no such port exists.
+ */
+ virtual PortHandle* get_port_by_name (const std::string&) const = 0;
+
+ /** Find the set of ports whose names, types and flags match
+ * specified values, place the names of each port into @param ports,
+ * and return the count of the number found.
+ *
+ * To avoid selecting by name, pass an empty string for @param
+ * port_name_pattern.
+ *
+ * To avoid selecting by type, pass DataType::NIL as @param type.
+ *
+ * To avoid selecting by flags, pass PortFlags (0) as @param flags.
+ */
+ virtual int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>& ports) const = 0;
+
+ /** Return the Ardour data type handled by the port referred to by @param
+ * port. Returns DataType::NIL if the port does not exist.
+ */
+ virtual DataType port_data_type (PortHandle port) const = 0;
+
+ /** Create a new port whose fullname will be the conjuction of my_name(),
+ * ":" and @param shortname. The port will handle data specified by @param
+ * type and will have the flags given by @param flags. If successfull,
+ * return a reference to the port, otherwise return a null pointer.
+ */
+ virtual PortHandle register_port (const std::string& shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags) = 0;
+
+ /* Destroy the port referred to by @param port, including all resources
+ * associated with it. This will also disconnect @param port from any ports it
+ * is connected to.
+ */
+ virtual void unregister_port (PortHandle) = 0;
+
+ /* Connection management */
+
+ /** Ensure that data written to the port named by @param src will be
+ * readable from the port named by @param dst. Return zero on success,
+ * non-zero otherwise.
+ */
+ virtual int connect (const std::string& src, const std::string& dst) = 0;
+
+ /** Remove any existing connection between the ports named by @param src and
+ * @param dst. Return zero on success, non-zero otherwise.
+ */
+ virtual int disconnect (const std::string& src, const std::string& dst) = 0;
+
+
+ /** Ensure that data written to the port referenced by @param portwill be
+ * readable from the port named by @param dst. Return zero on success,
+ * non-zero otherwise.
+ */
+ virtual int connect (PortHandle src, const std::string& dst) = 0;
+ /** Remove any existing connection between the port referenced by @param src and
+ * the port named @param dst. Return zero on success, non-zero otherwise.
+ */
+ virtual int disconnect (PortHandle src, const std::string& dst) = 0;
+
+ /** Remove all connections between the port referred to by @param port and
+ * any other ports. Return zero on success, non-zero otherwise.
+ */
+ virtual int disconnect_all (PortHandle port) = 0;
+
+ /** Return true if the port referred to by @param port has any connections
+ * to other ports. Return false otherwise.
+ */
+ virtual bool connected (PortHandle port, bool process_callback_safe = true) = 0;
+ /** Return true if the port referred to by @param port is connected to
+ * the port named by @param name. Return false otherwise.
+ */
+ virtual bool connected_to (PortHandle, const std::string& name, bool process_callback_safe = true) = 0;
+
+ /** Return true if the port referred to by @param port has any connections
+ * to ports marked with the PortFlag IsPhysical. Return false otherwise.
+ */
+ virtual bool physically_connected (PortHandle port, bool process_callback_safe = true) = 0;
+
+ /** Place the names of all ports connected to the port named by @param
+ * ports into @param names, and return the number of connections.
+ */
+ virtual int get_connections (PortHandle port, std::vector<std::string>& names, bool process_callback_safe = true) = 0;
+
+ /* MIDI */
+
+ /** Retrieve a MIDI event from the data at @param port_buffer. The event
+ number to be retrieved is given by @param event_index (a value of zero
+ indicates that the first event in the port_buffer should be retrieved).
+ *
+ * The data associated with the event will be copied into the buffer at
+ * @param buf and the number of bytes written will be stored in @param
+ * size. The timestamp of the event (which is always relative to the start
+ * of the current process cycle, in samples) will be stored in @param
+ * timestamp
+ */
+ virtual int midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index) = 0;
+
+ /** Place a MIDI event consisting of @param size bytes copied from the data
+ * at @param buf into the port buffer referred to by @param
+ * port_buffer. The MIDI event will be marked with a time given by @param
+ * timestamp. Return zero on success, non-zero otherwise.
+ *
+ * Events must be added monotonically to a port buffer. An attempt to
+ * add a non-monotonic event (e.g. out-of-order) will cause this method
+ * to return a failure status.
+ */
+ virtual int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size) = 0;
+
+ /** Return the number of MIDI events in the data at @param port_buffer
+ */
+ virtual uint32_t get_midi_event_count (void* port_buffer) = 0;
+
+ /** Clear the buffer at @param port_buffer of all MIDI events.
+ *
+ * After a call to this method, an immediate, subsequent call to
+ * get_midi_event_count() with the same @param port_buffer argument must
+ * return zero.
+ */
+ virtual void midi_clear (void* port_buffer) = 0;
+
+ /* Monitoring */
+
+ /** Return true if the implementation can offer input monitoring.
+ *
+ * Input monitoring involves the (selective) routing of incoming data
+ * to an outgoing data stream, without the data being passed to the CPU.
+ *
+ * Only certain audio hardware can provide this, and only certain audio
+ * APIs can offer it.
+ */
+ virtual bool can_monitor_input() const = 0;
+ /** Increment or decrement the number of requests to monitor the input
+ * of the hardware channel represented by the port referred to by @param
+ * port.
+ *
+ * If the number of requests rises above zero, input monitoring will
+ * be enabled (if can_monitor_input() returns true for the implementation).
+ *
+ * If the number of requests falls to zero, input monitoring will be
+ * disabled (if can_monitor_input() returns true for the implementation)
+ */
+ virtual int request_input_monitoring (PortHandle port, bool yn) = 0;
+ /* Force input monitoring of the hardware channel represented by the port
+ * referred to by @param port to be on or off, depending on the true/false
+ * status of @param yn. The request count is ignored when using this
+ * method, so if this is called with yn set to false, input monitoring will
+ * be disabled regardless of the number of requests to enable it.
+ */
+ virtual int ensure_input_monitoring (PortHandle port, bool yn) = 0;
+ /** Return true if input monitoring is enabled for the hardware channel
+ * represented by the port referred to by @param port. Return false
+ * otherwise.
+ */
+ virtual bool monitoring_input (PortHandle port) = 0;
+
+ /* Latency management
+ */
+
+ /** Set the latency range for the port referred to by @param port to @param
+ * r. The playback range will be set if @param for_playback is true,
+ * otherwise the capture range will be set.
+ */
+ virtual void set_latency_range (PortHandle port, bool for_playback, LatencyRange r) = 0;
+ /** Return the latency range for the port referred to by @param port.
+ * The playback range will be returned if @param for_playback is true,
+ * otherwise the capture range will be returned.
+ */
+ virtual LatencyRange get_latency_range (PortHandle port, bool for_playback) = 0;
+
+ /* Discovering physical ports */
+
+ /** Return true if the port referred to by @param port has the IsPhysical
+ * flag set. Return false otherwise.
+ */
+ virtual bool port_is_physical (PortHandle port) const = 0;
+
+ /** Store into @param names the names of all ports with the IsOutput and
+ * IsPhysical flag set, that handle data of type @param type.
+ *
+ * This can be used to discover outputs associated with hardware devices.
+ */
+ virtual void get_physical_outputs (DataType type, std::vector<std::string>& names) = 0;
+ /** Store into @param names the names of all ports with the IsInput and
+ * IsPhysical flags set, that handle data of type @param type.
+ *
+ * This can be used to discover inputs associated with hardware devices.
+ */
+ virtual void get_physical_inputs (DataType type, std::vector<std::string>& names) = 0;
+ /** Return the total count (possibly mixed between different data types)
+ of the number of ports with the IsPhysical and IsOutput flags set.
+ */
+ virtual ChanCount n_physical_outputs () const = 0;
+ /** Return the total count (possibly mixed between different data types)
+ of the number of ports with the IsPhysical and IsInput flags set.
+ */
+ virtual ChanCount n_physical_inputs () const = 0;
+
+ /** Return the address of the memory area where data for the port can be
+ * written (if the port has the PortFlag IsOutput set) or read (if the port
+ * has the PortFlag IsInput set).
+ *
+ * The return value is untyped because buffers containing different data
+ * depending on the port type.
+ */
+ virtual void* get_buffer (PortHandle, pframes_t) = 0;
+
+ /* MIDI ports (the ones in libmidi++) need this to be able to correctly
+ * schedule MIDI events within their buffers. It is a bit odd that we
+ * expose this here, because it is also exposed by AudioBackend, but they
+ * only have access to a PortEngine object, not an AudioBackend.
+ *
+ * Return the time according to the sample clock in use when the current
+ * buffer process cycle began.
+ *
+ * XXX to be removed after some more design cleanup.
+ */
+ virtual pframes_t sample_time_at_cycle_start () = 0;
+
+ protected:
+ PortManager& manager;
+};
+
+}
+
+#endif /* __libardour_port_engine_h__ */
diff --git a/libs/ardour/ardour/port_manager.h b/libs/ardour/ardour/port_manager.h
new file mode 100644
index 0000000000..6d45597a41
--- /dev/null
+++ b/libs/ardour/ardour/port_manager.h
@@ -0,0 +1,169 @@
+/*
+ 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"
+#include "ardour/midiport_manager.h"
+#include "ardour/port.h"
+#include "ardour/port_engine.h"
+
+namespace ARDOUR {
+
+class PortManager
+{
+ public:
+ typedef std::map<std::string,boost::shared_ptr<Port> > Ports;
+ typedef std::list<boost::shared_ptr<Port> > PortList;
+
+ PortManager ();
+ virtual ~PortManager() {}
+
+ void set_port_engine (PortEngine& pe);
+ PortEngine& port_engine() { return *_impl; }
+
+ uint32_t port_name_size() const;
+ std::string my_name() const;
+
+ /* Port registration */
+
+ boost::shared_ptr<Port> register_input_port (DataType, const std::string& portname, bool async = false);
+ boost::shared_ptr<Port> register_output_port (DataType, const std::string& portname, bool async = false);
+ int unregister_port (boost::shared_ptr<Port>);
+
+ /* Port connectivity */
+
+ int connect (const std::string& source, const std::string& destination);
+ int disconnect (const std::string& source, const std::string& destination);
+ int disconnect (boost::shared_ptr<Port>);
+ int reestablish_ports ();
+ int reconnect_ports ();
+
+ bool connected (const std::string&);
+ bool connected_to (const std::string&, const std::string&);
+ bool physically_connected (const std::string&);
+ int get_connections (const std::string&, std::vector<std::string>&);
+
+ /* Naming */
+
+ boost::shared_ptr<Port> get_port_by_name (const std::string &);
+ void port_renamed (const std::string&, const std::string&);
+ std::string make_port_name_relative (const std::string& name) const;
+ std::string make_port_name_non_relative (const std::string& name) const;
+ bool port_is_mine (const std::string& fullname) const;
+
+ /* other Port management */
+
+ bool port_is_physical (const std::string&) const;
+ void get_physical_outputs (DataType type, std::vector<std::string>&);
+ void get_physical_inputs (DataType type, std::vector<std::string>&);
+ ChanCount n_physical_outputs () const;
+ ChanCount n_physical_inputs () const;
+
+ int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>&);
+ int get_ports (DataType, PortList&);
+
+ void remove_all_ports ();
+
+ /* per-Port monitoring */
+
+ bool can_request_input_monitoring () const;
+ void request_input_monitoring (const std::string&, bool) const;
+ void ensure_input_monitoring (const std::string&, bool) const;
+
+ class PortRegistrationFailure : public std::exception {
+ public:
+ PortRegistrationFailure (std::string const & why = "")
+ : reason (why) {}
+
+ ~PortRegistrationFailure () throw () {}
+
+ const char *what() const throw () { return reason.c_str(); }
+
+ private:
+ std::string reason;
+ };
+
+ /* the port engine will invoke these callbacks when the time is right */
+
+ void registration_callback ();
+ int graph_order_callback ();
+ void connect_callback (const std::string&, const std::string&, bool connection);
+
+ bool port_remove_in_progress() const { return _port_remove_in_progress; }
+
+ /** Emitted if the backend notifies us of a graph order event */
+ PBD::Signal0<void> GraphReordered;
+
+ /** 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;
+
+ protected:
+ boost::shared_ptr<PortEngine> _impl;
+ SerializedRCUManager<Ports> ports;
+ bool _port_remove_in_progress;
+
+ boost::shared_ptr<Port> register_port (DataType type, const std::string& portname, bool input, bool async = false);
+ void port_registration_failure (const std::string& portname);
+
+ /** List of ports to be used between ::cycle_start() and ::cycle_end()
+ */
+ boost::shared_ptr<Ports> _cycle_ports;
+
+ void fade_out (gain_t, gain_t, pframes_t);
+ void silence (pframes_t nframes);
+ void check_monitoring ();
+ /** Signal the start of an audio cycle.
+ * This MUST be called before any reading/writing for this cycle.
+ * Realtime safe.
+ */
+ void cycle_start (pframes_t nframes);
+
+ /** Signal the end of an audio cycle.
+ * This signifies that the cycle began with @ref cycle_start has ended.
+ * This MUST be called at the end of each cycle.
+ * Realtime safe.
+ */
+ void cycle_end (pframes_t nframes);
+};
+
+
+
+} // namespace
+
+#endif /* __libardour_port_manager_h__ */
diff --git a/libs/ardour/ardour/public_diskstream.h b/libs/ardour/ardour/public_diskstream.h
index da481a6dee..125e1a21ce 100644
--- a/libs/ardour/ardour/public_diskstream.h
+++ b/libs/ardour/ardour/public_diskstream.h
@@ -33,8 +33,8 @@ public:
virtual ~PublicDiskstream() {}
virtual boost::shared_ptr<Playlist> playlist () = 0;
- virtual void request_jack_monitors_input (bool) = 0;
- virtual void ensure_jack_monitors_input (bool) = 0;
+ virtual void request_input_monitoring (bool) = 0;
+ virtual void ensure_input_monitoring (bool) = 0;
virtual bool destructive () const = 0;
virtual std::list<boost::shared_ptr<Source> > & last_capture_sources () = 0;
virtual void set_capture_offset () = 0;
diff --git a/libs/ardour/ardour/rc_configuration.h b/libs/ardour/ardour/rc_configuration.h
index ff1c5f035c..e2f68477a1 100644
--- a/libs/ardour/ardour/rc_configuration.h
+++ b/libs/ardour/ardour/rc_configuration.h
@@ -52,7 +52,6 @@ class RCConfiguration : public Configuration
XMLNode * instant_xml (const std::string& str);
XMLNode* control_protocol_state () { return _control_protocol_state; }
- std::list<XMLNode*> midi_port_states () { return _midi_port_states; }
/* define accessor methods */
@@ -81,11 +80,6 @@ class RCConfiguration : public Configuration
#undef CONFIG_VARIABLE_SPECIAL
XMLNode* _control_protocol_state;
-
- /** MIDI port nodes from the RC configuration. We store them so that we can set their
- state once the audio engine and hence ports are up.
- */
- std::list<XMLNode*> _midi_port_states;
};
/* XXX: rename this */
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 525dfbd849..43660d41cc 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -110,6 +110,8 @@ class IOProcessor;
class ImportStatus;
class MidiClockTicker;
class MidiControlUI;
+class MidiPortManager;
+class MidiPort;
class MidiRegion;
class MidiSource;
class MidiTrack;
@@ -381,9 +383,6 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
framecnt_t worst_track_latency () const { return _worst_track_latency; }
framecnt_t worst_playback_latency () const { return _worst_output_latency + _worst_track_latency; }
-#ifdef HAVE_JACK_SESSION
- void jack_session_event (jack_session_event_t* event);
-#endif
int save_state (std::string snapshot_name, bool pending = false, bool switch_to_snapshot = false);
int restore_state (std::string snapshot_name);
int save_template (std::string template_name);
@@ -556,6 +555,11 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
int remove_last_capture ();
+ /** handlers should return 0 for "everything OK", and any other value for
+ * "cannot setup audioengine".
+ */
+ static PBD::Signal1<int,uint32_t> AudioEngineSetupRequired;
+
/** handlers should return -1 for "stop cleanup",
0 for "yes, delete this playlist",
1 for "no, don't delete this playlist".
@@ -813,8 +817,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
boost::shared_ptr<SessionPlaylists> playlists;
void send_mmc_locate (framepos_t);
- int send_full_time_code (framepos_t);
- void send_song_position_pointer (framepos_t);
+ void queue_full_time_code () { _send_timecode_update = true; }
+ void queue_song_position_pointer () { /* currently does nothing */ }
bool step_editing() const { return (_step_editors > 0); }
@@ -863,6 +867,27 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
boost::shared_ptr<IO> ltc_input_io() { return _ltc_input; }
boost::shared_ptr<IO> ltc_output_io() { return _ltc_output; }
+ MIDI::Port* midi_input_port () const;
+ MIDI::Port* midi_output_port () const;
+ MIDI::Port* mmc_output_port () const;
+ MIDI::Port* mmc_input_port () const;
+
+ boost::shared_ptr<MidiPort> midi_clock_output_port () const;
+ boost::shared_ptr<MidiPort> midi_clock_input_port () const;
+ boost::shared_ptr<MidiPort> mtc_output_port () const;
+ boost::shared_ptr<MidiPort> mtc_input_port () const;
+
+ MIDI::MachineControl& mmc() { return *_mmc; }
+
+ /* Callbacks specifically related to JACK, and called directly
+ * from the JACK audio backend.
+ */
+
+#ifdef HAVE_JACK_SESSION
+ void jack_session_event (jack_session_event_t* event);
+#endif
+ void jack_timebase_callback (jack_transport_state_t, pframes_t, jack_position_t*, int);
+
protected:
friend class AudioEngine;
void set_block_size (pframes_t nframes);
@@ -1046,7 +1071,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
boost::scoped_ptr<SessionDirectory> _session_dir;
void hookup_io ();
- void when_engine_running ();
+ int when_engine_running ();
void graph_reordered ();
/** current snapshot name, without the .ardour suffix */
@@ -1112,8 +1137,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
void auto_loop_changed (Location *);
void auto_loop_declick_range (Location *, framepos_t &, framepos_t &);
- void first_stage_init (std::string path, std::string snapshot_name);
- int second_stage_init ();
+ void pre_engine_init (std::string path);
+ int post_engine_init ();
void remove_empty_sounds ();
void setup_midi_control ();
@@ -1216,7 +1241,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
framepos_t ltc_timecode_offset;
bool ltc_timecode_negative_offset;
- jack_latency_range_t ltc_out_latency;
+ LatencyRange ltc_out_latency;
void ltc_tx_initialize();
void ltc_tx_cleanup();
@@ -1261,6 +1286,13 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
void engine_halted ();
void xrun_recovery ();
+ /* These are synchronous and so can only be called from within the process
+ * cycle
+ */
+
+ int send_full_time_code (framepos_t, pframes_t nframes);
+ void send_song_position_pointer (framepos_t);
+
TempoMap *_tempo_map;
void tempo_map_changed (const PBD::PropertyChange&);
@@ -1429,9 +1461,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
*/
std::list<GQuark> _current_trans_quarks;
- void jack_timebase_callback (jack_transport_state_t, pframes_t, jack_position_t*, int);
- int jack_sync_callback (jack_transport_state_t, jack_position_t*);
- void reset_jack_connection (jack_client_t* jack);
+ int backend_sync_callback (TransportState, framepos_t);
+
void process_rtop (SessionEvent*);
void update_latency (bool playback);
@@ -1585,6 +1616,14 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
void reconnect_ltc_input ();
void reconnect_ltc_output ();
+
+ /* persistent, non-track related MIDI ports */
+ MidiPortManager* _midi_ports;
+ MIDI::MachineControl* _mmc;
+
+ void setup_ltc ();
+ void setup_click ();
+ void setup_bundles ();
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h
index 9862824da9..c60acb1df7 100644
--- a/libs/ardour/ardour/slave.h
+++ b/libs/ardour/ardour/slave.h
@@ -40,14 +40,12 @@
#define PLUSMINUS(A) ( ((A)<0) ? "-" : (((A)>0) ? "+" : "\u00B1") )
#define LEADINGZERO(A) ( (A)<10 ? " " : (A)<100 ? " " : (A)<1000 ? " " : "" )
-namespace MIDI {
- class Port;
-}
-
namespace ARDOUR {
class TempoMap;
class Session;
+class AudioEngine;
+class MidiPort;
/**
* @class Slave
@@ -252,10 +250,10 @@ class TimecodeSlave : public Slave {
class MTC_Slave : public TimecodeSlave {
public:
- MTC_Slave (Session&, MIDI::Port&);
+ MTC_Slave (Session&, MidiPort&);
~MTC_Slave ();
- void rebind (MIDI::Port&);
+ void rebind (MidiPort&);
bool speed_and_position (double&, framepos_t&);
bool locked() const;
@@ -273,7 +271,7 @@ class MTC_Slave : public TimecodeSlave {
private:
Session& session;
- MIDI::Port* port;
+ MidiPort* port;
PBD::ScopedConnectionList port_connections;
PBD::ScopedConnection config_connection;
bool can_notify_on_unknown_rate;
@@ -354,7 +352,7 @@ public:
std::string approximate_current_delta() const;
private:
- void parse_ltc(const jack_nframes_t, const jack_default_audio_sample_t * const, const framecnt_t);
+ void parse_ltc(const pframes_t, const Sample* const, const framecnt_t);
void process_ltc(framepos_t const);
void init_engine_dll (framepos_t, int32_t);
bool detect_discontinuity(LTCFrameExt *, int, bool);
@@ -391,7 +389,7 @@ public:
PBD::ScopedConnectionList port_connections;
PBD::ScopedConnection config_connection;
- jack_latency_range_t ltc_slave_latency;
+ LatencyRange ltc_slave_latency;
/* DLL - chase LTC */
int transport_direction;
@@ -404,13 +402,13 @@ public:
class MIDIClock_Slave : public Slave {
public:
- MIDIClock_Slave (Session&, MIDI::Port&, int ppqn = 24);
+ MIDIClock_Slave (Session&, MidiPort&, int ppqn = 24);
/// Constructor for unit tests
MIDIClock_Slave (ISlaveSessionProxy* session_proxy = 0, int ppqn = 24);
~MIDIClock_Slave ();
- void rebind (MIDI::Port&);
+ void rebind (MidiPort&);
bool speed_and_position (double&, framepos_t&);
bool locked() const;
@@ -426,7 +424,6 @@ class MIDIClock_Slave : public Slave {
protected:
ISlaveSessionProxy* session;
- MIDI::Port* port;
PBD::ScopedConnectionList port_connections;
/// pulses per quarter note for one MIDI clock frame (default 24)
@@ -492,7 +489,7 @@ class MIDIClock_Slave : public Slave {
class JACK_Slave : public Slave
{
public:
- JACK_Slave (jack_client_t*);
+ JACK_Slave (AudioEngine&);
~JACK_Slave ();
bool speed_and_position (double& speed, framepos_t& pos);
@@ -502,11 +499,10 @@ class JACK_Slave : public Slave
bool ok() const;
framecnt_t resolution () const { return 1; }
bool requires_seekahead () const { return false; }
- void reset_client (jack_client_t* jack);
bool is_always_synced() const { return true; }
private:
- jack_client_t* jack;
+ AudioEngine& engine;
double speed;
bool _starting;
};
diff --git a/libs/ardour/ardour/ticker.h b/libs/ardour/ardour/ticker.h
index b6e5376c12..7f0d1987fc 100644
--- a/libs/ardour/ardour/ticker.h
+++ b/libs/ardour/ardour/ticker.h
@@ -27,17 +27,13 @@
#include "ardour/session_handle.h"
-#ifndef TICKER_H_
-#define TICKER_H_
+#ifndef __libardour_ticker_h__
+#define __libardour_ticker_h__
-namespace MIDI {
- class Port;
-}
-
-namespace ARDOUR
-{
+namespace ARDOUR {
class Session;
+class MidiPort;
class MidiClockTicker : public SessionHandlePtr, boost::noncopyable
{
@@ -45,7 +41,7 @@ public:
MidiClockTicker ();
virtual ~MidiClockTicker();
- void tick (const framepos_t& transport_frames);
+ void tick (const framepos_t& transport_frames, pframes_t nframes);
bool has_midi_port() const { return _midi_port != 0; }
@@ -58,9 +54,6 @@ public:
/// slot for the signal session::TransportStateChange
void transport_state_changed();
- /// slot for the signal session::PositionChanged
- void position_changed (framepos_t position);
-
/// slot for the signal session::TransportLooped
void transport_looped();
@@ -70,23 +63,25 @@ public:
/// pulses per quarter note (default 24)
void set_ppqn(int ppqn) { _ppqn = ppqn; }
-private:
- MIDI::Port* _midi_port;
- int _ppqn;
- double _last_tick;
-
- class Position;
- boost::scoped_ptr<Position> _pos;
-
- double one_ppqn_in_frames (framepos_t transport_position);
-
- void send_midi_clock_event (pframes_t offset);
- void send_start_event (pframes_t offset);
- void send_continue_event (pframes_t offset);
- void send_stop_event (pframes_t offset);
- void send_position_event (uint32_t midi_clocks, pframes_t offset);
+ private:
+ boost::shared_ptr<MidiPort> _midi_port;
+ int _ppqn;
+ double _last_tick;
+ bool _send_pos;
+ bool _send_state;
+
+ class Position;
+ boost::scoped_ptr<Position> _pos;
+
+ double one_ppqn_in_frames (framepos_t transport_position);
+
+ void send_midi_clock_event (pframes_t offset, pframes_t nframes);
+ void send_start_event (pframes_t offset, pframes_t nframes);
+ void send_continue_event (pframes_t offset, pframes_t nframes);
+ void send_stop_event (pframes_t offset, pframes_t nframes);
+ void send_position_event (uint32_t midi_clocks, pframes_t offset, pframes_t nframes);
};
-
}
+ // namespace
-#endif /* TICKER_H_ */
+#endif /* __libardour_ticker_h__ */
diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h
index 7159261b51..bdf420763b 100644
--- a/libs/ardour/ardour/track.h
+++ b/libs/ardour/ardour/track.h
@@ -115,8 +115,8 @@ class Track : public Route, public PublicDiskstream
/* PublicDiskstream interface */
boost::shared_ptr<Playlist> playlist ();
- void request_jack_monitors_input (bool);
- void ensure_jack_monitors_input (bool);
+ void request_input_monitoring (bool);
+ void ensure_input_monitoring (bool);
bool destructive () const;
std::list<boost::shared_ptr<Source> > & last_capture_sources ();
void set_capture_offset ();
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index 2115149872..17bffc20e4 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -28,8 +28,6 @@
#include <stdint.h>
#include <inttypes.h>
-#include <jack/types.h>
-#include <jack/midiport.h>
#include "timecode/bbt_time.h"
#include "timecode/time.h"
@@ -53,12 +51,12 @@ namespace ARDOUR {
class Route;
class Region;
- typedef jack_default_audio_sample_t Sample;
- typedef float pan_t;
- typedef float gain_t;
- typedef uint32_t layer_t;
- typedef uint64_t microseconds_t;
- typedef jack_nframes_t pframes_t;
+ typedef float Sample;
+ typedef float pan_t;
+ typedef float gain_t;
+ typedef uint32_t layer_t;
+ typedef uint64_t microseconds_t;
+ typedef uint32_t pframes_t;
/* Any position measured in audio frames.
Assumed to be non-negative but not enforced.
@@ -585,6 +583,32 @@ namespace ARDOUR {
FadeSymmetric,
};
+ enum TransportState {
+ /* these values happen to match the constants used by JACK but
+ this equality cannot be assumed.
+ */
+ TransportStopped = 0,
+ TransportRolling = 1,
+ TransportLooping = 2,
+ TransportStarting = 3,
+ };
+
+ enum PortFlags {
+ /* these values happen to match the constants used by JACK but
+ this equality cannot be assumed.
+ */
+ IsInput = 0x1,
+ IsOutput = 0x2,
+ IsPhysical = 0x4,
+ CanMonitor = 0x8,
+ IsTerminal = 0x10
+ };
+
+ struct LatencyRange {
+ uint32_t min; //< samples
+ uint32_t max; //< samples
+ };
+
} // namespace ARDOUR