2013-07-24 19:30:08 -04:00
/*
2019-08-02 22:01:25 -04:00
* Copyright ( C ) 2013 - 2019 Paul Davis < paul @ linuxaudiosystems . com >
* Copyright ( C ) 2015 - 2019 Robin Gareus < robin @ gareus . org >
* Copyright ( C ) 2017 - 2018 Ben Loftis < ben @ harrisonconsoles . com >
*
* 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 .
*/
2013-07-24 19:30:08 -04:00
2021-01-16 00:45:12 -05:00
# include <algorithm>
2019-03-07 14:00:51 -05:00
# include <vector>
2016-07-08 17:09:09 -04:00
# ifdef COMPILER_MSVC
# include <ardourext/misc.h>
2021-10-31 13:17:01 -04:00
# include <io.h> // Microsoft's nearest equivalent to <unistd.h>
2016-07-08 17:09:09 -04:00
# else
# include <regex.h>
# endif
2016-10-20 16:34:06 -04:00
# include <glibmm/fileutils.h>
# include <glibmm/miscutils.h>
2013-07-31 19:47:20 -04:00
# include "pbd/error.h"
2019-03-07 14:00:51 -05:00
# include "pbd/strsplit.h"
2020-04-08 02:28:30 -04:00
# include "pbd/unwind.h"
2013-07-31 19:47:20 -04:00
2013-08-07 22:22:11 -04:00
# include "ardour/async_midi_port.h"
2013-09-13 11:21:15 -04:00
# include "ardour/audio_backend.h"
2013-07-31 19:47:20 -04:00
# include "ardour/audio_port.h"
2020-10-26 10:52:17 -04:00
# include "ardour/circular_buffer.h"
2013-09-13 11:21:15 -04:00
# include "ardour/debug.h"
2016-10-20 16:34:06 -04:00
# include "ardour/filesystem_paths.h"
2013-07-31 19:47:20 -04:00
# include "ardour/midi_port.h"
2013-08-07 22:22:11 -04:00
# include "ardour/midiport_manager.h"
2013-09-13 11:21:15 -04:00
# include "ardour/port_manager.h"
2015-05-09 15:05:31 -04:00
# include "ardour/profile.h"
2017-10-30 10:58:36 -04:00
# include "ardour/rt_tasklist.h"
2016-05-25 13:20:09 -04:00
# include "ardour/session.h"
2016-12-07 01:37:59 -05:00
# include "ardour/types_convert.h"
2013-07-31 19:47:20 -04:00
2016-07-14 14:44:52 -04:00
# include "pbd/i18n.h"
2013-07-24 19:30:08 -04:00
using namespace ARDOUR ;
2013-07-31 19:47:20 -04:00
using namespace PBD ;
using std : : string ;
using std : : vector ;
2013-07-24 19:30:08 -04:00
2022-05-16 10:43:39 -04:00
/* Cache dB -> coefficient calculation for dB/sec falloff.
* @ n_samples engine - buffer - size
* @ rate engine sample - rate
* @ return coefficiant taking user preferences meter_falloff ( dB / sec ) into account
*/
struct FallOffCache {
FallOffCache ( )
: _falloff ( 1.0 )
, _cfg_db_s ( 0 )
, _n_samples ( 0 )
, _rate ( 0 )
{
}
float calc ( pframes_t n_samples , samplecnt_t rate )
{
if ( n_samples = = 0 | | rate = = 0 ) {
return 1.0 ;
}
if ( Config - > get_meter_falloff ( ) ! = _cfg_db_s | | n_samples ! = _n_samples | | rate ! = _rate ) {
_cfg_db_s = Config - > get_meter_falloff ( ) ;
_n_samples = n_samples ;
_rate = rate ;
# ifdef _GNU_SOURCE
_falloff = exp10f ( - 0.05f * _cfg_db_s * _n_samples / _rate ) ;
# else
_falloff = powf ( 10.f , - 0.05f * _cfg_db_s * _n_samples / _rate ) ;
# endif
}
return _falloff ;
}
private :
float _falloff ;
float _cfg_db_s ;
pframes_t _n_samples ;
samplecnt_t _rate ;
} ;
static FallOffCache falloff_cache ;
void
PortManager : : falloff_cache_calc ( pframes_t n_samples , samplecnt_t rate )
{
falloff_cache . calc ( n_samples , rate ) ;
}
2021-01-16 00:45:12 -05:00
PortManager : : AudioInputPort : : AudioInputPort ( samplecnt_t sz )
: scope ( AudioPortScope ( new CircularSampleBuffer ( sz ) ) )
, meter ( AudioPortMeter ( new DPM ) )
2021-10-31 13:17:01 -04:00
{
}
2021-01-16 00:45:12 -05:00
2022-05-16 10:43:39 -04:00
void
PortManager : : AudioInputPort : : apply_falloff ( pframes_t n_samples , samplecnt_t rate , bool reset )
{
if ( reset ) {
meter - > reset ( ) ;
}
if ( meter - > level > 1e-10 ) {
meter - > level * = falloff_cache . calc ( n_samples , rate ) ;
} else {
meter - > level = 0 ;
}
}
void
PortManager : : AudioInputPort : : silence ( pframes_t n_samples )
{
meter - > level = 0 ;
scope - > silence ( n_samples ) ;
}
void
PortManager : : AudioInputPort : : process ( Sample const * buf , pframes_t n_samples , bool reset )
{
scope - > write ( buf , n_samples ) ;
float level = reset ? 0 : meter - > level ;
level = compute_peak ( buf , n_samples , level ) ;
meter - > level = std : : min ( level , 100.f ) ; // cut off at +40dBFS for falloff.
meter - > peak = std : : max ( meter - > peak , level ) ;
}
2021-01-16 00:45:12 -05:00
PortManager : : MIDIInputPort : : MIDIInputPort ( samplecnt_t sz )
: monitor ( MIDIPortMonitor ( new CircularEventBuffer ( sz ) ) )
, meter ( MIDIPortMeter ( new MPM ) )
2021-10-31 13:17:01 -04:00
{
}
2021-01-16 00:45:12 -05:00
2022-05-16 10:43:39 -04:00
void
PortManager : : MIDIInputPort : : apply_falloff ( pframes_t n_samples , samplecnt_t rate , bool reset )
{
for ( size_t i = 0 ; i < 17 ; + + i ) {
/* falloff */
if ( ! reset & & meter - > chn_active [ i ] > 1e-10 ) {
meter - > chn_active [ i ] * = falloff_cache . calc ( n_samples , rate ) ;
} else {
meter - > chn_active [ i ] = 0 ;
}
}
}
void
PortManager : : MIDIInputPort : : process_event ( uint8_t const * buf , size_t size )
{
if ( size = = 0 | | buf [ 0 ] = = 0xfe ) {
/* ignore active sensing */
return ;
}
if ( ( buf [ 0 ] & 0xf0 ) = = 0xf0 ) {
meter - > chn_active [ 16 ] = 1.0 ;
} else {
int chn = ( buf [ 0 ] & 0x0f ) ;
meter - > chn_active [ chn ] = 1.0 ;
}
monitor - > write ( buf , size ) ;
}
2023-02-16 18:33:28 -05:00
PortManager : : PortID : : PortID ( std : : shared_ptr < AudioBackend > b , DataType dt , bool in , std : : string const & pn )
2021-01-10 22:23:15 -05:00
: backend ( b - > name ( ) )
, port_name ( pn )
, data_type ( dt )
, input ( in )
{
if ( dt = = DataType : : MIDI ) {
/* Audio device name is not applicable for MIDI ports */
device_name = " " ;
2021-10-31 13:17:01 -04:00
} else if ( b - > use_separate_input_and_output_devices ( ) ) {
2021-01-10 22:23:15 -05:00
device_name = in ? b - > input_device_name ( ) : b - > output_device_name ( ) ;
} else {
device_name = b - > device_name ( ) ;
}
}
PortManager : : PortID : : PortID ( XMLNode const & node , bool old_midi_format )
: data_type ( DataType : : NIL )
, input ( false )
{
bool err = false ;
if ( node . name ( ) ! = ( old_midi_format ? " port " : " PortID " ) ) {
throw failed_constructor ( ) ;
}
err | = ! node . get_property ( " backend " , backend ) ;
err | = ! node . get_property ( " input " , input ) ;
if ( old_midi_format ) {
err | = ! node . get_property ( " name " , port_name ) ;
2021-10-31 13:17:01 -04:00
data_type = DataType : : MIDI ;
2021-01-10 22:23:15 -05:00
device_name = " " ;
} else {
err | = ! node . get_property ( " device-name " , device_name ) ;
err | = ! node . get_property ( " port-name " , port_name ) ;
err | = ! node . get_property ( " data-type " , data_type ) ;
}
if ( err ) {
throw failed_constructor ( ) ;
}
}
XMLNode &
PortManager : : PortID : : state ( ) const
{
2021-10-31 13:17:01 -04:00
XMLNode * node = new XMLNode ( " PortID " ) ;
2021-01-10 22:23:15 -05:00
node - > set_property ( " backend " , backend ) ;
node - > set_property ( " device-name " , device_name ) ;
node - > set_property ( " port-name " , port_name ) ;
node - > set_property ( " data-type " , data_type ) ;
node - > set_property ( " input " , input ) ;
return * node ;
}
PortManager : : PortMetaData : : PortMetaData ( XMLNode const & node )
{
bool err = false ;
err | = ! node . get_property ( " pretty-name " , pretty_name ) ;
err | = ! node . get_property ( " properties " , properties ) ;
if ( err ) {
throw failed_constructor ( ) ;
}
}
/* ****************************************************************************/
2013-07-24 19:30:08 -04:00
PortManager : : PortManager ( )
2021-05-06 15:10:29 -04:00
: _ports ( new Ports )
2013-07-31 19:47:20 -04:00
, _port_remove_in_progress ( false )
2016-10-13 17:18:42 -04:00
, _port_deletions_pending ( 8192 ) /* ick, arbitrary sizing */
2021-01-10 22:23:15 -05:00
, _midi_info_dirty ( true )
2021-01-16 00:45:12 -05:00
, _audio_input_ports ( new AudioInputPorts )
, _midi_input_ports ( new MIDIInputPorts )
2013-07-24 19:30:08 -04:00
{
2023-02-17 02:31:21 -05:00
_reset_meters . store ( 1 ) ;
2021-01-10 22:23:15 -05:00
load_port_info ( ) ;
2013-07-24 19:30:08 -04:00
}
2016-10-13 17:18:42 -04:00
void
PortManager : : clear_pending_port_deletions ( )
{
Port * p ;
2021-10-31 13:17:01 -04:00
DEBUG_TRACE ( DEBUG : : Ports , string_compose ( " pending port deletions: %1 \n " , _port_deletions_pending . read_space ( ) ) ) ;
2016-10-14 12:30:16 -04:00
2016-10-13 17:18:42 -04:00
while ( _port_deletions_pending . read ( & p , 1 ) = = 1 ) {
delete p ;
}
}
2013-07-24 19:30:08 -04:00
void
2023-12-03 14:38:31 -05:00
PortManager : : remove_session_ports ( )
2013-07-24 19:30:08 -04:00
{
/* make sure that JACK callbacks that will be invoked as we cleanup
* ports know that they have nothing to do .
*/
2020-04-08 02:28:30 -04:00
PBD : : Unwinder < bool > uw ( _port_remove_in_progress , true ) ;
2013-07-24 19:30:08 -04:00
2023-12-03 14:38:31 -05:00
/* process lock MUST be held by caller */
2013-07-24 19:30:08 -04:00
{
2023-12-03 14:38:31 -05:00
RCUWriter < Ports > writer ( _ports ) ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < Ports > ps = writer . get_copy ( ) ;
2023-12-03 14:38:31 -05:00
for ( auto i = ps - > begin ( ) ; i ! = ps - > end ( ) ; ) {
std : : shared_ptr < Port > port = i - > second ;
if ( i - > second - > flags ( ) & TransportMasterPort ) {
+ + i ;
} else {
i = ps - > erase ( i ) ;
}
}
2013-07-24 19:30:08 -04:00
}
/* clear dead wood list in RCU */
2021-05-06 15:10:29 -04:00
_ports . flush ( ) ;
2013-07-24 19:30:08 -04:00
2016-10-13 17:18:42 -04:00
/* clear out pending port deletion list. we know this is safe because
* the auto connect thread in Session is already dead when this is
* done . It doesn ' t use shared_ptr < Port > anyway .
*/
_port_deletions_pending . reset ( ) ;
2013-07-24 19:30:08 -04:00
}
string
2013-07-31 19:47:20 -04:00
PortManager : : make_port_name_relative ( const string & portname ) const
2013-07-24 19:30:08 -04:00
{
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2013-08-01 18:49:40 -04:00
return portname ;
}
2015-10-07 13:16:22 -04:00
string : : size_type colon = portname . find ( ' : ' ) ;
2013-07-24 19:30:08 -04:00
2015-10-07 13:16:22 -04:00
if ( colon = = string : : npos ) {
return portname ;
2013-07-24 19:30:08 -04:00
}
2021-10-31 13:17:01 -04:00
if ( portname . substr ( 0 , colon ) = = _backend - > my_name ( ) ) {
return portname . substr ( colon + 1 ) ;
2013-07-24 19:30:08 -04:00
}
return portname ;
}
string
2013-07-31 19:47:20 -04:00
PortManager : : make_port_name_non_relative ( const string & portname ) const
2013-07-24 19:30:08 -04:00
{
string str ;
if ( portname . find_first_of ( ' : ' ) ! = string : : npos ) {
return portname ;
}
2021-10-31 13:17:01 -04:00
str = _backend - > my_name ( ) ;
2013-07-24 19:30:08 -04:00
str + = ' : ' ;
str + = portname ;
return str ;
}
2015-03-08 12:24:53 -04:00
std : : string
2021-10-31 13:17:01 -04:00
PortManager : : get_pretty_name_by_name ( const std : : string & portname ) const
2015-03-08 12:24:53 -04:00
{
PortEngine : : PortHandle ph = _backend - > get_port_by_name ( portname ) ;
2019-03-07 14:00:51 -05:00
2015-03-08 12:24:53 -04:00
if ( ph ) {
std : : string value ;
std : : string type ;
2019-03-07 14:00:51 -05:00
if ( 0 = = _backend - > get_port_property ( ph , " http://jackaudio.org/metadata/pretty-name " , value , type ) ) {
2015-03-08 12:24:53 -04:00
return value ;
}
}
2019-03-07 14:00:51 -05:00
2021-10-31 13:17:01 -04:00
return string ( ) ;
2015-03-08 12:24:53 -04:00
}
2023-05-02 17:35:31 -04:00
std : : string
PortManager : : get_hardware_port_name_by_name ( const std : : string & portname ) const
{
PortEngine : : PortHandle ph = _backend - > get_port_by_name ( portname ) ;
if ( ph ) {
std : : string value ;
std : : string type ;
if ( 0 = = _backend - > get_port_property ( ph , " http://ardour.org/metadata/hardware-port-name " , value , type ) ) {
return value ;
} else {
return short_port_name_from_port_name ( portname ) ;
}
}
return string ( ) ;
}
2013-07-24 19:30:08 -04:00
bool
2013-07-31 19:47:20 -04:00
PortManager : : port_is_mine ( const string & portname ) const
2013-07-24 19:30:08 -04:00
{
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2013-08-01 18:49:40 -04:00
return true ;
}
2021-10-31 13:17:01 -04:00
string self = _backend - > my_name ( ) ;
2013-07-31 19:47:20 -04:00
2013-07-24 19:30:08 -04:00
if ( portname . find_first_of ( ' : ' ) ! = string : : npos ) {
2013-07-31 19:47:20 -04:00
if ( portname . substr ( 0 , self . length ( ) ) ! = self ) {
2017-10-29 13:36:32 -04:00
return false ;
}
}
2013-07-24 19:30:08 -04:00
2017-10-29 13:36:32 -04:00
return true ;
2013-07-24 19:30:08 -04:00
}
bool
2013-07-31 19:47:20 -04:00
PortManager : : port_is_physical ( const std : : string & portname ) const
2013-07-24 19:30:08 -04:00
{
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2013-08-01 18:49:40 -04:00
return false ;
}
2013-09-13 11:21:15 -04:00
PortEngine : : PortHandle ph = _backend - > get_port_by_name ( portname ) ;
2013-07-31 19:47:20 -04:00
if ( ! ph ) {
2013-07-24 19:30:08 -04:00
return false ;
}
2013-09-13 11:21:15 -04:00
return _backend - > port_is_physical ( ph ) ;
2013-07-24 19:30:08 -04:00
}
2013-08-01 14:43:12 -04:00
void
2016-10-21 16:32:46 -04:00
PortManager : : filter_midi_ports ( vector < string > & ports , MidiPortFlags include , MidiPortFlags exclude )
{
if ( ! include & & ! exclude ) {
return ;
}
2021-01-10 22:23:15 -05:00
Glib : : Threads : : Mutex : : Lock lm ( _port_info_mutex ) ;
fill_midi_port_info_locked ( ) ;
2016-10-21 16:32:46 -04:00
2021-10-31 13:17:01 -04:00
for ( vector < string > : : iterator si = ports . begin ( ) ; si ! = ports . end ( ) ; ) {
2021-01-10 22:23:15 -05:00
PortInfo : : iterator x ;
for ( x = _port_info . begin ( ) ; x ! = _port_info . end ( ) ; + + x ) {
if ( x - > first . data_type ! = DataType : : MIDI ) {
2016-10-21 16:32:46 -04:00
continue ;
}
2021-01-10 22:23:15 -05:00
if ( x - > first . backend ! = _backend - > name ( ) ) {
2016-10-21 16:32:46 -04:00
continue ;
}
2021-01-10 22:23:15 -05:00
if ( x - > first . port_name = = * si ) {
break ;
2018-09-18 18:51:59 -04:00
}
2021-01-10 22:23:15 -05:00
}
2018-09-18 18:51:59 -04:00
2021-10-31 13:17:01 -04:00
if ( x = = _port_info . end ( ) ) {
2021-01-10 22:23:15 -05:00
+ + si ;
continue ;
}
if ( include ) {
if ( ( x - > second . properties & include ) ! = include ) {
/* properties do not include requested ones */
si = ports . erase ( si ) ;
continue ;
2018-09-18 18:51:59 -04:00
}
2021-01-10 22:23:15 -05:00
}
2018-09-18 18:51:59 -04:00
2021-01-10 22:23:15 -05:00
if ( exclude ) {
if ( ( x - > second . properties & exclude ) ) {
/* properties include ones to avoid */
si = ports . erase ( si ) ;
continue ;
}
2018-09-18 18:51:59 -04:00
}
2021-01-10 22:23:15 -05:00
+ + si ;
2016-10-21 16:32:46 -04:00
}
}
void
PortManager : : get_physical_outputs ( DataType type , std : : vector < std : : string > & s , MidiPortFlags include , MidiPortFlags exclude )
2013-08-01 14:43:12 -04:00
{
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2016-04-26 08:35:47 -04:00
s . clear ( ) ;
2013-08-01 18:49:40 -04:00
return ;
}
2013-09-13 11:21:15 -04:00
_backend - > get_physical_outputs ( type , s ) ;
2016-10-21 16:32:46 -04:00
filter_midi_ports ( s , include , exclude ) ;
2013-08-01 14:43:12 -04:00
}
2015-10-04 14:51:05 -04:00
2013-08-01 14:43:12 -04:00
void
2016-10-21 16:32:46 -04:00
PortManager : : get_physical_inputs ( DataType type , std : : vector < std : : string > & s , MidiPortFlags include , MidiPortFlags exclude )
2013-08-01 14:43:12 -04:00
{
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2016-04-26 08:35:47 -04:00
s . clear ( ) ;
2013-08-01 18:49:40 -04:00
return ;
}
2013-09-13 11:21:15 -04:00
_backend - > get_physical_inputs ( type , s ) ;
2016-10-21 16:32:46 -04:00
filter_midi_ports ( s , include , exclude ) ;
2013-08-01 14:43:12 -04:00
}
2015-10-04 14:51:05 -04:00
2013-08-01 14:43:12 -04:00
ChanCount
PortManager : : n_physical_outputs ( ) const
{
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2013-08-01 18:49:40 -04:00
return ChanCount : : ZERO ;
}
2013-09-13 11:21:15 -04:00
return _backend - > n_physical_outputs ( ) ;
2013-08-01 14:43:12 -04:00
}
2015-10-04 14:51:05 -04:00
2013-08-01 14:43:12 -04:00
ChanCount
PortManager : : n_physical_inputs ( ) const
{
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2013-08-01 18:49:40 -04:00
return ChanCount : : ZERO ;
}
2013-09-13 11:21:15 -04:00
return _backend - > n_physical_inputs ( ) ;
2013-08-01 14:43:12 -04:00
}
2013-07-24 19:30:08 -04:00
/** @param name Full or short name of port
* @ return Corresponding Port or 0.
*/
2023-02-16 18:33:28 -05:00
std : : shared_ptr < Port >
2013-07-31 19:47:20 -04:00
PortManager : : get_port_by_name ( const string & portname )
2013-07-24 19:30:08 -04:00
{
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2023-02-16 18:33:28 -05:00
return std : : shared_ptr < Port > ( ) ;
2013-08-01 18:49:40 -04:00
}
2017-10-29 13:36:32 -04:00
if ( ! port_is_mine ( portname ) ) {
/* not an ardour port */
2023-02-16 18:33:28 -05:00
return std : : shared_ptr < Port > ( ) ;
2017-10-29 13:36:32 -04:00
}
2013-07-24 19:30:08 -04:00
2023-04-07 17:33:13 -04:00
std : : shared_ptr < Ports const > pr = _ports . reader ( ) ;
std : : string rel = make_port_name_relative ( portname ) ;
Ports : : const_iterator x = pr - > find ( rel ) ;
2013-07-24 19:30:08 -04:00
2021-10-31 13:17:01 -04:00
if ( x ! = pr - > end ( ) ) {
2013-07-24 19:30:08 -04:00
/* its possible that the port was renamed by some 3rd party and
2017-10-29 13:36:32 -04:00
* 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 ) .
*/
2021-10-31 13:17:01 -04:00
const std : : string check = make_port_name_relative ( _backend - > get_port_name ( x - > second - > port_handle ( ) ) ) ;
2013-07-24 19:30:08 -04:00
if ( check ! = rel ) {
x - > second - > set_name ( check ) ;
}
return x - > second ;
}
2023-02-16 18:33:28 -05:00
return std : : shared_ptr < Port > ( ) ;
2013-07-24 19:30:08 -04:00
}
void
2013-07-31 19:47:20 -04:00
PortManager : : port_renamed ( const std : : string & old_relative_name , const std : : string & new_relative_name )
2013-07-24 19:30:08 -04:00
{
2021-10-31 13:17:01 -04:00
RCUWriter < Ports > writer ( _ports ) ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < Ports > p = writer . get_copy ( ) ;
2021-10-31 13:17:01 -04:00
Ports : : iterator x = p - > find ( old_relative_name ) ;
2015-10-05 10:17:49 -04:00
2021-10-31 13:17:01 -04:00
if ( x ! = p - > end ( ) ) {
2023-02-16 18:33:28 -05:00
std : : shared_ptr < Port > port = x - > second ;
2013-07-24 19:30:08 -04:00
p - > erase ( x ) ;
p - > insert ( make_pair ( new_relative_name , port ) ) ;
}
}
2013-08-07 22:22:11 -04:00
int
PortManager : : get_ports ( DataType type , PortList & pl )
{
2023-04-07 17:33:13 -04:00
std : : shared_ptr < Ports const > plist = _ports . reader ( ) ;
for ( auto const & p : * plist ) {
if ( p . second - > type ( ) = = type ) {
pl . push_back ( p . second ) ;
2013-08-07 22:22:11 -04:00
}
}
2021-10-31 13:17:01 -04:00
return pl . size ( ) ;
2013-08-07 22:22:11 -04:00
}
2013-07-31 19:47:20 -04:00
int
PortManager : : get_ports ( const string & port_name_pattern , DataType type , PortFlags flags , vector < string > & s )
2013-07-24 19:30:08 -04:00
{
2021-10-31 13:17:01 -04:00
s . clear ( ) ;
2015-05-03 20:06:59 -04:00
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2013-08-01 18:49:40 -04:00
return 0 ;
}
2016-07-09 12:20:54 -04:00
return _backend - > get_ports ( port_name_pattern , type , flags , s ) ;
2013-07-24 19:30:08 -04:00
}
2022-09-20 17:51:52 -04:00
size_t
PortManager : : session_port_count ( ) const
{
size_t cnt = 0 ;
for ( auto const & p : * _ports . reader ( ) ) {
if ( p . second - > flags ( ) & TransportSyncPort ) {
continue ;
}
+ + cnt ;
}
return cnt ;
}
2013-07-24 19:30:08 -04:00
void
2013-07-31 19:47:20 -04:00
PortManager : : port_registration_failure ( const std : : string & portname )
2013-07-24 19:30:08 -04:00
{
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2013-08-01 18:49:40 -04:00
return ;
}
2021-10-31 13:17:01 -04:00
string full_portname = _backend - > my_name ( ) ;
2013-07-24 19:30:08 -04:00
full_portname + = ' : ' ;
full_portname + = portname ;
2013-09-13 11:21:15 -04:00
PortEngine : : PortHandle p = _backend - > get_port_by_name ( full_portname ) ;
2021-10-31 13:17:01 -04:00
string reason ;
2013-07-24 19:30:08 -04:00
if ( p ) {
reason = string_compose ( _ ( " a port with the name \" %1 \" already exists: check for duplicated track/bus names " ) , portname ) ;
} else {
2013-07-31 19:47:20 -04:00
reason = string_compose ( _ ( " No more ports are available. You will need to stop %1 and restart with more ports if you need this many tracks. " ) , PROGRAM_NAME ) ;
2013-07-24 19:30:08 -04:00
}
2021-10-31 13:17:01 -04:00
throw PortRegistrationFailure ( string_compose ( _ ( " AudioEngine: cannot register port \" %1 \" : %2 " ) , portname , reason ) . c_str ( ) ) ;
2013-07-24 19:30:08 -04:00
}
2021-10-31 13:17:01 -04:00
struct PortDeleter {
void operator ( ) ( Port * p )
{
AudioEngine : : instance ( ) - > add_pending_port_deletion ( p ) ;
2016-10-13 17:18:42 -04:00
}
} ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < Port >
2016-06-20 12:47:05 -04:00
PortManager : : register_port ( DataType dtype , const string & portname , bool input , bool async , PortFlags flags )
2013-07-24 19:30:08 -04:00
{
2023-02-16 18:33:28 -05:00
std : : shared_ptr < Port > newport ;
2013-07-24 19:30:08 -04:00
2016-06-20 12:47:05 -04:00
/* limit the possible flags that can be set */
2021-10-31 13:17:01 -04:00
flags = PortFlags ( flags & ( Hidden | Shadow | IsTerminal | TransportSyncPort ) ) ;
2016-06-20 12:47:05 -04:00
2013-07-24 19:30:08 -04:00
try {
if ( dtype = = DataType : : AUDIO ) {
2013-08-07 22:22:11 -04:00
DEBUG_TRACE ( DEBUG : : Ports , string_compose ( " registering AUDIO port %1, input %2 \n " ,
2021-10-31 13:17:01 -04:00
portname , input ) ) ;
2016-10-13 17:18:42 -04:00
newport . reset ( new AudioPort ( portname , PortFlags ( ( input ? IsInput : IsOutput ) | flags ) ) ,
2021-10-31 13:17:01 -04:00
PortDeleter ( ) ) ;
2013-07-24 19:30:08 -04:00
} else if ( dtype = = DataType : : MIDI ) {
2013-08-07 22:22:11 -04:00
if ( async ) {
DEBUG_TRACE ( DEBUG : : Ports , string_compose ( " registering ASYNC MIDI port %1, input %2 \n " ,
2021-10-31 13:17:01 -04:00
portname , input ) ) ;
2016-10-13 17:18:42 -04:00
newport . reset ( new AsyncMIDIPort ( portname , PortFlags ( ( input ? IsInput : IsOutput ) | flags ) ) ,
2021-10-31 13:17:01 -04:00
PortDeleter ( ) ) ;
2021-01-21 23:19:47 -05:00
_midi_info_dirty = true ;
2013-08-07 22:22:11 -04:00
} else {
DEBUG_TRACE ( DEBUG : : Ports , string_compose ( " registering MIDI port %1, input %2 \n " ,
2021-10-31 13:17:01 -04:00
portname , input ) ) ;
2016-10-13 17:18:42 -04:00
newport . reset ( new MidiPort ( portname , PortFlags ( ( input ? IsInput : IsOutput ) | flags ) ) ,
2021-10-31 13:17:01 -04:00
PortDeleter ( ) ) ;
2013-08-07 22:22:11 -04:00
}
2013-07-24 19:30:08 -04:00
} else {
2019-02-15 12:27:22 -05:00
throw PortRegistrationFailure ( string_compose ( " unable to create port '%1': %2 " , portname , _ ( " (unknown type) " ))) ;
2013-07-24 19:30:08 -04:00
}
2021-10-31 13:17:01 -04:00
newport - > set_buffer_size ( AudioEngine : : instance ( ) - > samples_per_cycle ( ) ) ;
2019-07-11 01:39:02 -04:00
2021-10-31 13:17:01 -04:00
RCUWriter < Ports > writer ( _ports ) ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < Ports > ps = writer . get_copy ( ) ;
2013-07-24 19:30:08 -04:00
ps - > insert ( make_pair ( make_port_name_relative ( portname ) , newport ) ) ;
/* writer goes out of scope, forces update */
}
catch ( PortRegistrationFailure & err ) {
throw err ;
} catch ( std : : exception & e ) {
2021-10-31 13:17:01 -04:00
throw PortRegistrationFailure ( string_compose ( " unable to create port '%1': %2 " , portname , e . what ( ) ) . c_str ( ) ) ;
2013-07-24 19:30:08 -04:00
} catch ( . . . ) {
2019-02-15 12:27:22 -05:00
throw PortRegistrationFailure ( string_compose ( " unable to create port '%1': %2 " , portname , _ ( " (unknown error) " ))) ;
2013-07-24 19:30:08 -04:00
}
2013-08-07 22:22:11 -04:00
2021-10-31 13:17:01 -04:00
DEBUG_TRACE ( DEBUG : : Ports , string_compose ( " \t %2 port registration success, ports now = %1 \n " , _ports . reader ( ) - > size ( ) , this ) ) ;
2013-08-07 22:22:11 -04:00
return newport ;
2013-07-24 19:30:08 -04:00
}
2023-02-16 18:33:28 -05:00
std : : shared_ptr < Port >
2016-06-20 12:47:05 -04:00
PortManager : : register_input_port ( DataType type , const string & portname , bool async , PortFlags extra_flags )
2013-07-24 19:30:08 -04:00
{
2016-06-20 12:47:05 -04:00
return register_port ( type , portname , true , async , extra_flags ) ;
2013-07-24 19:30:08 -04:00
}
2023-02-16 18:33:28 -05:00
std : : shared_ptr < Port >
2016-06-20 12:47:05 -04:00
PortManager : : register_output_port ( DataType type , const string & portname , bool async , PortFlags extra_flags )
2013-07-24 19:30:08 -04:00
{
2016-06-20 12:47:05 -04:00
return register_port ( type , portname , false , async , extra_flags ) ;
2013-07-24 19:30:08 -04:00
}
int
2023-02-16 18:33:28 -05:00
PortManager : : unregister_port ( std : : shared_ptr < Port > port )
2013-07-24 19:30:08 -04:00
{
2016-08-08 08:26:58 -04:00
/* This is a little subtle. We do not call the backend's port
* unregistration code from here . That is left for the Port
* destructor . We are trying to drop references to the Port object
* here , so that its destructor will run and it will unregister itself .
*/
2013-07-24 19:30:08 -04:00
/* caller must hold process lock */
{
2021-10-31 13:17:01 -04:00
RCUWriter < Ports > writer ( _ports ) ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < Ports > ps = writer . get_copy ( ) ;
2021-10-31 13:17:01 -04:00
Ports : : iterator x = ps - > find ( make_port_name_relative ( port - > name ( ) ) ) ;
2013-07-24 19:30:08 -04:00
2021-10-31 13:17:01 -04:00
if ( x ! = ps - > end ( ) ) {
DEBUG_TRACE ( DEBUG : : Ports , string_compose ( " removing %1 from port map (uc=%2) \n " , port - > name ( ) , port . use_count ( ) ) ) ;
2013-07-24 19:30:08 -04:00
ps - > erase ( x ) ;
}
/* writer goes out of scope, forces update */
}
2021-05-06 15:10:29 -04:00
_ports . flush ( ) ;
2013-07-24 19:30:08 -04:00
return 0 ;
}
bool
PortManager : : connected ( const string & port_name )
{
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2013-08-01 18:49:40 -04:00
return false ;
}
2013-09-13 11:21:15 -04:00
PortEngine : : PortHandle handle = _backend - > get_port_by_name ( port_name ) ;
2013-07-24 19:30:08 -04:00
if ( ! handle ) {
return false ;
}
2013-09-13 11:21:15 -04:00
return _backend - > connected ( handle ) ;
2013-07-24 19:30:08 -04:00
}
2016-04-26 08:35:47 -04:00
bool
PortManager : : physically_connected ( const string & port_name )
{
if ( ! _backend ) {
return false ;
}
PortEngine : : PortHandle handle = _backend - > get_port_by_name ( port_name ) ;
if ( ! handle ) {
return false ;
}
return _backend - > physically_connected ( handle ) ;
}
int
PortManager : : get_connections ( const string & port_name , std : : vector < std : : string > & s )
{
if ( ! _backend ) {
s . clear ( ) ;
return 0 ;
}
PortEngine : : PortHandle handle = _backend - > get_port_by_name ( port_name ) ;
if ( ! handle ) {
s . clear ( ) ;
return 0 ;
}
return _backend - > get_connections ( handle , s ) ;
}
2013-07-24 19:30:08 -04:00
int
2013-07-31 19:47:20 -04:00
PortManager : : connect ( const string & source , const string & destination )
2013-07-24 19:30:08 -04:00
{
int ret ;
string s = make_port_name_non_relative ( source ) ;
string d = make_port_name_non_relative ( destination ) ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < Port > src = get_port_by_name ( s ) ;
std : : shared_ptr < Port > dst = get_port_by_name ( d ) ;
2013-07-24 19:30:08 -04:00
if ( src ) {
ret = src - > connect ( d ) ;
} else if ( dst ) {
ret = dst - > connect ( s ) ;
} else {
2013-09-05 21:39:43 -04:00
/* neither port is known to us ...hand-off to the PortEngine
*/
2013-09-13 11:21:15 -04:00
if ( _backend ) {
ret = _backend - > connect ( s , d ) ;
2013-09-05 21:39:43 -04:00
} else {
ret = - 1 ;
}
2013-07-24 19:30:08 -04:00
}
if ( ret > 0 ) {
/* already exists - no error, no warning */
} else if ( ret < 0 ) {
2021-10-31 13:17:01 -04:00
error < < string_compose ( _ ( " AudioEngine: cannot connect %1 (%2) to %3 (%4) " ) ,
source , s , destination , d )
2013-07-24 19:30:08 -04:00
< < endmsg ;
}
return ret ;
}
int
2013-07-31 19:47:20 -04:00
PortManager : : disconnect ( const string & source , const string & destination )
2013-07-24 19:30:08 -04:00
{
int ret ;
string s = make_port_name_non_relative ( source ) ;
string d = make_port_name_non_relative ( destination ) ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < Port > src = get_port_by_name ( s ) ;
std : : shared_ptr < Port > dst = get_port_by_name ( d ) ;
2013-07-24 19:30:08 -04:00
if ( src ) {
2013-09-05 21:39:43 -04:00
ret = src - > disconnect ( d ) ;
2013-07-24 19:30:08 -04:00
} else if ( dst ) {
2013-09-05 21:39:43 -04:00
ret = dst - > disconnect ( s ) ;
2013-07-24 19:30:08 -04:00
} else {
2013-09-05 21:39:43 -04:00
/* neither port is known to us ...hand-off to the PortEngine
*/
2013-09-13 11:21:15 -04:00
if ( _backend ) {
ret = _backend - > disconnect ( s , d ) ;
2013-09-05 21:39:43 -04:00
} else {
ret = - 1 ;
}
2013-07-24 19:30:08 -04:00
}
return ret ;
}
int
2023-02-16 18:33:28 -05:00
PortManager : : disconnect ( std : : shared_ptr < Port > port )
2013-07-24 19:30:08 -04:00
{
return port - > disconnect_all ( ) ;
}
2016-10-19 23:17:08 -04:00
int
2021-10-31 13:17:01 -04:00
PortManager : : disconnect ( std : : string const & name )
2016-10-19 23:17:08 -04:00
{
PortEngine : : PortHandle ph = _backend - > get_port_by_name ( name ) ;
if ( ph ) {
return _backend - > disconnect_all ( ph ) ;
}
return - 2 ;
}
2013-07-30 17:48:57 -04:00
int
PortManager : : reestablish_ports ( )
{
2023-04-07 17:33:13 -04:00
_midi_info_dirty = true ;
Ports : : const_iterator i ;
std : : shared_ptr < Ports const > p = _ports . reader ( ) ;
2021-10-31 13:17:01 -04:00
DEBUG_TRACE ( DEBUG : : Ports , string_compose ( " reestablish %1 ports \n " , p - > size ( ) ) ) ;
2013-08-07 22:22:11 -04:00
2021-10-31 13:17:01 -04:00
for ( i = p - > begin ( ) ; i ! = p - > end ( ) ; + + i ) {
2013-07-30 17:48:57 -04:00
if ( i - > second - > reestablish ( ) ) {
2021-10-31 13:17:01 -04:00
error < < string_compose ( _ ( " Re-establising port %1 failed " ) , i - > second - > name ( ) ) < < endmsg ;
std : : cerr < < string_compose ( _ ( " Re-establising port %1 failed " ) , i - > second - > name ( ) ) < < std : : endl ;
2013-07-30 17:48:57 -04:00
break ;
}
}
2021-10-31 13:17:01 -04:00
if ( i ! = p - > end ( ) ) {
2013-07-30 17:48:57 -04:00
/* failed */
2023-12-03 14:38:31 -05:00
remove_session_ports ( ) ;
2013-07-30 17:48:57 -04:00
return - 1 ;
}
2021-10-31 13:17:01 -04:00
if ( ! _backend - > info ( ) . already_configured ( ) ) {
2021-01-10 22:23:15 -05:00
std : : vector < std : : string > port_names ;
get_physical_inputs ( DataType : : AUDIO , port_names ) ;
set_pretty_names ( port_names , DataType : : AUDIO , true ) ;
port_names . clear ( ) ;
get_physical_outputs ( DataType : : AUDIO , port_names ) ;
set_pretty_names ( port_names , DataType : : AUDIO , false ) ;
port_names . clear ( ) ;
get_physical_inputs ( DataType : : MIDI , port_names ) ;
set_pretty_names ( port_names , DataType : : MIDI , true ) ;
port_names . clear ( ) ;
get_physical_outputs ( DataType : : MIDI , port_names ) ;
set_pretty_names ( port_names , DataType : : MIDI , false ) ;
}
2021-10-31 13:17:01 -04:00
if ( Config - > get_work_around_jack_no_copy_optimization ( ) & & AudioEngine : : instance ( ) - > current_backend_name ( ) = = X_ ( " JACK " ) ) {
port_engine ( ) . register_port ( X_ ( " physical_audio_input_monitor_enable " ) , DataType : : AUDIO , ARDOUR : : PortFlags ( IsInput | IsTerminal | Hidden ) ) ;
port_engine ( ) . register_port ( X_ ( " physical_midi_input_monitor_enable " ) , DataType : : MIDI , ARDOUR : : PortFlags ( IsInput | IsTerminal | Hidden ) ) ;
2021-03-20 19:06:44 -04:00
}
2021-01-16 00:45:12 -05:00
update_input_ports ( true ) ;
2013-07-30 17:48:57 -04:00
return 0 ;
}
2021-01-10 22:23:15 -05:00
void
PortManager : : set_pretty_names ( std : : vector < std : : string > const & port_names , DataType dt , bool input )
{
Glib : : Threads : : Mutex : : Lock lm ( _port_info_mutex ) ;
2021-10-31 13:17:01 -04:00
for ( std : : vector < std : : string > : : const_iterator p = port_names . begin ( ) ; p ! = port_names . end ( ) ; + + p ) {
2021-01-10 22:23:15 -05:00
if ( port_is_mine ( * p ) ) {
continue ;
}
PortEngine : : PortHandle ph = _backend - > get_port_by_name ( * p ) ;
if ( ! ph ) {
continue ;
}
2021-10-31 13:17:01 -04:00
PortID pid ( _backend , dt , input , * p ) ;
2021-01-10 22:23:15 -05:00
PortInfo : : iterator x = _port_info . find ( pid ) ;
2021-10-31 13:17:01 -04:00
if ( x = = _port_info . end ( ) ) {
2021-01-10 22:23:15 -05:00
continue ;
}
2021-10-31 13:17:01 -04:00
_backend - > set_port_property ( ph , " http://jackaudio.org/metadata/pretty-name " , x - > second . pretty_name , string ( ) ) ;
2021-01-10 22:23:15 -05:00
}
}
2013-07-30 17:48:57 -04:00
int
PortManager : : reconnect_ports ( )
{
2023-04-07 17:33:13 -04:00
std : : shared_ptr < Ports const > p = _ports . reader ( ) ;
2013-07-30 17:48:57 -04:00
2019-09-25 15:02:31 -04:00
/* re-establish connections */
2015-10-05 10:17:49 -04:00
2021-10-31 13:17:01 -04:00
DEBUG_TRACE ( DEBUG : : Ports , string_compose ( " reconnect %1 ports \n " , p - > size ( ) ) ) ;
2015-10-05 10:17:49 -04:00
2023-05-26 16:30:46 -04:00
Session * s = AudioEngine : : instance ( ) - > session ( ) ;
if ( s & & s - > master_out ( ) & & ! s - > master_out ( ) - > output ( ) - > has_ext_connection ( ) ) {
s - > auto_connect_master_bus ( ) ;
}
if ( s & & s - > monitor_out ( ) & & ! s - > monitor_out ( ) - > output ( ) - > has_ext_connection ( ) ) {
s - > auto_connect_monitor_bus ( ) ;
}
2023-06-26 15:45:28 -04:00
if ( s & & s - > click_io ( ) & & ! s - > click_io ( ) - > has_ext_connection ( ) ) {
s - > auto_connect_io ( s - > click_io ( ) ) ;
}
2023-05-26 16:30:46 -04:00
2023-04-07 17:33:13 -04:00
for ( auto const & i : * p ) {
if ( i . second - > reconnect ( ) ) {
PortConnectedOrDisconnected ( i . second , i . first , std : : weak_ptr < Port > ( ) , " " , false ) ;
2021-02-03 22:40:53 -05:00
}
2013-07-30 17:48:57 -04:00
}
2021-10-31 13:17:01 -04:00
if ( Config - > get_work_around_jack_no_copy_optimization ( ) & & AudioEngine : : instance ( ) - > current_backend_name ( ) = = X_ ( " JACK " ) ) {
std : : string const audio_port = AudioEngine : : instance ( ) - > make_port_name_non_relative ( X_ ( " physical_audio_input_monitor_enable " ) ) ;
std : : string const midi_port = AudioEngine : : instance ( ) - > make_port_name_non_relative ( X_ ( " physical_midi_input_monitor_enable " ) ) ;
2021-06-13 11:40:34 -04:00
std : : vector < std : : string > audio_ports ;
2021-10-31 13:10:28 -04:00
std : : vector < std : : string > midi_ports ;
2021-06-13 11:40:34 -04:00
get_physical_inputs ( DataType : : AUDIO , audio_ports ) ;
2021-10-31 13:10:28 -04:00
get_physical_inputs ( DataType : : MIDI , midi_ports ) ;
2021-10-31 13:17:01 -04:00
for ( std : : vector < std : : string > : : iterator p = audio_ports . begin ( ) ; p ! = audio_ports . end ( ) ; + + p ) {
port_engine ( ) . connect ( * p , audio_port ) ;
2021-10-31 13:10:28 -04:00
}
2021-10-31 13:17:01 -04:00
for ( std : : vector < std : : string > : : iterator p = midi_ports . begin ( ) ; p ! = midi_ports . end ( ) ; + + p ) {
port_engine ( ) . connect ( * p , midi_port ) ;
2021-06-13 11:40:34 -04:00
}
}
2013-07-30 17:48:57 -04:00
return 0 ;
}
2013-07-31 19:47:20 -04:00
void
PortManager : : connect_callback ( const string & a , const string & b , bool conn )
{
2019-10-28 18:07:38 -04:00
DEBUG_TRACE ( DEBUG : : BackendCallbacks , string_compose ( X_ ( " connect callback %1 + %2 connected ? %3 \n " ) , a , b , conn ) ) ;
2023-04-07 17:33:13 -04:00
std : : shared_ptr < Port > port_a ;
std : : shared_ptr < Port > port_b ;
Ports : : const_iterator x ;
std : : shared_ptr < Ports const > pr = _ports . reader ( ) ;
2013-07-31 19:47:20 -04:00
x = pr - > find ( make_port_name_relative ( a ) ) ;
2021-10-31 13:17:01 -04:00
if ( x ! = pr - > end ( ) ) {
2013-07-31 19:47:20 -04:00
port_a = x - > second ;
}
x = pr - > find ( make_port_name_relative ( b ) ) ;
2021-10-31 13:17:01 -04:00
if ( x ! = pr - > end ( ) ) {
2013-07-31 19:47:20 -04:00
port_b = x - > second ;
}
2018-09-18 18:51:59 -04:00
if ( conn ) {
if ( port_a & & ! port_b ) {
port_a - > increment_external_connections ( ) ;
} else if ( port_b & & ! port_a ) {
port_b - > increment_external_connections ( ) ;
2023-03-07 09:28:59 -05:00
} else if ( port_a & & port_b ) {
port_a - > increment_internal_connections ( ) ;
port_a - > increment_internal_connections ( ) ;
2018-09-18 18:51:59 -04:00
}
} else {
if ( port_a & & ! port_b ) {
port_a - > decrement_external_connections ( ) ;
} else if ( port_b & & ! port_a ) {
port_b - > decrement_external_connections ( ) ;
2023-03-07 09:28:59 -05:00
} else if ( port_a & & port_b ) {
port_a - > decrement_internal_connections ( ) ;
port_a - > decrement_internal_connections ( ) ;
2018-09-18 18:51:59 -04:00
}
}
2013-07-31 19:47:20 -04:00
PortConnectedOrDisconnected (
2021-10-31 13:17:01 -04:00
port_a , a ,
port_b , b ,
conn ) ; /* EMIT SIGNAL */
2015-10-05 10:17:49 -04:00
}
2013-07-31 19:47:20 -04:00
void
PortManager : : registration_callback ( )
{
2019-10-28 18:07:38 -04:00
DEBUG_TRACE ( DEBUG : : BackendCallbacks , " port registration callback \n " ) ;
2021-01-10 22:23:15 -05:00
if ( _port_remove_in_progress ) {
return ;
}
2016-10-20 16:34:06 -04:00
2021-01-16 00:45:12 -05:00
update_input_ports ( false ) ;
2021-01-10 22:23:15 -05:00
PortRegisteredOrUnregistered ( ) ; /* EMIT SIGNAL */
2013-07-31 19:47:20 -04:00
}
2013-08-01 14:43:12 -04:00
2021-10-31 13:10:28 -04:00
struct MIDIConnectCall {
MIDIConnectCall ( std : : vector < std : : string > const & pl )
: port_list ( pl )
2021-10-31 13:17:01 -04:00
{
}
2021-10-31 13:10:28 -04:00
std : : vector < std : : string > port_list ;
} ;
static void *
2021-10-31 13:17:01 -04:00
_midi_connect ( void * arg )
2021-10-31 13:10:28 -04:00
{
2021-10-31 13:17:01 -04:00
MIDIConnectCall * mcl = static_cast < MIDIConnectCall * > ( arg ) ;
std : : string const our_name = AudioEngine : : instance ( ) - > make_port_name_non_relative ( X_ ( " physical_midi_input_monitor_enable " ) ) ;
2021-10-31 13:10:28 -04:00
for ( vector < string > : : const_iterator p = mcl - > port_list . begin ( ) ; p ! = mcl - > port_list . end ( ) ; + + p ) {
2021-10-31 13:17:01 -04:00
AudioEngine : : instance ( ) - > connect ( * p , our_name ) ;
2021-10-31 13:10:28 -04:00
}
delete mcl ;
return 0 ;
}
2021-01-16 00:45:12 -05:00
void
PortManager : : update_input_ports ( bool clear )
{
std : : vector < std : : string > audio_ports ;
std : : vector < std : : string > midi_ports ;
std : : vector < std : : string > new_audio ;
std : : vector < std : : string > old_audio ;
std : : vector < std : : string > new_midi ;
std : : vector < std : : string > old_midi ;
get_physical_inputs ( DataType : : AUDIO , audio_ports ) ;
get_physical_inputs ( DataType : : MIDI , midi_ports ) ;
if ( clear ) {
new_audio = audio_ports ;
new_midi = midi_ports ;
2021-02-07 08:02:50 -05:00
_monitor_port . clear_ports ( true ) ;
2021-01-16 00:45:12 -05:00
} else {
2023-04-07 17:33:13 -04:00
std : : shared_ptr < AudioInputPorts const > aip = _audio_input_ports . reader ( ) ;
2021-01-16 00:45:12 -05:00
/* find new audio ports */
2021-10-31 13:17:01 -04:00
for ( std : : vector < std : : string > : : iterator p = audio_ports . begin ( ) ; p ! = audio_ports . end ( ) ; + + p ) {
2021-01-16 00:45:12 -05:00
if ( port_is_mine ( * p ) | | ! _backend - > get_port_by_name ( * p ) ) {
continue ;
}
if ( aip - > find ( * p ) = = aip - > end ( ) ) {
new_audio . push_back ( * p ) ;
}
}
/* find stale audio ports */
2023-04-07 17:33:13 -04:00
for ( auto const & p : * aip ) {
if ( std : : find ( audio_ports . begin ( ) , audio_ports . end ( ) , p . first ) = = audio_ports . end ( ) ) {
old_audio . push_back ( p . first ) ;
2021-01-16 00:45:12 -05:00
}
}
2023-04-07 17:33:13 -04:00
std : : shared_ptr < MIDIInputPorts const > mip = _midi_input_ports . reader ( ) ;
2021-01-16 00:45:12 -05:00
/* find new MIDI ports */
2021-10-31 13:17:01 -04:00
for ( std : : vector < std : : string > : : iterator p = midi_ports . begin ( ) ; p ! = midi_ports . end ( ) ; + + p ) {
2021-01-16 00:45:12 -05:00
if ( port_is_mine ( * p ) | | ! _backend - > get_port_by_name ( * p ) ) {
continue ;
}
2021-03-26 11:46:15 -04:00
# ifdef HAVE_ALSA
if ( ( * p ) . find ( X_ ( " Midi Through " ) ) ! = string : : npos | | ( * p ) . find ( X_ ( " Midi-Through " ) ) ! = string : : npos ) {
continue ;
}
# endif
2021-01-16 00:45:12 -05:00
if ( mip - > find ( * p ) = = mip - > end ( ) ) {
new_midi . push_back ( * p ) ;
}
}
/* find stale audio ports */
2023-04-07 17:33:13 -04:00
for ( auto const & p : * mip ) {
if ( std : : find ( midi_ports . begin ( ) , midi_ports . end ( ) , p . first ) = = midi_ports . end ( ) ) {
old_midi . push_back ( p . first ) ;
2021-01-16 00:45:12 -05:00
}
}
}
if ( ! new_audio . empty ( ) | | ! old_audio . empty ( ) | | clear ) {
2021-10-31 13:17:01 -04:00
RCUWriter < AudioInputPorts > apwr ( _audio_input_ports ) ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < AudioInputPorts > apw = apwr . get_copy ( ) ;
2021-01-16 00:45:12 -05:00
if ( clear ) {
apw - > clear ( ) ;
} else {
2021-10-31 13:17:01 -04:00
for ( std : : vector < std : : string > : : const_iterator p = old_audio . begin ( ) ; p ! = old_audio . end ( ) ; + + p ) {
2021-01-16 00:45:12 -05:00
apw - > erase ( * p ) ;
2021-02-07 08:02:50 -05:00
_monitor_port . remove_port ( * p , true ) ;
2021-01-16 00:45:12 -05:00
}
}
2021-10-31 13:17:01 -04:00
for ( std : : vector < std : : string > : : const_iterator p = new_audio . begin ( ) ; p ! = new_audio . end ( ) ; + + p ) {
2021-01-16 00:45:12 -05:00
if ( port_is_mine ( * p ) | | ! _backend - > get_port_by_name ( * p ) ) {
continue ;
}
apw - > insert ( make_pair ( * p , AudioInputPort ( 24288 ) ) ) ; // 2^19 ~ 1MB / port
}
}
2021-10-31 13:10:28 -04:00
std : : vector < std : : string > physical_midi_connection_list ;
2021-01-16 00:45:12 -05:00
if ( ! new_midi . empty ( ) | | ! old_midi . empty ( ) | | clear ) {
2021-10-31 13:17:01 -04:00
RCUWriter < MIDIInputPorts > mpwr ( _midi_input_ports ) ;
2023-02-16 18:33:28 -05:00
std : : shared_ptr < MIDIInputPorts > mpw = mpwr . get_copy ( ) ;
2021-01-16 00:45:12 -05:00
if ( clear ) {
mpw - > clear ( ) ;
} else {
2021-10-31 13:17:01 -04:00
for ( std : : vector < std : : string > : : const_iterator p = old_midi . begin ( ) ; p ! = old_midi . end ( ) ; + + p ) {
2021-01-16 00:45:12 -05:00
mpw - > erase ( * p ) ;
}
}
2021-10-31 13:17:01 -04:00
for ( std : : vector < std : : string > : : const_iterator p = new_midi . begin ( ) ; p ! = new_midi . end ( ) ; + + p ) {
2021-01-16 00:45:12 -05:00
if ( port_is_mine ( * p ) | | ! _backend - > get_port_by_name ( * p ) ) {
continue ;
}
2021-03-26 11:46:15 -04:00
# ifdef HAVE_ALSA
if ( ( * p ) . find ( X_ ( " Midi Through " ) ) ! = string : : npos | | ( * p ) . find ( X_ ( " Midi-Through " ) ) ! = string : : npos ) {
continue ;
}
# endif
2021-01-16 00:45:12 -05:00
mpw - > insert ( make_pair ( * p , MIDIInputPort ( 32 ) ) ) ;
2021-08-04 07:41:40 -04:00
2021-10-31 13:17:01 -04:00
if ( Config - > get_work_around_jack_no_copy_optimization ( ) & & AudioEngine : : instance ( ) - > current_backend_name ( ) = = X_ ( " JACK " ) ) {
2021-10-31 13:10:28 -04:00
physical_midi_connection_list . push_back ( * p ) ;
2021-08-04 07:41:40 -04:00
}
2021-01-16 00:45:12 -05:00
}
}
if ( clear ) {
2022-05-08 20:20:45 -04:00
/* don't send notification for initial setup.
2021-10-31 13:10:28 -04:00
* Physical I / O is initially connected in
* reconnect_ports ( ) , it is too early to
* do this when called from : : reestablish_ports ( )
* " JACK: Cannot connect ports owned by inactive clients "
*/
2021-01-16 00:45:12 -05:00
return ;
}
2021-10-31 13:10:28 -04:00
if ( ! physical_midi_connection_list . empty ( ) ) {
/* handle hotplug, connect in bg thread, because
* " JACK: Cannot callback the server in notification thread! "
*/
2021-10-31 13:17:01 -04:00
pthread_t thread ;
2021-10-31 13:10:28 -04:00
MIDIConnectCall * mcl = new MIDIConnectCall ( physical_midi_connection_list ) ;
pthread_create_and_store ( " midi-connect " , & thread , _midi_connect , mcl ) ;
pthread_detach ( thread ) ;
}
2021-01-16 00:45:12 -05:00
if ( ! old_audio . empty ( ) ) {
PhysInputChanged ( DataType : : AUDIO , old_audio , false ) ;
}
if ( ! old_midi . empty ( ) ) {
PhysInputChanged ( DataType : : MIDI , old_midi , false ) ;
}
if ( ! new_audio . empty ( ) ) {
PhysInputChanged ( DataType : : AUDIO , new_audio , true ) ;
}
if ( ! new_midi . empty ( ) ) {
PhysInputChanged ( DataType : : MIDI , new_midi , true ) ;
}
}
2013-08-01 14:43:12 -04:00
bool
PortManager : : can_request_input_monitoring ( ) const
{
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2013-08-01 18:49:40 -04:00
return false ;
}
2013-09-13 11:21:15 -04:00
return _backend - > can_monitor_input ( ) ;
2013-08-01 14:43:12 -04:00
}
2015-10-04 14:51:05 -04:00
2013-08-01 14:43:12 -04:00
void
PortManager : : request_input_monitoring ( const string & name , bool yn ) const
{
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2013-08-01 18:49:40 -04:00
return ;
}
2013-09-13 11:21:15 -04:00
PortEngine : : PortHandle ph = _backend - > get_port_by_name ( name ) ;
2013-08-01 14:43:12 -04:00
if ( ph ) {
2013-09-13 11:21:15 -04:00
_backend - > request_input_monitoring ( ph , yn ) ;
2013-08-01 14:43:12 -04:00
}
}
2015-10-04 14:51:05 -04:00
2013-08-01 14:43:12 -04:00
void
PortManager : : ensure_input_monitoring ( const string & name , bool yn ) const
{
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2013-08-01 18:49:40 -04:00
return ;
}
2013-09-13 11:21:15 -04:00
PortEngine : : PortHandle ph = _backend - > get_port_by_name ( name ) ;
2013-08-01 14:43:12 -04:00
if ( ph ) {
2013-09-13 11:21:15 -04:00
_backend - > ensure_input_monitoring ( ph , yn ) ;
2013-08-01 14:43:12 -04:00
}
}
2013-08-01 18:49:40 -04:00
uint32_t
2021-10-31 13:17:01 -04:00
PortManager : : port_name_size ( ) const
2013-08-01 18:49:40 -04:00
{
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2013-08-01 18:49:40 -04:00
return 0 ;
}
2015-10-05 10:17:49 -04:00
2013-09-13 11:21:15 -04:00
return _backend - > port_name_size ( ) ;
2013-08-01 18:49:40 -04:00
}
string
2021-10-31 13:17:01 -04:00
PortManager : : my_name ( ) const
2013-08-01 18:49:40 -04:00
{
2013-09-13 11:21:15 -04:00
if ( ! _backend ) {
2021-10-31 13:17:01 -04:00
return string ( ) ;
2013-08-01 18:49:40 -04:00
}
2015-10-05 10:17:49 -04:00
2021-10-31 13:17:01 -04:00
return _backend - > my_name ( ) ;
2013-08-01 18:49:40 -04:00
}
int
PortManager : : graph_order_callback ( )
{
2019-10-28 18:07:38 -04:00
DEBUG_TRACE ( DEBUG : : BackendCallbacks , " graph order callback \n " ) ;
2013-08-01 18:49:40 -04:00
if ( ! _port_remove_in_progress ) {
2021-10-31 13:17:01 -04:00
GraphReordered ( ) ; /* EMIT SIGNAL */
2013-08-01 18:49:40 -04:00
}
return 0 ;
}
2013-08-07 22:22:11 -04:00
void
2017-10-30 10:58:36 -04:00
PortManager : : cycle_start ( pframes_t nframes , Session * s )
2013-08-07 22:22:11 -04:00
{
Port : : set_global_port_buffer_offset ( 0 ) ;
2017-10-29 13:30:18 -04:00
Port : : set_cycle_samplecnt ( nframes ) ;
2013-08-07 22:22:11 -04:00
2021-05-06 15:10:29 -04:00
_cycle_ports = _ports . reader ( ) ;
2013-08-07 22:22:11 -04:00
2022-05-16 10:43:39 -04:00
/* pre-calc/cache value */
falloff_cache . calc ( nframes , s ? s - > nominal_sample_rate ( ) : 0 ) ;
2017-11-04 12:11:10 -04:00
/* TODO optimize
* - when speed = = 1.0 , the resampler copies data without processing
2017-11-05 18:12:32 -05:00
* it may ( or may not ) be more efficient to just run all in sequence .
2017-11-04 12:11:10 -04:00
*
* - single sequential task for ' lightweight ' tasks would make sense
* ( run it in parallel with ' heavy ' resampling .
* * output ports ( sends_output ( ) ) only set a flag
* * midi - ports only scale event timestamps
*
* - a threshold parallel vs searial processing may be appropriate .
* amount of work ( how many connected ports are there , how
* many resamplers need to run ) vs . available CPU cores and semaphore
* synchronization overhead .
2017-11-05 18:12:32 -05:00
*
* - input ports : it would make sense to resample each input only once
* ( rather than resample into each ardour - owned input port ) .
* A single external source - port may be connected to many ardour
* input - ports . Currently re - sampling is per input .
2017-11-04 12:11:10 -04:00
*/
2023-02-16 18:33:28 -05:00
std : : shared_ptr < RTTaskList > tl ;
2022-05-11 17:45:51 -04:00
if ( s ) {
tl = s - > rt_tasklist ( ) ;
}
2022-09-20 17:51:52 -04:00
if ( tl & & fabs ( Port : : resample_ratio ( ) ) ! = 1.0 ) {
2023-04-07 17:33:13 -04:00
for ( auto const & p : * _cycle_ports ) {
if ( ! ( p . second - > flags ( ) & TransportSyncPort ) ) {
tl - > push_back ( boost : : bind ( & Port : : cycle_start , p . second , nframes ) ) ;
2019-07-08 12:01:25 -04:00
}
2017-10-30 10:58:36 -04:00
}
2022-05-11 17:45:51 -04:00
tl - > push_back ( boost : : bind ( & PortManager : : run_input_meters , this , nframes , s ? s - > nominal_sample_rate ( ) : 0 ) ) ;
tl - > process ( ) ;
2017-10-30 10:58:36 -04:00
} else {
2023-04-07 17:33:13 -04:00
for ( auto const & p : * _cycle_ports ) {
if ( ! ( p . second - > flags ( ) & TransportSyncPort ) ) {
p . second - > cycle_start ( nframes ) ;
2019-07-08 12:01:25 -04:00
}
2017-10-30 10:58:36 -04:00
}
2021-02-02 20:32:10 -05:00
run_input_meters ( nframes , s ? s - > nominal_sample_rate ( ) : 0 ) ;
2013-08-07 22:22:11 -04:00
}
}
void
2017-10-30 10:58:36 -04:00
PortManager : : cycle_end ( pframes_t nframes , Session * s )
2013-08-07 22:22:11 -04:00
{
2017-11-04 12:11:10 -04:00
// see optimzation note in ::cycle_start()
2023-02-16 18:33:28 -05:00
std : : shared_ptr < RTTaskList > tl ;
2022-05-11 17:45:51 -04:00
if ( s ) {
tl = s - > rt_tasklist ( ) ;
}
2022-09-20 17:51:52 -04:00
if ( tl & & fabs ( Port : : resample_ratio ( ) ) ! = 1.0 ) {
2023-04-07 17:33:13 -04:00
for ( auto const & p : * _cycle_ports ) {
if ( ! ( p . second - > flags ( ) & TransportSyncPort ) ) {
tl - > push_back ( boost : : bind ( & Port : : cycle_end , p . second , nframes ) ) ;
2019-07-08 12:01:25 -04:00
}
2017-10-30 10:58:36 -04:00
}
2022-05-11 17:45:51 -04:00
tl - > process ( ) ;
2017-10-30 10:58:36 -04:00
} else {
2023-04-07 17:33:13 -04:00
for ( auto const & p : * _cycle_ports ) {
if ( ! ( p . second - > flags ( ) & TransportSyncPort ) ) {
p . second - > cycle_end ( nframes ) ;
2019-07-08 12:01:25 -04:00
}
2017-10-30 10:58:36 -04:00
}
2013-08-07 22:22:11 -04:00
}
2023-04-07 17:33:13 -04:00
for ( auto const & p : * _cycle_ports ) {
2019-11-03 09:18:04 -05:00
/* AudioEngine::split_cycle flushes buffers until Port::port_offset.
* Now only flush remaining events ( after Port : : port_offset ) */
2023-04-07 17:33:13 -04:00
p . second - > flush_buffers ( nframes * Port : : resample_ratio ( ) - Port : : port_offset ( ) ) ;
2013-08-07 22:22:11 -04:00
}
_cycle_ports . reset ( ) ;
/* we are done */
}
void
2021-10-31 13:17:01 -04:00
PortManager : : silence ( pframes_t nframes , Session * s )
2013-08-07 22:22:11 -04:00
{
2023-04-07 17:33:13 -04:00
for ( auto const & p : * _cycle_ports ) {
if ( s & & p . second = = s - > mtc_output_port ( ) ) {
2016-05-25 13:20:09 -04:00
continue ;
}
2023-04-07 17:33:13 -04:00
if ( s & & p . second = = s - > midi_clock_output_port ( ) ) {
2016-05-25 13:20:09 -04:00
continue ;
}
2023-04-07 17:33:13 -04:00
if ( s & & p . second = = s - > ltc_output_port ( ) ) {
2016-05-25 13:20:09 -04:00
continue ;
2016-09-22 00:02:38 -04:00
}
2023-04-07 17:33:13 -04:00
if ( std : : dynamic_pointer_cast < AsyncMIDIPort > ( p . second ) ) {
2016-09-22 00:02:38 -04:00
continue ;
2016-05-25 13:20:09 -04:00
}
2023-04-07 17:33:13 -04:00
if ( p . second - > sends_output ( ) ) {
p . second - > get_buffer ( nframes ) . silence ( nframes ) ;
2013-08-07 22:22:11 -04:00
}
}
}
2023-01-30 17:17:29 -05:00
2022-05-09 23:38:38 -04:00
void
2023-01-30 17:17:29 -05:00
PortManager : : reinit ( bool with_ratio )
2022-05-09 23:38:38 -04:00
{
for ( auto const & p : * _ports . reader ( ) ) {
2023-01-30 17:17:29 -05:00
p . second - > reinit ( with_ratio ) ;
2022-05-09 23:38:38 -04:00
}
}
2013-08-07 22:22:11 -04:00
2015-05-03 17:06:21 -04:00
void
2015-05-03 18:29:15 -04:00
PortManager : : silence_outputs ( pframes_t nframes )
2015-05-03 17:06:21 -04:00
{
std : : vector < std : : string > port_names ;
2021-10-31 13:17:01 -04:00
if ( get_ports ( " " , DataType : : AUDIO , IsOutput , port_names ) ) {
for ( std : : vector < std : : string > : : iterator p = port_names . begin ( ) ; p ! = port_names . end ( ) ; + + p ) {
if ( ! port_is_mine ( * p ) ) {
2015-05-03 17:06:21 -04:00
continue ;
}
PortEngine : : PortHandle ph = _backend - > get_port_by_name ( * p ) ;
if ( ! ph ) {
continue ;
}
2021-10-31 13:17:01 -04:00
void * buf = _backend - > get_buffer ( ph , nframes ) ;
2015-05-03 17:06:21 -04:00
if ( ! buf ) {
continue ;
}
2021-10-31 13:17:01 -04:00
memset ( buf , 0 , sizeof ( float ) * nframes ) ;
2015-05-03 17:06:21 -04:00
}
}
2021-10-31 13:17:01 -04:00
if ( get_ports ( " " , DataType : : MIDI , IsOutput , port_names ) ) {
for ( std : : vector < std : : string > : : iterator p = port_names . begin ( ) ; p ! = port_names . end ( ) ; + + p ) {
if ( ! port_is_mine ( * p ) ) {
2015-05-03 17:06:21 -04:00
continue ;
}
PortEngine : : PortHandle ph = _backend - > get_port_by_name ( * p ) ;
if ( ! ph ) {
continue ;
}
2021-10-31 13:17:01 -04:00
void * buf = _backend - > get_buffer ( ph , nframes ) ;
2015-05-03 17:06:21 -04:00
if ( ! buf ) {
continue ;
}
_backend - > midi_clear ( buf ) ;
}
}
}
2013-08-07 22:22:11 -04:00
void
PortManager : : check_monitoring ( )
{
2023-04-07 17:33:13 -04:00
for ( auto const & p : * _cycle_ports ) {
2013-08-07 22:22:11 -04:00
bool x ;
2023-04-07 17:33:13 -04:00
if ( p . second - > last_monitor ( ) ! = ( x = p . second - > monitoring_input ( ) ) ) {
p . second - > set_last_monitor ( x ) ;
2013-08-07 22:22:11 -04:00
/* XXX I think this is dangerous, due to
a likely mutex in the signal handlers . . .
*/
2023-04-07 17:33:13 -04:00
p . second - > MonitorInputChanged ( x ) ; /* EMIT SIGNAL */
2013-08-07 22:22:11 -04:00
}
}
}
void
2017-10-30 12:27:13 -04:00
PortManager : : cycle_end_fade_out ( gain_t base_gain , gain_t gain_step , pframes_t nframes , Session * s )
2013-08-07 22:22:11 -04:00
{
2017-11-04 12:11:10 -04:00
// see optimzation note in ::cycle_start()
2023-02-16 18:33:28 -05:00
std : : shared_ptr < RTTaskList > tl ;
2022-05-11 17:45:51 -04:00
if ( s ) {
tl = s - > rt_tasklist ( ) ;
}
2022-09-20 17:51:52 -04:00
if ( tl & & fabs ( Port : : resample_ratio ( ) ) ! = 1.0 ) {
2023-04-07 17:33:13 -04:00
for ( auto const & p : * _cycle_ports ) {
if ( ! ( p . second - > flags ( ) & TransportSyncPort ) ) {
tl - > push_back ( boost : : bind ( & Port : : cycle_end , p . second , nframes ) ) ;
2019-07-08 12:01:25 -04:00
}
2017-10-30 12:27:13 -04:00
}
2022-05-11 17:45:51 -04:00
tl - > process ( ) ;
2017-10-30 12:27:13 -04:00
} else {
2023-04-07 17:33:13 -04:00
for ( auto const & p : * _cycle_ports ) {
if ( ! ( p . second - > flags ( ) & TransportSyncPort ) ) {
p . second - > cycle_end ( nframes ) ;
2019-07-08 12:01:25 -04:00
}
2017-10-30 12:27:13 -04:00
}
}
2015-10-05 10:17:49 -04:00
2023-04-07 17:33:13 -04:00
for ( auto const & p : * _cycle_ports ) {
p . second - > flush_buffers ( nframes ) ;
2017-10-30 12:27:13 -04:00
2023-04-07 17:33:13 -04:00
if ( p . second - > sends_output ( ) ) {
std : : shared_ptr < AudioPort > ap = std : : dynamic_pointer_cast < AudioPort > ( p . second ) ;
2013-08-07 22:22:11 -04:00
if ( ap ) {
Sample * s = ap - > engine_get_whole_audio_buffer ( ) ;
2021-10-31 13:17:01 -04:00
gain_t g = base_gain ;
2015-10-05 10:17:49 -04:00
2013-08-07 22:22:11 -04:00
for ( pframes_t n = 0 ; n < nframes ; + + n ) {
* s + + * = g ;
g - = gain_step ;
}
}
}
}
2017-10-30 12:27:13 -04:00
_cycle_ports . reset ( ) ;
/* we are done */
2013-08-07 22:22:11 -04:00
}
2013-09-13 11:21:15 -04:00
PortEngine &
2021-10-31 13:17:01 -04:00
PortManager : : port_engine ( )
2013-09-13 11:21:15 -04:00
{
assert ( _backend ) ;
return * _backend ;
}
2016-07-08 17:09:09 -04:00
bool
PortManager : : port_is_control_only ( std : : string const & name )
{
static regex_t compiled_pattern ;
2021-10-31 13:17:01 -04:00
static string pattern ;
2016-07-08 17:09:09 -04:00
2021-10-31 13:17:01 -04:00
if ( pattern . empty ( ) ) {
2016-07-08 17:09:09 -04:00
/* This is a list of regular expressions that match ports
* related to physical MIDI devices that we do not want to
* expose as normal physical ports .
*/
2021-10-31 13:17:01 -04:00
const char * const control_only_ports [ ] = {
2016-07-08 17:09:09 -04:00
X_ ( " .*Ableton Push.* " ) ,
2016-07-09 12:20:54 -04:00
X_ ( " .*FaderPort .* " ) ,
2017-04-05 05:04:16 -04:00
X_ ( " .*FaderPort8 .* " ) ,
2017-12-12 08:13:34 -05:00
X_ ( " .*FaderPort16 .* " ) ,
2018-07-31 08:46:20 -04:00
X_ ( " .*FaderPort2 .* " ) ,
2017-11-10 09:24:49 -05:00
X_ ( " .*US-2400 .* " ) ,
X_ ( " .*Mackie .* " ) ,
2020-06-11 17:19:05 -04:00
X_ ( " .*MIDI Control .* " ) ,
2023-05-07 10:21:37 -04:00
X_ ( " .*Console1 .* " ) ,
2016-07-08 17:09:09 -04:00
} ;
pattern = " ( " ;
2021-10-31 13:17:01 -04:00
for ( size_t n = 0 ; n < sizeof ( control_only_ports ) / sizeof ( control_only_ports [ 0 ] ) ; + + n ) {
2016-07-08 17:09:09 -04:00
if ( n > 0 ) {
pattern + = ' | ' ;
}
pattern + = control_only_ports [ n ] ;
}
pattern + = ' ) ' ;
2021-10-31 13:17:01 -04:00
regcomp ( & compiled_pattern , pattern . c_str ( ) , REG_EXTENDED | REG_NOSUB ) ;
2016-07-08 17:09:09 -04:00
}
2021-10-31 13:17:01 -04:00
return regexec ( & compiled_pattern , name . c_str ( ) , 0 , 0 , 0 ) = = 0 ;
2016-07-08 17:09:09 -04:00
}
2016-10-19 15:12:49 -04:00
2021-10-31 13:17:01 -04:00
static bool
ends_with ( std : : string const & str , std : : string const & end )
2021-10-31 11:33:03 -04:00
{
const size_t str_size = str . size ( ) ;
2021-10-31 13:17:01 -04:00
const size_t end_size = end . size ( ) ;
2021-10-31 11:33:03 -04:00
if ( str_size < end_size ) {
return false ;
}
return 0 = = str . compare ( str_size - end_size , end_size , end ) ;
}
2021-01-10 22:23:15 -05:00
bool
PortManager : : port_is_virtual_piano ( std : : string const & name )
2016-10-19 17:17:30 -04:00
{
2021-10-31 11:33:03 -04:00
return ends_with ( name , X_ ( " :x-virtual-keyboard " ) ) ;
}
bool
PortManager : : port_is_physical_input_monitor_enable ( std : : string const & name )
{
2021-10-31 13:17:01 -04:00
if ( Config - > get_work_around_jack_no_copy_optimization ( ) & & AudioEngine : : instance ( ) - > current_backend_name ( ) = = X_ ( " JACK " ) ) {
2021-10-31 11:33:03 -04:00
if ( ends_with ( name , X_ ( " :physical_midi_input_monitor_enable " ) ) ) {
return true ;
}
if ( ends_with ( name , X_ ( " :physical_audio_input_monitor_enable " ) ) ) {
return true ;
}
2021-01-10 22:23:15 -05:00
}
2021-10-31 11:33:03 -04:00
return false ;
2021-01-10 22:23:15 -05:00
}
2016-10-20 16:34:06 -04:00
2021-01-10 22:23:15 -05:00
MidiPortFlags
PortManager : : midi_port_metadata ( std : : string const & name )
{
Glib : : Threads : : Mutex : : Lock lm ( _port_info_mutex ) ;
2016-10-20 16:34:06 -04:00
fill_midi_port_info_locked ( ) ;
2021-10-31 13:17:01 -04:00
PortID pid ( _backend , DataType : : MIDI , true , name ) ;
2021-01-10 22:23:15 -05:00
PortInfo : : iterator x = _port_info . find ( pid ) ;
2021-10-31 13:17:01 -04:00
if ( x ! = _port_info . end ( ) ) {
2021-01-10 22:23:15 -05:00
return x - > second . properties ;
}
2016-10-20 16:34:06 -04:00
2021-01-10 22:23:15 -05:00
pid . input = false ;
2021-10-31 13:17:01 -04:00
x = _port_info . find ( pid ) ;
if ( x ! = _port_info . end ( ) ) {
2021-01-10 22:23:15 -05:00
return x - > second . properties ;
2016-10-20 16:34:06 -04:00
}
2021-01-10 22:23:15 -05:00
return MidiPortFlags ( 0 ) ;
2016-10-19 17:17:30 -04:00
}
2016-10-19 15:12:49 -04:00
void
2021-01-10 22:23:15 -05:00
PortManager : : get_configurable_midi_ports ( vector < string > & copy , bool for_input )
2016-10-19 15:12:49 -04:00
{
2021-01-10 22:23:15 -05:00
if ( ! _backend ) {
return ;
}
2016-10-20 16:34:06 -04:00
2021-01-10 22:23:15 -05:00
{
Glib : : Threads : : Mutex : : Lock lm ( _port_info_mutex ) ;
fill_midi_port_info_locked ( ) ;
}
2016-10-20 16:34:06 -04:00
2021-10-31 13:17:01 -04:00
PortFlags flags = PortFlags ( ( for_input ? IsOutput : IsInput ) | IsPhysical ) ;
2021-01-10 22:23:15 -05:00
std : : vector < string > ports ;
2021-10-31 13:17:01 -04:00
AudioEngine : : instance ( ) - > get_ports ( string ( ) , DataType : : MIDI , flags , ports ) ;
for ( vector < string > : : iterator p = ports . begin ( ) ; p ! = ports . end ( ) ; + + p ) {
2021-01-10 22:23:15 -05:00
if ( port_is_mine ( * p ) & & ! port_is_virtual_piano ( * p ) ) {
continue ;
}
if ( ( * p ) . find ( X_ ( " Midi Through " ) ) ! = string : : npos | | ( * p ) . find ( X_ ( " Midi-Through " ) ) ! = string : : npos ) {
continue ;
}
copy . push_back ( * p ) ;
2016-10-20 16:34:06 -04:00
}
}
void
PortManager : : get_midi_selection_ports ( vector < string > & copy )
{
2021-01-10 22:23:15 -05:00
Glib : : Threads : : Mutex : : Lock lm ( _port_info_mutex ) ;
2016-10-20 16:34:06 -04:00
fill_midi_port_info_locked ( ) ;
2021-01-10 22:23:15 -05:00
for ( PortInfo : : const_iterator x = _port_info . begin ( ) ; x ! = _port_info . end ( ) ; + + x ) {
if ( x - > first . data_type ! = DataType : : MIDI | | ! x - > first . input ) {
continue ;
}
2016-10-20 16:34:06 -04:00
if ( x - > second . properties & MidiPortSelection ) {
2021-01-10 22:23:15 -05:00
copy . push_back ( x - > first . port_name ) ;
2016-10-20 16:34:06 -04:00
}
}
}
void
2021-01-10 22:23:15 -05:00
PortManager : : set_port_pretty_name ( string const & port , string const & pretty )
2016-10-20 16:34:06 -04:00
{
2021-01-10 22:23:15 -05:00
PortEngine : : PortHandle ph = _backend - > get_port_by_name ( port ) ;
if ( ! ph ) {
return ;
2016-10-20 16:34:06 -04:00
}
2021-01-10 22:23:15 -05:00
/* port-manager only handles physical I/O names */
assert ( _backend - > get_port_flags ( ph ) & IsPhysical ) ;
2016-10-20 16:34:06 -04:00
2021-10-31 13:17:01 -04:00
_backend - > set_port_property ( ph , " http://jackaudio.org/metadata/pretty-name " , pretty , string ( ) ) ;
2016-10-20 16:34:06 -04:00
2021-01-10 22:23:15 -05:00
{
/* backend IsOutput ports = capture = input ports for libardour */
2021-10-31 13:17:01 -04:00
PortID pid ( _backend , _backend - > port_data_type ( ph ) , _backend - > get_port_flags ( ph ) & IsOutput , port ) ;
2021-01-10 22:23:15 -05:00
Glib : : Threads : : Mutex : : Lock lm ( _port_info_mutex ) ;
fill_midi_port_info_locked ( ) ;
if ( ! pretty . empty ( ) ) {
_port_info [ pid ] . pretty_name = pretty ;
} else {
/* remove empty */
PortInfo : : iterator x = _port_info . find ( pid ) ;
2021-10-31 13:17:01 -04:00
if ( x ! = _port_info . end ( ) & & x - > second . properties = = MidiPortFlags ( 0 ) ) {
2021-01-10 22:23:15 -05:00
_port_info . erase ( x ) ;
}
}
2016-10-20 16:34:06 -04:00
}
2021-01-10 22:23:15 -05:00
save_port_info ( ) ;
2021-10-31 13:17:01 -04:00
MidiPortInfoChanged ( ) ; /* EMIT SIGNAL*/
2021-01-10 22:23:15 -05:00
PortPrettyNameChanged ( port ) ; /* EMIT SIGNAL */
2016-10-19 15:12:49 -04:00
}
void
2021-01-10 22:23:15 -05:00
PortManager : : add_midi_port_flags ( string const & port , MidiPortFlags flags )
2016-10-19 15:12:49 -04:00
{
2021-01-10 22:23:15 -05:00
assert ( flags ! = MidiPortFlags ( 0 ) ) ;
PortEngine : : PortHandle ph = _backend - > get_port_by_name ( port ) ;
if ( ! ph ) {
return ;
}
2016-10-19 17:17:30 -04:00
bool emit = false ;
{
2021-10-31 13:17:01 -04:00
PortID pid ( _backend , _backend - > port_data_type ( ph ) , _backend - > get_port_flags ( ph ) & IsOutput , port ) ;
2021-01-10 22:23:15 -05:00
Glib : : Threads : : Mutex : : Lock lm ( _port_info_mutex ) ;
2016-10-20 16:34:06 -04:00
fill_midi_port_info_locked ( ) ;
2021-01-10 22:23:15 -05:00
/* Add MIDI port if present */
if ( _port_info [ pid ] . properties ! = flags ) {
2021-10-31 13:17:01 -04:00
_port_info [ pid ] . properties = MidiPortFlags ( _port_info [ pid ] . properties | flags ) ;
emit = true ;
2016-10-19 17:17:30 -04:00
}
}
if ( emit ) {
2016-10-20 16:34:06 -04:00
if ( flags & MidiPortSelection ) {
MidiSelectionPortsChanged ( ) ; /* EMIT SIGNAL */
}
if ( flags ! = MidiPortSelection ) {
MidiPortInfoChanged ( ) ; /* EMIT SIGNAL */
}
2021-01-10 22:23:15 -05:00
save_port_info ( ) ;
2016-10-19 15:12:49 -04:00
}
}
void
2021-01-10 22:23:15 -05:00
PortManager : : remove_midi_port_flags ( string const & port , MidiPortFlags flags )
2016-10-19 15:12:49 -04:00
{
2021-01-10 22:23:15 -05:00
assert ( flags ! = MidiPortFlags ( 0 ) ) ;
PortEngine : : PortHandle ph = _backend - > get_port_by_name ( port ) ;
if ( ! ph ) {
return ;
}
2016-10-19 17:17:30 -04:00
bool emit = false ;
{
2021-10-31 13:17:01 -04:00
PortID pid ( _backend , _backend - > port_data_type ( ph ) , _backend - > get_port_flags ( ph ) & IsOutput , port ) ;
2021-01-10 22:23:15 -05:00
Glib : : Threads : : Mutex : : Lock lm ( _port_info_mutex ) ;
2016-10-20 16:34:06 -04:00
fill_midi_port_info_locked ( ) ;
2021-01-10 22:23:15 -05:00
PortInfo : : iterator x = _port_info . find ( pid ) ;
2016-10-20 16:34:06 -04:00
2021-10-31 13:17:01 -04:00
if ( x ! = _port_info . end ( ) ) {
2016-10-20 16:34:06 -04:00
if ( x - > second . properties & flags ) { // at least one is set
x - > second . properties = MidiPortFlags ( x - > second . properties & ~ flags ) ;
2021-10-31 13:17:01 -04:00
emit = true ;
2016-10-20 16:34:06 -04:00
}
2021-01-10 22:23:15 -05:00
/* remove empty */
if ( x - > second . properties = = MidiPortFlags ( 0 ) & & x - > second . pretty_name . empty ( ) ) {
_port_info . erase ( x ) ;
}
2016-10-19 17:17:30 -04:00
}
}
if ( emit ) {
2016-10-20 16:34:06 -04:00
if ( flags & MidiPortSelection ) {
MidiSelectionPortsChanged ( ) ; /* EMIT SIGNAL */
}
if ( flags ! = MidiPortSelection ) {
MidiPortInfoChanged ( ) ; /* EMIT SIGNAL */
}
2021-01-10 22:23:15 -05:00
save_port_info ( ) ;
2016-10-19 15:12:49 -04:00
}
}
2021-01-10 22:23:15 -05:00
string
PortManager : : port_info_file ( )
{
2021-10-31 13:17:01 -04:00
return Glib : : build_filename ( user_config_directory ( ) , X_ ( " port_metadata " ) ) ;
2021-01-10 22:23:15 -05:00
}
# if CURRENT_SESSION_FILE_VERSION < 6999
2016-10-20 16:34:06 -04:00
string
PortManager : : midi_port_info_file ( )
{
2021-10-31 13:17:01 -04:00
return Glib : : build_filename ( user_config_directory ( ) , X_ ( " midi_port_info " ) ) ;
2016-10-20 16:34:06 -04:00
}
2021-01-10 22:23:15 -05:00
# endif
2016-10-20 16:34:06 -04:00
2016-10-19 15:12:49 -04:00
void
2021-01-10 22:23:15 -05:00
PortManager : : save_port_info ( )
2016-10-19 15:12:49 -04:00
{
2021-01-10 22:23:15 -05:00
XMLNode * root = new XMLNode ( " PortMeta " ) ;
root - > set_property ( " version " , 1 ) ;
2016-10-20 16:34:06 -04:00
2016-10-19 17:17:30 -04:00
{
2021-01-10 22:23:15 -05:00
Glib : : Threads : : Mutex : : Lock lm ( _port_info_mutex ) ;
for ( PortInfo : : const_iterator i = _port_info . begin ( ) ; i ! = _port_info . end ( ) ; + + i ) {
2021-01-21 23:19:47 -05:00
if ( port_is_virtual_piano ( i - > first . port_name ) ) {
continue ;
}
2021-01-10 22:23:15 -05:00
XMLNode & node = i - > first . state ( ) ;
node . set_property ( " pretty-name " , i - > second . pretty_name ) ;
node . set_property ( " properties " , i - > second . properties ) ;
root - > add_child_nocopy ( node ) ;
2016-10-20 16:34:06 -04:00
}
}
XMLTree tree ;
tree . set_root ( root ) ;
2021-01-10 22:23:15 -05:00
if ( ! tree . write ( port_info_file ( ) ) ) {
error < < string_compose ( _ ( " Could not save port info to %1 " ) , port_info_file ( ) ) < < endmsg ;
2016-10-20 16:34:06 -04:00
}
}
void
2021-01-10 22:23:15 -05:00
PortManager : : load_port_info ( )
2016-10-20 16:34:06 -04:00
{
2021-01-10 22:23:15 -05:00
_port_info . clear ( ) ;
# if CURRENT_SESSION_FILE_VERSION < 6999
/* import old Ardour 6 MIDI meta-data */
string a6path = midi_port_info_file ( ) ;
2016-10-20 16:34:06 -04:00
2021-01-10 22:23:15 -05:00
if ( Glib : : file_test ( a6path , Glib : : FILE_TEST_EXISTS ) ) {
XMLTree tree ;
if ( ! tree . read ( a6path ) ) {
warning < < string_compose ( _ ( " Cannot load/convert MIDI port info from '%1'. " ) , a6path ) < < endmsg ;
} else {
2021-10-31 13:17:01 -04:00
for ( XMLNodeConstIterator i = tree . root ( ) - > children ( ) . begin ( ) ; i ! = tree . root ( ) - > children ( ) . end ( ) ; + + i ) {
2021-01-10 22:23:15 -05:00
string name ;
string backend ;
bool input ;
if ( ! ( * i ) - > get_property ( X_ ( " name " ) , name ) | |
! ( * i ) - > get_property ( X_ ( " backend " ) , backend ) | |
! ( * i ) - > get_property ( X_ ( " input " ) , input ) ) {
error < < string_compose ( _ ( " MIDI port info file '%1' contains invalid port description - please remove it. " ) , a6path ) < < endmsg ;
continue ;
}
try {
2021-10-31 13:17:01 -04:00
PortID id ( * * i , true ) ;
2021-01-10 22:23:15 -05:00
PortMetaData meta ( * * i ) ;
_port_info [ id ] = meta ;
} catch ( . . . ) {
error < < string_compose ( _ ( " MIDI port info file '%1' contains invalid meta data - please remove it. " ) , a6path ) < < endmsg ;
}
}
}
}
# endif
XMLTree tree ;
2021-10-31 13:17:01 -04:00
string path = port_info_file ( ) ;
2016-10-20 16:34:06 -04:00
if ( ! Glib : : file_test ( path , Glib : : FILE_TEST_EXISTS ) ) {
return ;
}
if ( ! tree . read ( path ) ) {
2021-01-10 22:23:15 -05:00
error < < string_compose ( _ ( " Cannot load port info from '%1'. " ) , path ) < < endmsg ;
2016-10-20 16:34:06 -04:00
return ;
}
2021-10-31 13:17:01 -04:00
for ( XMLNodeConstIterator i = tree . root ( ) - > children ( ) . begin ( ) ; i ! = tree . root ( ) - > children ( ) . end ( ) ; + + i ) {
2021-01-10 22:23:15 -05:00
try {
2021-10-31 13:17:01 -04:00
PortID id ( * * i ) ;
2021-01-10 22:23:15 -05:00
PortMetaData meta ( * * i ) ;
_port_info [ id ] = meta ;
} catch ( . . . ) {
error < < string_compose ( _ ( " port info file '%1' contains invalid information - please remove it. " ) , path ) < < endmsg ;
2016-10-20 16:34:06 -04:00
}
2019-03-07 14:00:51 -05:00
}
2016-10-20 16:34:06 -04:00
}
2019-03-07 23:57:53 -05:00
string
2021-10-31 13:17:01 -04:00
PortManager : : short_port_name_from_port_name ( std : : string const & full_name ) const
2019-03-07 23:57:53 -05:00
{
string : : size_type colon = full_name . find_first_of ( ' : ' ) ;
2021-10-31 13:17:01 -04:00
if ( colon = = string : : npos | | colon = = full_name . length ( ) ) {
2019-03-07 23:57:53 -05:00
return full_name ;
}
2021-10-31 13:17:01 -04:00
return full_name . substr ( colon + 1 ) ;
2019-03-07 23:57:53 -05:00
}
2016-10-20 16:34:06 -04:00
void
PortManager : : fill_midi_port_info_locked ( )
{
/* MIDI info mutex MUST be held */
2021-01-10 22:23:15 -05:00
if ( ! _midi_info_dirty | | ! _backend ) {
2016-10-20 16:34:06 -04:00
return ;
}
std : : vector < string > ports ;
2021-10-31 13:17:01 -04:00
AudioEngine : : instance ( ) - > get_ports ( string ( ) , DataType : : MIDI , IsOutput , ports ) ;
for ( vector < string > : : iterator p = ports . begin ( ) ; p ! = ports . end ( ) ; + + p ) {
2021-01-10 22:23:15 -05:00
if ( port_is_mine ( * p ) & & ! port_is_virtual_piano ( * p ) ) {
2016-10-20 16:34:06 -04:00
continue ;
}
2021-10-31 13:17:01 -04:00
PortID pid ( _backend , DataType : : MIDI , true , * p ) ;
2021-01-10 22:23:15 -05:00
PortInfo : : iterator x = _port_info . find ( pid ) ;
2021-10-31 13:17:01 -04:00
if ( x ! = _port_info . end ( ) ) {
2021-01-10 22:23:15 -05:00
continue ;
}
2019-03-07 14:00:51 -05:00
2021-01-10 22:23:15 -05:00
MidiPortFlags flags ( MidiPortFlags ( 0 ) ) ;
2016-10-21 16:32:46 -04:00
2021-01-10 22:23:15 -05:00
if ( port_is_control_only ( * p ) ) {
flags = MidiPortControl ;
} else if ( port_is_virtual_piano ( * p ) ) {
2021-10-31 13:17:01 -04:00
flags = MidiPortFlags ( MidiPortSelection | MidiPortMusic ) ;
2021-01-10 22:23:15 -05:00
}
2019-03-07 14:00:51 -05:00
2021-01-18 09:36:01 -05:00
# ifdef HAVE_ALSA
2021-01-10 22:23:15 -05:00
if ( ( * p ) . find ( X_ ( " Midi Through " ) ) ! = string : : npos | | ( * p ) . find ( X_ ( " Midi-Through " ) ) ! = string : : npos ) {
flags = MidiPortFlags ( flags | MidiPortVirtual ) ;
}
2021-01-18 09:36:01 -05:00
# endif
2019-03-07 14:00:51 -05:00
2021-01-10 22:23:15 -05:00
if ( flags ! = MidiPortFlags ( 0 ) ) {
_port_info [ pid ] . properties = flags ;
2016-10-20 16:34:06 -04:00
}
}
2021-10-31 13:17:01 -04:00
AudioEngine : : instance ( ) - > get_ports ( string ( ) , DataType : : MIDI , IsInput , ports ) ;
for ( vector < string > : : iterator p = ports . begin ( ) ; p ! = ports . end ( ) ; + + p ) {
2016-10-20 16:34:06 -04:00
if ( port_is_mine ( * p ) ) {
continue ;
}
2021-10-31 13:17:01 -04:00
PortID pid ( _backend , DataType : : MIDI , false , * p ) ;
2021-01-10 22:23:15 -05:00
PortInfo : : iterator x = _port_info . find ( pid ) ;
2021-10-31 13:17:01 -04:00
if ( x ! = _port_info . end ( ) ) {
2021-01-10 22:23:15 -05:00
continue ;
}
2019-03-07 14:00:51 -05:00
2021-01-10 22:23:15 -05:00
MidiPortFlags flags ( MidiPortFlags ( 0 ) ) ;
2016-10-21 16:32:46 -04:00
2021-01-10 22:23:15 -05:00
if ( port_is_control_only ( * p ) ) {
flags = MidiPortControl ;
}
2019-03-07 14:00:51 -05:00
2021-01-18 09:36:01 -05:00
# ifdef HAVE_ALSA
2021-01-10 22:23:15 -05:00
if ( ( * p ) . find ( X_ ( " Midi Through " ) ) ! = string : : npos | | ( * p ) . find ( X_ ( " Midi-Through " ) ) ! = string : : npos ) {
flags = MidiPortFlags ( flags | MidiPortVirtual ) ;
}
2021-01-18 09:36:01 -05:00
# endif
2019-03-07 14:00:51 -05:00
2021-01-10 22:23:15 -05:00
if ( flags ! = MidiPortFlags ( 0 ) ) {
_port_info [ pid ] . properties = flags ;
2016-10-20 16:34:06 -04:00
}
}
2021-01-10 22:23:15 -05:00
_midi_info_dirty = false ;
2016-10-19 15:12:49 -04:00
}
2019-07-11 01:39:02 -04:00
void
PortManager : : set_port_buffer_sizes ( pframes_t n )
{
2023-04-07 17:33:13 -04:00
std : : shared_ptr < Ports const > all = _ports . reader ( ) ;
for ( auto const & p : * all ) {
p . second - > set_buffer_size ( n ) ;
2019-07-11 01:39:02 -04:00
}
2021-02-07 08:02:50 -05:00
_monitor_port . set_buffer_size ( n ) ;
2019-07-11 01:39:02 -04:00
}
2020-04-06 17:45:20 -04:00
bool
2020-04-06 22:07:17 -04:00
PortManager : : check_for_ambiguous_latency ( bool log ) const
2020-04-06 17:45:20 -04:00
{
2023-04-07 17:33:13 -04:00
bool rv = false ;
std : : shared_ptr < Ports const > plist = _ports . reader ( ) ;
for ( auto const & pi : * plist ) {
std : : shared_ptr < Port > const & p ( pi . second ) ;
2021-09-14 15:34:43 -04:00
/* check one to many connections */
if ( ! p - > sends_output ( ) | | ( p - > flags ( ) & IsTerminal ) | | ! p - > connected ( ) ) {
2020-04-06 22:06:02 -04:00
continue ;
}
2023-02-16 18:33:28 -05:00
if ( std : : dynamic_pointer_cast < AsyncMIDIPort > ( p ) ) {
2020-04-07 07:32:28 -04:00
continue ;
}
assert ( port_is_mine ( p - > name ( ) ) ) ;
2021-09-14 15:34:43 -04:00
LatencyRange range ;
2021-10-31 13:17:01 -04:00
range . min = ~ ( ( pframes_t ) 0 ) ;
2021-09-14 15:34:43 -04:00
range . max = 0 ;
p - > collect_latency_from_backend ( range , true ) ;
if ( range . min ! = range . max ) {
2020-04-06 22:06:02 -04:00
if ( log ) {
2021-10-31 13:17:01 -04:00
warning < < string_compose ( _ ( " Ambiguous latency for port '%1' (%2, %3) " ) , p - > name ( ) , range . min , range . max ) < < endmsg ;
2020-04-06 22:06:02 -04:00
rv = true ;
} else {
2020-04-06 17:45:20 -04:00
return true ;
}
}
}
return rv ;
}
2020-10-26 10:52:17 -04:00
void
PortManager : : reset_input_meters ( )
{
2023-02-17 02:31:21 -05:00
_reset_meters . store ( 1 ) ;
2020-10-26 10:52:17 -04:00
}
2021-01-16 00:45:12 -05:00
PortManager : : AudioInputPorts
PortManager : : audio_input_ports ( ) const
{
2023-04-07 17:33:13 -04:00
std : : shared_ptr < AudioInputPorts const > p = _audio_input_ports . reader ( ) ;
2021-01-16 00:45:12 -05:00
return * p ;
}
PortManager : : MIDIInputPorts
PortManager : : midi_input_ports ( ) const
{
2023-04-07 17:33:13 -04:00
std : : shared_ptr < MIDIInputPorts const > p = _midi_input_ports . reader ( ) ;
2021-01-16 00:45:12 -05:00
return * p ;
}
2020-10-26 10:52:17 -04:00
void
PortManager : : run_input_meters ( pframes_t n_samples , samplecnt_t rate )
{
2021-01-16 00:45:12 -05:00
if ( n_samples = = 0 ) {
return ;
}
2020-10-26 10:52:17 -04:00
2023-02-17 02:31:21 -05:00
int canderef ( 1 ) ;
const bool reset = _reset_meters . compare_exchange_strong ( canderef , 0 ) ;
2020-10-26 10:52:17 -04:00
2021-06-08 08:34:01 -04:00
_monitor_port . monitor ( port_engine ( ) , n_samples ) ;
2021-02-07 08:02:50 -05:00
2020-10-26 10:52:17 -04:00
/* calculate peak of all physical inputs (readable ports) */
2023-04-07 17:33:13 -04:00
std : : shared_ptr < AudioInputPorts const > aip = _audio_input_ports . reader ( ) ;
2020-10-26 10:52:17 -04:00
2023-04-07 17:33:13 -04:00
for ( auto const & p : * aip ) {
assert ( ! port_is_mine ( p . first ) ) ;
AudioInputPort & ai = * const_cast < AudioInputPort * > ( & p . second ) ;
2021-01-13 19:47:25 -05:00
2022-05-16 10:43:39 -04:00
ai . apply_falloff ( n_samples , rate , reset ) ;
2021-06-08 10:42:35 -04:00
2023-04-07 17:33:13 -04:00
PortEngine : : PortHandle ph = _backend - > get_port_by_name ( p . first ) ;
2021-06-08 10:42:35 -04:00
if ( ! ph ) {
continue ;
2020-10-26 10:52:17 -04:00
}
2021-10-31 13:17:01 -04:00
Sample * buf = ( Sample * ) _backend - > get_buffer ( ph , n_samples ) ;
2020-10-26 10:52:17 -04:00
if ( ! buf ) {
2021-03-20 18:09:36 -04:00
/* can this happen? */
2022-05-16 10:43:39 -04:00
ai . silence ( n_samples ) ;
2020-10-26 10:52:17 -04:00
continue ;
}
2022-05-16 10:43:39 -04:00
ai . process ( buf , n_samples , reset ) ;
2020-10-26 10:52:17 -04:00
}
/* MIDI */
2023-04-07 17:33:13 -04:00
std : : shared_ptr < MIDIInputPorts const > mip = _midi_input_ports . reader ( ) ;
for ( auto const & p : * mip ) {
assert ( ! port_is_mine ( p . first ) ) ;
2020-10-26 10:52:17 -04:00
2023-04-07 17:33:13 -04:00
PortEngine : : PortHandle ph = _backend - > get_port_by_name ( p . first ) ;
2023-10-31 17:35:05 -04:00
if ( ! ph ) {
2021-01-13 19:47:25 -05:00
continue ;
}
2023-04-07 17:33:13 -04:00
MIDIInputPort & mi = * const_cast < MIDIInputPort * > ( & p . second ) ;
2022-05-16 10:43:39 -04:00
mi . apply_falloff ( n_samples , rate , reset ) ;
2020-10-26 10:52:17 -04:00
2021-10-31 13:17:01 -04:00
void * buffer = _backend - > get_buffer ( ph , n_samples ) ;
2020-10-26 10:52:17 -04:00
const pframes_t event_count = _backend - > get_midi_event_count ( buffer ) ;
for ( pframes_t i = 0 ; i < event_count ; + + i ) {
2021-10-31 13:17:01 -04:00
pframes_t timestamp ;
size_t size ;
2020-10-26 10:52:17 -04:00
uint8_t const * buf ;
_backend - > midi_event_get ( timestamp , size , & buf , buffer , i ) ;
2022-05-16 10:43:39 -04:00
mi . process_event ( buf , size ) ;
2020-10-26 10:52:17 -04:00
}
}
}
2021-05-06 19:43:19 -04:00
# ifndef NDEBUG
void
PortManager : : list_all_ports ( ) const
{
2023-04-07 17:33:13 -04:00
std : : shared_ptr < Ports const > plist = _ports . reader ( ) ;
for ( auto const & p : * plist ) {
std : : cout < < p . first < < " \n " ;
2021-05-06 19:43:19 -04:00
}
}
void
PortManager : : list_cycle_ports ( ) const
{
2023-04-07 17:33:13 -04:00
for ( auto const & p : * _cycle_ports ) {
std : : cout < < p . first < < " \n " ;
2021-05-06 19:43:19 -04:00
}
}
# endif