ardour/libs/ardour/ardour/port_manager.h

397 lines
12 KiB
C++

/*
* Copyright (C) 2013-2019 Paul Davis <paul@linuxaudiosystems.com>
* Copyright (C) 2015-2017 Robin Gareus <robin@gareus.org>
*
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __libardour_port_manager_h__
#define __libardour_port_manager_h__
#include <atomic>
#include <cstdint>
#include <exception>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "pbd/natsort.h"
#include "pbd/rcu.h"
#include "pbd/ringbuffer.h"
#include "ardour/chan_count.h"
#include "ardour/midiport_manager.h"
#include "ardour/monitor_port.h"
#include "ardour/port.h"
namespace ARDOUR {
class PortEngine;
class AudioBackend;
class Session;
class CircularSampleBuffer;
class CircularEventBuffer;
class LIBARDOUR_API PortManager
{
public:
struct DPM {
DPM ()
{
reset ();
}
void reset ()
{
level = 0;
peak = 0;
}
Sample level;
Sample peak;
};
struct MPM {
MPM ()
{
reset ();
}
void reset ()
{
memset (chn_active, 0, sizeof (float) * 17);
}
bool active (int chn) const {
if (chn < 0 || chn > 16) {
return false;
}
return chn_active[chn] > 0.1;
}
/* 0..15: MIDI Channel Event, 16: System Common Message */
float chn_active[17];
};
struct SortByPortName {
bool operator() (std::string const& a, std::string const& b) const {
return PBD::naturally_less (a.c_str (), b.c_str ());
}
};
typedef std::map<std::string, std::shared_ptr<Port>, SortByPortName> Ports;
typedef std::list<std::shared_ptr<Port> > PortList;
typedef std::shared_ptr<CircularSampleBuffer> AudioPortScope;
typedef std::shared_ptr<CircularEventBuffer> MIDIPortMonitor;
typedef std::shared_ptr<DPM> AudioPortMeter;
typedef std::shared_ptr<MPM> MIDIPortMeter;
struct AudioInputPort {
AudioInputPort (samplecnt_t);
AudioPortScope scope;
AudioPortMeter meter;
void apply_falloff (pframes_t, samplecnt_t sr, bool reset = false);
void silence (pframes_t);
void process (Sample const*, pframes_t, bool reset = false);
};
struct MIDIInputPort {
MIDIInputPort (samplecnt_t);
MIDIPortMonitor monitor;
MIDIPortMeter meter;
void apply_falloff (pframes_t, samplecnt_t sr, bool reset = false);
void process_event (uint8_t const*, size_t);
};
typedef std::map<std::string, AudioInputPort, SortByPortName> AudioInputPorts;
typedef std::map<std::string, MIDIInputPort, SortByPortName> MIDIInputPorts;
PortManager ();
virtual ~PortManager () {}
PortEngine& port_engine ();
static void falloff_cache_calc (pframes_t, samplecnt_t);
uint32_t port_name_size () const;
std::string my_name () const;
size_t total_port_count () const { return _ports.reader ()->size (); }
size_t session_port_count () const;
#ifndef NDEBUG
void list_cycle_ports () const;
void list_all_ports () const;
#endif
/* Port registration */
std::shared_ptr<Port> register_input_port (DataType, const std::string& portname, bool async = false, PortFlags extra_flags = PortFlags (0));
std::shared_ptr<Port> register_output_port (DataType, const std::string& portname, bool async = false, PortFlags extra_flags = PortFlags (0));
int unregister_port (std::shared_ptr<Port>);
/* Port connectivity */
int connect (const std::string& source, const std::string& destination);
int disconnect (const std::string& source, const std::string& destination);
int disconnect (std::shared_ptr<Port>);
int disconnect (std::string const&);
int reestablish_ports ();
int reconnect_ports ();
bool connected (const std::string&);
bool physically_connected (const std::string&);
int get_connections (const std::string&, std::vector<std::string>&);
/* Naming */
std::shared_ptr<Port> get_port_by_name (const std::string&);
void port_renamed (const std::string&, const std::string&);
std::string make_port_name_relative (const std::string& name) const;
std::string make_port_name_non_relative (const std::string& name) const;
std::string get_pretty_name_by_name (const std::string& portname) const;
std::string get_hardware_port_name_by_name (const std::string& portname) const;
std::string short_port_name_from_port_name (std::string const& full_name) const;
bool port_is_mine (const std::string& fullname) const;
static bool port_is_virtual_piano (std::string const&);
static bool port_is_control_only (std::string const&);
static bool port_is_physical_input_monitor_enable (std::string const&);
/* other Port management */
bool port_is_physical (const std::string&) const;
void get_physical_outputs (DataType type, std::vector<std::string>&,
MidiPortFlags include = MidiPortFlags (0),
MidiPortFlags exclude = MidiPortFlags (0));
void get_physical_inputs (DataType type, std::vector<std::string>&,
MidiPortFlags include = MidiPortFlags (0),
MidiPortFlags exclude = MidiPortFlags (0));
ChanCount n_physical_outputs () const;
ChanCount n_physical_inputs () const;
int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>&);
int get_ports (DataType, PortList&);
void set_port_pretty_name (std::string const&, std::string const&);
void remove_session_ports ();
/** reset port-buffers. e.g. after freewheeling */
void reinit (bool with_ratio = false);
void clear_pending_port_deletions ();
virtual void add_pending_port_deletion (Port*) = 0;
PBD::RingBuffer<Port*>& port_deletions_pending ()
{
return _port_deletions_pending;
}
bool check_for_ambiguous_latency (bool log = false) const;
/* per-Port monitoring */
bool can_request_input_monitoring () const;
void request_input_monitoring (const std::string&, bool) const;
void ensure_input_monitoring (const std::string&, bool) const;
class PortRegistrationFailure : public std::exception
{
public:
PortRegistrationFailure (std::string const& why = "")
: reason (why) {}
~PortRegistrationFailure () throw () {}
const char* what () const throw ()
{
return reason.c_str ();
}
private:
std::string reason;
};
/* the port engine will invoke these callbacks when the time is right */
void registration_callback ();
int graph_order_callback ();
void connect_callback (const std::string&, const std::string&, bool connection);
bool port_remove_in_progress () const
{
return _port_remove_in_progress;
}
MidiPortFlags midi_port_metadata (std::string const&);
void get_configurable_midi_ports (std::vector<std::string>&, bool for_input);
void get_midi_selection_ports (std::vector<std::string>&);
void add_midi_port_flags (std::string const&, MidiPortFlags);
void remove_midi_port_flags (std::string const&, MidiPortFlags);
/** Emitted if the list of ports to be used for MIDI selection tracking changes */
PBD::Signal0<void> MidiSelectionPortsChanged;
/** Emitted if anything other than the selection property for a MIDI port changes */
PBD::Signal0<void> MidiPortInfoChanged;
/** Emitted if pretty-name of a port changed */
PBD::Signal1<void, std::string> PortPrettyNameChanged;
/** Emitted if the backend notifies us of a graph order event */
PBD::Signal0<void> GraphReordered;
/** Emitted if a Port is registered or unregistered */
PBD::Signal0<void> PortRegisteredOrUnregistered;
/** Emitted if a Port is connected or disconnected.
* The Port parameters are the ports being connected / disconnected, or 0 if they are not known to Ardour.
* The std::string parameters are the (long) port names.
* The bool parameter is true if ports were connected, or false for disconnected.
*/
PBD::Signal5<void, std::weak_ptr<Port>, std::string, std::weak_ptr<Port>, std::string, bool> PortConnectedOrDisconnected;
PBD::Signal3<void, DataType, std::vector<std::string>, bool> PhysInputChanged;
/* Input port meters and monitors */
void reset_input_meters ();
AudioInputPorts audio_input_ports () const;
MIDIInputPorts midi_input_ports () const;
MonitorPort& monitor_port () {
return _monitor_port;
}
protected:
std::shared_ptr<AudioBackend> _backend;
SerializedRCUManager<Ports> _ports;
bool _port_remove_in_progress;
PBD::RingBuffer<Port*> _port_deletions_pending;
std::shared_ptr<Port> register_port (DataType type, const std::string& portname, bool input, bool async = false, PortFlags extra_flags = PortFlags (0));
void port_registration_failure (const std::string& portname);
/** List of ports to be used between \ref cycle_start() and \ref cycle_end() */
std::shared_ptr<Ports const> _cycle_ports;
void silence (pframes_t nframes, Session* s = 0);
void silence_outputs (pframes_t nframes);
void check_monitoring ();
/** Signal the start of an audio cycle.
* This MUST be called before any reading/writing for this cycle.
* Realtime safe.
*/
void cycle_start (pframes_t nframes, Session* s = 0);
/** Signal the end of an audio cycle.
* This signifies that the cycle began with @ref cycle_start has ended.
* This MUST be called at the end of each cycle.
* Realtime safe.
*/
void cycle_end (pframes_t nframes, Session* s = 0);
void cycle_end_fade_out (gain_t, gain_t, pframes_t, Session* s = 0);
static std::string port_info_file ();
static std::string midi_port_info_file ();
void filter_midi_ports (std::vector<std::string>&, MidiPortFlags, MidiPortFlags);
void set_port_buffer_sizes (pframes_t);
private:
void run_input_meters (pframes_t, samplecnt_t);
void set_pretty_names (std::vector<std::string> const&, DataType, bool);
void fill_midi_port_info_locked ();
void load_port_info ();
void save_port_info ();
void update_input_ports (bool);
MonitorPort _monitor_port;
struct PortID {
PortID (std::shared_ptr<AudioBackend>, DataType, bool, std::string const&);
PortID (XMLNode const&, bool old_midi_format = false);
std::string backend;
std::string device_name;
std::string port_name;
DataType data_type;
bool input;
XMLNode& state () const;
bool operator< (PortID const& o) const {
if (backend != o.backend) {
return backend < o.backend;
}
if (device_name != o.device_name) {
return device_name < o.device_name;
}
if (port_name != o.port_name) {
return PBD::naturally_less (port_name.c_str (), o.port_name.c_str ());
}
if (input != o.input) {
return input;
}
return (uint32_t) data_type < (uint32_t) o.data_type;
}
bool operator== (PortID const& o) const {
if (backend != o.backend) {
return false;
}
if (device_name != o.device_name) {
return false;
}
if (port_name != o.port_name) {
return false;
}
if (input != o.input) {
return false;
}
if (data_type != o.data_type) {
return false;
}
return true;
}
};
struct PortMetaData {
PortMetaData () : properties (MidiPortFlags (0)) {}
PortMetaData (XMLNode const&);
std::string pretty_name;
MidiPortFlags properties;
};
typedef std::map<PortID, PortMetaData> PortInfo;
mutable Glib::Threads::Mutex _port_info_mutex;
PortInfo _port_info;
bool _midi_info_dirty;
SerializedRCUManager<AudioInputPorts> _audio_input_ports;
SerializedRCUManager<MIDIInputPorts> _midi_input_ports;
std::atomic<int> _reset_meters;
};
} // namespace ARDOUR
#endif /* __libardour_port_manager_h__ */