mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-07 15:25:01 +01:00
part-way through getting the audioengine changes to compile
This commit is contained in:
parent
3d95822716
commit
9ac6bb9bef
43 changed files with 891 additions and 878 deletions
|
|
@ -33,16 +33,16 @@ class AudioEngine;
|
||||||
class AudioBackend {
|
class AudioBackend {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum State {
|
AudioBackend (AudioEngine& e) : engine (e){}
|
||||||
Stopped = 0x1,
|
|
||||||
Running = 0x2,
|
|
||||||
Paused = 0x4,
|
|
||||||
Freewheeling = 0x8,
|
|
||||||
};
|
|
||||||
|
|
||||||
AudioBackend (AudioEngine& e) : engine (e), _state (Stopped) {}
|
|
||||||
virtual ~AudioBackend () {}
|
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 true if the underlying mechanism/API is still available
|
/** return true if the underlying mechanism/API is still available
|
||||||
* for us to utilize. return false if some or all of the AudioBackend
|
* for us to utilize. return false if some or all of the AudioBackend
|
||||||
* API can no longer be effectively used.
|
* API can no longer be effectively used.
|
||||||
|
|
@ -261,7 +261,7 @@ class AudioBackend {
|
||||||
virtual TransportState transport_state () { return TransportStopped; }
|
virtual TransportState transport_state () { return TransportStopped; }
|
||||||
/** Attempt to locate the transport to @param pos
|
/** Attempt to locate the transport to @param pos
|
||||||
*/
|
*/
|
||||||
virtual void transport_locate (framepos_t pos) {}
|
virtual void transport_locate (framepos_t /*pos*/) {}
|
||||||
/** Return the current transport location, in samples measured
|
/** Return the current transport location, in samples measured
|
||||||
* from the origin (defined by the transport time master)
|
* from the origin (defined by the transport time master)
|
||||||
*/
|
*/
|
||||||
|
|
@ -275,11 +275,11 @@ class AudioBackend {
|
||||||
* JACK is the only currently known audio API with the concept of a shared
|
* JACK is the only currently known audio API with the concept of a shared
|
||||||
* transport timebase.
|
* transport timebase.
|
||||||
*/
|
*/
|
||||||
virtual int set_time_master (bool yn) { return 0; }
|
virtual int set_time_master (bool /*yn*/) { return 0; }
|
||||||
|
|
||||||
virtual framecnt_t sample_rate () const;
|
virtual framecnt_t sample_rate () const;
|
||||||
virtual pframes_t samples_per_cycle () const;
|
virtual pframes_t samples_per_cycle () const;
|
||||||
virtual int usecs_per_cycle () const { return _usecs_per_cycle; }
|
virtual int usecs_per_cycle () const { return 1000000 * (samples_per_cycle() / sample_rate()); }
|
||||||
virtual size_t raw_buffer_size (DataType t);
|
virtual size_t raw_buffer_size (DataType t);
|
||||||
|
|
||||||
/* Process time */
|
/* Process time */
|
||||||
|
|
@ -326,7 +326,7 @@ class AudioBackend {
|
||||||
* Can ONLY be called from within a process() callback tree (which implies
|
* Can ONLY be called from within a process() callback tree (which implies
|
||||||
* that it can only be called by a process thread)
|
* that it can only be called by a process thread)
|
||||||
*/
|
*/
|
||||||
virtual bool get_sync_offset (pframes_t& offset) const { return 0; }
|
virtual bool get_sync_offset (pframes_t& /*offset*/) const { return false; }
|
||||||
|
|
||||||
/** Create a new thread suitable for running part of the buffer process
|
/** Create a new thread suitable for running part of the buffer process
|
||||||
* cycle (i.e. Realtime scheduling, memory allocation, etc. etc are all
|
* cycle (i.e. Realtime scheduling, memory allocation, etc. etc are all
|
||||||
|
|
@ -338,17 +338,6 @@ class AudioBackend {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AudioEngine& engine;
|
AudioEngine& engine;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ class AudioDiskstream : public Diskstream
|
||||||
XMLNode& get_state(void);
|
XMLNode& get_state(void);
|
||||||
int set_state(const XMLNode& node, int version);
|
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) {
|
static void swap_by_ptr (Sample *first, Sample *last) {
|
||||||
while (first < last) {
|
while (first < last) {
|
||||||
|
|
@ -159,7 +159,7 @@ class AudioDiskstream : public Diskstream
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
bool is_physical () const;
|
bool is_physical () const;
|
||||||
void request_jack_monitors_input (bool) const;
|
void request_input_monitoring (bool) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Information about one of our channels */
|
/** Information about one of our channels */
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ class AudioPort : public Port
|
||||||
protected:
|
protected:
|
||||||
friend class AudioEngine;
|
friend class AudioEngine;
|
||||||
|
|
||||||
AudioPort (std::string const &, Flags);
|
AudioPort (std::string const &, PortFlags);
|
||||||
/* special access for engine only */
|
/* special access for engine only */
|
||||||
Sample* engine_get_whole_audio_buffer ();
|
Sample* engine_get_whole_audio_buffer ();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@
|
||||||
#include "ardour/session_handle.h"
|
#include "ardour/session_handle.h"
|
||||||
#include "ardour/types.h"
|
#include "ardour/types.h"
|
||||||
#include "ardour/chan_count.h"
|
#include "ardour/chan_count.h"
|
||||||
|
#include "ardour/port_manager.h"
|
||||||
|
|
||||||
#ifdef HAVE_JACK_SESSION
|
#ifdef HAVE_JACK_SESSION
|
||||||
#include <jack/session.h>
|
#include <jack/session.h>
|
||||||
|
|
@ -61,37 +62,60 @@ class Session;
|
||||||
class ProcessThread;
|
class ProcessThread;
|
||||||
class AudioBackend;
|
class AudioBackend;
|
||||||
|
|
||||||
class AudioEngine : public SessionHandlePtr
|
class AudioEngine : public SessionHandlePtr, public PortManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::map<std::string,boost::shared_ptr<Port> > Ports;
|
|
||||||
|
|
||||||
AudioEngine (std::string client_name, std::string session_uuid);
|
static AudioEngine* create (const std::string& client_name, const std::string& session_uuid);
|
||||||
|
|
||||||
virtual ~AudioEngine ();
|
virtual ~AudioEngine ();
|
||||||
|
|
||||||
static int discover_backends();
|
int discover_backends();
|
||||||
std::vector<std::string> available_backends() const;
|
std::vector<std::string> available_backends() const;
|
||||||
std::string current_backend_name () const;
|
std::string current_backend_name () const;
|
||||||
|
int set_backend (const std::string&);
|
||||||
|
|
||||||
ProcessThread* main_thread() const { return _main_thread; }
|
ProcessThread* main_thread() const { return _main_thread; }
|
||||||
|
|
||||||
std::string client_name() const { return backend_client_name; }
|
std::string client_name() const { return backend_client_name; }
|
||||||
|
|
||||||
int stop (bool forever = false);
|
/* START BACKEND PROXY API
|
||||||
int start ();
|
*
|
||||||
int pause ();
|
* See audio_backend.h for full documentation and semantics. These wrappers
|
||||||
int freewheel (bool onoff);
|
* just forward to a backend implementation.
|
||||||
bool freewheeling() const { return _freewheeling; }
|
*/
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* END BACKEND PROXY API */
|
||||||
|
|
||||||
|
bool freewheeling() const { return _freewheeling; }
|
||||||
bool running() const { return _running; }
|
bool running() const { return _running; }
|
||||||
|
|
||||||
Glib::Threads::Mutex& process_lock() { return _process_lock; }
|
Glib::Threads::Mutex& process_lock() { return _process_lock; }
|
||||||
|
|
||||||
int request_buffer_size (pframes_t);
|
int request_buffer_size (pframes_t);
|
||||||
|
|
||||||
framecnt_t processed_frames() const { return _processed_frames; }
|
framecnt_t processed_frames() const { return _processed_frames; }
|
||||||
|
|
||||||
float get_cpu_load();
|
|
||||||
|
|
||||||
void set_session (Session *);
|
void set_session (Session *);
|
||||||
void remove_session (); // not a replacement for SessionHandle::session_going_away()
|
void remove_session (); // not a replacement for SessionHandle::session_going_away()
|
||||||
|
|
||||||
|
|
@ -161,8 +185,11 @@ public:
|
||||||
int process_callback (pframes_t nframes);
|
int process_callback (pframes_t nframes);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
AudioEngine (const std::string& client_name, const std::string& session_uuid);
|
||||||
|
|
||||||
static AudioEngine* _instance;
|
static AudioEngine* _instance;
|
||||||
|
|
||||||
|
AudioBackend* _backend;
|
||||||
Glib::Threads::Mutex _process_lock;
|
Glib::Threads::Mutex _process_lock;
|
||||||
Glib::Threads::Cond session_removed;
|
Glib::Threads::Cond session_removed;
|
||||||
bool session_remove_pending;
|
bool session_remove_pending;
|
||||||
|
|
@ -187,6 +214,8 @@ public:
|
||||||
Glib::Threads::Thread* m_meter_thread;
|
Glib::Threads::Thread* m_meter_thread;
|
||||||
ProcessThread* _main_thread;
|
ProcessThread* _main_thread;
|
||||||
|
|
||||||
|
std::string backend_client_name;
|
||||||
|
std::string backend_session_uuid;
|
||||||
|
|
||||||
void meter_thread ();
|
void meter_thread ();
|
||||||
void start_metering_thread ();
|
void start_metering_thread ();
|
||||||
|
|
@ -196,6 +225,11 @@ public:
|
||||||
|
|
||||||
void parameter_changed (const std::string&);
|
void parameter_changed (const std::string&);
|
||||||
PBD::ScopedConnection config_connection;
|
PBD::ScopedConnection config_connection;
|
||||||
|
|
||||||
|
typedef std::map<std::string,AudioBackend*> BackendMap;
|
||||||
|
BackendMap _backends;
|
||||||
|
AudioBackend* backend_discover (const std::string&);
|
||||||
|
void drop_backend ();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ARDOUR
|
} // namespace ARDOUR
|
||||||
|
|
|
||||||
39
libs/ardour/ardour/backend_search_path.h
Normal file
39
libs/ardour/ardour/backend_search_path.h
Normal file
|
|
@ -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__ */
|
||||||
|
|
@ -21,11 +21,11 @@
|
||||||
#define __ardour_data_type_h__
|
#define __ardour_data_type_h__
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <jack/jack.h>
|
#include <stdint.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
|
||||||
/** A type of Data Ardour is capable of processing.
|
/** A type of Data Ardour is capable of processing.
|
||||||
*
|
*
|
||||||
* The majority of this class is dedicated to conversion to and from various
|
* The majority of this class is dedicated to conversion to and from various
|
||||||
|
|
@ -61,22 +61,14 @@ public:
|
||||||
|
|
||||||
/** Construct from a string (Used for loading from XML and Ports)
|
/** 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
|
* 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)
|
DataType(const std::string& str)
|
||||||
: _symbol(NIL) {
|
: _symbol(NIL) {
|
||||||
if (str == "audio" || str == JACK_DEFAULT_AUDIO_TYPE)
|
if (!g_ascii_strncasecmp(str.c_str(), "audio", str.length())) {
|
||||||
_symbol = AUDIO;
|
_symbol = AUDIO;
|
||||||
else if (str == "midi" || str == JACK_DEFAULT_MIDI_TYPE)
|
} else if (!g_ascii_strncasecmp(str.c_str(), "midi", str.length())) {
|
||||||
_symbol = MIDI;
|
_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 */
|
/** Inverse of the from-string constructor */
|
||||||
|
|
@ -125,7 +117,6 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace ARDOUR
|
} // namespace ARDOUR
|
||||||
|
|
||||||
#endif // __ardour_data_type_h__
|
#endif // __ardour_data_type_h__
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ extern const char* const route_templates_dir_name;
|
||||||
extern const char* const surfaces_dir_name;
|
extern const char* const surfaces_dir_name;
|
||||||
extern const char* const user_config_dir_name;
|
extern const char* const user_config_dir_name;
|
||||||
extern const char* const panner_dir_name;
|
extern const char* const panner_dir_name;
|
||||||
|
extern const char* const backend_dir_name;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,18 @@ ifdef HAVE_JACK_SESSION
|
||||||
|
|
||||||
ChanCount n_physical (unsigned long) const;
|
ChanCount n_physical (unsigned long) const;
|
||||||
void get_physical (DataType, unsigned long, std::vector<std::string> &);
|
void get_physical (DataType, unsigned long, std::vector<std::string> &);
|
||||||
|
|
||||||
|
/* pffooo */
|
||||||
|
|
||||||
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ public:
|
||||||
void copy(const MidiBuffer& copy);
|
void copy(const MidiBuffer& copy);
|
||||||
|
|
||||||
bool push_back(const Evoral::MIDIEvent<TimeType>& event);
|
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);
|
bool push_back(TimeType time, size_t size, const uint8_t* data);
|
||||||
uint8_t* reserve(TimeType time, size_t size);
|
uint8_t* reserve(TimeType time, size_t size);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ class MidiPort : public Port {
|
||||||
protected:
|
protected:
|
||||||
friend class AudioEngine;
|
friend class AudioEngine;
|
||||||
|
|
||||||
MidiPort (const std::string& name, Flags);
|
MidiPort (const std::string& name, PortFlags);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MidiBuffer* _buffer;
|
MidiBuffer* _buffer;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#include "pbd/signals.h"
|
#include "pbd/signals.h"
|
||||||
|
|
||||||
#include "ardour/data_type.h"
|
#include "ardour/data_type.h"
|
||||||
|
#include "ardour/port_engine.h"
|
||||||
#include "ardour/types.h"
|
#include "ardour/types.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
@ -40,11 +41,6 @@ class Buffer;
|
||||||
class Port : public boost::noncopyable
|
class Port : public boost::noncopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Flags {
|
|
||||||
IsInput = JackPortIsInput,
|
|
||||||
IsOutput = JackPortIsOutput,
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual ~Port ();
|
virtual ~Port ();
|
||||||
|
|
||||||
static void set_connecting_blocked( bool yn ) {
|
static void set_connecting_blocked( bool yn ) {
|
||||||
|
|
@ -62,7 +58,7 @@ public:
|
||||||
int set_name (std::string const &);
|
int set_name (std::string const &);
|
||||||
|
|
||||||
/** @return flags */
|
/** @return flags */
|
||||||
Flags flags () const {
|
PortFlags flags () const {
|
||||||
return _flags;
|
return _flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,8 +86,8 @@ public:
|
||||||
virtual int connect (Port *);
|
virtual int connect (Port *);
|
||||||
int disconnect (Port *);
|
int disconnect (Port *);
|
||||||
|
|
||||||
void request_monitor_input (bool);
|
void request_input_monitoring (bool);
|
||||||
void ensure_monitor_input (bool);
|
void ensure_input_monitoring (bool);
|
||||||
bool monitoring_input () const;
|
bool monitoring_input () const;
|
||||||
int reestablish ();
|
int reestablish ();
|
||||||
int reconnect ();
|
int reconnect ();
|
||||||
|
|
@ -99,7 +95,7 @@ public:
|
||||||
bool last_monitor() const { return _last_monitor; }
|
bool last_monitor() const { return _last_monitor; }
|
||||||
void set_last_monitor (bool yn) { _last_monitor = yn; }
|
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 (jack_latency_range_t& range, bool playback) const;
|
||||||
|
|
||||||
|
|
@ -122,8 +118,6 @@ public:
|
||||||
|
|
||||||
bool physically_connected () const;
|
bool physically_connected () const;
|
||||||
|
|
||||||
static void set_engine (AudioEngine *);
|
|
||||||
|
|
||||||
PBD::Signal1<void,bool> MonitorInputChanged;
|
PBD::Signal1<void,bool> MonitorInputChanged;
|
||||||
static PBD::Signal2<void,boost::shared_ptr<Port>,boost::shared_ptr<Port> > PostDisconnect;
|
static PBD::Signal2<void,boost::shared_ptr<Port>,boost::shared_ptr<Port> > PostDisconnect;
|
||||||
static PBD::Signal0<void> PortDrop;
|
static PBD::Signal0<void> PortDrop;
|
||||||
|
|
@ -143,9 +137,9 @@ public:
|
||||||
|
|
||||||
protected:
|
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 bool _connecting_blocked;
|
||||||
static pframes_t _global_port_buffer_offset; /* access only from process() tree */
|
static pframes_t _global_port_buffer_offset; /* access only from process() tree */
|
||||||
|
|
@ -156,15 +150,13 @@ protected:
|
||||||
jack_latency_range_t _private_playback_latency;
|
jack_latency_range_t _private_playback_latency;
|
||||||
jack_latency_range_t _private_capture_latency;
|
jack_latency_range_t _private_capture_latency;
|
||||||
|
|
||||||
static AudioEngine* _engine; ///< the AudioEngine
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string _name; ///< port short name
|
std::string _name; ///< port short name
|
||||||
Flags _flags; ///< flags
|
PortFlags _flags; ///< flags
|
||||||
bool _last_monitor;
|
bool _last_monitor;
|
||||||
|
|
||||||
/** ports that we are connected to, kept so that we can
|
/** 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;
|
std::set<std::string> _connections;
|
||||||
|
|
||||||
|
|
|
||||||
139
libs/ardour/ardour/port_engine.h
Normal file
139
libs/ardour/ardour/port_engine.h
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
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 {
|
||||||
|
|
||||||
|
/** 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() {}
|
||||||
|
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;
|
||||||
|
|
||||||
|
virtual bool connected() const = 0;
|
||||||
|
|
||||||
|
virtual int set_port_name (PortHandle, const std::string&) = 0;
|
||||||
|
virtual std::string get_port_name (PortHandle) const = 0;
|
||||||
|
virtual PortHandle* get_port_by_name (const std::string&) const = 0;
|
||||||
|
|
||||||
|
virtual PortHandle register_port (const std::string&, DataType::Symbol, ARDOUR::PortFlags) = 0;
|
||||||
|
virtual void unregister_port (PortHandle) = 0;
|
||||||
|
virtual bool connected (PortHandle) = 0;
|
||||||
|
virtual int disconnect_all (PortHandle) = 0;
|
||||||
|
virtual bool connected_to (PortHandle, const std::string&) = 0;
|
||||||
|
virtual int get_connections (PortHandle, std::vector<std::string>&) = 0;
|
||||||
|
virtual bool physically_connected (PortHandle) = 0;
|
||||||
|
virtual int connect (PortHandle, const std::string&) = 0;
|
||||||
|
virtual int disconnect (PortHandle, const std::string&) = 0;
|
||||||
|
|
||||||
|
/* MIDI */
|
||||||
|
|
||||||
|
virtual void midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index) = 0;
|
||||||
|
virtual int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size) = 0;
|
||||||
|
virtual uint32_t get_midi_event_count (void* port_buffer);
|
||||||
|
virtual void midi_clear (void* port_buffer);
|
||||||
|
|
||||||
|
/* Monitoring */
|
||||||
|
|
||||||
|
virtual bool can_monitor_input() const = 0;
|
||||||
|
virtual int request_input_monitoring (PortHandle, bool) = 0;
|
||||||
|
virtual int ensure_input_monitoring (PortHandle, bool) = 0;
|
||||||
|
virtual bool monitoring_input (PortHandle) = 0;
|
||||||
|
|
||||||
|
/* Latency management
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct LatencyRange {
|
||||||
|
uint32_t min;
|
||||||
|
uint32_t max;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void set_latency_range (PortHandle, int dir, LatencyRange) = 0;
|
||||||
|
virtual LatencyRange get_latency_range (PortHandle, int dir) = 0;
|
||||||
|
virtual LatencyRange get_connected_latency_range (PortHandle, int dir) = 0;
|
||||||
|
|
||||||
|
virtual void* get_buffer (PortHandle, pframes_t) = 0;
|
||||||
|
|
||||||
|
virtual pframes_t last_frame_time () const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __libardour_port_engine_h__ */
|
||||||
|
|
@ -32,11 +32,11 @@
|
||||||
#include "pbd/rcu.h"
|
#include "pbd/rcu.h"
|
||||||
|
|
||||||
#include "ardour/chan_count.h"
|
#include "ardour/chan_count.h"
|
||||||
|
#include "ardour/port.h"
|
||||||
|
#include "ardour/port_engine.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
class Port;
|
|
||||||
|
|
||||||
class PortManager
|
class PortManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -45,35 +45,43 @@ class PortManager
|
||||||
PortManager();
|
PortManager();
|
||||||
virtual ~PortManager() {}
|
virtual ~PortManager() {}
|
||||||
|
|
||||||
|
PortEngine& port_engine() { return *_impl; }
|
||||||
|
|
||||||
/* Port registration */
|
/* Port registration */
|
||||||
|
|
||||||
virtual boost::shared_ptr<Port> register_input_port (DataType, const std::string& portname) = 0;
|
boost::shared_ptr<Port> register_input_port (DataType, const std::string& portname);
|
||||||
virtual boost::shared_ptr<Port> register_output_port (DataType, const std::string& portname) = 0;
|
boost::shared_ptr<Port> register_output_port (DataType, const std::string& portname);
|
||||||
virtual int unregister_port (boost::shared_ptr<Port>) = 0;
|
int unregister_port (boost::shared_ptr<Port>);
|
||||||
|
|
||||||
/* Port connectivity */
|
/* Port connectivity */
|
||||||
|
|
||||||
virtual int connect (const std::string& source, const std::string& destination) = 0;
|
int connect (const std::string& source, const std::string& destination);
|
||||||
virtual int disconnect (const std::string& source, const std::string& destination) = 0;
|
int disconnect (const std::string& source, const std::string& destination);
|
||||||
virtual int disconnect (boost::shared_ptr<Port>) = 0;
|
int disconnect (boost::shared_ptr<Port>);
|
||||||
|
bool connected (const std::string&);
|
||||||
|
|
||||||
/* other Port management */
|
/* other Port management */
|
||||||
|
|
||||||
virtual bool port_is_physical (const std::string&) const = 0;
|
bool port_is_physical (const std::string&) const;
|
||||||
virtual void get_physical_outputs (DataType type, std::vector<std::string>&) = 0;
|
void get_physical_outputs (DataType type, std::vector<std::string>&);
|
||||||
virtual void get_physical_inputs (DataType type, std::vector<std::string>&) = 0;
|
void get_physical_inputs (DataType type, std::vector<std::string>&);
|
||||||
virtual boost::shared_ptr<Port> get_port_by_name (const std::string &) = 0;
|
boost::shared_ptr<Port> get_port_by_name (const std::string &);
|
||||||
virtual void port_renamed (const std::string&, const std::string&) = 0;
|
void port_renamed (const std::string&, const std::string&);
|
||||||
virtual ChanCount n_physical_outputs () const = 0;
|
ChanCount n_physical_outputs () const;
|
||||||
virtual ChanCount n_physical_inputs () const = 0;
|
ChanCount n_physical_inputs () const;
|
||||||
virtual const char ** get_ports (const std::string& port_name_pattern, const std::string& type_name_pattern, uint32_t flags) = 0;
|
const char ** get_ports (const std::string& port_name_pattern, const std::string& type_name_pattern, uint32_t flags);
|
||||||
|
|
||||||
void remove_all_ports ();
|
void remove_all_ports ();
|
||||||
|
|
||||||
/* per-Port monitoring */
|
/* per-Port monitoring */
|
||||||
|
|
||||||
virtual bool can_request_input_monitoring () const = 0;
|
bool can_request_input_monitoring () const;
|
||||||
virtual void request_input_monitoring (const std::string&, bool) const = 0;
|
void request_input_monitoring (const std::string&, bool) const;
|
||||||
|
void ensure_input_monitoring (const std::string&, bool) const;
|
||||||
|
|
||||||
|
std::string make_port_name_relative (const std::string&) const;
|
||||||
|
std::string make_port_name_non_relative (const std::string&) const;
|
||||||
|
bool port_is_mine (const std::string&) const;
|
||||||
|
|
||||||
class PortRegistrationFailure : public std::exception {
|
class PortRegistrationFailure : public std::exception {
|
||||||
public:
|
public:
|
||||||
|
|
@ -82,23 +90,17 @@ class PortManager
|
||||||
|
|
||||||
~PortRegistrationFailure () throw () {}
|
~PortRegistrationFailure () throw () {}
|
||||||
|
|
||||||
virtual const char *what() const throw () { return reason.c_str(); }
|
const char *what() const throw () { return reason.c_str(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string reason;
|
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:
|
protected:
|
||||||
|
PortEngine* _impl;
|
||||||
SerializedRCUManager<Ports> ports;
|
SerializedRCUManager<Ports> ports;
|
||||||
|
|
||||||
boost::shared_ptr<Port> register_port (DataType type, const std::string& portname, bool input);
|
boost::shared_ptr<Port> register_port (DataType type, const std::string& portname, bool input);
|
||||||
void port_registration_failure (const std::string& portname);
|
void port_registration_failure (const std::string& portname);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -584,6 +584,25 @@ namespace ARDOUR {
|
||||||
FadeSymmetric,
|
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 = 1,
|
||||||
|
IsOutput = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace ARDOUR
|
} // namespace ARDOUR
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1729,7 +1729,7 @@ AudioDiskstream::prep_record_enable ()
|
||||||
if (Config->get_monitoring_model() == HardwareMonitoring) {
|
if (Config->get_monitoring_model() == HardwareMonitoring) {
|
||||||
|
|
||||||
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
|
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
|
||||||
(*chan)->source.request_jack_monitors_input (!(_session.config.get_auto_input() && rolling));
|
(*chan)->source.request_input_monitoring (!(_session.config.get_auto_input() && rolling));
|
||||||
capturing_sources.push_back ((*chan)->write_source);
|
capturing_sources.push_back ((*chan)->write_source);
|
||||||
(*chan)->write_source->mark_streaming_write_started ();
|
(*chan)->write_source->mark_streaming_write_started ();
|
||||||
}
|
}
|
||||||
|
|
@ -1750,7 +1750,7 @@ AudioDiskstream::prep_record_disable ()
|
||||||
boost::shared_ptr<ChannelList> c = channels.reader();
|
boost::shared_ptr<ChannelList> c = channels.reader();
|
||||||
if (Config->get_monitoring_model() == HardwareMonitoring) {
|
if (Config->get_monitoring_model() == HardwareMonitoring) {
|
||||||
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
|
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
|
||||||
(*chan)->source.request_jack_monitors_input (false);
|
(*chan)->source.request_input_monitoring (false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
capturing_sources.clear ();
|
capturing_sources.clear ();
|
||||||
|
|
@ -2016,12 +2016,12 @@ AudioDiskstream::allocate_temporary_buffers ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioDiskstream::request_jack_monitors_input (bool yn)
|
AudioDiskstream::request_input_monitoring (bool yn)
|
||||||
{
|
{
|
||||||
boost::shared_ptr<ChannelList> c = channels.reader();
|
boost::shared_ptr<ChannelList> c = channels.reader();
|
||||||
|
|
||||||
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
|
for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
|
||||||
(*chan)->source.request_jack_monitors_input (yn);
|
(*chan)->source.request_input_monitoring (yn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2344,13 +2344,13 @@ AudioDiskstream::ChannelSource::is_physical () const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioDiskstream::ChannelSource::request_jack_monitors_input (bool yn) const
|
AudioDiskstream::ChannelSource::request_input_monitoring (bool yn) const
|
||||||
{
|
{
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return AudioEngine::instance()->request_jack_monitors_input (name, yn);
|
return AudioEngine::instance()->request_input_monitoring (name, yn);
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioDiskstream::ChannelInfo::ChannelInfo (framecnt_t playback_bufsize, framecnt_t capture_bufsize, framecnt_t speed_size, framecnt_t wrap_size)
|
AudioDiskstream::ChannelInfo::ChannelInfo (framecnt_t playback_bufsize, framecnt_t capture_bufsize, framecnt_t speed_size, framecnt_t wrap_size)
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,17 @@
|
||||||
#include "pbd/stacktrace.h"
|
#include "pbd/stacktrace.h"
|
||||||
|
|
||||||
#include "ardour/audio_buffer.h"
|
#include "ardour/audio_buffer.h"
|
||||||
|
#include "ardour/audioengine.h"
|
||||||
#include "ardour/audio_port.h"
|
#include "ardour/audio_port.h"
|
||||||
#include "ardour/data_type.h"
|
#include "ardour/data_type.h"
|
||||||
|
#include "ardour/port_engine.h"
|
||||||
|
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
AudioPort::AudioPort (const std::string& name, Flags flags)
|
#define port_engine AudioEngine::instance()->port_engine()
|
||||||
|
|
||||||
|
AudioPort::AudioPort (const std::string& name, PortFlags flags)
|
||||||
: Port (name, DataType::AUDIO, flags)
|
: Port (name, DataType::AUDIO, flags)
|
||||||
, _buffer (new AudioBuffer (0))
|
, _buffer (new AudioBuffer (0))
|
||||||
{
|
{
|
||||||
|
|
@ -73,7 +77,7 @@ AudioBuffer&
|
||||||
AudioPort::get_audio_buffer (pframes_t nframes)
|
AudioPort::get_audio_buffer (pframes_t nframes)
|
||||||
{
|
{
|
||||||
/* caller must hold process lock */
|
/* caller must hold process lock */
|
||||||
_buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes) +
|
_buffer->set_data ((Sample *) port_engine.get_buffer (_port_handle, _cycle_nframes) +
|
||||||
_global_port_buffer_offset + _port_buffer_offset, nframes);
|
_global_port_buffer_offset + _port_buffer_offset, nframes);
|
||||||
return *_buffer;
|
return *_buffer;
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +86,7 @@ Sample*
|
||||||
AudioPort::engine_get_whole_audio_buffer ()
|
AudioPort::engine_get_whole_audio_buffer ()
|
||||||
{
|
{
|
||||||
/* caller must hold process lock */
|
/* caller must hold process lock */
|
||||||
return (Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes);
|
return (Sample *) port_engine.get_buffer (_port_handle, _cycle_nframes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,14 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include <glibmm/timer.h>
|
#include <glibmm/timer.h>
|
||||||
|
#include <glibmm/pattern.h>
|
||||||
|
#include <glibmm/module.h>
|
||||||
|
|
||||||
|
#include "pbd/epa.h"
|
||||||
|
#include "pbd/file_utils.h"
|
||||||
#include "pbd/pthread_utils.h"
|
#include "pbd/pthread_utils.h"
|
||||||
#include "pbd/stacktrace.h"
|
#include "pbd/stacktrace.h"
|
||||||
#include "pbd/unknown_type.h"
|
#include "pbd/unknown_type.h"
|
||||||
#include "pbd/epa.h"
|
|
||||||
|
|
||||||
#include <jack/weakjack.h>
|
#include <jack/weakjack.h>
|
||||||
|
|
||||||
|
|
@ -39,7 +42,9 @@
|
||||||
#include "midi++/manager.h"
|
#include "midi++/manager.h"
|
||||||
|
|
||||||
#include "ardour/audio_port.h"
|
#include "ardour/audio_port.h"
|
||||||
|
#include "ardour/audio_backend.h"
|
||||||
#include "ardour/audioengine.h"
|
#include "ardour/audioengine.h"
|
||||||
|
#include "ardour/backend_search_path.h"
|
||||||
#include "ardour/buffer.h"
|
#include "ardour/buffer.h"
|
||||||
#include "ardour/cycle_timer.h"
|
#include "ardour/cycle_timer.h"
|
||||||
#include "ardour/internal_send.h"
|
#include "ardour/internal_send.h"
|
||||||
|
|
@ -58,8 +63,9 @@ using namespace PBD;
|
||||||
gint AudioEngine::m_meter_exit;
|
gint AudioEngine::m_meter_exit;
|
||||||
AudioEngine* AudioEngine::_instance = 0;
|
AudioEngine* AudioEngine::_instance = 0;
|
||||||
|
|
||||||
AudioEngine::AudioEngine ()
|
AudioEngine::AudioEngine (const std::string& bcn, const std::string& bsu)
|
||||||
: session_remove_pending (false)
|
: _backend (0)
|
||||||
|
, session_remove_pending (false)
|
||||||
, session_removal_countdown (-1)
|
, session_removal_countdown (-1)
|
||||||
, monitor_check_interval (INT32_MAX)
|
, monitor_check_interval (INT32_MAX)
|
||||||
, last_monitor_check (0)
|
, last_monitor_check (0)
|
||||||
|
|
@ -70,14 +76,16 @@ AudioEngine::AudioEngine ()
|
||||||
, port_remove_in_progress (false)
|
, port_remove_in_progress (false)
|
||||||
, m_meter_thread (0)
|
, m_meter_thread (0)
|
||||||
, _main_thread (0)
|
, _main_thread (0)
|
||||||
|
, backend_client_name (bcn)
|
||||||
|
, backend_session_uuid (bsu)
|
||||||
{
|
{
|
||||||
g_atomic_int_set (&m_meter_exit, 0);
|
g_atomic_int_set (&m_meter_exit, 0);
|
||||||
|
|
||||||
Port::set_engine (this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioEngine::~AudioEngine ()
|
AudioEngine::~AudioEngine ()
|
||||||
{
|
{
|
||||||
|
drop_backend ();
|
||||||
|
|
||||||
config_connection.disconnect ();
|
config_connection.disconnect ();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -88,18 +96,38 @@ AudioEngine::~AudioEngine ()
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioEngine*
|
AudioEngine*
|
||||||
AudioEngine::create ()
|
AudioEngine::create (const std::string& bcn, const std::string& bsu)
|
||||||
{
|
{
|
||||||
if (_instance) {
|
if (_instance) {
|
||||||
return _instance;
|
return _instance;
|
||||||
}
|
}
|
||||||
return new AudioEngine;
|
return new AudioEngine (bcn, bsu);
|
||||||
}
|
}
|
||||||
|
|
||||||
jack_client_t*
|
void
|
||||||
AudioEngine::jack() const
|
AudioEngine::drop_backend ()
|
||||||
{
|
{
|
||||||
return _jack;
|
if (_backend) {
|
||||||
|
_backend->stop ();
|
||||||
|
delete _backend;
|
||||||
|
_backend = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
AudioEngine::set_backend (const std::string& name)
|
||||||
|
{
|
||||||
|
BackendMap::iterator b = _backends.find (name);
|
||||||
|
|
||||||
|
if (b == _backends.end()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_backend ();
|
||||||
|
|
||||||
|
_backend = b->second;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -120,70 +148,6 @@ _thread_init_callback (void * /*arg*/)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
AudioEngine::start ()
|
|
||||||
{
|
|
||||||
GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
|
|
||||||
|
|
||||||
if (!_running) {
|
|
||||||
|
|
||||||
if (!jack_port_type_get_buffer_size) {
|
|
||||||
warning << _("This version of JACK is old - you should upgrade to a newer version that supports jack_port_type_get_buffer_size()") << endmsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_session) {
|
|
||||||
BootMessage (_("Connect session to engine"));
|
|
||||||
_session->set_frame_rate (jack_get_sample_rate (_priv_jack));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* a proxy for whether jack_activate() will definitely call the buffer size
|
|
||||||
* callback. with older versions of JACK, this function symbol will be null.
|
|
||||||
* this is reliable, but not clean.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!jack_port_type_get_buffer_size) {
|
|
||||||
jack_bufsize_callback (jack_get_buffer_size (_priv_jack));
|
|
||||||
}
|
|
||||||
|
|
||||||
_processed_frames = 0;
|
|
||||||
last_monitor_check = 0;
|
|
||||||
|
|
||||||
set_jack_callbacks ();
|
|
||||||
|
|
||||||
if (jack_activate (_priv_jack) == 0) {
|
|
||||||
_running = true;
|
|
||||||
_has_run = true;
|
|
||||||
Running(); /* EMIT SIGNAL */
|
|
||||||
} else {
|
|
||||||
// error << _("cannot activate JACK client") << endmsg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _running ? 0 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
AudioEngine::stop (bool forever)
|
|
||||||
{
|
|
||||||
GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
|
|
||||||
|
|
||||||
if (_priv_jack) {
|
|
||||||
if (forever) {
|
|
||||||
disconnect_from_jack ();
|
|
||||||
} else {
|
|
||||||
jack_deactivate (_priv_jack);
|
|
||||||
MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */
|
|
||||||
Stopped(); /* EMIT SIGNAL */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (forever) {
|
|
||||||
stop_metering_thread ();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _running ? -1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioEngine::split_cycle (pframes_t offset)
|
AudioEngine::split_cycle (pframes_t offset)
|
||||||
|
|
@ -208,7 +172,6 @@ AudioEngine::split_cycle (pframes_t offset)
|
||||||
int
|
int
|
||||||
AudioEngine::process_callback (pframes_t nframes)
|
AudioEngine::process_callback (pframes_t nframes)
|
||||||
{
|
{
|
||||||
GET_PRIVATE_JACK_POINTER_RET(_jack,0);
|
|
||||||
Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK);
|
Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK);
|
||||||
|
|
||||||
PT_TIMING_REF;
|
PT_TIMING_REF;
|
||||||
|
|
@ -436,7 +399,7 @@ AudioEngine::set_session (Session *s)
|
||||||
|
|
||||||
start_metering_thread ();
|
start_metering_thread ();
|
||||||
|
|
||||||
pframes_t blocksize = jack_get_buffer_size (_jack);
|
pframes_t blocksize = _backend->get_buffer_size ();
|
||||||
|
|
||||||
/* page in as much of the session process code as we
|
/* page in as much of the session process code as we
|
||||||
can before we really start running.
|
can before we really start running.
|
||||||
|
|
@ -484,288 +447,6 @@ AudioEngine::remove_session ()
|
||||||
remove_all_ports ();
|
remove_all_ports ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
AudioEngine::port_registration_failure (const std::string& portname)
|
|
||||||
{
|
|
||||||
GET_PRIVATE_JACK_POINTER (_jack);
|
|
||||||
string full_portname = jack_client_name;
|
|
||||||
full_portname += ':';
|
|
||||||
full_portname += portname;
|
|
||||||
|
|
||||||
|
|
||||||
jack_port_t* p = jack_port_by_name (_priv_jack, full_portname.c_str());
|
|
||||||
string reason;
|
|
||||||
|
|
||||||
if (p) {
|
|
||||||
reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
|
|
||||||
} else {
|
|
||||||
reason = string_compose (_("No more JACK ports are available. You will need to stop %1 and restart JACK with more ports if you need this many tracks."), PROGRAM_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::shared_ptr<Port>
|
|
||||||
AudioEngine::register_port (DataType dtype, const string& portname, bool input)
|
|
||||||
{
|
|
||||||
boost::shared_ptr<Port> newport;
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (dtype == DataType::AUDIO) {
|
|
||||||
newport.reset (new AudioPort (portname, (input ? Port::IsInput : Port::IsOutput)));
|
|
||||||
} else if (dtype == DataType::MIDI) {
|
|
||||||
newport.reset (new MidiPort (portname, (input ? Port::IsInput : Port::IsOutput)));
|
|
||||||
} else {
|
|
||||||
throw PortRegistrationFailure("unable to create port (unknown type)");
|
|
||||||
}
|
|
||||||
|
|
||||||
RCUWriter<Ports> writer (ports);
|
|
||||||
boost::shared_ptr<Ports> ps = writer.get_copy ();
|
|
||||||
ps->insert (make_pair (make_port_name_relative (portname), newport));
|
|
||||||
|
|
||||||
/* writer goes out of scope, forces update */
|
|
||||||
|
|
||||||
return newport;
|
|
||||||
}
|
|
||||||
|
|
||||||
catch (PortRegistrationFailure& err) {
|
|
||||||
throw err;
|
|
||||||
} catch (std::exception& e) {
|
|
||||||
throw PortRegistrationFailure(string_compose(
|
|
||||||
_("unable to create port: %1"), e.what()).c_str());
|
|
||||||
} catch (...) {
|
|
||||||
throw PortRegistrationFailure("unable to create port (unknown error)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::shared_ptr<Port>
|
|
||||||
AudioEngine::register_input_port (DataType type, const string& portname)
|
|
||||||
{
|
|
||||||
return register_port (type, portname, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::shared_ptr<Port>
|
|
||||||
AudioEngine::register_output_port (DataType type, const string& portname)
|
|
||||||
{
|
|
||||||
return register_port (type, portname, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
AudioEngine::unregister_port (boost::shared_ptr<Port> port)
|
|
||||||
{
|
|
||||||
/* caller must hold process lock */
|
|
||||||
|
|
||||||
if (!_running) {
|
|
||||||
/* probably happening when the engine has been halted by JACK,
|
|
||||||
in which case, there is nothing we can do here.
|
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
RCUWriter<Ports> writer (ports);
|
|
||||||
boost::shared_ptr<Ports> ps = writer.get_copy ();
|
|
||||||
Ports::iterator x = ps->find (make_port_name_relative (port->name()));
|
|
||||||
|
|
||||||
if (x != ps->end()) {
|
|
||||||
ps->erase (x);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* writer goes out of scope, forces update */
|
|
||||||
}
|
|
||||||
|
|
||||||
ports.flush ();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
AudioEngine::connect (const string& source, const string& destination)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!_running) {
|
|
||||||
if (!_has_run) {
|
|
||||||
fatal << _("connect called before engine was started") << endmsg;
|
|
||||||
/*NOTREACHED*/
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string s = make_port_name_non_relative (source);
|
|
||||||
string d = make_port_name_non_relative (destination);
|
|
||||||
|
|
||||||
|
|
||||||
boost::shared_ptr<Port> src = get_port_by_name (s);
|
|
||||||
boost::shared_ptr<Port> dst = get_port_by_name (d);
|
|
||||||
|
|
||||||
if (src) {
|
|
||||||
ret = src->connect (d);
|
|
||||||
} else if (dst) {
|
|
||||||
ret = dst->connect (s);
|
|
||||||
} else {
|
|
||||||
/* neither port is known to us, and this API isn't intended for use as a general patch bay */
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret > 0) {
|
|
||||||
/* already exists - no error, no warning */
|
|
||||||
} else if (ret < 0) {
|
|
||||||
error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
|
|
||||||
source, s, destination, d)
|
|
||||||
<< endmsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
AudioEngine::disconnect (const string& source, const string& destination)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!_running) {
|
|
||||||
if (!_has_run) {
|
|
||||||
fatal << _("disconnect called before engine was started") << endmsg;
|
|
||||||
/*NOTREACHED*/
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string s = make_port_name_non_relative (source);
|
|
||||||
string d = make_port_name_non_relative (destination);
|
|
||||||
|
|
||||||
boost::shared_ptr<Port> src = get_port_by_name (s);
|
|
||||||
boost::shared_ptr<Port> dst = get_port_by_name (d);
|
|
||||||
|
|
||||||
if (src) {
|
|
||||||
ret = src->disconnect (d);
|
|
||||||
} else if (dst) {
|
|
||||||
ret = dst->disconnect (s);
|
|
||||||
} else {
|
|
||||||
/* neither port is known to us, and this API isn't intended for use as a general patch bay */
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
AudioEngine::disconnect (boost::shared_ptr<Port> port)
|
|
||||||
{
|
|
||||||
GET_PRIVATE_JACK_POINTER_RET (_jack,-1);
|
|
||||||
|
|
||||||
if (!_running) {
|
|
||||||
if (!_has_run) {
|
|
||||||
fatal << _("disconnect called before engine was started") << endmsg;
|
|
||||||
/*NOTREACHED*/
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return port->disconnect_all ();
|
|
||||||
}
|
|
||||||
|
|
||||||
ARDOUR::framecnt_t
|
|
||||||
AudioEngine::frame_rate () const
|
|
||||||
{
|
|
||||||
GET_PRIVATE_JACK_POINTER_RET (_jack, 0);
|
|
||||||
if (_frame_rate == 0) {
|
|
||||||
return (_frame_rate = jack_get_sample_rate (_priv_jack));
|
|
||||||
} else {
|
|
||||||
return _frame_rate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t
|
|
||||||
AudioEngine::raw_buffer_size (DataType t)
|
|
||||||
{
|
|
||||||
std::map<DataType,size_t>::const_iterator s = _raw_buffer_sizes.find(t);
|
|
||||||
return (s != _raw_buffer_sizes.end()) ? s->second : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ARDOUR::pframes_t
|
|
||||||
AudioEngine::frames_per_cycle () const
|
|
||||||
{
|
|
||||||
GET_PRIVATE_JACK_POINTER_RET (_jack,0);
|
|
||||||
if (_buffer_size == 0) {
|
|
||||||
return jack_get_buffer_size (_jack);
|
|
||||||
} else {
|
|
||||||
return _buffer_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @param name Full or short name of port
|
|
||||||
* @return Corresponding Port or 0.
|
|
||||||
*/
|
|
||||||
|
|
||||||
boost::shared_ptr<Port>
|
|
||||||
AudioEngine::get_port_by_name (const string& portname)
|
|
||||||
{
|
|
||||||
if (!_running) {
|
|
||||||
if (!_has_run) {
|
|
||||||
fatal << _("get_port_by_name() called before engine was started") << endmsg;
|
|
||||||
/*NOTREACHED*/
|
|
||||||
} else {
|
|
||||||
boost::shared_ptr<Port> ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!port_is_mine (portname)) {
|
|
||||||
/* not an ardour port */
|
|
||||||
return boost::shared_ptr<Port> ();
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::shared_ptr<Ports> pr = ports.reader();
|
|
||||||
std::string rel = make_port_name_relative (portname);
|
|
||||||
Ports::iterator x = pr->find (rel);
|
|
||||||
|
|
||||||
if (x != pr->end()) {
|
|
||||||
/* its possible that the port was renamed by some 3rd party and
|
|
||||||
we don't know about it. check for this (the check is quick
|
|
||||||
and cheap), and if so, rename the port (which will alter
|
|
||||||
the port map as a side effect).
|
|
||||||
*/
|
|
||||||
const std::string check = make_port_name_relative (jack_port_name (x->second->jack_port()));
|
|
||||||
if (check != rel) {
|
|
||||||
x->second->set_name (check);
|
|
||||||
}
|
|
||||||
return x->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
return boost::shared_ptr<Port> ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AudioEngine::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
|
|
||||||
{
|
|
||||||
RCUWriter<Ports> writer (ports);
|
|
||||||
boost::shared_ptr<Ports> p = writer.get_copy();
|
|
||||||
Ports::iterator x = p->find (old_relative_name);
|
|
||||||
|
|
||||||
if (x != p->end()) {
|
|
||||||
boost::shared_ptr<Port> port = x->second;
|
|
||||||
p->erase (x);
|
|
||||||
p->insert (make_pair (new_relative_name, port));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char **
|
|
||||||
AudioEngine::get_ports (const string& port_name_pattern, const string& type_name_pattern, uint32_t flags)
|
|
||||||
{
|
|
||||||
GET_PRIVATE_JACK_POINTER_RET (_jack,0);
|
|
||||||
if (!_running) {
|
|
||||||
if (!_has_run) {
|
|
||||||
fatal << _("get_ports called before engine was started") << endmsg;
|
|
||||||
/*NOTREACHED*/
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return jack_get_ports (_priv_jack, port_name_pattern.c_str(), type_name_pattern.c_str(), flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioEngine::died ()
|
AudioEngine::died ()
|
||||||
|
|
@ -777,104 +458,11 @@ AudioEngine::died ()
|
||||||
_running = false;
|
_running = false;
|
||||||
_buffer_size = 0;
|
_buffer_size = 0;
|
||||||
_frame_rate = 0;
|
_frame_rate = 0;
|
||||||
_jack = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
AudioEngine::can_request_hardware_monitoring ()
|
|
||||||
{
|
|
||||||
GET_PRIVATE_JACK_POINTER_RET (_jack,false);
|
|
||||||
const char ** ports;
|
|
||||||
|
|
||||||
if ((ports = jack_get_ports (_priv_jack, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortCanMonitor)) == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
free (ports);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChanCount
|
|
||||||
AudioEngine::n_physical (unsigned long flags) const
|
|
||||||
{
|
|
||||||
ChanCount c;
|
|
||||||
|
|
||||||
GET_PRIVATE_JACK_POINTER_RET (_jack, c);
|
|
||||||
|
|
||||||
const char ** ports = jack_get_ports (_priv_jack, NULL, NULL, JackPortIsPhysical | flags);
|
|
||||||
if (ports == 0) {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; ports[i]; ++i) {
|
|
||||||
if (!strstr (ports[i], "Midi-Through")) {
|
|
||||||
DataType t (jack_port_type (jack_port_by_name (_jack, ports[i])));
|
|
||||||
c.set (t, c.get (t) + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free (ports);
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChanCount
|
|
||||||
AudioEngine::n_physical_inputs () const
|
|
||||||
{
|
|
||||||
return n_physical (JackPortIsInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
ChanCount
|
|
||||||
AudioEngine::n_physical_outputs () const
|
|
||||||
{
|
|
||||||
return n_physical (JackPortIsOutput);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
AudioEngine::get_physical (DataType type, unsigned long flags, vector<string>& phy)
|
|
||||||
{
|
|
||||||
GET_PRIVATE_JACK_POINTER (_jack);
|
|
||||||
const char ** ports;
|
|
||||||
|
|
||||||
if ((ports = jack_get_ports (_priv_jack, NULL, type.to_jack_type(), JackPortIsPhysical | flags)) == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ports) {
|
|
||||||
for (uint32_t i = 0; ports[i]; ++i) {
|
|
||||||
if (strstr (ports[i], "Midi-Through")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
phy.push_back (ports[i]);
|
|
||||||
}
|
|
||||||
free (ports);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get physical ports for which JackPortIsOutput is set; ie those that correspond to
|
|
||||||
* a physical input connector.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
AudioEngine::get_physical_inputs (DataType type, vector<string>& ins)
|
|
||||||
{
|
|
||||||
get_physical (type, JackPortIsOutput, ins);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get physical ports for which JackPortIsInput is set; ie those that correspond to
|
|
||||||
* a physical output connector.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
AudioEngine::get_physical_outputs (DataType type, vector<string>& outs)
|
|
||||||
{
|
|
||||||
get_physical (type, JackPortIsInput, outs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
AudioEngine::reset_timebase ()
|
AudioEngine::reset_timebase ()
|
||||||
{
|
{
|
||||||
GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
|
|
||||||
if (_session) {
|
if (_session) {
|
||||||
if (_session->config.get_jack_time_master()) {
|
if (_session->config.get_jack_time_master()) {
|
||||||
_backend->set_time_master (true);
|
_backend->set_time_master (true);
|
||||||
|
|
@ -885,93 +473,6 @@ AudioEngine::reset_timebase ()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
AudioEngine::remove_all_ports ()
|
|
||||||
{
|
|
||||||
/* make sure that JACK callbacks that will be invoked as we cleanup
|
|
||||||
* ports know that they have nothing to do.
|
|
||||||
*/
|
|
||||||
|
|
||||||
port_remove_in_progress = true;
|
|
||||||
|
|
||||||
/* process lock MUST be held by caller
|
|
||||||
*/
|
|
||||||
|
|
||||||
{
|
|
||||||
RCUWriter<Ports> writer (ports);
|
|
||||||
boost::shared_ptr<Ports> ps = writer.get_copy ();
|
|
||||||
ps->clear ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clear dead wood list in RCU */
|
|
||||||
|
|
||||||
ports.flush ();
|
|
||||||
|
|
||||||
port_remove_in_progress = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
string
|
|
||||||
AudioEngine::make_port_name_relative (string portname) const
|
|
||||||
{
|
|
||||||
string::size_type len;
|
|
||||||
string::size_type n;
|
|
||||||
|
|
||||||
len = portname.length();
|
|
||||||
|
|
||||||
for (n = 0; n < len; ++n) {
|
|
||||||
if (portname[n] == ':') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((n != len) && (portname.substr (0, n) == jack_client_name)) {
|
|
||||||
return portname.substr (n+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return portname;
|
|
||||||
}
|
|
||||||
|
|
||||||
string
|
|
||||||
AudioEngine::make_port_name_non_relative (string portname) const
|
|
||||||
{
|
|
||||||
string str;
|
|
||||||
|
|
||||||
if (portname.find_first_of (':') != string::npos) {
|
|
||||||
return portname;
|
|
||||||
}
|
|
||||||
|
|
||||||
str = jack_client_name;
|
|
||||||
str += ':';
|
|
||||||
str += portname;
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
AudioEngine::port_is_mine (const string& portname) const
|
|
||||||
{
|
|
||||||
if (portname.find_first_of (':') != string::npos) {
|
|
||||||
if (portname.substr (0, jack_client_name.length ()) != jack_client_name) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
AudioEngine::port_is_physical (const std::string& portname) const
|
|
||||||
{
|
|
||||||
GET_PRIVATE_JACK_POINTER_RET(_jack, false);
|
|
||||||
|
|
||||||
jack_port_t *port = jack_port_by_name (_priv_jack, portname.c_str());
|
|
||||||
|
|
||||||
if (!port) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return jack_port_flags (port) & JackPortIsPhysical;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioEngine::destroy ()
|
AudioEngine::destroy ()
|
||||||
|
|
@ -986,6 +487,8 @@ AudioEngine::discover_backends ()
|
||||||
vector<std::string> backend_modules;
|
vector<std::string> backend_modules;
|
||||||
AudioBackend* backend;
|
AudioBackend* backend;
|
||||||
|
|
||||||
|
_backends.clear ();
|
||||||
|
|
||||||
Glib::PatternSpec so_extension_pattern("*.so");
|
Glib::PatternSpec so_extension_pattern("*.so");
|
||||||
Glib::PatternSpec dylib_extension_pattern("*.dylib");
|
Glib::PatternSpec dylib_extension_pattern("*.dylib");
|
||||||
|
|
||||||
|
|
@ -1002,10 +505,12 @@ AudioEngine::discover_backends ()
|
||||||
_backends.insert (make_pair (backend->name(), backend));
|
_backends.insert (make_pair (backend->name(), backend));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return _backends.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioBackend*
|
AudioBackend*
|
||||||
AudioEngine::backend_discover (string path)
|
AudioEngine::backend_discover (const string& path)
|
||||||
{
|
{
|
||||||
Glib::Module* module = new Glib::Module(path);
|
Glib::Module* module = new Glib::Module(path);
|
||||||
AudioBackend* (*dfunc)(void);
|
AudioBackend* (*dfunc)(void);
|
||||||
|
|
@ -1030,3 +535,202 @@ AudioEngine::backend_discover (string path)
|
||||||
|
|
||||||
return backend;
|
return backend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* BACKEND PROXY WRAPPERS */
|
||||||
|
|
||||||
|
int
|
||||||
|
AudioEngine::start ()
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_running) {
|
||||||
|
|
||||||
|
if (_session) {
|
||||||
|
BootMessage (_("Connect session to engine"));
|
||||||
|
_session->set_frame_rate (_backend->sample_rate());
|
||||||
|
}
|
||||||
|
|
||||||
|
_processed_frames = 0;
|
||||||
|
last_monitor_check = 0;
|
||||||
|
|
||||||
|
if (_backend->start() == 0) {
|
||||||
|
_running = true;
|
||||||
|
_has_run = true;
|
||||||
|
Running(); /* EMIT SIGNAL */
|
||||||
|
} else {
|
||||||
|
/* should report error? */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _running ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
AudioEngine::stop ()
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _backend->stop ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
AudioEngine::pause ()
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _backend->pause ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
AudioEngine::freewheel (bool start_stop)
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _freewheeling will be set when first Freewheel signal occurs */
|
||||||
|
|
||||||
|
return _backend->freewheel (start_stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
AudioEngine::get_cpu_load() const
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return _backend->get_cpu_load ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioEngine::transport_start ()
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return _backend->transport_start ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioEngine::transport_stop ()
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return _backend->transport_stop ();
|
||||||
|
}
|
||||||
|
|
||||||
|
TransportState
|
||||||
|
AudioEngine::transport_state ()
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return TransportStopped;
|
||||||
|
}
|
||||||
|
return _backend->transport_state ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioEngine::transport_locate (framepos_t pos)
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return _backend->transport_locate (pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
framepos_t
|
||||||
|
AudioEngine::transport_frame()
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return _backend->transport_frame ();
|
||||||
|
}
|
||||||
|
|
||||||
|
framecnt_t
|
||||||
|
AudioEngine::sample_rate () const
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return _backend->sample_rate ();
|
||||||
|
}
|
||||||
|
|
||||||
|
pframes_t
|
||||||
|
AudioEngine::samples_per_cycle () const
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return _backend->samples_per_cycle ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
AudioEngine::usecs_per_cycle () const
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _backend->start ();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
AudioEngine::raw_buffer_size (DataType t)
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _backend->raw_buffer_size (t);
|
||||||
|
}
|
||||||
|
|
||||||
|
pframes_t
|
||||||
|
AudioEngine::sample_time ()
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return _backend->sample_time ();
|
||||||
|
}
|
||||||
|
|
||||||
|
pframes_t
|
||||||
|
AudioEngine::sample_time_at_cycle_start ()
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return _backend->sample_time_at_cycle_start ();
|
||||||
|
}
|
||||||
|
|
||||||
|
pframes_t
|
||||||
|
AudioEngine::samples_since_cycle_start ()
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return _backend->samples_since_cycle_start ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
AudioEngine::get_sync_offset (pframes_t& offset) const
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return _backend->get_sync_offset (offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
AudioEngine::create_process_thread (boost::function<void()> func, pthread_t* thr, size_t stacksize)
|
||||||
|
{
|
||||||
|
if (!_backend) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _backend->create_process_thread (func, thr, stacksize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
45
libs/ardour/backend_search_path.cc
Normal file
45
libs/ardour/backend_search_path.cc
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glibmm/miscutils.h>
|
||||||
|
|
||||||
|
#include "ardour/backend_search_path.h"
|
||||||
|
#include "ardour/directory_names.h"
|
||||||
|
#include "ardour/filesystem_paths.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const char * const backend_env_variable_name = "ARDOUR_BACKEND_PATH";
|
||||||
|
} // anonymous
|
||||||
|
|
||||||
|
using namespace PBD;
|
||||||
|
|
||||||
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
SearchPath
|
||||||
|
backend_search_path ()
|
||||||
|
{
|
||||||
|
SearchPath spath(user_config_directory ());
|
||||||
|
spath += ardour_dll_directory ();
|
||||||
|
spath.add_subdirectory_to_paths(backend_dir_name);
|
||||||
|
|
||||||
|
spath += SearchPath(Glib::getenv(backend_env_variable_name));
|
||||||
|
return spath;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ARDOUR
|
||||||
|
|
@ -454,19 +454,16 @@ Bundle::connected_to_anything (AudioEngine& engine)
|
||||||
Bundle::PortList const & ports = channel_ports (i);
|
Bundle::PortList const & ports = channel_ports (i);
|
||||||
|
|
||||||
for (uint32_t j = 0; j < ports.size(); ++j) {
|
for (uint32_t j = 0; j < ports.size(); ++j) {
|
||||||
/* ports[j] may not be an Ardour port, so use JACK directly
|
|
||||||
|
/* ports[j] may not be an Ardour port, so use the port manager directly
|
||||||
rather than doing it with Port.
|
rather than doing it with Port.
|
||||||
*/
|
*/
|
||||||
jack_port_t* jp = jack_port_by_name (engine.jack(), ports[j].c_str());
|
|
||||||
if (jp) {
|
if (engine.connected (ports[j])) {
|
||||||
const char ** c = jack_port_get_all_connections (engine.jack(), jp);
|
|
||||||
if (c) {
|
|
||||||
jack_free (c);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ namespace ARDOUR {
|
||||||
|
|
||||||
CapturingProcessor::CapturingProcessor (Session & session)
|
CapturingProcessor::CapturingProcessor (Session & session)
|
||||||
: Processor (session, X_("capture point"))
|
: Processor (session, X_("capture point"))
|
||||||
, block_size (session.engine().frames_per_cycle())
|
, block_size (AudioEngine::instance()->samples_per_cycle())
|
||||||
{
|
{
|
||||||
realloc_buffers ();
|
realloc_buffers ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ const char* const templates_dir_name = X_("templates");
|
||||||
const char* const route_templates_dir_name = X_("route_templates");
|
const char* const route_templates_dir_name = X_("route_templates");
|
||||||
const char* const surfaces_dir_name = X_("surfaces");
|
const char* const surfaces_dir_name = X_("surfaces");
|
||||||
const char* const panner_dir_name = X_("panners");
|
const char* const panner_dir_name = X_("panners");
|
||||||
|
const char* const backend_dir_name = X_("backends");
|
||||||
|
|
||||||
/* these should end up using variants of PROGRAM_NAME */
|
/* these should end up using variants of PROGRAM_NAME */
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ RegionExportChannelFactory::RegionExportChannelFactory (Session * session, Audio
|
||||||
: region (region)
|
: region (region)
|
||||||
, track (track)
|
, track (track)
|
||||||
, type (type)
|
, type (type)
|
||||||
, frames_per_cycle (session->engine().frames_per_cycle ())
|
, frames_per_cycle (session->engine().samples_per_cycle ())
|
||||||
, buffers_up_to_date (false)
|
, buffers_up_to_date (false)
|
||||||
, region_start (region.position())
|
, region_start (region.position())
|
||||||
, position (region_start)
|
, position (region_start)
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ ExportGraphBuilder::ExportGraphBuilder (Session const & session)
|
||||||
: session (session)
|
: session (session)
|
||||||
, thread_pool (hardware_concurrency())
|
, thread_pool (hardware_concurrency())
|
||||||
{
|
{
|
||||||
process_buffer_frames = session.engine().frames_per_cycle();
|
process_buffer_frames = session.engine().samples_per_cycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportGraphBuilder::~ExportGraphBuilder ()
|
ExportGraphBuilder::~ExportGraphBuilder ()
|
||||||
|
|
@ -505,7 +505,7 @@ ExportGraphBuilder::ChannelConfig::ChannelConfig (ExportGraphBuilder & parent, F
|
||||||
|
|
||||||
config = new_config;
|
config = new_config;
|
||||||
|
|
||||||
framecnt_t max_frames = parent.session.engine().frames_per_cycle();
|
framecnt_t max_frames = parent.session.engine().samples_per_cycle();
|
||||||
interleaver.reset (new Interleaver<Sample> ());
|
interleaver.reset (new Interleaver<Sample> ());
|
||||||
interleaver->init (new_config.channel_config->get_n_chans(), max_frames);
|
interleaver->init (new_config.channel_config->get_n_chans(), max_frames);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -338,7 +338,7 @@ void
|
||||||
ARDOUR::init_post_engine ()
|
ARDOUR::init_post_engine ()
|
||||||
{
|
{
|
||||||
/* the MIDI Manager is needed by the ControlProtocolManager */
|
/* the MIDI Manager is needed by the ControlProtocolManager */
|
||||||
MIDI::Manager::create (AudioEngine::instance()->jack());
|
MIDI::Manager::create (AudioEngine::instance()->port_engine());
|
||||||
|
|
||||||
ControlProtocolManager::instance().discover_control_protocols ();
|
ControlProtocolManager::instance().discover_control_protocols ();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -310,7 +310,7 @@ bool
|
||||||
InternalSend::configure_io (ChanCount in, ChanCount out)
|
InternalSend::configure_io (ChanCount in, ChanCount out)
|
||||||
{
|
{
|
||||||
bool ret = Send::configure_io (in, out);
|
bool ret = Send::configure_io (in, out);
|
||||||
set_block_size (_session.engine().frames_per_cycle());
|
set_block_size (_session.engine().samples_per_cycle());
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,43 @@
|
||||||
int
|
int
|
||||||
JACKAudioBackend::start ()
|
JACKAudioBackend::start ()
|
||||||
{
|
{
|
||||||
Glib::Threads::Mutex::Lock lm (_state_lock);
|
GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
|
||||||
|
|
||||||
if (running()) {
|
if (!_running) {
|
||||||
/* already running */
|
|
||||||
return 1;
|
if (!jack_port_type_get_buffer_size) {
|
||||||
|
warning << _("This version of JACK is old - you should upgrade to a newer version that supports jack_port_type_get_buffer_size()") << endmsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_session) {
|
||||||
|
BootMessage (_("Connect session to engine"));
|
||||||
|
_session->set_frame_rate (jack_get_sample_rate (_priv_jack));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* a proxy for whether jack_activate() will definitely call the buffer size
|
||||||
|
* callback. with older versions of JACK, this function symbol will be null.
|
||||||
|
* this is reliable, but not clean.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!jack_port_type_get_buffer_size) {
|
||||||
|
jack_bufsize_callback (jack_get_buffer_size (_priv_jack));
|
||||||
|
}
|
||||||
|
|
||||||
|
_processed_frames = 0;
|
||||||
|
last_monitor_check = 0;
|
||||||
|
|
||||||
|
set_jack_callbacks ();
|
||||||
|
|
||||||
|
if (jack_activate (_priv_jack) == 0) {
|
||||||
|
_running = true;
|
||||||
|
_has_run = true;
|
||||||
|
Running(); /* EMIT SIGNAL */
|
||||||
|
} else {
|
||||||
|
// error << _("cannot activate JACK client") << endmsg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _running ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -70,6 +101,39 @@ JACKAudioBackend::get_parameters (Parameters& params) const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* parameters */
|
||||||
|
|
||||||
|
ARDOUR::pframes_t
|
||||||
|
AudioEngine::frames_per_cycle () const
|
||||||
|
{
|
||||||
|
GET_PRIVATE_JACK_POINTER_RET (_jack,0);
|
||||||
|
if (_buffer_size == 0) {
|
||||||
|
return jack_get_buffer_size (_jack);
|
||||||
|
} else {
|
||||||
|
return _buffer_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ARDOUR::framecnt_t
|
||||||
|
AudioEngine::frame_rate () const
|
||||||
|
{
|
||||||
|
GET_PRIVATE_JACK_POINTER_RET (_jack, 0);
|
||||||
|
if (_frame_rate == 0) {
|
||||||
|
return (_frame_rate = jack_get_sample_rate (_priv_jack));
|
||||||
|
} else {
|
||||||
|
return _frame_rate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
AudioEngine::raw_buffer_size (DataType t)
|
||||||
|
{
|
||||||
|
std::map<DataType,size_t>::const_iterator s = _raw_buffer_sizes.find(t);
|
||||||
|
return (s != _raw_buffer_sizes.end()) ? s->second : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*--- private support methods ---*/
|
/*--- private support methods ---*/
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -540,7 +604,7 @@ JACKAudioBackend::process_thread ()
|
||||||
|
|
||||||
pframes_t nframes = jack_cycle_wait (_priv_jack);
|
pframes_t nframes = jack_cycle_wait (_priv_jack);
|
||||||
|
|
||||||
if (process_callback (nframes)) {
|
if (engine.process_callback (nframes)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -420,15 +420,15 @@ bool
|
||||||
LTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
LTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
||||||
{
|
{
|
||||||
bool engine_init_called = false;
|
bool engine_init_called = false;
|
||||||
framepos_t now = session.engine().frame_time_at_cycle_start();
|
framepos_t now = session.engine().sample_time_at_cycle_start();
|
||||||
framepos_t sess_pos = session.transport_frame(); // corresponds to now
|
framepos_t sess_pos = session.transport_frame(); // corresponds to now
|
||||||
framecnt_t nframes = session.engine().frames_per_cycle();
|
framecnt_t nframes = session.engine().samples_per_cycle();
|
||||||
|
|
||||||
jack_default_audio_sample_t *in;
|
Sample* in;
|
||||||
|
|
||||||
boost::shared_ptr<Port> ltcport = session.ltc_input_port();
|
boost::shared_ptr<Port> ltcport = session.ltc_input_port();
|
||||||
|
|
||||||
in = (jack_default_audio_sample_t*) jack_port_get_buffer (ltcport->jack_port(), nframes);
|
in = (Sample*) AudioEngine::instance()->port_engine().get_buffer (ltcport->port_handle(), nframes);
|
||||||
|
|
||||||
frameoffset_t skip = now - (monotonic_cnt + nframes);
|
frameoffset_t skip = now - (monotonic_cnt + nframes);
|
||||||
monotonic_cnt = now;
|
monotonic_cnt = now;
|
||||||
|
|
@ -441,7 +441,7 @@ LTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
||||||
else if (engine_dll_initstate != transport_direction && ltc_speed != 0) {
|
else if (engine_dll_initstate != transport_direction && ltc_speed != 0) {
|
||||||
engine_dll_initstate = transport_direction;
|
engine_dll_initstate = transport_direction;
|
||||||
init_engine_dll(last_ltc_frame + rint(ltc_speed * double(2 * nframes + now - last_timestamp)),
|
init_engine_dll(last_ltc_frame + rint(ltc_speed * double(2 * nframes + now - last_timestamp)),
|
||||||
session.engine().frames_per_cycle());
|
session.engine().samples_per_cycle());
|
||||||
engine_init_called = true;
|
engine_init_called = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -521,8 +521,8 @@ LTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
||||||
t0 = t1;
|
t0 = t1;
|
||||||
t1 += b * e + e2;
|
t1 += b * e + e2;
|
||||||
e2 += c * e;
|
e2 += c * e;
|
||||||
speed_flt = (t1 - t0) / double(session.engine().frames_per_cycle());
|
speed_flt = (t1 - t0) / double(session.engine().samples_per_cycle());
|
||||||
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, speed_flt, e2 - session.engine().frames_per_cycle() ));
|
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, speed_flt, e2 - session.engine().samples_per_cycle() ));
|
||||||
} else {
|
} else {
|
||||||
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC adjusting elapsed (no DLL) from %1 by %2\n", elapsed, (2 * nframes * ltc_speed)));
|
DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC adjusting elapsed (no DLL) from %1 by %2\n", elapsed, (2 * nframes * ltc_speed)));
|
||||||
speed_flt = 0;
|
speed_flt = 0;
|
||||||
|
|
|
||||||
|
|
@ -190,55 +190,6 @@ MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Push an event into the buffer.
|
|
||||||
*
|
|
||||||
* Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
|
|
||||||
* That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
|
|
||||||
* Realtime safe.
|
|
||||||
* @return false if operation failed (not enough room)
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
MidiBuffer::push_back(const jack_midi_event_t& ev)
|
|
||||||
{
|
|
||||||
const size_t stamp_size = sizeof(TimeType);
|
|
||||||
|
|
||||||
if (_size + stamp_size + ev.size >= _capacity) {
|
|
||||||
cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Evoral::midi_event_is_valid(ev.buffer, ev.size)) {
|
|
||||||
cerr << "WARNING: MidiBuffer ignoring illegal MIDI event" << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if (DEBUG::MidiIO & PBD::debug_bits) {
|
|
||||||
DEBUG_STR_DECL(a);
|
|
||||||
DEBUG_STR_APPEND(a, string_compose ("midibuffer %1 push jack event @ %2 sz %3 ", this, ev.time, ev.size));
|
|
||||||
for (size_t i=0; i < ev.size; ++i) {
|
|
||||||
DEBUG_STR_APPEND(a,hex);
|
|
||||||
DEBUG_STR_APPEND(a,"0x");
|
|
||||||
DEBUG_STR_APPEND(a,(int)ev.buffer[i]);
|
|
||||||
DEBUG_STR_APPEND(a,' ');
|
|
||||||
}
|
|
||||||
DEBUG_STR_APPEND(a,'\n');
|
|
||||||
DEBUG_TRACE (DEBUG::MidiIO, DEBUG_STR(a).str());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint8_t* const write_loc = _data + _size;
|
|
||||||
*((TimeType*)write_loc) = ev.time;
|
|
||||||
memcpy(write_loc + stamp_size, ev.buffer, ev.size);
|
|
||||||
|
|
||||||
_size += stamp_size + ev.size;
|
|
||||||
_silent = false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Reserve space for a new event in the buffer.
|
/** Reserve space for a new event in the buffer.
|
||||||
*
|
*
|
||||||
* This call is for copying MIDI directly into the buffer, the data location
|
* This call is for copying MIDI directly into the buffer, the data location
|
||||||
|
|
|
||||||
|
|
@ -1097,7 +1097,7 @@ MidiDiskstream::prep_record_enable ()
|
||||||
boost::shared_ptr<MidiPort> sp = _source_port.lock ();
|
boost::shared_ptr<MidiPort> sp = _source_port.lock ();
|
||||||
|
|
||||||
if (sp && Config->get_monitoring_model() == HardwareMonitoring) {
|
if (sp && Config->get_monitoring_model() == HardwareMonitoring) {
|
||||||
sp->request_jack_monitors_input (!(_session.config.get_auto_input() && rolling));
|
sp->request_input_monitoring (!(_session.config.get_auto_input() && rolling));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1250,7 +1250,7 @@ MidiDiskstream::ensure_jack_monitors_input (bool yn)
|
||||||
boost::shared_ptr<MidiPort> sp = _source_port.lock ();
|
boost::shared_ptr<MidiPort> sp = _source_port.lock ();
|
||||||
|
|
||||||
if (sp) {
|
if (sp) {
|
||||||
sp->ensure_jack_monitors_input (yn);
|
sp->ensure_input_monitoring (yn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,9 @@
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
MidiPort::MidiPort (const std::string& name, Flags flags)
|
#define port_engine AudioEngine::instance()->port_engine()
|
||||||
|
|
||||||
|
MidiPort::MidiPort (const std::string& name, PortFlags flags)
|
||||||
: Port (name, DataType::MIDI, flags)
|
: Port (name, DataType::MIDI, flags)
|
||||||
, _has_been_mixed_down (false)
|
, _has_been_mixed_down (false)
|
||||||
, _resolve_required (false)
|
, _resolve_required (false)
|
||||||
|
|
@ -48,7 +50,7 @@ MidiPort::cycle_start (pframes_t nframes)
|
||||||
_buffer->clear ();
|
_buffer->clear ();
|
||||||
|
|
||||||
if (sends_output ()) {
|
if (sends_output ()) {
|
||||||
jack_midi_clear_buffer (jack_port_get_buffer (_jack_port, nframes));
|
port_engine.midi_clear (port_engine.get_buffer (_port_handle, nframes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,31 +65,33 @@ MidiPort::get_midi_buffer (pframes_t nframes)
|
||||||
|
|
||||||
if (_input_active) {
|
if (_input_active) {
|
||||||
|
|
||||||
void* jack_buffer = jack_port_get_buffer (_jack_port, nframes);
|
void* buffer = port_engine.get_buffer (_port_handle, nframes);
|
||||||
const pframes_t event_count = jack_midi_get_event_count (jack_buffer);
|
const pframes_t event_count = port_engine.get_midi_event_count (buffer);
|
||||||
|
|
||||||
/* suck all relevant MIDI events from the JACK MIDI port buffer
|
/* suck all relevant MIDI events from the MIDI port buffer
|
||||||
into our MidiBuffer
|
into our MidiBuffer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (pframes_t i = 0; i < event_count; ++i) {
|
for (pframes_t i = 0; i < event_count; ++i) {
|
||||||
|
|
||||||
jack_midi_event_t ev;
|
pframes_t timestamp;
|
||||||
|
size_t size;
|
||||||
|
uint8_t* buf;
|
||||||
|
|
||||||
jack_midi_event_get (&ev, jack_buffer, i);
|
port_engine.midi_event_get (timestamp, size, &buf, buffer, i);
|
||||||
|
|
||||||
if (ev.buffer[0] == 0xfe) {
|
if (buf[0] == 0xfe) {
|
||||||
/* throw away active sensing */
|
/* throw away active sensing */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check that the event is in the acceptable time range */
|
/* check that the event is in the acceptable time range */
|
||||||
|
|
||||||
if ((ev.time >= (_global_port_buffer_offset + _port_buffer_offset)) &&
|
if ((timestamp >= (_global_port_buffer_offset + _port_buffer_offset)) &&
|
||||||
(ev.time < (_global_port_buffer_offset + _port_buffer_offset + nframes))) {
|
(timestamp < (_global_port_buffer_offset + _port_buffer_offset + nframes))) {
|
||||||
_buffer->push_back (ev);
|
_buffer->push_back (timestamp, size, buf);
|
||||||
} else {
|
} else {
|
||||||
cerr << "Dropping incoming MIDI at time " << ev.time << "; offset="
|
cerr << "Dropping incoming MIDI at time " << timestamp << "; offset="
|
||||||
<< _global_port_buffer_offset << " limit="
|
<< _global_port_buffer_offset << " limit="
|
||||||
<< (_global_port_buffer_offset + _port_buffer_offset + nframes) << "\n";
|
<< (_global_port_buffer_offset + _port_buffer_offset + nframes) << "\n";
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +125,7 @@ MidiPort::cycle_split ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiPort::resolve_notes (void* jack_buffer, MidiBuffer::TimeType when)
|
MidiPort::resolve_notes (void* port_buffer, MidiBuffer::TimeType when)
|
||||||
{
|
{
|
||||||
for (uint8_t channel = 0; channel <= 0xF; channel++) {
|
for (uint8_t channel = 0; channel <= 0xF; channel++) {
|
||||||
|
|
||||||
|
|
@ -132,13 +136,13 @@ MidiPort::resolve_notes (void* jack_buffer, MidiBuffer::TimeType when)
|
||||||
* that prioritize sustain over AllNotesOff
|
* that prioritize sustain over AllNotesOff
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (jack_midi_event_write (jack_buffer, when, ev, 3) != 0) {
|
if (port_engine.midi_event_put (port_buffer, when, ev, 3) != 0) {
|
||||||
cerr << "failed to deliver sustain-zero on channel " << channel << " on port " << name() << endl;
|
cerr << "failed to deliver sustain-zero on channel " << channel << " on port " << name() << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
ev[1] = MIDI_CTL_ALL_NOTES_OFF;
|
ev[1] = MIDI_CTL_ALL_NOTES_OFF;
|
||||||
|
|
||||||
if (jack_midi_event_write (jack_buffer, 0, ev, 3) != 0) {
|
if (port_engine.midi_event_put (port_buffer, 0, ev, 3) != 0) {
|
||||||
cerr << "failed to deliver ALL NOTES OFF on channel " << channel << " on port " << name() << endl;
|
cerr << "failed to deliver ALL NOTES OFF on channel " << channel << " on port " << name() << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -149,11 +153,11 @@ MidiPort::flush_buffers (pframes_t nframes)
|
||||||
{
|
{
|
||||||
if (sends_output ()) {
|
if (sends_output ()) {
|
||||||
|
|
||||||
void* jack_buffer = jack_port_get_buffer (_jack_port, nframes);
|
void* port_buffer = port_engine.get_buffer (_port_handle, nframes);
|
||||||
|
|
||||||
if (_resolve_required) {
|
if (_resolve_required) {
|
||||||
/* resolve all notes at the start of the buffer */
|
/* resolve all notes at the start of the buffer */
|
||||||
resolve_notes (jack_buffer, 0);
|
resolve_notes (port_buffer, 0);
|
||||||
_resolve_required = false;
|
_resolve_required = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -166,7 +170,7 @@ MidiPort::flush_buffers (pframes_t nframes)
|
||||||
assert (ev.time() < (nframes + _global_port_buffer_offset + _port_buffer_offset));
|
assert (ev.time() < (nframes + _global_port_buffer_offset + _port_buffer_offset));
|
||||||
|
|
||||||
if (ev.time() >= _global_port_buffer_offset + _port_buffer_offset) {
|
if (ev.time() >= _global_port_buffer_offset + _port_buffer_offset) {
|
||||||
if (jack_midi_event_write (jack_buffer, (jack_nframes_t) ev.time(), ev.buffer(), ev.size()) != 0) {
|
if (port_engine.midi_event_put (port_buffer, (pframes_t) ev.time(), ev.buffer(), ev.size()) != 0) {
|
||||||
cerr << "write failed, drop flushed note off on the floor, time "
|
cerr << "write failed, drop flushed note off on the floor, time "
|
||||||
<< ev.time() << " > " << _global_port_buffer_offset + _port_buffer_offset << endl;
|
<< ev.time() << " > " << _global_port_buffer_offset + _port_buffer_offset << endl;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ MidiControlUI::midi_input_handler (IOCondition ioc, MIDI::Port* port)
|
||||||
CrossThreadChannel::drain (port->selectable());
|
CrossThreadChannel::drain (port->selectable());
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::MidiIO, string_compose ("data available on %1\n", port->name()));
|
DEBUG_TRACE (DEBUG::MidiIO, string_compose ("data available on %1\n", port->name()));
|
||||||
framepos_t now = _session.engine().frame_time();
|
framepos_t now = _session.engine().sample_time();
|
||||||
port->parse (now);
|
port->parse (now);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -579,7 +579,7 @@ MTC_Slave::init_engine_dll (framepos_t pos, framepos_t inc)
|
||||||
bool
|
bool
|
||||||
MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
||||||
{
|
{
|
||||||
framepos_t now = session.engine().frame_time_at_cycle_start();
|
framepos_t now = session.engine().sample_time_at_cycle_start();
|
||||||
framepos_t sess_pos = session.transport_frame(); // corresponds to now
|
framepos_t sess_pos = session.transport_frame(); // corresponds to now
|
||||||
//sess_pos -= session.engine().frames_since_cycle_start();
|
//sess_pos -= session.engine().frames_since_cycle_start();
|
||||||
|
|
||||||
|
|
@ -593,7 +593,7 @@ MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
||||||
if (last.timestamp == 0) { engine_dll_initstate = 0; }
|
if (last.timestamp == 0) { engine_dll_initstate = 0; }
|
||||||
else if (engine_dll_initstate != transport_direction && last.speed != 0) {
|
else if (engine_dll_initstate != transport_direction && last.speed != 0) {
|
||||||
engine_dll_initstate = transport_direction;
|
engine_dll_initstate = transport_direction;
|
||||||
init_engine_dll(last.position, session.engine().frames_per_cycle());
|
init_engine_dll(last.position, session.engine().samples_per_cycle());
|
||||||
engine_dll_reinitialized = true;
|
engine_dll_reinitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -643,8 +643,8 @@ MTC_Slave::speed_and_position (double& speed, framepos_t& pos)
|
||||||
te0 = te1;
|
te0 = te1;
|
||||||
te1 += be * e + ee2;
|
te1 += be * e + ee2;
|
||||||
ee2 += ce * e;
|
ee2 += ce * e;
|
||||||
speed_flt = (te1 - te0) / double(session.engine().frames_per_cycle());
|
speed_flt = (te1 - te0) / double(session.engine().samples_per_cycle());
|
||||||
DEBUG_TRACE (DEBUG::MTC, string_compose ("engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", te0, te1, e, speed_flt, ee2 - session.engine().frames_per_cycle() ));
|
DEBUG_TRACE (DEBUG::MTC, string_compose ("engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", te0, te1, e, speed_flt, ee2 - session.engine().samples_per_cycle() ));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#include "ardour/audioengine.h"
|
#include "ardour/audioengine.h"
|
||||||
#include "ardour/debug.h"
|
#include "ardour/debug.h"
|
||||||
#include "ardour/port.h"
|
#include "ardour/port.h"
|
||||||
|
#include "ardour/port_engine.h"
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
||||||
|
|
@ -40,13 +41,17 @@ using namespace PBD;
|
||||||
PBD::Signal2<void,boost::shared_ptr<Port>, boost::shared_ptr<Port> > Port::PostDisconnect;
|
PBD::Signal2<void,boost::shared_ptr<Port>, boost::shared_ptr<Port> > Port::PostDisconnect;
|
||||||
PBD::Signal0<void> Port::PortDrop;
|
PBD::Signal0<void> Port::PortDrop;
|
||||||
|
|
||||||
AudioEngine* Port::_engine = 0;
|
|
||||||
bool Port::_connecting_blocked = false;
|
bool Port::_connecting_blocked = false;
|
||||||
pframes_t Port::_global_port_buffer_offset = 0;
|
pframes_t Port::_global_port_buffer_offset = 0;
|
||||||
pframes_t Port::_cycle_nframes = 0;
|
pframes_t Port::_cycle_nframes = 0;
|
||||||
|
|
||||||
|
/* a handy define to shorten what would otherwise be a needlessly verbose
|
||||||
|
* repeated phrase
|
||||||
|
*/
|
||||||
|
#define port_engine AudioEngine::instance()->port_engine()
|
||||||
|
|
||||||
/** @param n Port short name */
|
/** @param n Port short name */
|
||||||
Port::Port (std::string const & n, DataType t, Flags f)
|
Port::Port (std::string const & n, DataType t, PortFlags f)
|
||||||
: _port_buffer_offset (0)
|
: _port_buffer_offset (0)
|
||||||
, _name (n)
|
, _name (n)
|
||||||
, _flags (f)
|
, _flags (f)
|
||||||
|
|
@ -64,11 +69,11 @@ Port::Port (std::string const & n, DataType t, Flags f)
|
||||||
|
|
||||||
assert (_name.find_first_of (':') == std::string::npos);
|
assert (_name.find_first_of (':') == std::string::npos);
|
||||||
|
|
||||||
if (!_engine->connected()) {
|
if (!port_engine.connected()) {
|
||||||
throw failed_constructor ();
|
throw failed_constructor ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((_jack_port = jack_port_register (_engine->jack (), _name.c_str (), t.to_jack_type (), _flags, 0)) == 0) {
|
if ((_jack_port = port_engine.register_port (_name, t.to_port_type (), _flags)) == 0) {
|
||||||
cerr << "Failed to register JACK port \"" << _name << "\", reason is unknown from here\n";
|
cerr << "Failed to register JACK port \"" << _name << "\", reason is unknown from here\n";
|
||||||
throw failed_constructor ();
|
throw failed_constructor ();
|
||||||
}
|
}
|
||||||
|
|
@ -85,11 +90,9 @@ Port::~Port ()
|
||||||
void
|
void
|
||||||
Port::drop ()
|
Port::drop ()
|
||||||
{
|
{
|
||||||
if (_jack_port) {
|
if (_port_handle) {
|
||||||
if (_engine->jack ()) {
|
port_engine.unregister_port (port_handle);
|
||||||
jack_port_unregister (_engine->jack (), _jack_port);
|
_port_handle = 0;
|
||||||
}
|
|
||||||
_jack_port = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,7 +100,7 @@ Port::drop ()
|
||||||
bool
|
bool
|
||||||
Port::connected () const
|
Port::connected () const
|
||||||
{
|
{
|
||||||
return (jack_port_connected (_jack_port) != 0);
|
return (port_engine.connected (_port_handle) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -191,9 +194,9 @@ Port::disconnect (std::string const & other)
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
if (sends_output ()) {
|
if (sends_output ()) {
|
||||||
r = jack_disconnect (_engine->jack (), this_fullname.c_str (), other_fullname.c_str ());
|
r = _engine->disconnect (this_fullname, other_fullname);
|
||||||
} else {
|
} else {
|
||||||
r = jack_disconnect (_engine->jack (), other_fullname.c_str (), this_fullname.c_str ());
|
r = _engine->disconnect (other_fullname, this_fullname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
|
|
@ -236,27 +239,22 @@ Port::disconnect (Port* o)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Port::set_engine (AudioEngine* e)
|
Port::request_input_monitoring (bool yn)
|
||||||
{
|
{
|
||||||
_engine = e;
|
port_eengine.request_input_monitoring (_port_handle, yn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Port::request_monitor_input (bool yn)
|
Port::ensure_input_monitoring (bool yn)
|
||||||
{
|
{
|
||||||
jack_port_request_monitor (_jack_port, yn);
|
port_engine.ensure_input_monitoring (_port_handle, yn);
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Port::ensure_monitor_input (bool yn)
|
|
||||||
{
|
|
||||||
jack_port_ensure_monitor (_jack_port, yn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Port::monitoring_input () const
|
Port::monitoring_input () const
|
||||||
{
|
{
|
||||||
return jack_port_monitoring_input (_jack_port);
|
|
||||||
|
return port_engine.monitoring_input (_port_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#!/usr/bin/env python
|
1#!/usr/bin/env python
|
||||||
from waflib.extras import autowaf as autowaf
|
from waflib.extras import autowaf as autowaf
|
||||||
from waflib import Options
|
from waflib import Options
|
||||||
import os
|
import os
|
||||||
|
|
@ -432,6 +432,25 @@ def build(bld):
|
||||||
elif bld.env['build_target'] == 'x86_64':
|
elif bld.env['build_target'] == 'x86_64':
|
||||||
obj.source += [ 'sse_functions_xmm.cc', 'sse_functions_64bit.s' ]
|
obj.source += [ 'sse_functions_xmm.cc', 'sse_functions_64bit.s' ]
|
||||||
|
|
||||||
|
# the JACK audio backend
|
||||||
|
|
||||||
|
obj = bld.shlib (features = 'c cxx cshlib cxxshlib', source='jack_audiobackend.cc')
|
||||||
|
obj.cxxflags = [ '-fPIC' ]
|
||||||
|
obj.name = 'jack_audiobackend'
|
||||||
|
obj.target = 'jack_audiobackend'
|
||||||
|
obj.uselib = [ 'JACK' ]
|
||||||
|
obj.use = [ 'ardour' ]
|
||||||
|
obj.vnum = '1.0.0'
|
||||||
|
obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
|
||||||
|
obj.includes = [ '.' ]
|
||||||
|
obj.defines = [
|
||||||
|
'PACKAGE="' + I18N_PACKAGE + '"',
|
||||||
|
'DATA_DIR="' + os.path.normpath(bld.env['DATADIR']) + '"',
|
||||||
|
'CONFIG_DIR="' + os.path.normpath(bld.env['SYSCONFDIR']) + '"',
|
||||||
|
'PROGRAM_NAME="' + bld.env['PROGRAM_NAME'] + '"',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
# i18n
|
# i18n
|
||||||
if bld.is_defined('ENABLE_NLS'):
|
if bld.is_defined('ENABLE_NLS'):
|
||||||
mo_files = bld.path.ant_glob('po/*.mo')
|
mo_files = bld.path.ant_glob('po/*.mo')
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,6 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <jack/jack.h>
|
|
||||||
#include <jack/midiport.h>
|
|
||||||
|
|
||||||
#include "pbd/xml++.h"
|
#include "pbd/xml++.h"
|
||||||
#include "pbd/error.h"
|
#include "pbd/error.h"
|
||||||
#include "pbd/failed_constructor.h"
|
#include "pbd/failed_constructor.h"
|
||||||
|
|
@ -45,37 +42,34 @@ template class EventRingBuffer<timestamp_t>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_t JackMIDIPort::_process_thread;
|
pthread_t JackMIDIPort::_process_thread;
|
||||||
Signal0<void> JackMIDIPort::JackHalted;
|
Signal0<void> JackMIDIPort::EngineHalted;
|
||||||
Signal0<void> JackMIDIPort::MakeConnections;
|
Signal0<void> JackMIDIPort::MakeConnections;
|
||||||
|
|
||||||
JackMIDIPort::JackMIDIPort (string const & name, Flags flags, jack_client_t* jack_client)
|
JackMIDIPort::JackMIDIPort (string const & name, Flags flags, ARDOUR::PortEngine& pengine)
|
||||||
: Port (name, flags)
|
: Port (name, flags)
|
||||||
|
, _port_engine (pengine)
|
||||||
|
, _port_handle (0)
|
||||||
, _currently_in_cycle (false)
|
, _currently_in_cycle (false)
|
||||||
, _nframes_this_cycle (0)
|
, _nframes_this_cycle (0)
|
||||||
, _jack_client (jack_client)
|
|
||||||
, _jack_port (0)
|
|
||||||
, _last_write_timestamp (0)
|
, _last_write_timestamp (0)
|
||||||
, output_fifo (512)
|
, output_fifo (512)
|
||||||
, input_fifo (1024)
|
, input_fifo (1024)
|
||||||
, xthread (true)
|
, xthread (true)
|
||||||
{
|
{
|
||||||
assert (jack_client);
|
|
||||||
init (name, flags);
|
init (name, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
JackMIDIPort::JackMIDIPort (const XMLNode& node, jack_client_t* jack_client)
|
JackMIDIPort::JackMIDIPort (const XMLNode& node, ARDOUR::PortEngine& pengine)
|
||||||
: Port (node)
|
: Port (node)
|
||||||
|
, _port_engine (pengine)
|
||||||
|
, _port_handle (0)
|
||||||
, _currently_in_cycle (false)
|
, _currently_in_cycle (false)
|
||||||
, _nframes_this_cycle (0)
|
, _nframes_this_cycle (0)
|
||||||
, _jack_client (jack_client)
|
|
||||||
, _jack_port (0)
|
|
||||||
, _last_write_timestamp (0)
|
, _last_write_timestamp (0)
|
||||||
, output_fifo (512)
|
, output_fifo (512)
|
||||||
, input_fifo (1024)
|
, input_fifo (1024)
|
||||||
, xthread (true)
|
, xthread (true)
|
||||||
{
|
{
|
||||||
assert (jack_client);
|
|
||||||
|
|
||||||
Descriptor desc (node);
|
Descriptor desc (node);
|
||||||
init (desc.tag, desc.flags);
|
init (desc.tag, desc.flags);
|
||||||
set_state (node);
|
set_state (node);
|
||||||
|
|
@ -89,17 +83,15 @@ JackMIDIPort::init (const string& /*name*/, Flags /*flags*/)
|
||||||
}
|
}
|
||||||
|
|
||||||
MakeConnections.connect_same_thread (connect_connection, boost::bind (&JackMIDIPort::make_connections, this));
|
MakeConnections.connect_same_thread (connect_connection, boost::bind (&JackMIDIPort::make_connections, this));
|
||||||
JackHalted.connect_same_thread (halt_connection, boost::bind (&JackMIDIPort::jack_halted, this));
|
EngineHalted.connect_same_thread (halt_connection, boost::bind (&JackMIDIPort::engine_halted, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
JackMIDIPort::~JackMIDIPort ()
|
JackMIDIPort::~JackMIDIPort ()
|
||||||
{
|
{
|
||||||
if (_jack_port) {
|
if (_port_handle) {
|
||||||
if (_jack_client) {
|
_port_engine.unregister_port (_port_handle);
|
||||||
jack_port_unregister (_jack_client, _jack_port);
|
_port_handle = 0;
|
||||||
_jack_port = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,7 +135,7 @@ JackMIDIPort::parse (framecnt_t timestamp)
|
||||||
void
|
void
|
||||||
JackMIDIPort::cycle_start (pframes_t nframes)
|
JackMIDIPort::cycle_start (pframes_t nframes)
|
||||||
{
|
{
|
||||||
assert (_jack_port);
|
assert (_port_handle);
|
||||||
|
|
||||||
_currently_in_cycle = true;
|
_currently_in_cycle = true;
|
||||||
_nframes_this_cycle = nframes;
|
_nframes_this_cycle = nframes;
|
||||||
|
|
@ -151,21 +143,23 @@ JackMIDIPort::cycle_start (pframes_t nframes)
|
||||||
assert(_nframes_this_cycle == nframes);
|
assert(_nframes_this_cycle == nframes);
|
||||||
|
|
||||||
if (sends_output()) {
|
if (sends_output()) {
|
||||||
void *buffer = jack_port_get_buffer (_jack_port, nframes);
|
void *buffer = _port_engine.get_buffer (_port_handle, nframes);
|
||||||
jack_midi_clear_buffer (buffer);
|
jack_midi_clear_buffer (buffer);
|
||||||
flush (buffer);
|
flush (buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (receives_input()) {
|
if (receives_input()) {
|
||||||
void* jack_buffer = jack_port_get_buffer(_jack_port, nframes);
|
void* buffer = _port_engine.get_buffer (_port_handle, nframes);
|
||||||
const pframes_t event_count = jack_midi_get_event_count(jack_buffer);
|
const pframes_t event_count = _port_engine.get_midi_event_count (buffer);
|
||||||
|
|
||||||
jack_midi_event_t ev;
|
pframes_t time;
|
||||||
timestamp_t cycle_start_frame = jack_last_frame_time (_jack_client);
|
size_t size;
|
||||||
|
uint8_t* buf;
|
||||||
|
timestamp_t cycle_start_frame = _port_engine.last_frame_time ();
|
||||||
|
|
||||||
for (pframes_t i = 0; i < event_count; ++i) {
|
for (pframes_t i = 0; i < event_count; ++i) {
|
||||||
jack_midi_event_get (&ev, jack_buffer, i);
|
_port_engine.midi_event_get (time, size, &buf, buffer, i);
|
||||||
input_fifo.write (cycle_start_frame + ev.time, (Evoral::EventType) 0, ev.size, ev.buffer);
|
input_fifo.write (cycle_start_frame + time, (Evoral::EventType) 0, size, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event_count) {
|
if (event_count) {
|
||||||
|
|
@ -178,7 +172,7 @@ void
|
||||||
JackMIDIPort::cycle_end ()
|
JackMIDIPort::cycle_end ()
|
||||||
{
|
{
|
||||||
if (sends_output()) {
|
if (sends_output()) {
|
||||||
flush (jack_port_get_buffer (_jack_port, _nframes_this_cycle));
|
flush (_port_engine.get_buffer (_port_handle, _nframes_this_cycle));
|
||||||
}
|
}
|
||||||
|
|
||||||
_currently_in_cycle = false;
|
_currently_in_cycle = false;
|
||||||
|
|
@ -186,10 +180,9 @@ JackMIDIPort::cycle_end ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JackMIDIPort::jack_halted ()
|
JackMIDIPort::engine_halted ()
|
||||||
{
|
{
|
||||||
_jack_client = 0;
|
_port_handle = 0;
|
||||||
_jack_port = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -216,7 +209,7 @@ JackMIDIPort::write (const byte * msg, size_t msglen, timestamp_t timestamp)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!_jack_client || !_jack_port) {
|
if (!_port_handle) {
|
||||||
/* poof ! make it just vanish into thin air, since we are no
|
/* poof ! make it just vanish into thin air, since we are no
|
||||||
longer connected to JACK.
|
longer connected to JACK.
|
||||||
*/
|
*/
|
||||||
|
|
@ -269,17 +262,17 @@ JackMIDIPort::write (const byte * msg, size_t msglen, timestamp_t timestamp)
|
||||||
timestamp = _last_write_timestamp;
|
timestamp = _last_write_timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ret = jack_midi_event_write (jack_port_get_buffer (_jack_port, _nframes_this_cycle),
|
if ((ret = _port_engine.midi_event_put (_port_engine.get_buffer (_port_handle, _nframes_this_cycle),
|
||||||
timestamp, msg, msglen)) == 0) {
|
timestamp, msg, msglen)) == 0) {
|
||||||
ret = msglen;
|
ret = msglen;
|
||||||
_last_write_timestamp = timestamp;
|
_last_write_timestamp = timestamp;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
cerr << "write of " << msglen << " @ " << timestamp << " failed, port holds "
|
cerr << "write of " << msglen << " @ " << timestamp << " failed, port holds "
|
||||||
<< jack_midi_get_event_count (jack_port_get_buffer (_jack_port, _nframes_this_cycle))
|
<< _port_engine.get_midi_event_count (_port_engine.get_buffer (_port_handle, _nframes_this_cycle))
|
||||||
<< " port is " << _jack_port
|
<< " port is " << _port_handle
|
||||||
<< " ntf = " << _nframes_this_cycle
|
<< " ntf = " << _nframes_this_cycle
|
||||||
<< " buf = " << jack_port_get_buffer (_jack_port, _nframes_this_cycle)
|
<< " buf = " << _port_engine.get_buffer (_port_handle, _nframes_this_cycle)
|
||||||
<< " ret = " << ret
|
<< " ret = " << ret
|
||||||
<< endl;
|
<< endl;
|
||||||
PBD::stacktrace (cerr, 20);
|
PBD::stacktrace (cerr, 20);
|
||||||
|
|
@ -305,7 +298,7 @@ JackMIDIPort::write (const byte * msg, size_t msglen, timestamp_t timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JackMIDIPort::flush (void* jack_port_buffer)
|
JackMIDIPort::flush (void* port_buffer)
|
||||||
{
|
{
|
||||||
RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0 } };
|
RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0 } };
|
||||||
size_t written;
|
size_t written;
|
||||||
|
|
@ -320,8 +313,7 @@ JackMIDIPort::flush (void* jack_port_buffer)
|
||||||
Evoral::Event<double>* evp = vec.buf[0];
|
Evoral::Event<double>* evp = vec.buf[0];
|
||||||
|
|
||||||
for (size_t n = 0; n < vec.len[0]; ++n, ++evp) {
|
for (size_t n = 0; n < vec.len[0]; ++n, ++evp) {
|
||||||
jack_midi_event_write (jack_port_buffer,
|
_port_engine.midi_event_put (port_buffer, (timestamp_t) evp->time(), evp->buffer(), evp->size());
|
||||||
(timestamp_t) evp->time(), evp->buffer(), evp->size());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -329,8 +321,7 @@ JackMIDIPort::flush (void* jack_port_buffer)
|
||||||
Evoral::Event<double>* evp = vec.buf[1];
|
Evoral::Event<double>* evp = vec.buf[1];
|
||||||
|
|
||||||
for (size_t n = 0; n < vec.len[1]; ++n, ++evp) {
|
for (size_t n = 0; n < vec.len[1]; ++n, ++evp) {
|
||||||
jack_midi_event_write (jack_port_buffer,
|
_port_engine.midi_event_put (port_buffer, (timestamp_t) evp->time(), evp->buffer(), evp->size());
|
||||||
(timestamp_t) evp->time(), evp->buffer(), evp->size());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -364,8 +355,21 @@ JackMIDIPort::read (byte *, size_t)
|
||||||
int
|
int
|
||||||
JackMIDIPort::create_port ()
|
JackMIDIPort::create_port ()
|
||||||
{
|
{
|
||||||
_jack_port = jack_port_register(_jack_client, _tagname.c_str(), JACK_DEFAULT_MIDI_TYPE, _flags, 0);
|
ARDOUR::PortFlags f = ARDOUR::PortFlags (0);
|
||||||
return _jack_port == 0 ? -1 : 0;
|
|
||||||
|
/* convert MIDI::Port::Flags to ARDOUR::PortFlags ... sigh */
|
||||||
|
|
||||||
|
if (_flags & IsInput) {
|
||||||
|
f = ARDOUR::PortFlags (f | ARDOUR::IsInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_flags & IsOutput) {
|
||||||
|
f = ARDOUR::PortFlags (f | ARDOUR::IsOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
_port_handle = _port_engine.register_port (_tagname, ARDOUR::DataType::MIDI, f);
|
||||||
|
|
||||||
|
return _port_handle == 0 ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLNode&
|
XMLNode&
|
||||||
|
|
@ -386,18 +390,16 @@ JackMIDIPort::get_state () const
|
||||||
write (device_inquiry, sizeof (device_inquiry), 0);
|
write (device_inquiry, sizeof (device_inquiry), 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (_jack_port) {
|
if (_port_handle) {
|
||||||
|
|
||||||
const char** jc = jack_port_get_connections (_jack_port);
|
vector<string> connections;
|
||||||
|
_port_engine.get_connections (_port_handle, connections);
|
||||||
string connection_string;
|
string connection_string;
|
||||||
if (jc) {
|
for (vector<string>::iterator i = connections.begin(); i != connections.end(); ++i) {
|
||||||
for (int i = 0; jc[i]; ++i) {
|
if (i != connections.begin()) {
|
||||||
if (i > 0) {
|
|
||||||
connection_string += ',';
|
connection_string += ',';
|
||||||
}
|
}
|
||||||
connection_string += jc[i];
|
connection_string += *i;
|
||||||
}
|
|
||||||
free (jc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!connection_string.empty()) {
|
if (!connection_string.empty()) {
|
||||||
|
|
@ -435,16 +437,10 @@ JackMIDIPort::make_connections ()
|
||||||
vector<string> ports;
|
vector<string> ports;
|
||||||
split (_connections, ports, ',');
|
split (_connections, ports, ',');
|
||||||
for (vector<string>::iterator x = ports.begin(); x != ports.end(); ++x) {
|
for (vector<string>::iterator x = ports.begin(); x != ports.end(); ++x) {
|
||||||
if (_jack_client) {
|
_port_engine.connect (_port_handle, *x);
|
||||||
if (receives_input()) {
|
|
||||||
jack_connect (_jack_client, (*x).c_str(), jack_port_name (_jack_port));
|
|
||||||
} else {
|
|
||||||
jack_connect (_jack_client, jack_port_name (_jack_port), (*x).c_str());
|
|
||||||
}
|
|
||||||
/* ignore failures */
|
/* ignore failures */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
connect_connection.disconnect ();
|
connect_connection.disconnect ();
|
||||||
}
|
}
|
||||||
|
|
@ -462,9 +458,8 @@ JackMIDIPort::is_process_thread()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
JackMIDIPort::reestablish (jack_client_t* jack)
|
JackMIDIPort::reestablish ()
|
||||||
{
|
{
|
||||||
_jack_client = jack;
|
|
||||||
int const r = create_port ();
|
int const r = create_port ();
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
|
|
|
||||||
|
|
@ -36,17 +36,17 @@ using namespace PBD;
|
||||||
|
|
||||||
Manager *Manager::theManager = 0;
|
Manager *Manager::theManager = 0;
|
||||||
|
|
||||||
Manager::Manager (jack_client_t* jack)
|
Manager::Manager (ARDOUR::PortEngine& eng)
|
||||||
: _ports (new PortList)
|
: _ports (new PortList)
|
||||||
{
|
{
|
||||||
_mmc = new MachineControl (this, jack);
|
_mmc = new MachineControl (this, eng);
|
||||||
|
|
||||||
_mtc_input_port = add_port (new MIDI::JackMIDIPort ("MTC in", Port::IsInput, jack));
|
_mtc_input_port = add_port (new MIDI::JackMIDIPort ("MTC in", Port::IsInput, eng));
|
||||||
_mtc_output_port = add_port (new MIDI::JackMIDIPort ("MTC out", Port::IsOutput, jack));
|
_mtc_output_port = add_port (new MIDI::JackMIDIPort ("MTC out", Port::IsOutput, eng));
|
||||||
_midi_input_port = add_port (new MIDI::JackMIDIPort ("MIDI control in", Port::IsInput, jack));
|
_midi_input_port = add_port (new MIDI::JackMIDIPort ("MIDI control in", Port::IsInput, eng));
|
||||||
_midi_output_port = add_port (new MIDI::JackMIDIPort ("MIDI control out", Port::IsOutput, jack));
|
_midi_output_port = add_port (new MIDI::JackMIDIPort ("MIDI control out", Port::IsOutput, eng));
|
||||||
_midi_clock_input_port = add_port (new MIDI::JackMIDIPort ("MIDI clock in", Port::IsInput, jack));
|
_midi_clock_input_port = add_port (new MIDI::JackMIDIPort ("MIDI clock in", Port::IsInput, eng));
|
||||||
_midi_clock_output_port = add_port (new MIDI::JackMIDIPort ("MIDI clock out", Port::IsOutput, jack));
|
_midi_clock_output_port = add_port (new MIDI::JackMIDIPort ("MIDI clock out", Port::IsOutput, eng));
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager::~Manager ()
|
Manager::~Manager ()
|
||||||
|
|
@ -113,14 +113,14 @@ Manager::cycle_end()
|
||||||
|
|
||||||
/** Re-register ports that disappear on JACK shutdown */
|
/** Re-register ports that disappear on JACK shutdown */
|
||||||
void
|
void
|
||||||
Manager::reestablish (jack_client_t* jack)
|
Manager::reestablish ()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<PortList> pr = _ports.reader ();
|
boost::shared_ptr<PortList> pr = _ports.reader ();
|
||||||
|
|
||||||
for (PortList::const_iterator p = pr->begin(); p != pr->end(); ++p) {
|
for (PortList::const_iterator p = pr->begin(); p != pr->end(); ++p) {
|
||||||
JackMIDIPort* pp = dynamic_cast<JackMIDIPort*> (*p);
|
JackMIDIPort* pp = dynamic_cast<JackMIDIPort*> (*p);
|
||||||
if (pp) {
|
if (pp) {
|
||||||
pp->reestablish (jack);
|
pp->reestablish ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -157,10 +157,10 @@ Manager::port (string const & n)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Manager::create (jack_client_t* jack)
|
Manager::create (ARDOUR::PortEngine& eng)
|
||||||
{
|
{
|
||||||
assert (theManager == 0);
|
assert (theManager == 0);
|
||||||
theManager = new Manager (jack);
|
theManager = new Manager (eng);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,6 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <jack/types.h>
|
|
||||||
|
|
||||||
#include "pbd/xml++.h"
|
#include "pbd/xml++.h"
|
||||||
#include "pbd/crossthread.h"
|
#include "pbd/crossthread.h"
|
||||||
#include "pbd/signals.h"
|
#include "pbd/signals.h"
|
||||||
|
|
@ -36,6 +34,8 @@
|
||||||
#include "midi++/parser.h"
|
#include "midi++/parser.h"
|
||||||
#include "midi++/port.h"
|
#include "midi++/port.h"
|
||||||
|
|
||||||
|
#include "ardour/port_engine.h"
|
||||||
|
|
||||||
namespace MIDI {
|
namespace MIDI {
|
||||||
|
|
||||||
class Channel;
|
class Channel;
|
||||||
|
|
@ -43,8 +43,8 @@ class PortRequest;
|
||||||
|
|
||||||
class JackMIDIPort : public Port {
|
class JackMIDIPort : public Port {
|
||||||
public:
|
public:
|
||||||
JackMIDIPort (std::string const &, Port::Flags, jack_client_t *);
|
JackMIDIPort (std::string const &, Port::Flags, ARDOUR::PortEngine&);
|
||||||
JackMIDIPort (const XMLNode&, jack_client_t *);
|
JackMIDIPort (const XMLNode&, ARDOUR::PortEngine&);
|
||||||
~JackMIDIPort ();
|
~JackMIDIPort ();
|
||||||
|
|
||||||
XMLNode& get_state () const;
|
XMLNode& get_state () const;
|
||||||
|
|
@ -61,7 +61,7 @@ class JackMIDIPort : public Port {
|
||||||
|
|
||||||
pframes_t nframes_this_cycle() const { return _nframes_this_cycle; }
|
pframes_t nframes_this_cycle() const { return _nframes_this_cycle; }
|
||||||
|
|
||||||
void reestablish (jack_client_t *);
|
void reestablish ();
|
||||||
void reconnect ();
|
void reconnect ();
|
||||||
|
|
||||||
static void set_process_thread (pthread_t);
|
static void set_process_thread (pthread_t);
|
||||||
|
|
@ -69,13 +69,14 @@ class JackMIDIPort : public Port {
|
||||||
static bool is_process_thread();
|
static bool is_process_thread();
|
||||||
|
|
||||||
static PBD::Signal0<void> MakeConnections;
|
static PBD::Signal0<void> MakeConnections;
|
||||||
static PBD::Signal0<void> JackHalted;
|
static PBD::Signal0<void> EngineHalted;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
ARDOUR::PortEngine& _port_engine;
|
||||||
|
ARDOUR::PortEngine::PortHandle _port_handle;
|
||||||
|
|
||||||
bool _currently_in_cycle;
|
bool _currently_in_cycle;
|
||||||
pframes_t _nframes_this_cycle;
|
pframes_t _nframes_this_cycle;
|
||||||
jack_client_t* _jack_client;
|
|
||||||
jack_port_t* _jack_port;
|
|
||||||
timestamp_t _last_write_timestamp;
|
timestamp_t _last_write_timestamp;
|
||||||
RingBuffer< Evoral::Event<double> > output_fifo;
|
RingBuffer< Evoral::Event<double> > output_fifo;
|
||||||
Evoral::EventRingBuffer<timestamp_t> input_fifo;
|
Evoral::EventRingBuffer<timestamp_t> input_fifo;
|
||||||
|
|
@ -89,8 +90,8 @@ private:
|
||||||
std::string _connections;
|
std::string _connections;
|
||||||
PBD::ScopedConnection connect_connection;
|
PBD::ScopedConnection connect_connection;
|
||||||
PBD::ScopedConnection halt_connection;
|
PBD::ScopedConnection halt_connection;
|
||||||
void flush (void* jack_port_buffer);
|
void flush (void* port_buffer);
|
||||||
void jack_halted ();
|
void engine_halted ();
|
||||||
void make_connections ();
|
void make_connections ();
|
||||||
void init (std::string const &, Flags);
|
void init (std::string const &, Flags);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,10 @@
|
||||||
#include "midi++/types.h"
|
#include "midi++/types.h"
|
||||||
#include "midi++/port.h"
|
#include "midi++/port.h"
|
||||||
|
|
||||||
|
namespace ARDOUR {
|
||||||
|
class PortEngine;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MIDI {
|
namespace MIDI {
|
||||||
|
|
||||||
class MachineControl;
|
class MachineControl;
|
||||||
|
|
@ -69,14 +73,14 @@ class Manager {
|
||||||
|
|
||||||
boost::shared_ptr<const PortList> get_midi_ports() const { return _ports.reader (); }
|
boost::shared_ptr<const PortList> get_midi_ports() const { return _ports.reader (); }
|
||||||
|
|
||||||
static void create (jack_client_t* jack);
|
static void create (ARDOUR::PortEngine&);
|
||||||
|
|
||||||
static Manager *instance () {
|
static Manager *instance () {
|
||||||
return theManager;
|
return theManager;
|
||||||
}
|
}
|
||||||
static void destroy ();
|
static void destroy ();
|
||||||
|
|
||||||
void reestablish (jack_client_t *);
|
void reestablish ();
|
||||||
void reconnect ();
|
void reconnect ();
|
||||||
|
|
||||||
PBD::Signal0<void> PortsChanged;
|
PBD::Signal0<void> PortsChanged;
|
||||||
|
|
@ -84,7 +88,7 @@ class Manager {
|
||||||
private:
|
private:
|
||||||
/* This is a SINGLETON pattern */
|
/* This is a SINGLETON pattern */
|
||||||
|
|
||||||
Manager (jack_client_t *);
|
Manager (ARDOUR::PortEngine&);
|
||||||
static Manager *theManager;
|
static Manager *theManager;
|
||||||
|
|
||||||
MIDI::MachineControl* _mmc;
|
MIDI::MachineControl* _mmc;
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,17 @@
|
||||||
|
|
||||||
#include <jack/types.h>
|
#include <jack/types.h>
|
||||||
#include "timecode/time.h"
|
#include "timecode/time.h"
|
||||||
|
|
||||||
#include "pbd/signals.h"
|
#include "pbd/signals.h"
|
||||||
#include "pbd/ringbuffer.h"
|
#include "pbd/ringbuffer.h"
|
||||||
|
|
||||||
#include "midi++/types.h"
|
#include "midi++/types.h"
|
||||||
#include "midi++/parser.h"
|
#include "midi++/parser.h"
|
||||||
|
|
||||||
|
namespace ARDOUR {
|
||||||
|
class PortEngine;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MIDI {
|
namespace MIDI {
|
||||||
|
|
||||||
class Port;
|
class Port;
|
||||||
|
|
@ -89,7 +95,7 @@ class MachineControl
|
||||||
cmdResume = 0x7F
|
cmdResume = 0x7F
|
||||||
};
|
};
|
||||||
|
|
||||||
MachineControl (Manager *, jack_client_t *);
|
MachineControl (Manager *, ARDOUR::PortEngine&);
|
||||||
|
|
||||||
Port* input_port() { return _input_port; }
|
Port* input_port() { return _input_port; }
|
||||||
Port* output_port() { return _output_port; }
|
Port* output_port() { return _output_port; }
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,9 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "timecode/time.h"
|
#include "timecode/time.h"
|
||||||
|
|
||||||
#include "pbd/error.h"
|
#include "pbd/error.h"
|
||||||
|
|
||||||
#include "midi++/mmc.h"
|
#include "midi++/mmc.h"
|
||||||
#include "midi++/port.h"
|
#include "midi++/port.h"
|
||||||
#include "midi++/jack_midi_port.h"
|
#include "midi++/jack_midi_port.h"
|
||||||
|
|
@ -196,15 +198,15 @@ static void build_mmc_cmd_map ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MachineControl::MachineControl (Manager* m, jack_client_t* jack)
|
MachineControl::MachineControl (Manager* m, ARDOUR::PortEngine& pengine)
|
||||||
{
|
{
|
||||||
build_mmc_cmd_map ();
|
build_mmc_cmd_map ();
|
||||||
|
|
||||||
_receive_device_id = 0x7f;
|
_receive_device_id = 0x7f;
|
||||||
_send_device_id = 0x7f;
|
_send_device_id = 0x7f;
|
||||||
|
|
||||||
_input_port = m->add_port (new JackMIDIPort ("MMC in", Port::IsInput, jack));
|
_input_port = m->add_port (new JackMIDIPort ("MMC in", Port::IsInput, pengine));
|
||||||
_output_port = m->add_port (new JackMIDIPort ("MMC out", Port::IsOutput, jack));
|
_output_port = m->add_port (new JackMIDIPort ("MMC out", Port::IsOutput, pengine));
|
||||||
|
|
||||||
_input_port->parser()->mmc.connect_same_thread (port_connections, boost::bind (&MachineControl::process_mmc_message, this, _1, _2, _3));
|
_input_port->parser()->mmc.connect_same_thread (port_connections, boost::bind (&MachineControl::process_mmc_message, this, _1, _2, _3));
|
||||||
_input_port->parser()->start.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_start, this));
|
_input_port->parser()->start.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_start, this));
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ out = 'build'
|
||||||
|
|
||||||
path_prefix = 'libs/midi++2/'
|
path_prefix = 'libs/midi++2/'
|
||||||
|
|
||||||
|
|
||||||
libmidi_sources = [
|
libmidi_sources = [
|
||||||
'midi.cc',
|
'midi.cc',
|
||||||
'channel.cc',
|
'channel.cc',
|
||||||
|
|
@ -68,7 +69,7 @@ def build(bld):
|
||||||
obj.cxxflags = [ '-fPIC', '-DWITH_JACK_MIDI' ]
|
obj.cxxflags = [ '-fPIC', '-DWITH_JACK_MIDI' ]
|
||||||
# everybody loves JACK
|
# everybody loves JACK
|
||||||
obj.export_includes = ['.']
|
obj.export_includes = ['.']
|
||||||
obj.includes = ['.', '../surfaces/control_protocol']
|
obj.includes = ['.', '../surfaces/control_protocol', '../ardour' ]
|
||||||
obj.name = 'libmidipp'
|
obj.name = 'libmidipp'
|
||||||
obj.target = 'midipp'
|
obj.target = 'midipp'
|
||||||
obj.uselib = 'GLIBMM SIGCPP XML JACK OSX'
|
obj.uselib = 'GLIBMM SIGCPP XML JACK OSX'
|
||||||
|
|
|
||||||
|
|
@ -1236,7 +1236,7 @@ MackieControlProtocol::midi_input_handler (IOCondition ioc, MIDI::Port* port)
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("data available on %1\n", port->name()));
|
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("data available on %1\n", port->name()));
|
||||||
framepos_t now = session->engine().frame_time();
|
framepos_t now = session->engine().sample_time();
|
||||||
port->parse (now);
|
port->parse (now);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,10 +59,10 @@ SurfacePort::SurfacePort (Surface& s)
|
||||||
_input_port = new MIDI::IPMIDIPort (_surface->mcp().ipmidi_base() +_surface->number());
|
_input_port = new MIDI::IPMIDIPort (_surface->mcp().ipmidi_base() +_surface->number());
|
||||||
_output_port = _input_port;
|
_output_port = _input_port;
|
||||||
} else {
|
} else {
|
||||||
jack_client_t* jack = MackieControlProtocol::instance()->get_session().engine().jack();
|
ARDOUR::PortEngine& port_engine (ARDOUR::AudioEngine::instance()->port_engine());
|
||||||
|
|
||||||
_input_port = new MIDI::JackMIDIPort (string_compose (_("%1 in"), _surface->name()), MIDI::Port::IsInput, jack);
|
_input_port = new MIDI::JackMIDIPort (string_compose (_("%1 in"), _surface->name()), MIDI::Port::IsInput, port_engine);
|
||||||
_output_port =new MIDI::JackMIDIPort (string_compose (_("%1 out"), _surface->name()), MIDI::Port::IsOutput, jack);
|
_output_port =new MIDI::JackMIDIPort (string_compose (_("%1 out"), _surface->name()), MIDI::Port::IsOutput, port_engine);
|
||||||
|
|
||||||
/* MackieControl has its own thread for handling input from the input
|
/* MackieControl has its own thread for handling input from the input
|
||||||
* port, and we don't want anything handling output from the output
|
* port, and we don't want anything handling output from the output
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue