2008-06-02 17:41:35 -04:00
/*
2010-04-13 16:48:33 -04:00
Copyright ( C ) 1999 - 2010 Paul Davis
2008-06-02 17:41:35 -04:00
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 0213 9 , USA .
*/
2010-05-01 11:09:19 -04:00
# include <stdint.h>
2008-06-02 17:41:35 -04:00
# include <algorithm>
# include <string>
# include <vector>
# include <sstream>
# include <fstream>
# include <cstdio> /* sprintf(3) ... grrr */
# include <cmath>
# include <cerrno>
# include <unistd.h>
# include <limits.h>
2012-07-25 13:48:55 -04:00
# include <glibmm/threads.h>
2008-06-02 17:41:35 -04:00
# include <glibmm/miscutils.h>
# include <glibmm/fileutils.h>
2010-07-27 20:43:15 -04:00
# include <boost/algorithm/string/erase.hpp>
2014-07-08 12:25:36 -04:00
# include "pbd/basename.h"
# include "pbd/boost_debug.h"
# include "pbd/convert.h"
2014-06-02 11:20:37 -04:00
# include "pbd/convert.h"
2009-02-25 13:26:51 -05:00
# include "pbd/error.h"
# include "pbd/file_utils.h"
2014-07-08 00:53:06 -04:00
# include "pbd/md5.h"
2013-07-15 08:05:37 -04:00
# include "pbd/search_path.h"
2014-07-08 12:25:36 -04:00
# include "pbd/stacktrace.h"
# include "pbd/stl_delete.h"
# include "pbd/unwind.h"
2009-02-25 13:26:51 -05:00
2009-07-21 08:05:44 -04:00
# include "ardour/amp.h"
2009-02-25 13:26:51 -05:00
# include "ardour/analyser.h"
2013-08-07 22:22:11 -04:00
# include "ardour/async_midi_port.h"
2009-02-25 13:26:51 -05:00
# include "ardour/audio_buffer.h"
# include "ardour/audio_diskstream.h"
2009-07-01 09:36:50 -04:00
# include "ardour/audio_port.h"
2009-02-25 13:26:51 -05:00
# include "ardour/audio_track.h"
# include "ardour/audioengine.h"
# include "ardour/audiofilesource.h"
# include "ardour/auditioner.h"
2010-04-13 16:48:33 -04:00
# include "ardour/buffer_manager.h"
2009-02-25 13:26:51 -05:00
# include "ardour/buffer_set.h"
# include "ardour/bundle.h"
2009-10-23 19:23:00 -04:00
# include "ardour/butler.h"
2009-02-25 13:26:51 -05:00
# include "ardour/click.h"
2011-05-04 11:00:43 -04:00
# include "ardour/control_protocol_manager.h"
2009-02-25 13:26:51 -05:00
# include "ardour/data_type.h"
2009-11-25 09:37:20 -05:00
# include "ardour/debug.h"
2009-02-25 13:26:51 -05:00
# include "ardour/filename_extensions.h"
2012-05-24 02:09:29 -04:00
# include "ardour/graph.h"
2013-08-07 22:22:11 -04:00
# include "ardour/midiport_manager.h"
2014-04-28 19:58:24 -04:00
# include "ardour/scene_changer.h"
2009-02-25 13:26:51 -05:00
# include "ardour/midi_track.h"
2009-12-08 22:05:14 -05:00
# include "ardour/midi_ui.h"
2012-05-24 02:09:29 -04:00
# include "ardour/operations.h"
2009-02-25 13:26:51 -05:00
# include "ardour/playlist.h"
2012-02-01 23:12:23 -05:00
# include "ardour/plugin.h"
2009-02-25 13:26:51 -05:00
# include "ardour/plugin_insert.h"
2012-05-24 02:09:29 -04:00
# include "ardour/process_thread.h"
2009-10-28 17:36:40 -04:00
# include "ardour/rc_configuration.h"
2009-02-25 13:26:51 -05:00
# include "ardour/recent_sessions.h"
2012-05-24 02:09:29 -04:00
# include "ardour/region.h"
2009-02-25 13:26:51 -05:00
# include "ardour/region_factory.h"
2011-11-09 12:44:39 -05:00
# include "ardour/route_graph.h"
2009-02-25 13:26:51 -05:00
# include "ardour/route_group.h"
2014-06-25 15:16:09 -04:00
# include "ardour/route_sorters.h"
2009-02-25 13:26:51 -05:00
# include "ardour/send.h"
# include "ardour/session.h"
# include "ardour/session_directory.h"
2009-12-03 16:52:10 -05:00
# include "ardour/session_playlists.h"
2009-02-25 13:26:51 -05:00
# include "ardour/smf_source.h"
# include "ardour/source_factory.h"
2013-09-09 22:40:54 -04:00
# include "ardour/speakers.h"
2014-04-10 08:58:04 -04:00
# include "ardour/track.h"
2009-02-25 13:26:51 -05:00
# include "ardour/utils.h"
2008-06-02 17:41:35 -04:00
2010-07-05 20:16:36 -04:00
# include "midi++/port.h"
2010-06-29 09:47:53 -04:00
# include "midi++/mmc.h"
2009-12-29 16:31:14 -05:00
2008-06-02 17:41:35 -04:00
# include "i18n.h"
2012-05-24 02:09:29 -04:00
namespace ARDOUR {
class MidiSource ;
class Processor ;
class Speakers ;
}
2008-06-02 17:41:35 -04:00
using namespace std ;
using namespace ARDOUR ;
using namespace PBD ;
bool Session : : _disable_all_loaded_plugins = false ;
2013-09-10 15:41:19 -04:00
PBD : : Signal1 < int , uint32_t > Session : : AudioEngineSetupRequired ;
2009-12-19 15:26:31 -05:00
PBD : : Signal1 < void , std : : string > Session : : Dialog ;
PBD : : Signal0 < int > Session : : AskAboutPendingState ;
2010-12-03 17:26:29 -05:00
PBD : : Signal2 < int , framecnt_t , framecnt_t > Session : : AskAboutSampleRateMismatch ;
2009-12-19 15:26:31 -05:00
PBD : : Signal0 < void > Session : : SendFeedback ;
2010-11-09 01:03:51 -05:00
PBD : : Signal3 < int , Session * , std : : string , DataType > Session : : MissingFile ;
2009-12-19 15:26:31 -05:00
2010-10-07 14:33:20 -04:00
PBD : : Signal1 < void , framepos_t > Session : : StartTimeChanged ;
PBD : : Signal1 < void , framepos_t > Session : : EndTimeChanged ;
2009-12-19 15:26:31 -05:00
PBD : : Signal2 < void , std : : string , std : : string > Session : : Exported ;
2009-12-20 11:50:41 -05:00
PBD : : Signal1 < int , boost : : shared_ptr < Playlist > > Session : : AskAboutPlaylistDeletion ;
2010-10-07 08:12:16 -04:00
PBD : : Signal0 < void > Session : : Quit ;
2011-11-09 12:44:39 -05:00
PBD : : Signal0 < void > Session : : FeedbackDetected ;
2011-11-11 08:52:27 -05:00
PBD : : Signal0 < void > Session : : SuccessfulGraphSort ;
2013-03-04 16:57:29 -05:00
PBD : : Signal2 < void , std : : string , std : : string > Session : : VersionMismatch ;
2008-06-02 17:41:35 -04:00
2014-05-26 00:58:44 -04:00
const framecnt_t Session : : bounce_chunk_size = 65536 ;
2009-12-10 12:45:18 -05:00
static void clean_up_session_event ( SessionEvent * ev ) { delete ev ; }
2009-12-11 18:30:48 -05:00
const SessionEvent : : RTeventCallback Session : : rt_cleanup ( clean_up_session_event ) ;
2009-12-10 12:45:18 -05:00
2012-06-18 14:28:26 -04:00
/** @param snapshot_name Snapshot name, without .ardour suffix */
2008-06-02 17:41:35 -04:00
Session : : Session ( AudioEngine & eng ,
2011-03-14 17:53:10 -04:00
const string & fullpath ,
const string & snapshot_name ,
2010-03-22 17:35:35 -04:00
BusProfile * bus_profile ,
2011-12-26 19:57:20 -05:00
string mix_template )
2013-09-10 15:41:19 -04:00
: playlists ( new SessionPlaylists )
, _engine ( eng )
, process_function ( & Session : : process_with_events )
2014-05-26 00:17:49 -04:00
, _bounce_processing_active ( false )
2013-09-10 15:41:19 -04:00
, waiting_for_sync_offset ( false )
, _base_frame_rate ( 0 )
, _current_frame_rate ( 0 )
, _nominal_frame_rate ( 0 )
, transport_sub_state ( 0 )
, _record_status ( Disabled )
, _transport_frame ( 0 )
, _session_range_location ( 0 )
, _slave ( 0 )
, _silent ( false )
, _transport_speed ( 0 )
, _default_transport_speed ( 1.0 )
, _last_transport_speed ( 0 )
2010-11-26 14:57:03 -05:00
, _target_transport_speed ( 0.0 )
2013-09-10 15:41:19 -04:00
, auto_play_legal ( false )
, _last_slave_transport_frame ( 0 )
, maximum_output_latency ( 0 )
2010-11-26 14:57:03 -05:00
, _requested_return_frame ( - 1 )
2013-09-10 15:41:19 -04:00
, current_block_size ( 0 )
, _worst_output_latency ( 0 )
, _worst_input_latency ( 0 )
, _worst_track_latency ( 0 )
, _have_captured ( false )
, _meter_hold ( 0 )
, _meter_falloff ( 0 )
, _non_soloed_outs_muted ( false )
, _listen_cnt ( 0 )
, _solo_isolated_cnt ( 0 )
, _writable ( false )
, _was_seamless ( Config - > get_seamless_loop ( ) )
2013-03-30 14:12:31 -04:00
, _under_nsm_control ( false )
2013-09-10 15:41:19 -04:00
, delta_accumulator_cnt ( 0 )
, average_slave_delta ( 1800 ) // !!! why 1800 ???
, average_dir ( 0 )
, have_first_delta_accumulator ( false )
, _slave_state ( Stopped )
, post_export_sync ( false )
, post_export_position ( 0 )
, _exporting ( false )
, _export_started ( false )
, _export_rolling ( false )
, _pre_export_mmc_enabled ( false )
, _name ( snapshot_name )
, _is_new ( true )
, _send_qf_mtc ( false )
, _pframes_since_last_mtc ( 0 )
, session_midi_feedback ( 0 )
, play_loop ( false )
, loop_changing ( false )
, last_loopend ( 0 )
2013-09-09 22:40:54 -04:00
, _session_dir ( new SessionDirectory ( fullpath ) )
2013-09-10 15:41:19 -04:00
, _current_snapshot_name ( snapshot_name )
2010-11-26 14:57:03 -05:00
, state_tree ( 0 )
2013-09-10 15:41:19 -04:00
, state_was_pending ( false )
2013-09-09 22:40:54 -04:00
, _state_of_the_state ( StateOfTheState ( CannotSave | InitialConnecting | Loading ) )
2014-06-28 15:27:36 -04:00
, _suspend_save ( 0 )
, _save_queued ( false )
2013-09-10 15:41:19 -04:00
, _last_roll_location ( 0 )
, _last_roll_or_reversal_location ( 0 )
, _last_record_location ( 0 )
, pending_locate_roll ( false )
, pending_locate_frame ( 0 )
, pending_locate_flush ( false )
, pending_abort ( false )
, pending_auto_loop ( false )
2010-11-26 14:57:03 -05:00
, _butler ( new Butler ( * this ) )
, _post_transport_work ( 0 )
2013-09-10 15:41:19 -04:00
, cumulative_rf_motion ( 0 )
, rf_scale ( 1.0 )
, _locations ( new Locations ( * this ) )
, step_speed ( 0 )
, outbound_mtc_timecode_frame ( 0 )
, next_quarter_frame_to_send ( - 1 )
, _frames_per_timecode_frame ( 0 )
, _frames_per_hour ( 0 )
, _timecode_frames_per_hour ( 0 )
, last_timecode_valid ( false )
, last_timecode_when ( 0 )
2010-11-26 14:57:03 -05:00
, _send_timecode_update ( false )
2013-09-10 15:41:19 -04:00
, ltc_encoder ( 0 )
2013-05-14 14:01:20 -04:00
, ltc_enc_buf ( 0 )
2013-09-10 15:41:19 -04:00
, ltc_buf_off ( 0 )
, ltc_buf_len ( 0 )
, ltc_speed ( 0 )
, ltc_enc_byte ( 0 )
, ltc_enc_pos ( 0 )
, ltc_enc_cnt ( 0 )
, ltc_enc_off ( 0 )
, restarting ( false )
, ltc_prev_cycle ( 0 )
, ltc_timecode_offset ( 0 )
, ltc_timecode_negative_offset ( false )
, midi_control_ui ( 0 )
, _tempo_map ( 0 )
2010-11-26 14:57:03 -05:00
, _all_route_group ( new RouteGroup ( * this , " all " ) )
, routes ( new RouteList )
2013-09-10 15:41:19 -04:00
, _adding_routes_in_progress ( false )
, destructive_index ( 0 )
2014-06-25 15:16:09 -04:00
, _track_number_decimals ( 1 )
2013-09-10 15:41:19 -04:00
, solo_update_disabled ( false )
, default_fade_steepness ( 0 )
, default_fade_msecs ( 0 )
2010-11-26 14:57:03 -05:00
, _total_free_4k_blocks ( 0 )
2012-06-12 12:41:29 -04:00
, _total_free_4k_blocks_uncertain ( false )
2013-09-10 15:41:19 -04:00
, no_questions_about_missing_files ( false )
, _playback_load ( 0 )
, _capture_load ( 0 )
2010-11-26 14:57:03 -05:00
, _bundles ( new BundleList )
, _bundle_xml_node ( 0 )
2011-01-19 12:38:46 -05:00
, _current_trans ( 0 )
2013-09-10 15:41:19 -04:00
, _clicking ( false )
2010-11-26 14:57:03 -05:00
, click_data ( 0 )
, click_emphasis_data ( 0 )
2013-09-10 15:41:19 -04:00
, click_length ( 0 )
, click_emphasis_length ( 0 )
, _clicks_cleared ( 0 )
2013-09-09 22:40:54 -04:00
, _play_range ( false )
2013-09-10 15:41:19 -04:00
, main_outs ( 0 )
2013-09-09 22:40:54 -04:00
, first_file_data_format_reset ( true )
, first_file_header_format_reset ( true )
2013-09-10 15:41:19 -04:00
, have_looped ( false )
, _have_rec_enabled_track ( false )
2013-09-09 22:40:54 -04:00
, _step_editors ( 0 )
2013-09-10 15:41:19 -04:00
, _suspend_timecode_transmission ( 0 )
2013-09-09 22:40:54 -04:00
, _speakers ( new Speakers )
2013-10-23 10:27:13 -04:00
, _order_hint ( 0 )
2013-09-09 22:40:54 -04:00
, ignore_route_processor_changes ( false )
2014-04-28 19:58:24 -04:00
, _scene_changer ( 0 )
2013-09-16 10:23:37 -04:00
, _midi_ports ( 0 )
, _mmc ( 0 )
2008-06-02 17:41:35 -04:00
{
2013-09-10 15:41:19 -04:00
uint32_t sr = 0 ;
2008-06-02 17:41:35 -04:00
2013-09-10 15:41:19 -04:00
pre_engine_init ( fullpath ) ;
2010-03-22 17:35:35 -04:00
if ( _is_new ) {
2013-09-16 09:57:22 -04:00
if ( ensure_engine ( sr ) ) {
destroy ( ) ;
throw failed_constructor ( ) ;
}
2010-05-09 16:48:21 -04:00
if ( create ( mix_template , bus_profile ) ) {
2008-06-02 17:41:35 -04:00
destroy ( ) ;
throw failed_constructor ( ) ;
}
2013-09-16 09:57:22 -04:00
2013-09-21 12:50:45 -04:00
/* if a mix template was provided, then ::create() will
* have copied it into the session and we need to load it
* so that we have the state ready for : : set_state ( )
* after the engine is started .
*
* Note that we do NOT try to get the sample rate from
* the template at this time , though doing so would
* be easy if we decided this was an appropriate part
* of a template .
*/
if ( ! mix_template . empty ( ) & & load_state ( _current_snapshot_name ) ) {
throw failed_constructor ( ) ;
}
2014-06-29 09:45:08 -04:00
/* load default session properties - if any */
config . load_state ( ) ;
2013-09-09 22:40:54 -04:00
} else {
2013-09-16 09:57:22 -04:00
2013-09-09 22:40:54 -04:00
if ( load_state ( _current_snapshot_name ) ) {
throw failed_constructor ( ) ;
}
2013-09-10 15:41:19 -04:00
/* try to get sample rate from XML state so that we
* can influence the SR if we set up the audio
* engine .
*/
if ( state_tree ) {
const XMLProperty * prop ;
if ( ( prop = state_tree - > root ( ) - > property ( X_ ( " sample-rate " ) ) ) ! = 0 ) {
sr = atoi ( prop - > value ( ) ) ;
}
}
2013-09-12 12:26:59 -04:00
2013-09-16 09:57:22 -04:00
if ( ensure_engine ( sr ) ) {
destroy ( ) ;
throw failed_constructor ( ) ;
}
2013-09-10 15:41:19 -04:00
}
if ( post_engine_init ( ) ) {
2008-06-02 17:41:35 -04:00
destroy ( ) ;
throw failed_constructor ( ) ;
}
2008-08-04 18:37:24 -04:00
2013-09-10 15:41:19 -04:00
store_recent_sessions ( _name , _path ) ;
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
bool was_dirty = dirty ( ) ;
_state_of_the_state = StateOfTheState ( _state_of_the_state & ~ Dirty ) ;
2009-12-21 13:23:07 -05:00
Config - > ParameterChanged . connect_same_thread ( * this , boost : : bind ( & Session : : config_changed , this , _1 , false ) ) ;
config . ParameterChanged . connect_same_thread ( * this , boost : : bind ( & Session : : config_changed , this , _1 , true ) ) ;
2008-06-02 17:41:35 -04:00
if ( was_dirty ) {
DirtyChanged ( ) ; /* EMIT SIGNAL */
}
2010-03-23 13:58:40 -04:00
2010-10-07 14:33:20 -04:00
StartTimeChanged . connect_same_thread ( * this , boost : : bind ( & Session : : start_time_changed , this , _1 ) ) ;
EndTimeChanged . connect_same_thread ( * this , boost : : bind ( & Session : : end_time_changed , this , _1 ) ) ;
2011-03-14 17:53:10 -04:00
_is_new = false ;
2013-09-11 16:33:40 -04:00
/* hook us up to the engine since we are now completely constructed */
BootMessage ( _ ( " Connect to engine " ) ) ;
_engine . set_session ( this ) ;
_engine . reset_timebase ( ) ;
BootMessage ( _ ( " Session loading complete " ) ) ;
2008-06-02 17:41:35 -04:00
}
Session : : ~ Session ( )
{
2012-01-14 17:02:59 -05:00
# ifdef PT_TIMING
ST . dump ( " ST.dump " ) ;
# endif
2008-06-02 17:41:35 -04:00
destroy ( ) ;
}
2013-09-12 17:06:21 -04:00
int
Session : : ensure_engine ( uint32_t desired_sample_rate )
{
if ( _engine . current_backend ( ) = = 0 ) {
/* backend is unknown ... */
boost : : optional < int > r = AudioEngineSetupRequired ( desired_sample_rate ) ;
if ( r . get_value_or ( - 1 ) ! = 0 ) {
return - 1 ;
}
} else if ( _engine . setup_required ( ) ) {
/* backend is known, but setup is needed */
boost : : optional < int > r = AudioEngineSetupRequired ( desired_sample_rate ) ;
if ( r . get_value_or ( - 1 ) ! = 0 ) {
return - 1 ;
}
} else if ( ! _engine . running ( ) ) {
if ( _engine . start ( ) ) {
return - 1 ;
}
}
/* at this point the engine should be running
*/
if ( ! _engine . running ( ) ) {
return - 1 ;
}
2013-09-16 12:08:19 -04:00
return immediately_post_engine ( ) ;
2013-09-16 09:57:22 -04:00
2013-09-16 12:08:19 -04:00
}
2013-09-16 09:57:22 -04:00
2013-09-16 12:08:19 -04:00
int
Session : : immediately_post_engine ( )
{
/* Do various initializations that should take place directly after we
* know that the engine is running , but before we either create a
* session or set state for an existing one .
*/
2013-09-16 09:57:22 -04:00
if ( how_many_dsp_threads ( ) > 1 ) {
/* For now, only create the graph if we are using >1 DSP threads, as
it is a bit slower than the old code with 1 thread .
*/
_process_graph . reset ( new Graph ( * this ) ) ;
}
2013-09-16 12:08:19 -04:00
/* every time we reconnect, recompute worst case output latencies */
_engine . Running . connect_same_thread ( * this , boost : : bind ( & Session : : initialize_latencies , this ) ) ;
2013-09-19 17:34:23 -04:00
if ( synced_to_engine ( ) ) {
2013-09-16 12:08:19 -04:00
_engine . transport_stop ( ) ;
}
if ( config . get_jack_time_master ( ) ) {
_engine . transport_locate ( _transport_frame ) ;
}
try {
BootMessage ( _ ( " Set up LTC " ) ) ;
setup_ltc ( ) ;
BootMessage ( _ ( " Set up Click " ) ) ;
setup_click ( ) ;
BootMessage ( _ ( " Set up standard connections " ) ) ;
setup_bundles ( ) ;
}
catch ( failed_constructor & err ) {
return - 1 ;
}
2013-09-12 17:06:21 -04:00
return 0 ;
}
2008-06-02 17:41:35 -04:00
void
Session : : destroy ( )
{
2009-11-25 09:37:20 -05:00
vector < void * > debug_pointers ;
2008-06-02 17:41:35 -04:00
/* if we got to here, leaving pending capture state around
is a mistake .
*/
remove_pending_capture_state ( ) ;
_state_of_the_state = StateOfTheState ( CannotSave | Deletion ) ;
2012-12-05 11:07:30 -05:00
/* disconnect from any and all signals that we are connected to */
drop_connections ( ) ;
2008-06-02 17:41:35 -04:00
_engine . remove_session ( ) ;
2012-06-21 11:00:10 -04:00
/* deregister all ports - there will be no process or any other
* callbacks from the engine any more .
*/
Port : : PortDrop ( ) ; /* EMIT SIGNAL */
2012-10-21 10:07:10 -04:00
ltc_tx_cleanup ( ) ;
2008-06-02 17:41:35 -04:00
/* clear history so that no references to objects are held any more */
_history . clear ( ) ;
/* clear state tree so that no references to objects are held any more */
2008-08-04 18:37:24 -04:00
2008-12-12 09:43:24 -05:00
delete state_tree ;
2008-06-02 17:41:35 -04:00
2009-10-15 14:56:11 -04:00
/* reset dynamic state version back to default */
2009-10-23 19:23:00 -04:00
2009-10-15 14:56:11 -04:00
Stateful : : loading_state_version = 0 ;
2010-04-14 19:58:20 -04:00
_butler - > drop_references ( ) ;
2009-12-23 23:04:01 -05:00
delete _butler ;
2012-06-14 07:45:10 -04:00
_butler = 0 ;
2009-12-08 22:05:14 -05:00
delete midi_control_ui ;
2011-03-14 17:53:10 -04:00
delete _all_route_group ;
2008-08-04 18:37:24 -04:00
2008-12-12 09:43:24 -05:00
if ( click_data ! = default_click ) {
2008-06-02 17:41:35 -04:00
delete [ ] click_data ;
}
2008-12-12 09:43:24 -05:00
if ( click_emphasis_data ! = default_click_emphasis ) {
2008-06-02 17:41:35 -04:00
delete [ ] click_emphasis_data ;
}
clear_clicks ( ) ;
2014-06-29 22:04:35 -04:00
/* need to remove auditioner before monitoring section
* otherwise it is re - connected */
auditioner . reset ( ) ;
/* drop references to routes held by the monitoring section
* specifically _monitor_out aux / listen references */
remove_monitor_section ( ) ;
2009-11-27 12:29:27 -05:00
/* clear out any pending dead wood from RCU managed objects */
routes . flush ( ) ;
_bundles . flush ( ) ;
2011-06-01 12:50:12 -04:00
2008-06-02 17:41:35 -04:00
AudioDiskstream : : free_working_buffers ( ) ;
2008-08-04 18:37:24 -04:00
2009-12-22 15:21:43 -05:00
/* tell everyone who is still standing that we're about to die */
drop_references ( ) ;
2008-06-02 17:41:35 -04:00
2009-12-22 15:21:43 -05:00
/* tell everyone to drop references and delete objects as we go */
2008-06-02 17:41:35 -04:00
2009-11-25 09:37:20 -05:00
DEBUG_TRACE ( DEBUG : : Destruction , " delete regions \n " ) ;
2010-03-06 10:40:42 -05:00
RegionFactory : : delete_all_regions ( ) ;
2008-06-02 17:41:35 -04:00
2009-11-25 09:37:20 -05:00
DEBUG_TRACE ( DEBUG : : Destruction , " delete routes \n " ) ;
2010-07-13 22:23:37 -04:00
2009-11-27 19:49:04 -05:00
/* reset these three references to special routes before we do the usual route delete thing */
_master_out . reset ( ) ;
2010-03-22 17:35:35 -04:00
_monitor_out . reset ( ) ;
2009-11-27 19:49:04 -05:00
2008-06-02 17:41:35 -04:00
{
RCUWriter < RouteList > writer ( routes ) ;
boost : : shared_ptr < RouteList > r = writer . get_copy ( ) ;
2009-12-22 15:21:43 -05:00
2008-06-02 17:41:35 -04:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2009-11-25 09:37:20 -05:00
DEBUG_TRACE ( DEBUG : : Destruction , string_compose ( " Dropping for route %1 ; pre-ref = %2 \n " , ( * i ) - > name ( ) , ( * i ) . use_count ( ) ) ) ;
2008-06-02 17:41:35 -04:00
( * i ) - > drop_references ( ) ;
}
2009-12-22 15:21:43 -05:00
2008-06-02 17:41:35 -04:00
r - > clear ( ) ;
/* writer goes out of scope and updates master */
}
routes . flush ( ) ;
2009-12-25 16:06:52 -05:00
2014-01-19 16:37:01 -05:00
{
DEBUG_TRACE ( DEBUG : : Destruction , " delete sources \n " ) ;
Glib : : Threads : : Mutex : : Lock lm ( source_lock ) ;
for ( SourceMap : : iterator i = sources . begin ( ) ; i ! = sources . end ( ) ; + + i ) {
DEBUG_TRACE ( DEBUG : : Destruction , string_compose ( " Dropping for source %1 ; pre-ref = %2 \n " , i - > second - > name ( ) , i - > second . use_count ( ) ) ) ;
i - > second - > drop_references ( ) ;
}
2009-11-27 19:49:04 -05:00
2014-01-19 16:37:01 -05:00
sources . clear ( ) ;
}
2009-11-27 19:49:04 -05:00
2009-11-25 09:37:20 -05:00
DEBUG_TRACE ( DEBUG : : Destruction , " delete route groups \n " ) ;
2009-07-03 20:20:02 -04:00
for ( list < RouteGroup * > : : iterator i = _route_groups . begin ( ) ; i ! = _route_groups . end ( ) ; + + i ) {
2011-06-01 12:50:12 -04:00
2008-06-02 17:41:35 -04:00
delete * i ;
}
2008-08-04 18:37:24 -04:00
2009-12-04 14:09:08 -05:00
/* not strictly necessary, but doing it here allows the shared_ptr debugging to work */
playlists . reset ( ) ;
2014-04-28 19:58:24 -04:00
delete _scene_changer ; _scene_changer = 0 ;
2013-09-16 10:23:37 -04:00
delete _mmc ; _mmc = 0 ;
delete _midi_ports ; _midi_ports = 0 ;
delete _locations ; _locations = 0 ;
2010-08-09 12:40:31 -04:00
2009-11-27 19:49:04 -05:00
DEBUG_TRACE ( DEBUG : : Destruction , " Session::destroy() done \n " ) ;
2011-02-10 13:13:15 -05:00
2011-02-10 13:33:43 -05:00
# ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
2011-02-10 13:13:15 -05:00
boost_debug_list_ptrs ( ) ;
2011-02-10 13:33:43 -05:00
# endif
2008-06-02 17:41:35 -04:00
}
void
2013-09-10 15:41:19 -04:00
Session : : setup_ltc ( )
2008-06-02 17:41:35 -04:00
{
2013-09-10 15:41:19 -04:00
XMLNode * child = 0 ;
2013-10-23 12:02:49 -04:00
_ltc_input . reset ( new IO ( * this , X_ ( " LTC In " ) , IO : : Input ) ) ;
_ltc_output . reset ( new IO ( * this , X_ ( " LTC Out " ) , IO : : Output ) ) ;
2013-09-10 15:41:19 -04:00
2013-10-23 12:02:49 -04:00
if ( state_tree & & ( child = find_named_node ( * state_tree - > root ( ) , X_ ( " LTC In " ) ) ) ! = 0 ) {
2013-09-10 15:41:19 -04:00
_ltc_input - > set_state ( * ( child - > children ( ) . front ( ) ) , Stateful : : loading_state_version ) ;
} else {
{
Glib : : Threads : : Mutex : : Lock lm ( AudioEngine : : instance ( ) - > process_lock ( ) ) ;
_ltc_input - > ensure_io ( ChanCount ( DataType : : AUDIO , 1 ) , true , this ) ;
}
reconnect_ltc_input ( ) ;
2008-06-02 17:41:35 -04:00
}
2013-09-10 15:41:19 -04:00
2013-10-23 12:02:49 -04:00
if ( state_tree & & ( child = find_named_node ( * state_tree - > root ( ) , X_ ( " LTC Out " ) ) ) ! = 0 ) {
2013-09-10 15:41:19 -04:00
_ltc_output - > set_state ( * ( child - > children ( ) . front ( ) ) , Stateful : : loading_state_version ) ;
} else {
{
Glib : : Threads : : Mutex : : Lock lm ( AudioEngine : : instance ( ) - > process_lock ( ) ) ;
_ltc_output - > ensure_io ( ChanCount ( DataType : : AUDIO , 1 ) , true , this ) ;
}
reconnect_ltc_output ( ) ;
2008-06-02 17:41:35 -04:00
}
2013-09-10 15:41:19 -04:00
/* fix up names of LTC ports because we don't want the normal
* IO style of NAME / TYPE - { in , out } N
*/
2013-10-23 12:02:49 -04:00
_ltc_input - > nth ( 0 ) - > set_name ( X_ ( " LTC-in " ) ) ;
_ltc_output - > nth ( 0 ) - > set_name ( X_ ( " LTC-out " ) ) ;
2013-09-10 15:41:19 -04:00
}
2008-06-02 17:41:35 -04:00
2013-09-10 15:41:19 -04:00
void
Session : : setup_click ( )
{
_clicking = false ;
2013-10-23 12:02:49 -04:00
_click_io . reset ( new ClickIO ( * this , X_ ( " Click " ) ) ) ;
2013-09-10 15:41:19 -04:00
_click_gain . reset ( new Amp ( * this ) ) ;
_click_gain - > activate ( ) ;
2013-10-02 16:17:22 -04:00
if ( state_tree ) {
2013-10-18 15:20:19 -04:00
setup_click_state ( state_tree - > root ( ) ) ;
} else {
setup_click_state ( 0 ) ;
2013-10-02 16:17:22 -04:00
}
}
void
2013-10-18 15:20:19 -04:00
Session : : setup_click_state ( const XMLNode * node )
2013-10-02 16:17:22 -04:00
{
const XMLNode * child = 0 ;
2013-10-18 15:20:19 -04:00
if ( node & & ( child = find_named_node ( * node , " Click " ) ) ! = 0 ) {
2012-10-25 15:46:23 -04:00
2013-09-10 15:41:19 -04:00
/* existing state for Click */
int c = 0 ;
2008-08-04 18:37:24 -04:00
2013-09-10 15:41:19 -04:00
if ( Stateful : : loading_state_version < 3000 ) {
c = _click_io - > set_state_2X ( * child - > children ( ) . front ( ) , Stateful : : loading_state_version , false ) ;
2012-10-25 15:46:23 -04:00
} else {
2013-09-10 15:41:19 -04:00
const XMLNodeList & children ( child - > children ( ) ) ;
XMLNodeList : : const_iterator i = children . begin ( ) ;
if ( ( c = _click_io - > set_state ( * * i , Stateful : : loading_state_version ) ) = = 0 ) {
+ + i ;
if ( i ! = children . end ( ) ) {
c = _click_gain - > set_state ( * * i , Stateful : : loading_state_version ) ;
2012-01-27 17:47:16 -05:00
}
2009-10-15 15:36:48 -04:00
}
2013-09-10 15:41:19 -04:00
}
2012-01-27 17:47:16 -05:00
2013-09-10 15:41:19 -04:00
if ( c = = 0 ) {
_clicking = Config - > get_clicking ( ) ;
2011-06-01 12:50:12 -04:00
2013-09-10 15:41:19 -04:00
} else {
2011-06-01 12:50:12 -04:00
2013-09-10 15:41:19 -04:00
error < < _ ( " could not setup Click I/O " ) < < endmsg ;
_clicking = false ;
}
2008-06-02 17:41:35 -04:00
2009-10-15 15:36:48 -04:00
2013-09-10 15:41:19 -04:00
} else {
2008-08-04 18:37:24 -04:00
2013-09-10 15:41:19 -04:00
/* default state for Click: dual-mono to first 2 physical outputs */
2008-06-02 17:41:35 -04:00
2013-09-10 15:41:19 -04:00
vector < string > outs ;
_engine . get_physical_outputs ( DataType : : AUDIO , outs ) ;
2010-07-27 21:40:36 -04:00
2013-09-10 15:41:19 -04:00
for ( uint32_t physport = 0 ; physport < 2 ; + + physport ) {
if ( outs . size ( ) > physport ) {
if ( _click_io - > add_port ( outs [ physport ] , this ) ) {
// relax, even though its an error
2010-07-27 21:40:36 -04:00
}
}
2008-06-02 17:41:35 -04:00
}
2011-06-01 12:50:12 -04:00
2013-09-10 15:41:19 -04:00
if ( _click_io - > n_ports ( ) > ChanCount : : ZERO ) {
_clicking = Config - > get_clicking ( ) ;
}
2008-06-02 17:41:35 -04:00
}
2013-09-10 15:41:19 -04:00
}
2008-06-02 17:41:35 -04:00
2013-09-10 15:41:19 -04:00
void
Session : : setup_bundles ( )
{
2010-07-27 21:40:36 -04:00
vector < string > inputs [ DataType : : num_types ] ;
vector < string > outputs [ DataType : : num_types ] ;
for ( uint32_t i = 0 ; i < DataType : : num_types ; + + i ) {
2010-08-04 11:42:45 -04:00
_engine . get_physical_inputs ( DataType ( DataType : : Symbol ( i ) ) , inputs [ i ] ) ;
_engine . get_physical_outputs ( DataType ( DataType : : Symbol ( i ) ) , outputs [ i ] ) ;
2010-07-27 21:40:36 -04:00
}
2009-01-23 19:57:34 -05:00
/* Create a set of Bundle objects that map
2009-02-02 17:17:06 -05:00
to the physical I / O currently available . We create both
mono and stereo bundles , so that the common cases of mono
and stereo tracks get bundles to put in their mixer strip
in / out menus . There may be a nicer way of achieving that ;
2009-10-14 12:10:01 -04:00
it doesn ' t really scale that well to higher channel counts
2009-05-13 17:34:09 -04:00
*/
2008-06-02 17:41:35 -04:00
2009-06-16 10:58:33 -04:00
/* mono output bundles */
2010-07-27 21:40:36 -04:00
for ( uint32_t np = 0 ; np < outputs [ DataType : : AUDIO ] . size ( ) ; + + np ) {
2008-06-02 17:41:35 -04:00
char buf [ 32 ] ;
snprintf ( buf , sizeof ( buf ) , _ ( " out % " PRIu32 ) , np + 1 ) ;
2011-03-14 17:53:10 -04:00
boost : : shared_ptr < Bundle > c ( new Bundle ( buf , true ) ) ;
2010-06-29 22:59:13 -04:00
c - > add_channel ( _ ( " mono " ) , DataType : : AUDIO ) ;
2010-07-27 21:40:36 -04:00
c - > set_port ( 0 , outputs [ DataType : : AUDIO ] [ np ] ) ;
2008-06-02 17:41:35 -04:00
2009-10-14 12:10:01 -04:00
add_bundle ( c ) ;
2008-06-02 17:41:35 -04:00
}
2009-06-16 10:58:33 -04:00
/* stereo output bundles */
2010-07-27 21:40:36 -04:00
for ( uint32_t np = 0 ; np < outputs [ DataType : : AUDIO ] . size ( ) ; np + = 2 ) {
if ( np + 1 < outputs [ DataType : : AUDIO ] . size ( ) ) {
2009-02-02 17:17:06 -05:00
char buf [ 32 ] ;
snprintf ( buf , sizeof ( buf ) , _ ( " out % " PRIu32 " +% " PRIu32 ) , np + 1 , np + 2 ) ;
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < Bundle > c ( new Bundle ( buf , true ) ) ;
2010-06-29 22:59:13 -04:00
c - > add_channel ( _ ( " L " ) , DataType : : AUDIO ) ;
2010-07-27 21:40:36 -04:00
c - > set_port ( 0 , outputs [ DataType : : AUDIO ] [ np ] ) ;
2010-06-29 22:59:13 -04:00
c - > add_channel ( _ ( " R " ) , DataType : : AUDIO ) ;
2010-07-27 21:40:36 -04:00
c - > set_port ( 1 , outputs [ DataType : : AUDIO ] [ np + 1 ] ) ;
2009-02-02 17:17:06 -05:00
add_bundle ( c ) ;
}
}
2009-06-16 10:58:33 -04:00
/* mono input bundles */
2010-07-27 21:40:36 -04:00
for ( uint32_t np = 0 ; np < inputs [ DataType : : AUDIO ] . size ( ) ; + + np ) {
2008-06-02 17:41:35 -04:00
char buf [ 32 ] ;
snprintf ( buf , sizeof ( buf ) , _ ( " in % " PRIu32 ) , np + 1 ) ;
2011-03-14 17:53:10 -04:00
boost : : shared_ptr < Bundle > c ( new Bundle ( buf , false ) ) ;
2010-06-29 22:59:13 -04:00
c - > add_channel ( _ ( " mono " ) , DataType : : AUDIO ) ;
2010-07-27 21:40:36 -04:00
c - > set_port ( 0 , inputs [ DataType : : AUDIO ] [ np ] ) ;
2008-06-02 17:41:35 -04:00
2009-10-14 12:10:01 -04:00
add_bundle ( c ) ;
2008-06-02 17:41:35 -04:00
}
2009-06-16 10:58:33 -04:00
/* stereo input bundles */
2010-07-27 21:40:36 -04:00
for ( uint32_t np = 0 ; np < inputs [ DataType : : AUDIO ] . size ( ) ; np + = 2 ) {
if ( np + 1 < inputs [ DataType : : AUDIO ] . size ( ) ) {
2009-02-02 17:17:06 -05:00
char buf [ 32 ] ;
snprintf ( buf , sizeof ( buf ) , _ ( " in % " PRIu32 " +% " PRIu32 ) , np + 1 , np + 2 ) ;
2011-03-14 17:53:10 -04:00
boost : : shared_ptr < Bundle > c ( new Bundle ( buf , false ) ) ;
2010-06-29 22:59:13 -04:00
c - > add_channel ( _ ( " L " ) , DataType : : AUDIO ) ;
2010-07-27 21:40:36 -04:00
c - > set_port ( 0 , inputs [ DataType : : AUDIO ] [ np ] ) ;
2010-06-29 22:59:13 -04:00
c - > add_channel ( _ ( " R " ) , DataType : : AUDIO ) ;
2010-07-27 21:40:36 -04:00
c - > set_port ( 1 , inputs [ DataType : : AUDIO ] [ np + 1 ] ) ;
2009-02-02 17:17:06 -05:00
add_bundle ( c ) ;
}
}
2009-10-14 12:10:01 -04:00
2010-07-27 20:43:15 -04:00
/* MIDI input bundles */
2010-07-27 21:40:36 -04:00
for ( uint32_t np = 0 ; np < inputs [ DataType : : MIDI ] . size ( ) ; + + np ) {
string n = inputs [ DataType : : MIDI ] [ np ] ;
2010-07-27 20:43:15 -04:00
boost : : erase_first ( n , X_ ( " alsa_pcm: " ) ) ;
2011-06-01 12:50:12 -04:00
2011-03-14 17:53:10 -04:00
boost : : shared_ptr < Bundle > c ( new Bundle ( n , false ) ) ;
2010-07-27 20:43:15 -04:00
c - > add_channel ( " " , DataType : : MIDI ) ;
2010-07-27 21:40:36 -04:00
c - > set_port ( 0 , inputs [ DataType : : MIDI ] [ np ] ) ;
2010-07-27 20:43:15 -04:00
add_bundle ( c ) ;
}
2011-06-01 12:50:12 -04:00
2010-07-27 20:43:15 -04:00
/* MIDI output bundles */
2010-07-27 21:40:36 -04:00
for ( uint32_t np = 0 ; np < outputs [ DataType : : MIDI ] . size ( ) ; + + np ) {
string n = outputs [ DataType : : MIDI ] [ np ] ;
2010-07-27 20:43:15 -04:00
boost : : erase_first ( n , X_ ( " alsa_pcm: " ) ) ;
2011-03-14 17:53:10 -04:00
boost : : shared_ptr < Bundle > c ( new Bundle ( n , true ) ) ;
2010-07-27 20:43:15 -04:00
c - > add_channel ( " " , DataType : : MIDI ) ;
2010-07-27 21:40:36 -04:00
c - > set_port ( 0 , outputs [ DataType : : MIDI ] [ np ] ) ;
2010-07-27 20:43:15 -04:00
add_bundle ( c ) ;
}
2013-09-10 15:41:19 -04:00
}
2012-01-17 20:30:44 -05:00
void
Session : : auto_connect_master_bus ( )
{
if ( ! _master_out | | ! Config - > get_auto_connect_standard_busses ( ) | | _monitor_out ) {
return ;
}
/* if requested auto-connect the outputs to the first N physical ports.
*/
uint32_t limit = _master_out - > n_outputs ( ) . n_total ( ) ;
vector < string > outputs [ DataType : : num_types ] ;
for ( uint32_t i = 0 ; i < DataType : : num_types ; + + i ) {
_engine . get_physical_outputs ( DataType ( DataType : : Symbol ( i ) ) , outputs [ i ] ) ;
}
for ( uint32_t n = 0 ; n < limit ; + + n ) {
boost : : shared_ptr < Port > p = _master_out - > output ( ) - > nth ( n ) ;
string connect_to ;
if ( outputs [ p - > type ( ) ] . size ( ) > n ) {
connect_to = outputs [ p - > type ( ) ] [ n ] ;
}
if ( ! connect_to . empty ( ) & & p - > connected_to ( connect_to ) = = false ) {
if ( _master_out - > output ( ) - > connect ( p , connect_to , this ) ) {
error < < string_compose ( _ ( " cannot connect master output %1 to %2 " ) , n , connect_to )
< < endmsg ;
break ;
2009-05-13 17:34:09 -04:00
}
2008-06-02 17:41:35 -04:00
}
2012-01-17 20:30:44 -05:00
}
}
2008-06-02 17:41:35 -04:00
2012-01-17 20:30:44 -05:00
void
Session : : remove_monitor_section ( )
{
if ( ! _monitor_out ) {
return ;
}
2008-06-02 17:41:35 -04:00
2012-03-25 15:38:17 -04:00
/* force reversion to Solo-In-Place */
2012-01-17 20:30:44 -05:00
Config - > set_solo_control_is_listen_control ( false ) ;
2009-07-01 09:36:50 -04:00
2014-01-16 17:22:19 -05:00
/* if we are auditioning, cancel it ... this is a workaround
to a problem ( auditioning does not execute the process graph ,
which is needed to remove routes when using > 1 core for processing )
*/
cancel_audition ( ) ;
2012-01-17 20:30:44 -05:00
{
/* Hold process lock while doing this so that we don't hear bits and
* pieces of audio as we work on each route .
*/
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( AudioEngine : : instance ( ) - > process_lock ( ) ) ;
2012-01-17 20:30:44 -05:00
/* Connect tracks to monitor section. Note that in an
existing session , the internal sends will already exist , but we want the
routes to notice that they connect to the control out specifically .
*/
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
PBD : : Unwinder < bool > uw ( ignore_route_processor_changes , true ) ;
for ( RouteList : : iterator x = r - > begin ( ) ; x ! = r - > end ( ) ; + + x ) {
if ( ( * x ) - > is_monitor ( ) ) {
/* relax */
} else if ( ( * x ) - > is_master ( ) ) {
/* relax */
} else {
2012-01-18 12:51:57 -05:00
( * x ) - > remove_aux_or_listen ( _monitor_out ) ;
2012-01-17 20:30:44 -05:00
}
}
}
2009-07-01 09:36:50 -04:00
2012-01-17 20:30:44 -05:00
remove_route ( _monitor_out ) ;
auto_connect_master_bus ( ) ;
2014-01-16 17:22:19 -05:00
if ( auditioner ) {
auditioner - > connect ( ) ;
}
2012-01-17 20:30:44 -05:00
}
2009-10-14 12:10:01 -04:00
2012-01-17 20:30:44 -05:00
void
Session : : add_monitor_section ( )
{
RouteList rl ;
2009-10-14 12:10:01 -04:00
2012-01-17 20:30:44 -05:00
if ( _monitor_out | | ! _master_out ) {
return ;
}
2009-07-01 09:36:50 -04:00
2014-08-01 16:44:42 -04:00
boost : : shared_ptr < Route > r ( new Route ( * this , _ ( " Monitor " ) , Route : : MonitorOut , DataType : : AUDIO ) ) ;
2009-07-01 09:36:50 -04:00
2012-01-17 20:30:44 -05:00
if ( r - > init ( ) ) {
return ;
}
2009-07-01 09:36:50 -04:00
2012-01-17 20:30:44 -05:00
# ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
// boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
# endif
{
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( AudioEngine : : instance ( ) - > process_lock ( ) ) ;
2012-01-17 20:30:44 -05:00
r - > input ( ) - > ensure_io ( _master_out - > output ( ) - > n_ports ( ) , false , this ) ;
r - > output ( ) - > ensure_io ( _master_out - > output ( ) - > n_ports ( ) , false , this ) ;
}
2009-07-01 09:36:50 -04:00
2012-01-17 20:30:44 -05:00
rl . push_back ( r ) ;
2012-03-07 08:24:20 -05:00
add_routes ( rl , false , false , false ) ;
2012-01-17 20:30:44 -05:00
assert ( _monitor_out ) ;
2009-07-01 09:36:50 -04:00
2012-01-17 20:30:44 -05:00
/* AUDIO ONLY as of june 29th 2009, because listen semantics for anything else
are undefined , at best .
*/
uint32_t limit = _monitor_out - > n_inputs ( ) . n_audio ( ) ;
if ( _master_out ) {
/* connect the inputs to the master bus outputs. this
* represents a separate data feed from the internal sends from
* each route . as of jan 2011 , it allows the monitor section to
* conditionally ignore either the internal sends or the normal
* input feed , but we should really find a better way to do
* this , i think .
*/
_master_out - > output ( ) - > disconnect ( this ) ;
for ( uint32_t n = 0 ; n < limit ; + + n ) {
boost : : shared_ptr < AudioPort > p = _monitor_out - > input ( ) - > ports ( ) . nth_audio_port ( n ) ;
boost : : shared_ptr < AudioPort > o = _master_out - > output ( ) - > ports ( ) . nth_audio_port ( n ) ;
if ( o ) {
string connect_to = o - > name ( ) ;
if ( _monitor_out - > input ( ) - > connect ( p , connect_to , this ) ) {
error < < string_compose ( _ ( " cannot connect control input %1 to %2 " ) , n , connect_to )
< < endmsg ;
break ;
}
}
}
}
/* if monitor section is not connected, connect it to physical outs
*/
if ( Config - > get_auto_connect_standard_busses ( ) & & ! _monitor_out - > output ( ) - > connected ( ) ) {
if ( ! Config - > get_monitor_bus_preferred_bundle ( ) . empty ( ) ) {
boost : : shared_ptr < Bundle > b = bundle_by_name ( Config - > get_monitor_bus_preferred_bundle ( ) ) ;
if ( b ) {
2012-10-18 12:15:11 -04:00
_monitor_out - > output ( ) - > connect_ports_to_bundle ( b , true , this ) ;
2012-01-17 20:30:44 -05:00
} else {
warning < < string_compose ( _ ( " The preferred I/O for the monitor bus (%1) cannot be found " ) ,
Config - > get_monitor_bus_preferred_bundle ( ) )
< < endmsg ;
}
} else {
/* Monitor bus is audio only */
2009-07-01 19:14:27 -04:00
2012-01-17 20:30:44 -05:00
vector < string > outputs [ DataType : : num_types ] ;
2011-03-14 17:53:10 -04:00
2012-01-17 20:30:44 -05:00
for ( uint32_t i = 0 ; i < DataType : : num_types ; + + i ) {
_engine . get_physical_outputs ( DataType ( DataType : : Symbol ( i ) ) , outputs [ i ] ) ;
}
2013-09-16 12:08:19 -04:00
uint32_t mod = outputs [ DataType : : AUDIO ] . size ( ) ;
uint32_t limit = _monitor_out - > n_outputs ( ) . get ( DataType : : AUDIO ) ;
2012-01-17 20:30:44 -05:00
if ( mod ! = 0 ) {
for ( uint32_t n = 0 ; n < limit ; + + n ) {
boost : : shared_ptr < Port > p = _monitor_out - > output ( ) - > ports ( ) . port ( DataType : : AUDIO , n ) ;
string connect_to ;
if ( outputs [ DataType : : AUDIO ] . size ( ) > ( n % mod ) ) {
connect_to = outputs [ DataType : : AUDIO ] [ n % mod ] ;
}
if ( ! connect_to . empty ( ) ) {
if ( _monitor_out - > output ( ) - > connect ( p , connect_to , this ) ) {
error < < string_compose (
_ ( " cannot connect control output %1 to %2 " ) ,
n , connect_to )
< < endmsg ;
break ;
2009-07-01 19:14:27 -04:00
}
2009-06-16 10:58:33 -04:00
}
}
2008-06-02 17:41:35 -04:00
}
}
}
2012-01-17 20:30:44 -05:00
/* Hold process lock while doing this so that we don't hear bits and
* pieces of audio as we work on each route .
*/
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( AudioEngine : : instance ( ) - > process_lock ( ) ) ;
2008-06-02 17:41:35 -04:00
2012-01-17 20:30:44 -05:00
/* Connect tracks to monitor section. Note that in an
existing session , the internal sends will already exist , but we want the
routes to notice that they connect to the control out specifically .
*/
2011-09-21 13:28:13 -04:00
2012-01-17 20:30:44 -05:00
boost : : shared_ptr < RouteList > rls = routes . reader ( ) ;
2008-06-02 17:41:35 -04:00
2012-01-17 20:30:44 -05:00
PBD : : Unwinder < bool > uw ( ignore_route_processor_changes , true ) ;
for ( RouteList : : iterator x = rls - > begin ( ) ; x ! = rls - > end ( ) ; + + x ) {
if ( ( * x ) - > is_monitor ( ) ) {
/* relax */
} else if ( ( * x ) - > is_master ( ) ) {
/* relax */
} else {
( * x ) - > enable_monitor_send ( ) ;
}
}
2014-01-16 17:22:19 -05:00
if ( auditioner ) {
auditioner - > connect ( ) ;
}
2008-06-02 17:41:35 -04:00
}
void
2010-03-22 17:35:35 -04:00
Session : : hookup_io ( )
2008-06-02 17:41:35 -04:00
{
/* stop graph reordering notifications from
causing resorts , etc .
*/
_state_of_the_state = StateOfTheState ( _state_of_the_state | InitialConnecting ) ;
2009-05-13 17:34:09 -04:00
if ( ! auditioner ) {
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
/* we delay creating the auditioner till now because
it makes its own connections to ports .
*/
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
try {
2011-02-22 16:15:42 -05:00
boost : : shared_ptr < Auditioner > a ( new Auditioner ( * this ) ) ;
2010-11-26 14:57:03 -05:00
if ( a - > init ( ) ) {
2011-02-22 16:15:42 -05:00
throw failed_constructor ( ) ;
2010-11-26 14:57:03 -05:00
}
a - > use_new_diskstream ( ) ;
2011-02-22 16:15:42 -05:00
auditioner = a ;
2008-06-02 17:41:35 -04:00
}
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
catch ( failed_constructor & err ) {
warning < < _ ( " cannot create Auditioner: no auditioning of regions possible " ) < < endmsg ;
}
}
/* load bundles, which we may have postponed earlier on */
if ( _bundle_xml_node ) {
load_bundles ( * _bundle_xml_node ) ;
delete _bundle_xml_node ;
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
/* Tell all IO objects to connect themselves together */
IO : : enable_connecting ( ) ;
2013-08-07 22:22:11 -04:00
/* Now tell all "floating" ports to connect to whatever
they should be connected to .
*/
AudioEngine : : instance ( ) - > reconnect_ports ( ) ;
2008-06-02 17:41:35 -04:00
/* Anyone who cares about input state, wake up and do something */
IOConnectionsComplete ( ) ; /* EMIT SIGNAL */
_state_of_the_state = StateOfTheState ( _state_of_the_state & ~ InitialConnecting ) ;
/* now handle the whole enchilada as if it was one
graph reorder event .
*/
graph_reordered ( ) ;
2009-07-01 09:36:50 -04:00
/* update the full solo state, which can't be
correctly determined on a per - route basis , but
needs the global overview that only the session
has .
*/
2008-06-02 17:41:35 -04:00
2009-07-01 09:36:50 -04:00
update_route_solo_state ( ) ;
2008-06-02 17:41:35 -04:00
}
void
2010-04-21 16:42:22 -04:00
Session : : track_playlist_changed ( boost : : weak_ptr < Track > wp )
2008-06-02 17:41:35 -04:00
{
2010-04-21 16:42:22 -04:00
boost : : shared_ptr < Track > track = wp . lock ( ) ;
if ( ! track ) {
2009-11-10 18:54:04 -05:00
return ;
}
2011-06-01 12:50:12 -04:00
2008-06-02 17:41:35 -04:00
boost : : shared_ptr < Playlist > playlist ;
2010-04-21 16:42:22 -04:00
if ( ( playlist = track - > playlist ( ) ) ! = 0 ) {
2011-01-19 12:38:56 -05:00
playlist - > RegionAdded . connect_same_thread ( * this , boost : : bind ( & Session : : playlist_region_added , this , _1 ) ) ;
playlist - > RangesMoved . connect_same_thread ( * this , boost : : bind ( & Session : : playlist_ranges_moved , this , _1 ) ) ;
2011-03-01 11:23:31 -05:00
playlist - > RegionsExtended . connect_same_thread ( * this , boost : : bind ( & Session : : playlist_regions_extended , this , _1 ) ) ;
2008-06-02 17:41:35 -04:00
}
}
bool
Session : : record_enabling_legal ( ) const
{
/* this used to be in here, but survey says.... we don't need to restrict it */
2009-10-14 12:10:01 -04:00
// if (record_status() == Recording) {
// return false;
// }
2008-06-02 17:41:35 -04:00
if ( Config - > get_all_safe ( ) ) {
return false ;
}
return true ;
}
2011-03-05 18:16:32 -05:00
void
Session : : set_track_monitor_input_status ( bool yn )
{
2011-03-14 17:53:10 -04:00
boost : : shared_ptr < RouteList > rl = routes . reader ( ) ;
for ( RouteList : : iterator i = rl - > begin ( ) ; i ! = rl - > end ( ) ; + + i ) {
boost : : shared_ptr < AudioTrack > tr = boost : : dynamic_pointer_cast < AudioTrack > ( * i ) ;
if ( tr & & tr - > record_enabled ( ) ) {
//cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl;
2013-08-09 13:56:23 -04:00
tr - > request_input_monitoring ( yn ) ;
2011-03-14 17:53:10 -04:00
}
}
2011-03-05 18:16:32 -05:00
}
2008-06-02 17:41:35 -04:00
void
Session : : auto_punch_start_changed ( Location * location )
{
2009-12-03 21:15:12 -05:00
replace_event ( SessionEvent : : PunchIn , location - > start ( ) ) ;
2008-06-02 17:41:35 -04:00
2009-05-13 20:13:27 -04:00
if ( get_record_enabled ( ) & & config . get_punch_in ( ) ) {
2008-06-02 17:41:35 -04:00
/* capture start has been changed, so save new pending state */
save_state ( " " , true ) ;
}
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
void
Session : : auto_punch_end_changed ( Location * location )
{
2010-12-03 17:26:29 -05:00
framepos_t when_to_stop = location - > end ( ) ;
2008-06-02 17:41:35 -04:00
// when_to_stop += _worst_output_latency + _worst_input_latency;
2009-12-03 21:15:12 -05:00
replace_event ( SessionEvent : : PunchOut , when_to_stop ) ;
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
void
Session : : auto_punch_changed ( Location * location )
{
2010-12-03 17:26:29 -05:00
framepos_t when_to_stop = location - > end ( ) ;
2008-06-02 17:41:35 -04:00
2009-12-03 21:15:12 -05:00
replace_event ( SessionEvent : : PunchIn , location - > start ( ) ) ;
2008-06-02 17:41:35 -04:00
//when_to_stop += _worst_output_latency + _worst_input_latency;
2009-12-03 21:15:12 -05:00
replace_event ( SessionEvent : : PunchOut , when_to_stop ) ;
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
2012-06-20 14:46:05 -04:00
/** @param loc A loop location.
* @ param pos Filled in with the start time of the required fade - out ( in session frames ) .
* @ param length Filled in with the length of the required fade - out .
*/
void
Session : : auto_loop_declick_range ( Location * loc , framepos_t & pos , framepos_t & length )
{
pos = max ( loc - > start ( ) , loc - > end ( ) - 64 ) ;
length = loc - > end ( ) - pos ;
}
2008-06-02 17:41:35 -04:00
void
Session : : auto_loop_changed ( Location * location )
{
2009-12-03 21:15:12 -05:00
replace_event ( SessionEvent : : AutoLoop , location - > end ( ) , location - > start ( ) ) ;
2012-06-20 14:46:05 -04:00
framepos_t dcp ;
framecnt_t dcl ;
auto_loop_declick_range ( location , dcp , dcl ) ;
replace_event ( SessionEvent : : AutoLoopDeclick , dcp , dcl ) ;
2008-06-02 17:41:35 -04:00
if ( transport_rolling ( ) & & play_loop ) {
2009-10-30 14:14:25 -04:00
// if (_transport_frame > location->end()) {
if ( _transport_frame < location - > start ( ) | | _transport_frame > location - > end ( ) ) {
2008-06-02 17:41:35 -04:00
// relocate to beginning of loop
2009-12-03 21:15:12 -05:00
clear_events ( SessionEvent : : LocateRoll ) ;
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
request_locate ( location - > start ( ) , true ) ;
}
else if ( Config - > get_seamless_loop ( ) & & ! loop_changing ) {
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
// schedule a locate-roll to refill the diskstreams at the
// previous loop end
loop_changing = true ;
if ( location - > end ( ) > last_loopend ) {
2009-12-03 21:15:12 -05:00
clear_events ( SessionEvent : : LocateRoll ) ;
SessionEvent * ev = new SessionEvent ( SessionEvent : : LocateRoll , SessionEvent : : Add , last_loopend , last_loopend , 0 , true ) ;
2008-06-02 17:41:35 -04:00
queue_event ( ev ) ;
}
}
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
last_loopend = location - > end ( ) ;
}
void
Session : : set_auto_punch_location ( Location * location )
{
Location * existing ;
2010-08-09 12:40:31 -04:00
if ( ( existing = _locations - > auto_punch_location ( ) ) ! = 0 & & existing ! = location ) {
2009-12-17 13:24:23 -05:00
punch_connections . drop_connections ( ) ;
2008-06-02 17:41:35 -04:00
existing - > set_auto_punch ( false , this ) ;
2009-12-03 21:15:12 -05:00
remove_event ( existing - > start ( ) , SessionEvent : : PunchIn ) ;
clear_events ( SessionEvent : : PunchOut ) ;
2008-06-02 17:41:35 -04:00
auto_punch_location_changed ( 0 ) ;
}
set_dirty ( ) ;
if ( location = = 0 ) {
return ;
}
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
if ( location - > end ( ) < = location - > start ( ) ) {
error < < _ ( " Session: you can't use that location for auto punch (start <= end) " ) < < endmsg ;
return ;
}
2009-12-17 13:24:23 -05:00
punch_connections . drop_connections ( ) ;
2008-08-04 18:37:24 -04:00
2009-12-21 13:23:07 -05:00
location - > start_changed . connect_same_thread ( punch_connections , boost : : bind ( & Session : : auto_punch_start_changed , this , _1 ) ) ;
location - > end_changed . connect_same_thread ( punch_connections , boost : : bind ( & Session : : auto_punch_end_changed , this , _1 ) ) ;
location - > changed . connect_same_thread ( punch_connections , boost : : bind ( & Session : : auto_punch_changed , this , _1 ) ) ;
2008-06-02 17:41:35 -04:00
location - > set_auto_punch ( true , this ) ;
auto_punch_changed ( location ) ;
auto_punch_location_changed ( location ) ;
}
void
Session : : set_auto_loop_location ( Location * location )
{
Location * existing ;
2010-08-09 12:40:31 -04:00
if ( ( existing = _locations - > auto_loop_location ( ) ) ! = 0 & & existing ! = location ) {
2009-12-17 13:24:23 -05:00
loop_connections . drop_connections ( ) ;
2008-06-02 17:41:35 -04:00
existing - > set_auto_loop ( false , this ) ;
2009-12-03 21:15:12 -05:00
remove_event ( existing - > end ( ) , SessionEvent : : AutoLoop ) ;
2012-06-20 14:46:05 -04:00
framepos_t dcp ;
framecnt_t dcl ;
auto_loop_declick_range ( existing , dcp , dcl ) ;
remove_event ( dcp , SessionEvent : : AutoLoopDeclick ) ;
2008-06-02 17:41:35 -04:00
auto_loop_location_changed ( 0 ) ;
}
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
set_dirty ( ) ;
if ( location = = 0 ) {
return ;
}
if ( location - > end ( ) < = location - > start ( ) ) {
2013-01-15 09:15:01 -05:00
error < < _ ( " You cannot use this location for auto-loop because it has zero or negative length " ) < < endmsg ;
2008-06-02 17:41:35 -04:00
return ;
}
last_loopend = location - > end ( ) ;
2008-08-04 18:37:24 -04:00
2009-12-17 13:24:23 -05:00
loop_connections . drop_connections ( ) ;
2008-08-04 18:37:24 -04:00
2009-12-21 13:23:07 -05:00
location - > start_changed . connect_same_thread ( loop_connections , boost : : bind ( & Session : : auto_loop_changed , this , _1 ) ) ;
location - > end_changed . connect_same_thread ( loop_connections , boost : : bind ( & Session : : auto_loop_changed , this , _1 ) ) ;
location - > changed . connect_same_thread ( loop_connections , boost : : bind ( & Session : : auto_loop_changed , this , _1 ) ) ;
2008-06-02 17:41:35 -04:00
location - > set_auto_loop ( true , this ) ;
/* take care of our stuff first */
auto_loop_changed ( location ) ;
/* now tell everyone else */
auto_loop_location_changed ( location ) ;
}
void
2009-07-21 11:55:17 -04:00
Session : : locations_added ( Location * )
2008-06-02 17:41:35 -04:00
{
set_dirty ( ) ;
}
void
Session : : locations_changed ( )
{
2010-08-09 12:40:31 -04:00
_locations - > apply ( * this , & Session : : handle_locations_changed ) ;
2008-06-02 17:41:35 -04:00
}
void
Session : : handle_locations_changed ( Locations : : LocationList & locations )
{
Locations : : LocationList : : iterator i ;
Location * location ;
bool set_loop = false ;
bool set_punch = false ;
for ( i = locations . begin ( ) ; i ! = locations . end ( ) ; + + i ) {
location = * i ;
if ( location - > is_auto_punch ( ) ) {
set_auto_punch_location ( location ) ;
set_punch = true ;
}
if ( location - > is_auto_loop ( ) ) {
set_auto_loop_location ( location ) ;
set_loop = true ;
}
2008-08-04 18:37:24 -04:00
2010-04-18 17:29:48 -04:00
if ( location - > is_session_range ( ) ) {
_session_range_location = location ;
2008-09-10 11:03:30 -04:00
}
2008-06-02 17:41:35 -04:00
}
if ( ! set_loop ) {
set_auto_loop_location ( 0 ) ;
}
if ( ! set_punch ) {
set_auto_punch_location ( 0 ) ;
}
set_dirty ( ) ;
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
void
Session : : enable_record ( )
{
2011-08-11 13:36:42 -04:00
if ( _transport_speed ! = 0.0 & & _transport_speed ! = 1.0 ) {
2011-08-10 16:21:18 -04:00
/* no recording at anything except normal speed */
2011-08-09 17:17:55 -04:00
return ;
}
2010-11-26 14:57:03 -05:00
while ( 1 ) {
RecordState rs = ( RecordState ) g_atomic_int_get ( & _record_status ) ;
2011-06-01 12:50:12 -04:00
2010-11-26 14:57:03 -05:00
if ( rs = = Recording ) {
break ;
}
2011-08-09 17:17:55 -04:00
2010-11-26 14:57:03 -05:00
if ( g_atomic_int_compare_and_exchange ( & _record_status , rs , Recording ) ) {
2011-06-01 12:50:12 -04:00
2010-11-26 14:57:03 -05:00
_last_record_location = _transport_frame ;
2013-09-05 13:22:34 -04:00
_mmc - > send ( MIDI : : MachineControlCommand ( MIDI : : MachineControl : : cmdRecordStrobe ) ) ;
2011-06-01 12:50:12 -04:00
2010-11-26 14:57:03 -05:00
if ( Config - > get_monitoring_model ( ) = = HardwareMonitoring & & config . get_auto_input ( ) ) {
2011-03-14 17:53:10 -04:00
set_track_monitor_input_status ( true ) ;
2010-11-26 14:57:03 -05:00
}
2011-06-01 12:50:12 -04:00
2010-11-26 14:57:03 -05:00
RecordStateChanged ( ) ;
break ;
}
}
2008-06-02 17:41:35 -04:00
}
void
Session : : disable_record ( bool rt_context , bool force )
{
RecordState rs ;
if ( ( rs = ( RecordState ) g_atomic_int_get ( & _record_status ) ) ! = Disabled ) {
if ( ( ! Config - > get_latched_record_enable ( ) & & ! play_loop ) | | force ) {
g_atomic_int_set ( & _record_status , Disabled ) ;
2013-09-05 13:22:34 -04:00
_mmc - > send ( MIDI : : MachineControlCommand ( MIDI : : MachineControl : : cmdRecordExit ) ) ;
2008-06-02 17:41:35 -04:00
} else {
if ( rs = = Recording ) {
g_atomic_int_set ( & _record_status , Enabled ) ;
}
}
2009-05-13 20:13:27 -04:00
if ( Config - > get_monitoring_model ( ) = = HardwareMonitoring & & config . get_auto_input ( ) ) {
2011-03-14 17:53:10 -04:00
set_track_monitor_input_status ( false ) ;
2008-06-02 17:41:35 -04:00
}
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
RecordStateChanged ( ) ; /* emit signal */
if ( ! rt_context ) {
remove_pending_capture_state ( ) ;
}
}
}
void
Session : : step_back_from_record ( )
{
2010-04-12 18:35:06 -04:00
if ( g_atomic_int_compare_and_exchange ( & _record_status , Recording , Enabled ) ) {
2008-06-02 17:41:35 -04:00
2009-05-13 20:13:27 -04:00
if ( Config - > get_monitoring_model ( ) = = HardwareMonitoring & & config . get_auto_input ( ) ) {
2011-03-14 17:53:10 -04:00
set_track_monitor_input_status ( false ) ;
2008-06-02 17:41:35 -04:00
}
2011-10-21 19:12:19 -04:00
RecordStateChanged ( ) ; /* emit signal */
2008-06-02 17:41:35 -04:00
}
}
void
Session : : maybe_enable_record ( )
{
2010-11-26 14:57:03 -05:00
if ( _step_editors > 0 ) {
return ;
}
2010-07-24 12:40:56 -04:00
2008-06-02 17:41:35 -04:00
g_atomic_int_set ( & _record_status , Enabled ) ;
2010-09-21 11:02:45 -04:00
/* This function is currently called from somewhere other than an RT thread.
This save_state ( ) call therefore doesn ' t impact anything . Doing it here
means that we save pending state of which sources the next record will use ,
which gives us some chance of recovering from a crash during the record .
*/
2011-06-01 12:50:12 -04:00
2010-09-21 11:02:45 -04:00
save_state ( " " , true ) ;
2011-06-01 12:50:12 -04:00
2008-06-02 17:41:35 -04:00
if ( _transport_speed ) {
2009-05-13 20:13:27 -04:00
if ( ! config . get_punch_in ( ) ) {
2008-06-02 17:41:35 -04:00
enable_record ( ) ;
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
} else {
2013-09-05 13:22:34 -04:00
_mmc - > send ( MIDI : : MachineControlCommand ( MIDI : : MachineControl : : cmdRecordPause ) ) ;
2008-06-02 17:41:35 -04:00
RecordStateChanged ( ) ; /* EMIT SIGNAL */
}
set_dirty ( ) ;
}
2010-09-17 14:20:37 -04:00
framepos_t
2008-06-02 17:41:35 -04:00
Session : : audible_frame ( ) const
{
2010-09-17 14:20:37 -04:00
framepos_t ret ;
framepos_t tf ;
2010-12-03 17:26:29 -05:00
framecnt_t offset ;
2008-06-02 17:41:35 -04:00
/* the first of these two possible settings for "offset"
2008-08-04 18:37:24 -04:00
mean that the audible frame is stationary until
2008-06-02 17:41:35 -04:00
audio emerges from the latency compensation
" pseudo-pipeline " .
the second means that the audible frame is stationary
until audio would emerge from a physical port
in the absence of any plugin latency compensation
*/
2011-03-09 00:19:44 -05:00
offset = worst_playback_latency ( ) ;
2008-06-02 17:41:35 -04:00
if ( offset > current_block_size ) {
offset - = current_block_size ;
2008-08-04 18:37:24 -04:00
} else {
2008-06-02 17:41:35 -04:00
/* XXX is this correct? if we have no external
physical connections and everything is internal
then surely this is zero ? still , how
likely is that anyway ?
*/
offset = current_block_size ;
}
2013-09-19 17:34:23 -04:00
if ( synced_to_engine ( ) ) {
2008-06-02 17:41:35 -04:00
tf = _engine . transport_frame ( ) ;
} else {
tf = _transport_frame ;
}
2009-10-14 12:10:01 -04:00
2008-06-02 17:41:35 -04:00
ret = tf ;
if ( ! non_realtime_work_pending ( ) ) {
/* MOVING */
2010-04-26 20:57:46 -04:00
/* Check to see if we have passed the first guaranteed
2009-02-02 12:11:51 -05:00
audible frame past our last start position . if not ,
return that last start point because in terms
2008-12-12 09:43:24 -05:00
of audible frames , we have not moved yet .
2010-04-26 20:57:46 -04:00
` Start position ' in this context means the time we last
2012-06-25 21:40:34 -04:00
either started , located , or changed transport direction .
2008-12-12 09:43:24 -05:00
*/
if ( _transport_speed > 0.0f ) {
if ( ! play_loop | | ! have_looped ) {
2010-04-26 20:57:46 -04:00
if ( tf < _last_roll_or_reversal_location + offset ) {
return _last_roll_or_reversal_location ;
2008-12-12 09:43:24 -05:00
}
2009-10-14 12:10:01 -04:00
}
2008-12-12 09:43:24 -05:00
/* forwards */
ret - = offset ;
} else if ( _transport_speed < 0.0f ) {
2008-08-04 18:37:24 -04:00
2008-12-12 09:43:24 -05:00
/* XXX wot? no backward looping? */
2010-04-26 20:57:46 -04:00
if ( tf > _last_roll_or_reversal_location - offset ) {
return _last_roll_or_reversal_location ;
2008-12-12 09:43:24 -05:00
} else {
/* backwards */
ret + = offset ;
}
}
2008-06-02 17:41:35 -04:00
}
return ret ;
}
void
2010-12-03 17:26:29 -05:00
Session : : set_frame_rate ( framecnt_t frames_per_second )
2008-06-02 17:41:35 -04:00
{
2010-12-03 17:26:29 -05:00
/** \fn void Session::set_frame_size(framecnt_t)
2008-08-04 18:37:24 -04:00
the AudioEngine object that calls this guarantees
2008-06-02 17:41:35 -04:00
that it will not be called while we are also in
: : process ( ) . Its fine to do things that block
here .
*/
_base_frame_rate = frames_per_second ;
2013-09-11 09:59:56 -04:00
_nominal_frame_rate = frames_per_second ;
2008-06-02 17:41:35 -04:00
sync_time_vars ( ) ;
clear_clicks ( ) ;
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
// XXX we need some equivalent to this, somehow
// SndFileSource::setup_standard_crossfades (frames_per_second);
set_dirty ( ) ;
/* XXX need to reset/reinstantiate all LADSPA plugins */
}
void
2010-12-03 17:26:29 -05:00
Session : : set_block_size ( pframes_t nframes )
2008-06-02 17:41:35 -04:00
{
2008-08-04 18:37:24 -04:00
/* the AudioEngine guarantees
2008-06-02 17:41:35 -04:00
that it will not be called while we are also in
: : process ( ) . It is therefore fine to do things that block
here .
*/
2011-06-19 19:02:55 -04:00
2008-08-04 18:37:24 -04:00
{
2008-06-02 17:41:35 -04:00
current_block_size = nframes ;
2010-04-13 16:48:33 -04:00
ensure_buffers ( ) ;
2008-06-02 17:41:35 -04:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
( * i ) - > set_block_size ( nframes ) ;
}
2008-08-04 18:37:24 -04:00
2010-04-21 16:42:22 -04:00
boost : : shared_ptr < RouteList > rl = routes . reader ( ) ;
for ( RouteList : : iterator i = rl - > begin ( ) ; i ! = rl - > end ( ) ; + + i ) {
boost : : shared_ptr < Track > tr = boost : : dynamic_pointer_cast < Track > ( * i ) ;
if ( tr ) {
tr - > set_block_size ( nframes ) ;
}
2008-06-02 17:41:35 -04:00
}
set_worst_io_latencies ( ) ;
}
}
static void
2010-11-29 17:07:42 -05:00
trace_terminal ( boost : : shared_ptr < Route > r1 , boost : : shared_ptr < Route > rbase )
2008-06-02 17:41:35 -04:00
{
2011-03-14 17:53:10 -04:00
boost : : shared_ptr < Route > r2 ;
2008-06-02 17:41:35 -04:00
2010-04-26 23:10:53 -04:00
if ( r1 - > feeds ( rbase ) & & rbase - > feeds ( r1 ) ) {
2008-06-02 17:41:35 -04:00
info < < string_compose ( _ ( " feedback loop setup between %1 and %2 " ) , r1 - > name ( ) , rbase - > name ( ) ) < < endmsg ;
return ;
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
/* make a copy of the existing list of routes that feed r1 */
2010-11-26 14:57:03 -05:00
Route : : FedBy existing ( r1 - > fed_by ( ) ) ;
2011-06-01 12:50:12 -04:00
2008-06-02 17:41:35 -04:00
/* for each route that feeds r1, recurse, marking it as feeding
rbase as well .
*/
2010-04-26 23:10:53 -04:00
for ( Route : : FedBy : : iterator i = existing . begin ( ) ; i ! = existing . end ( ) ; + + i ) {
if ( ! ( r2 = i - > r . lock ( ) ) ) {
2009-11-27 12:29:27 -05:00
/* (*i) went away, ignore it */
continue ;
}
2011-06-01 12:50:12 -04:00
2008-06-02 17:41:35 -04:00
/* r2 is a route that feeds r1 which somehow feeds base. mark
base as being fed by r2
*/
2010-04-26 23:10:53 -04:00
rbase - > add_fed_by ( r2 , i - > sends_only ) ;
2008-06-02 17:41:35 -04:00
if ( r2 ! = rbase ) {
/* 2nd level feedback loop detection. if r1 feeds or is fed by r2,
stop here .
2009-11-27 12:29:27 -05:00
*/
2008-06-02 17:41:35 -04:00
2010-04-26 23:10:53 -04:00
if ( r1 - > feeds ( r2 ) & & r2 - > feeds ( r1 ) ) {
2008-06-02 17:41:35 -04:00
continue ;
}
/* now recurse, so that we can mark base as being fed by
all routes that feed r2
*/
trace_terminal ( r2 , rbase ) ;
}
}
}
void
Session : : resort_routes ( )
{
/* don't do anything here with signals emitted
2011-10-26 11:14:53 -04:00
by Routes during initial setup or while we
are being destroyed .
2008-06-02 17:41:35 -04:00
*/
2011-10-26 11:14:53 -04:00
if ( _state_of_the_state & ( InitialConnecting | Deletion ) ) {
2008-06-02 17:41:35 -04:00
return ;
}
{
RCUWriter < RouteList > writer ( routes ) ;
2011-03-14 17:53:10 -04:00
boost : : shared_ptr < RouteList > r = writer . get_copy ( ) ;
2008-06-02 17:41:35 -04:00
resort_routes_using ( r ) ;
/* writer goes out of scope and forces update */
}
2010-04-26 23:10:53 -04:00
# ifndef NDEBUG
2010-11-26 14:57:03 -05:00
boost : : shared_ptr < RouteList > rl = routes . reader ( ) ;
for ( RouteList : : iterator i = rl - > begin ( ) ; i ! = rl - > end ( ) ; + + i ) {
DEBUG_TRACE ( DEBUG : : Graph , string_compose ( " %1 fed by ... \n " , ( * i ) - > name ( ) ) ) ;
2011-06-01 12:50:12 -04:00
2010-11-26 14:57:03 -05:00
const Route : : FedBy & fb ( ( * i ) - > fed_by ( ) ) ;
for ( Route : : FedBy : : const_iterator f = fb . begin ( ) ; f ! = fb . end ( ) ; + + f ) {
boost : : shared_ptr < Route > sf = f - > r . lock ( ) ;
if ( sf ) {
DEBUG_TRACE ( DEBUG : : Graph , string_compose ( " \t %1 (sends only ? %2) \n " , sf - > name ( ) , f - > sends_only ) ) ;
}
}
}
2010-04-26 23:10:53 -04:00
# endif
2008-06-02 17:41:35 -04:00
}
2011-11-07 11:01:46 -05:00
2011-11-09 12:44:39 -05:00
/** This is called whenever we need to rebuild the graph of how we will process
* routes .
* @ param r List of routes , in any order .
*/
2008-06-02 17:41:35 -04:00
void
2010-11-29 17:07:42 -05:00
Session : : resort_routes_using ( boost : : shared_ptr < RouteList > r )
2008-06-02 17:41:35 -04:00
{
2011-11-09 12:44:39 -05:00
/* We are going to build a directed graph of our routes;
this is where the edges of that graph are put .
*/
GraphEdges edges ;
/* Go through all routes doing two things:
*
* 1. Collect the edges of the route graph . Each of these edges
* is a pair of routes , one of which directly feeds the other
* either by a JACK connection or by an internal send .
*
* 2. Begin the process of making routes aware of which other
* routes directly or indirectly feed them . This information
* is used by the solo code .
*/
2011-11-07 11:01:46 -05:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2008-08-04 18:37:24 -04:00
2011-11-09 12:44:39 -05:00
/* Clear out the route's list of direct or indirect feeds */
2010-04-26 23:10:53 -04:00
( * i ) - > clear_fed_by ( ) ;
2008-08-04 18:37:24 -04:00
2011-11-07 11:01:46 -05:00
for ( RouteList : : iterator j = r - > begin ( ) ; j ! = r - > end ( ) ; + + j ) {
2008-08-04 18:37:24 -04:00
2010-11-26 14:57:03 -05:00
bool via_sends_only ;
2010-04-26 23:10:53 -04:00
2011-11-09 12:44:39 -05:00
/* See if this *j feeds *i according to the current state of the JACK
connections and internal sends .
*/
if ( ( * j ) - > direct_feeds_according_to_reality ( * i , & via_sends_only ) ) {
/* add the edge to the graph (part #1) */
edges . add ( * j , * i , via_sends_only ) ;
/* tell the route (for part #2) */
2010-04-26 23:10:53 -04:00
( * i ) - > add_fed_by ( * j , via_sends_only ) ;
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
}
}
2008-08-04 18:37:24 -04:00
2011-11-09 12:44:39 -05:00
/* Attempt a topological sort of the route graph */
2011-11-07 17:39:16 -05:00
boost : : shared_ptr < RouteList > sorted_routes = topological_sort ( r , edges ) ;
2011-11-09 12:44:39 -05:00
2013-04-15 10:02:57 -04:00
if ( sorted_routes ) {
2011-11-09 12:44:39 -05:00
/* We got a satisfactory topological sort, so there is no feedback;
use this new graph .
Note : the process graph rechain does not require a
topologically - sorted list , but hey ho .
*/
2012-01-22 07:28:49 -05:00
if ( _process_graph ) {
_process_graph - > rechain ( sorted_routes , edges ) ;
}
2011-11-09 12:44:39 -05:00
_current_route_graph = edges ;
/* Complete the building of the routes' lists of what directly
or indirectly feeds them .
*/
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
trace_terminal ( * i , * i ) ;
}
2012-06-19 11:51:56 -04:00
* r = * sorted_routes ;
2010-06-03 16:38:01 -04:00
2010-04-26 23:10:53 -04:00
# ifndef NDEBUG
2011-11-09 12:44:39 -05:00
DEBUG_TRACE ( DEBUG : : Graph , " Routes resorted, order follows: \n " ) ;
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
DEBUG_TRACE ( DEBUG : : Graph , string_compose ( " \t %1 signal order %2 \n " ,
2013-10-20 09:19:43 -04:00
( * i ) - > name ( ) , ( * i ) - > order_key ( ) ) ) ;
2011-11-09 12:44:39 -05:00
}
2008-06-02 17:41:35 -04:00
# endif
2008-08-04 18:37:24 -04:00
2011-11-11 08:52:27 -05:00
SuccessfulGraphSort ( ) ; /* EMIT SIGNAL */
2013-04-15 10:02:57 -04:00
} else {
2011-11-09 12:44:39 -05:00
/* The topological sort failed, so we have a problem. Tell everyone
and stick to the old graph ; this will continue to be processed , so
until the feedback is fixed , what is played back will not quite
reflect what is actually connected . Note also that we do not
do trace_terminal here , as it would fail due to an endless recursion ,
so the solo code will think that everything is still connected
as it was before .
*/
FeedbackDetected ( ) ; /* EMIT SIGNAL */
}
2008-06-02 17:41:35 -04:00
}
2011-02-26 20:59:04 -05:00
/** Find a route name starting with \a base, maybe followed by the
* lowest \ a id . \ a id will always be added if \ a definitely_add_number
* is true on entry ; otherwise it will only be added if required
* to make the name unique .
2010-02-23 17:45:07 -05:00
*
2011-02-26 20:59:04 -05:00
* Names are constructed like e . g . " Audio 3 " for base = " Audio " and id = 3.
* The available route name with the lowest ID will be used , and \ a id
* will be set to the ID .
2010-02-23 17:45:07 -05:00
*
2011-02-26 20:59:04 -05:00
* \ return false if a route name could not be found , and \ a track_name
* and \ a id do not reflect a free route name .
2010-02-23 17:45:07 -05:00
*/
bool
2011-02-26 20:59:04 -05:00
Session : : find_route_name ( string const & base , uint32_t & id , char * name , size_t name_len , bool definitely_add_number )
2010-02-23 17:45:07 -05:00
{
2011-02-26 20:59:04 -05:00
if ( ! definitely_add_number & & route_by_name ( base ) = = 0 ) {
/* juse use the base */
snprintf ( name , name_len , " %s " , base . c_str ( ) ) ;
return true ;
}
2011-06-01 12:50:12 -04:00
2010-02-23 17:45:07 -05:00
do {
2011-02-26 20:59:04 -05:00
snprintf ( name , name_len , " %s % " PRIu32 , base . c_str ( ) , id ) ;
2010-02-23 17:45:07 -05:00
if ( route_by_name ( name ) = = 0 ) {
return true ;
}
+ + id ;
2013-04-01 20:45:57 -04:00
2010-02-23 17:45:07 -05:00
} while ( id < ( UINT_MAX - 1 ) ) ;
return false ;
}
2011-03-15 15:32:21 -04:00
/** Count the total ins and outs of all non-hidden tracks in the session and return them in in and out */
2010-02-23 17:45:07 -05:00
void
2011-03-15 15:32:21 -04:00
Session : : count_existing_track_channels ( ChanCount & in , ChanCount & out )
2010-02-23 17:45:07 -05:00
{
in = ChanCount : : ZERO ;
out = ChanCount : : ZERO ;
2011-03-14 16:33:47 -04:00
2011-03-14 17:53:10 -04:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2011-03-14 16:33:47 -04:00
2010-02-23 17:45:07 -05:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2011-03-15 15:32:21 -04:00
boost : : shared_ptr < Track > tr = boost : : dynamic_pointer_cast < Track > ( * i ) ;
2013-04-06 16:04:02 -04:00
if ( tr & & ! tr - > is_auditioner ( ) ) {
2011-03-15 15:32:21 -04:00
in + = tr - > n_inputs ( ) ;
out + = tr - > n_outputs ( ) ;
2010-02-23 17:45:07 -05:00
}
}
}
2011-02-26 20:59:04 -05:00
/** Caller must not hold process lock
2011-11-07 19:31:17 -05:00
* @ param name_template string to use for the start of the name , or " " to use " MIDI " .
2012-02-01 23:12:23 -05:00
* @ param instrument plugin info for the instrument to insert pre - fader , if any
2011-02-26 20:59:04 -05:00
*/
2008-06-02 17:41:35 -04:00
list < boost : : shared_ptr < MidiTrack > >
2012-06-21 21:45:16 -04:00
Session : : new_midi_track ( const ChanCount & input , const ChanCount & output , boost : : shared_ptr < PluginInfo > instrument ,
TrackMode mode , RouteGroup * route_group , uint32_t how_many , string name_template )
2008-06-02 17:41:35 -04:00
{
char track_name [ 32 ] ;
2010-02-26 18:35:58 -05:00
uint32_t track_id = 0 ;
2008-06-02 17:41:35 -04:00
string port ;
RouteList new_routes ;
list < boost : : shared_ptr < MidiTrack > > ret ;
2008-08-04 18:37:24 -04:00
2011-11-07 19:31:17 -05:00
bool const use_number = ( how_many ! = 1 ) | | name_template . empty ( ) | | name_template = = _ ( " MIDI " ) ;
2011-06-01 12:50:12 -04:00
2008-06-02 17:41:35 -04:00
while ( how_many ) {
2011-11-07 19:31:17 -05:00
if ( ! find_route_name ( name_template . empty ( ) ? _ ( " MIDI " ) : name_template , + + track_id , track_name , sizeof ( track_name ) , use_number ) ) {
2010-02-23 17:45:07 -05:00
error < < " cannot find name for new midi track " < < endmsg ;
goto failed ;
}
2008-06-02 17:41:35 -04:00
2011-03-14 17:53:10 -04:00
boost : : shared_ptr < MidiTrack > track ;
2011-06-01 12:50:12 -04:00
2008-06-02 17:41:35 -04:00
try {
2011-02-22 16:15:42 -05:00
track . reset ( new MidiTrack ( * this , track_name , Route : : Flag ( 0 ) , mode ) ) ;
2010-03-24 23:40:07 -04:00
2011-02-22 16:15:42 -05:00
if ( track - > init ( ) ) {
2010-11-26 14:57:03 -05:00
goto failed ;
}
2010-03-24 23:40:07 -04:00
2011-02-22 16:15:42 -05:00
track - > use_new_diskstream ( ) ;
2010-03-24 23:40:07 -04:00
2011-02-10 13:33:43 -05:00
# ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
2011-10-29 11:52:38 -04:00
// boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
2011-02-10 13:33:43 -05:00
# endif
2010-11-25 18:46:24 -05:00
{
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( AudioEngine : : instance ( ) - > process_lock ( ) ) ;
2012-06-21 21:45:16 -04:00
if ( track - > input ( ) - > ensure_io ( input , false , this ) ) {
error < < " cannot configure " < < input < < " out configuration for new midi track " < < endmsg ;
2010-11-25 18:46:24 -05:00
goto failed ;
}
2009-06-09 16:21:19 -04:00
2012-06-21 21:45:16 -04:00
if ( track - > output ( ) - > ensure_io ( output , false , this ) ) {
error < < " cannot configure " < < output < < " out configuration for new midi track " < < endmsg ;
2010-11-25 18:46:24 -05:00
goto failed ;
}
2008-06-02 17:41:35 -04:00
}
2010-04-21 17:29:15 -04:00
track - > non_realtime_input_change ( ) ;
2010-06-23 16:14:07 -04:00
2009-12-10 13:33:54 -05:00
if ( route_group ) {
route_group - > add ( track ) ;
}
2008-08-04 18:37:24 -04:00
2009-12-21 13:23:07 -05:00
track - > DiskstreamChanged . connect_same_thread ( * this , boost : : bind ( & Session : : resort_routes , this ) ) ;
2012-06-25 08:46:13 -04:00
if ( Config - > get_remote_model ( ) = = UserOrdered ) {
track - > set_remote_control_id ( next_control_id ( ) ) ;
}
2008-06-02 17:41:35 -04:00
new_routes . push_back ( track ) ;
ret . push_back ( track ) ;
}
catch ( failed_constructor & err ) {
error < < _ ( " Session: could not create new midi track. " ) < < endmsg ;
goto failed ;
}
catch ( AudioEngine : : PortRegistrationFailure & pfe ) {
2013-01-09 10:05:04 -05:00
error < < 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 ) < < endmsg ;
2008-06-02 17:41:35 -04:00
goto failed ;
}
- - how_many ;
}
failed :
if ( ! new_routes . empty ( ) ) {
2014-06-28 15:36:13 -04:00
StateProtector sp ( this ) ;
2012-03-07 08:24:20 -05:00
add_routes ( new_routes , true , true , true ) ;
2012-02-01 23:12:23 -05:00
if ( instrument ) {
for ( RouteList : : iterator r = new_routes . begin ( ) ; r ! = new_routes . end ( ) ; + + r ) {
PluginPtr plugin = instrument - > load ( * this ) ;
boost : : shared_ptr < Processor > p ( new PluginInsert ( * this , plugin ) ) ;
( * r ) - > add_processor ( p , PreFader ) ;
}
}
2008-06-02 17:41:35 -04:00
}
return ret ;
}
2011-03-20 18:09:46 -04:00
void
Session : : midi_output_change_handler ( IOChange change , void * /*src*/ , boost : : weak_ptr < Route > wmt )
{
boost : : shared_ptr < Route > midi_track ( wmt . lock ( ) ) ;
if ( ! midi_track ) {
return ;
}
if ( ( change . type & IOChange : : ConfigurationChanged ) & & Config - > get_output_auto_connect ( ) ! = ManualConnect ) {
if ( change . after . n_audio ( ) < = change . before . n_audio ( ) ) {
return ;
}
2011-06-01 12:50:12 -04:00
/* new audio ports: make sure the audio goes somewhere useful,
2011-03-20 18:09:46 -04:00
unless the user has no - auto - connect selected .
2011-06-01 12:50:12 -04:00
2011-03-20 18:09:46 -04:00
The existing ChanCounts don ' t matter for this call as they are only
to do with matching input and output indices , and we are only changing
outputs here .
*/
ChanCount dummy ;
2011-06-01 12:50:12 -04:00
2011-03-20 18:09:46 -04:00
auto_connect_route ( midi_track , dummy , dummy , false , false , ChanCount ( ) , change . before ) ;
}
}
2011-03-14 16:33:47 -04:00
/** @param connect_inputs true to connect inputs as well as outputs, false to connect just outputs.
2010-08-30 18:34:21 -04:00
* @ param input_start Where to start from when auto - connecting inputs ; e . g . if this is 0 , auto - connect starting from input 0.
* @ param output_start As \ a input_start , but for outputs .
*/
2010-02-23 17:45:07 -05:00
void
2011-06-01 12:50:12 -04:00
Session : : auto_connect_route ( boost : : shared_ptr < Route > route , ChanCount & existing_inputs , ChanCount & existing_outputs ,
2011-03-14 16:33:47 -04:00
bool with_lock , bool connect_inputs , ChanCount input_start , ChanCount output_start )
2008-06-02 17:41:35 -04:00
{
2011-03-14 17:53:10 -04:00
if ( ! IO : : connecting_legal ) {
return ;
}
2011-03-14 16:33:47 -04:00
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( AudioEngine : : instance ( ) - > process_lock ( ) , Glib : : Threads : : NOT_LOCK ) ;
2011-03-14 16:33:47 -04:00
2011-03-14 17:53:10 -04:00
if ( with_lock ) {
lm . acquire ( ) ;
}
2011-03-14 16:33:47 -04:00
2010-02-23 17:45:07 -05:00
/* If both inputs and outputs are auto-connected to physical ports,
use the max of input and output offsets to ensure auto - connected
port numbers always match up ( e . g . the first audio input and the
first audio output of the route will have the same physical
port number ) . Otherwise just use the lowest input or output
offset possible .
*/
2010-07-20 18:59:10 -04:00
2011-03-16 02:49:23 -04:00
DEBUG_TRACE ( DEBUG : : Graph ,
string_compose ( " Auto-connect: existing in = %1 out = %2 \n " ,
existing_inputs , existing_outputs ) ) ;
2011-03-14 16:33:47 -04:00
2010-02-23 17:45:07 -05:00
const bool in_out_physical =
2011-03-14 17:53:10 -04:00
( Config - > get_input_auto_connect ( ) & AutoConnectPhysical )
2010-07-20 18:59:10 -04:00
& & ( Config - > get_output_auto_connect ( ) & AutoConnectPhysical )
& & connect_inputs ;
2008-06-02 17:41:35 -04:00
2011-03-15 15:32:21 -04:00
const ChanCount in_offset = in_out_physical
? ChanCount : : max ( existing_inputs , existing_outputs )
: existing_inputs ;
2008-06-02 17:41:35 -04:00
2010-02-23 17:45:07 -05:00
const ChanCount out_offset = in_out_physical
? ChanCount : : max ( existing_inputs , existing_outputs )
: existing_outputs ;
2008-06-02 17:41:35 -04:00
2010-02-23 17:45:07 -05:00
for ( DataType : : iterator t = DataType : : begin ( ) ; t ! = DataType : : end ( ) ; + + t ) {
vector < string > physinputs ;
vector < string > physoutputs ;
_engine . get_physical_outputs ( * t , physoutputs ) ;
_engine . get_physical_inputs ( * t , physinputs ) ;
2010-07-20 18:59:10 -04:00
if ( ! physinputs . empty ( ) & & connect_inputs ) {
2010-02-23 17:45:07 -05:00
uint32_t nphysical_in = physinputs . size ( ) ;
2011-03-14 16:33:47 -04:00
2011-03-16 02:49:23 -04:00
DEBUG_TRACE ( DEBUG : : Graph ,
string_compose ( " There are %1 physical inputs of type %2 \n " ,
nphysical_in , * t ) ) ;
2011-03-14 16:33:47 -04:00
2010-08-30 18:34:21 -04:00
for ( uint32_t i = input_start . get ( * t ) ; i < route - > n_inputs ( ) . get ( * t ) & & i < nphysical_in ; + + i ) {
2010-06-21 19:45:30 -04:00
string port ;
2011-06-01 12:50:12 -04:00
2010-02-23 17:45:07 -05:00
if ( Config - > get_input_auto_connect ( ) & AutoConnectPhysical ) {
2011-03-16 02:49:23 -04:00
DEBUG_TRACE ( DEBUG : : Graph ,
string_compose ( " Get index %1 + %2 % %3 = %4 \n " ,
in_offset . get ( * t ) , i , nphysical_in ,
( in_offset . get ( * t ) + i ) % nphysical_in ) ) ;
2010-02-23 17:45:07 -05:00
port = physinputs [ ( in_offset . get ( * t ) + i ) % nphysical_in ] ;
}
2011-03-16 02:49:23 -04:00
DEBUG_TRACE ( DEBUG : : Graph ,
string_compose ( " Connect route %1 IN to %2 \n " ,
route - > name ( ) , port ) ) ;
2011-03-14 16:33:47 -04:00
2011-03-20 18:09:46 -04:00
if ( ! port . empty ( ) & & route - > input ( ) - > connect ( route - > input ( ) - > ports ( ) . port ( * t , i ) , port , this ) ) {
2010-02-23 17:45:07 -05:00
break ;
2008-06-02 17:41:35 -04:00
}
2011-03-20 18:09:46 -04:00
ChanCount one_added ( * t , 1 ) ;
existing_inputs + = one_added ;
2008-06-02 17:41:35 -04:00
}
}
2010-02-23 17:45:07 -05:00
if ( ! physoutputs . empty ( ) ) {
uint32_t nphysical_out = physoutputs . size ( ) ;
2010-08-30 18:34:21 -04:00
for ( uint32_t i = output_start . get ( * t ) ; i < route - > n_outputs ( ) . get ( * t ) ; + + i ) {
2010-06-21 19:45:30 -04:00
string port ;
2008-09-28 18:56:43 -04:00
2014-01-03 12:19:18 -05:00
if ( ( * t ) = = DataType : : MIDI & & ( Config - > get_output_auto_connect ( ) & AutoConnectPhysical ) ) {
2010-02-23 17:45:07 -05:00
port = physoutputs [ ( out_offset . get ( * t ) + i ) % nphysical_out ] ;
2014-01-03 12:19:18 -05:00
} else if ( ( * t ) = = DataType : : AUDIO & & ( Config - > get_output_auto_connect ( ) & AutoConnectMaster ) ) {
2011-03-20 18:09:46 -04:00
/* master bus is audio only */
2010-02-23 17:45:07 -05:00
if ( _master_out & & _master_out - > n_inputs ( ) . get ( * t ) > 0 ) {
port = _master_out - > input ( ) - > ports ( ) . port ( * t ,
i % _master_out - > input ( ) - > n_ports ( ) . get ( * t ) ) - > name ( ) ;
}
}
2008-06-02 17:41:35 -04:00
2011-03-16 02:49:23 -04:00
DEBUG_TRACE ( DEBUG : : Graph ,
string_compose ( " Connect route %1 OUT to %2 \n " ,
route - > name ( ) , port ) ) ;
2011-03-14 16:33:47 -04:00
2011-03-20 18:09:46 -04:00
if ( ! port . empty ( ) & & route - > output ( ) - > connect ( route - > output ( ) - > ports ( ) . port ( * t , i ) , port , this ) ) {
2010-02-23 17:45:07 -05:00
break ;
}
2011-03-20 18:09:46 -04:00
ChanCount one_added ( * t , 1 ) ;
existing_outputs + = one_added ;
2010-02-23 17:45:07 -05:00
}
}
}
}
2008-06-02 17:41:35 -04:00
2011-02-26 20:59:04 -05:00
/** Caller must not hold process lock
* @ param name_template string to use for the start of the name , or " " to use " Audio " .
*/
2010-02-26 18:35:58 -05:00
list < boost : : shared_ptr < AudioTrack > >
2012-01-17 20:30:44 -05:00
Session : : new_audio_track ( int input_channels , int output_channels , TrackMode mode , RouteGroup * route_group ,
uint32_t how_many , string name_template )
2010-02-23 17:45:07 -05:00
{
char track_name [ 32 ] ;
2010-02-26 18:35:58 -05:00
uint32_t track_id = 0 ;
2010-02-23 17:45:07 -05:00
string port ;
RouteList new_routes ;
list < boost : : shared_ptr < AudioTrack > > ret ;
2008-08-04 18:37:24 -04:00
2011-06-22 19:37:02 -04:00
bool const use_number = ( how_many ! = 1 ) | | name_template . empty ( ) | | name_template = = _ ( " Audio " ) ;
2011-06-01 12:50:12 -04:00
2010-02-23 17:45:07 -05:00
while ( how_many ) {
2011-02-27 06:23:30 -05:00
if ( ! find_route_name ( name_template . empty ( ) ? _ ( " Audio " ) : name_template , + + track_id , track_name , sizeof ( track_name ) , use_number ) ) {
2010-02-23 17:45:07 -05:00
error < < " cannot find name for new audio track " < < endmsg ;
goto failed ;
}
2008-06-02 17:41:35 -04:00
2011-03-14 17:53:10 -04:00
boost : : shared_ptr < AudioTrack > track ;
2011-06-01 12:50:12 -04:00
2008-06-02 17:41:35 -04:00
try {
2011-02-22 16:15:42 -05:00
track . reset ( new AudioTrack ( * this , track_name , Route : : Flag ( 0 ) , mode ) ) ;
2010-03-24 23:40:07 -04:00
2011-02-22 16:15:42 -05:00
if ( track - > init ( ) ) {
2010-11-26 14:57:03 -05:00
goto failed ;
}
2010-03-24 23:40:07 -04:00
2011-02-22 16:15:42 -05:00
track - > use_new_diskstream ( ) ;
2010-03-24 23:40:07 -04:00
2011-02-10 13:33:43 -05:00
# ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
2011-10-29 11:52:38 -04:00
// boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
2011-02-10 13:33:43 -05:00
# endif
2010-11-25 18:46:24 -05:00
{
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( AudioEngine : : instance ( ) - > process_lock ( ) ) ;
2009-10-14 12:10:01 -04:00
2010-11-25 18:46:24 -05:00
if ( track - > input ( ) - > ensure_io ( ChanCount ( DataType : : AUDIO , input_channels ) , false , this ) ) {
error < < string_compose (
_ ( " cannot configure %1 in/%2 out configuration for new audio track " ) ,
input_channels , output_channels )
< < endmsg ;
goto failed ;
}
2011-06-01 12:50:12 -04:00
2010-11-25 18:46:24 -05:00
if ( track - > output ( ) - > ensure_io ( ChanCount ( DataType : : AUDIO , output_channels ) , false , this ) ) {
error < < string_compose (
_ ( " cannot configure %1 in/%2 out configuration for new audio track " ) ,
input_channels , output_channels )
< < endmsg ;
goto failed ;
}
}
2008-06-02 17:41:35 -04:00
2009-12-10 13:33:54 -05:00
if ( route_group ) {
route_group - > add ( track ) ;
}
2009-06-20 11:40:26 -04:00
2010-04-21 17:29:15 -04:00
track - > non_realtime_input_change ( ) ;
2008-08-04 18:37:24 -04:00
2009-12-21 13:23:07 -05:00
track - > DiskstreamChanged . connect_same_thread ( * this , boost : : bind ( & Session : : resort_routes , this ) ) ;
2012-06-25 08:46:13 -04:00
if ( Config - > get_remote_model ( ) = = UserOrdered ) {
track - > set_remote_control_id ( next_control_id ( ) ) ;
}
2008-06-02 17:41:35 -04:00
new_routes . push_back ( track ) ;
ret . push_back ( track ) ;
}
catch ( failed_constructor & err ) {
error < < _ ( " Session: could not create new audio track. " ) < < endmsg ;
goto failed ;
}
catch ( AudioEngine : : PortRegistrationFailure & pfe ) {
2009-04-15 14:04:23 -04:00
error < < pfe . what ( ) < < endmsg ;
2008-06-02 17:41:35 -04:00
goto failed ;
}
- - how_many ;
}
failed :
if ( ! new_routes . empty ( ) ) {
2014-06-28 15:36:13 -04:00
StateProtector sp ( this ) ;
2012-03-07 08:24:20 -05:00
add_routes ( new_routes , true , true , true ) ;
2008-06-02 17:41:35 -04:00
}
return ret ;
}
2011-02-26 20:59:04 -05:00
/** Caller must not hold process lock.
* @ param name_template string to use for the start of the name , or " " to use " Bus " .
*/
2009-01-30 02:40:13 -05:00
RouteList
2011-02-26 20:59:04 -05:00
Session : : new_audio_route ( int input_channels , int output_channels , RouteGroup * route_group , uint32_t how_many , string name_template )
2008-06-02 17:41:35 -04:00
{
char bus_name [ 32 ] ;
2010-02-26 18:35:58 -05:00
uint32_t bus_id = 0 ;
2008-06-02 17:41:35 -04:00
string port ;
RouteList ret ;
2011-06-22 19:37:02 -04:00
bool const use_number = ( how_many ! = 1 ) | | name_template . empty ( ) | | name_template = = _ ( " Bus " ) ;
2008-06-02 17:41:35 -04:00
while ( how_many ) {
2011-02-27 06:23:30 -05:00
if ( ! find_route_name ( name_template . empty ( ) ? _ ( " Bus " ) : name_template , + + bus_id , bus_name , sizeof ( bus_name ) , use_number ) ) {
2010-02-23 17:45:07 -05:00
error < < " cannot find name for new audio bus " < < endmsg ;
goto failure ;
}
2008-06-02 17:41:35 -04:00
try {
2011-02-22 16:15:42 -05:00
boost : : shared_ptr < Route > bus ( new Route ( * this , bus_name , Route : : Flag ( 0 ) , DataType : : AUDIO ) ) ;
2010-03-24 23:40:07 -04:00
2011-02-22 16:15:42 -05:00
if ( bus - > init ( ) ) {
2010-11-26 14:57:03 -05:00
goto failure ;
}
2010-03-24 23:40:07 -04:00
2011-02-10 13:33:43 -05:00
# ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
2011-10-29 11:52:38 -04:00
// boost_debug_shared_ptr_mark_interesting (bus.get(), "Route");
2011-02-10 13:33:43 -05:00
# endif
2010-11-25 18:46:24 -05:00
{
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( AudioEngine : : instance ( ) - > process_lock ( ) ) ;
2009-06-09 16:21:19 -04:00
2010-11-25 18:46:24 -05:00
if ( bus - > input ( ) - > ensure_io ( ChanCount ( DataType : : AUDIO , input_channels ) , false , this ) ) {
error < < string_compose ( _ ( " cannot configure %1 in/%2 out configuration for new audio track " ) ,
input_channels , output_channels )
< < endmsg ;
goto failure ;
}
2011-06-01 12:50:12 -04:00
2010-11-25 18:46:24 -05:00
if ( bus - > output ( ) - > ensure_io ( ChanCount ( DataType : : AUDIO , output_channels ) , false , this ) ) {
error < < string_compose ( _ ( " cannot configure %1 in/%2 out configuration for new audio track " ) ,
input_channels , output_channels )
< < endmsg ;
goto failure ;
}
2008-06-02 17:41:35 -04:00
}
2008-08-04 18:37:24 -04:00
2009-12-10 13:33:54 -05:00
if ( route_group ) {
route_group - > add ( bus ) ;
}
2012-06-25 08:46:13 -04:00
if ( Config - > get_remote_model ( ) = = UserOrdered ) {
bus - > set_remote_control_id ( next_control_id ( ) ) ;
}
2008-06-02 17:41:35 -04:00
2011-01-05 10:52:27 -05:00
bus - > add_internal_return ( ) ;
2009-11-18 23:25:46 -05:00
2008-06-02 17:41:35 -04:00
ret . push_back ( bus ) ;
2012-12-13 08:44:11 -05:00
ARDOUR : : GUIIdle ( ) ;
2008-06-02 17:41:35 -04:00
}
2008-08-04 18:37:24 -04:00
2012-12-13 08:44:11 -05:00
2008-06-02 17:41:35 -04:00
catch ( failed_constructor & err ) {
error < < _ ( " Session: could not create new audio route. " ) < < endmsg ;
goto failure ;
}
catch ( AudioEngine : : PortRegistrationFailure & pfe ) {
2009-04-15 14:04:23 -04:00
error < < pfe . what ( ) < < endmsg ;
2008-06-02 17:41:35 -04:00
goto failure ;
}
- - how_many ;
}
failure :
if ( ! ret . empty ( ) ) {
2014-06-28 15:36:13 -04:00
StateProtector sp ( this ) ;
2012-03-07 08:24:20 -05:00
add_routes ( ret , false , true , true ) ; // autoconnect outputs only
2008-06-02 17:41:35 -04:00
}
return ret ;
}
2009-03-02 11:52:40 -05:00
RouteList
2013-04-01 20:45:57 -04:00
Session : : new_route_from_template ( uint32_t how_many , const std : : string & template_path , const std : : string & name_base )
2009-03-02 11:52:40 -05:00
{
RouteList ret ;
uint32_t control_id ;
XMLTree tree ;
2010-02-26 18:35:58 -05:00
uint32_t number = 0 ;
2013-04-01 20:45:57 -04:00
const uint32_t being_added = how_many ;
2009-03-02 11:52:40 -05:00
if ( ! tree . read ( template_path . c_str ( ) ) ) {
return ret ;
}
XMLNode * node = tree . root ( ) ;
2012-01-24 08:43:48 -05:00
IO : : disable_connecting ( ) ;
2012-01-17 20:30:44 -05:00
control_id = next_control_id ( ) ;
2009-03-02 11:52:40 -05:00
while ( how_many ) {
2011-11-16 18:03:59 -05:00
XMLNode node_copy ( * node ) ;
2009-10-14 12:10:01 -04:00
2011-11-16 18:03:59 -05:00
/* Remove IDs of everything so that new ones are used */
node_copy . remove_property_recursively ( X_ ( " id " ) ) ;
2009-03-02 11:52:40 -05:00
2011-11-16 18:03:59 -05:00
try {
char name [ 32 ] ;
2013-04-01 20:45:57 -04:00
if ( ! name_base . empty ( ) ) {
/* if we're adding more than one routes, force
* all the names of the new routes to be
* numbered , via the final parameter .
*/
if ( ! find_route_name ( name_base . c_str ( ) , + + number , name , sizeof ( name ) , ( being_added > 1 ) ) ) {
fatal < < _ ( " Session: UINT_MAX routes? impossible! " ) < < endmsg ;
/*NOTREACHDE*/
}
} else {
string const route_name = node_copy . property ( X_ ( " name " ) ) - > value ( ) ;
/* generate a new name by adding a number to the end of the template name */
if ( ! find_route_name ( route_name . c_str ( ) , + + number , name , sizeof ( name ) , true ) ) {
fatal < < _ ( " Session: UINT_MAX routes? impossible! " ) < < endmsg ;
/*NOTREACHED*/
}
2010-05-08 20:47:16 -04:00
}
2009-03-02 11:52:40 -05:00
2011-11-16 18:03:59 -05:00
/* set this name in the XML description that we are about to use */
Route : : set_name_in_state ( node_copy , name ) ;
2009-03-05 12:27:05 -05:00
2011-11-16 18:03:59 -05:00
/* trim bitslots from listen sends so that new ones are used */
XMLNodeList children = node_copy . children ( ) ;
for ( XMLNodeList : : iterator i = children . begin ( ) ; i ! = children . end ( ) ; + + i ) {
if ( ( * i ) - > name ( ) = = X_ ( " Processor " ) ) {
XMLProperty * role = ( * i ) - > property ( X_ ( " role " ) ) ;
if ( role & & role - > value ( ) = = X_ ( " Listen " ) ) {
( * i ) - > remove_property ( X_ ( " bitslot " ) ) ;
}
}
}
2011-03-14 17:53:10 -04:00
boost : : shared_ptr < Route > route ( XMLRouteFactory ( node_copy , 3000 ) ) ;
2010-05-08 20:47:16 -04:00
2009-03-02 11:52:40 -05:00
if ( route = = 0 ) {
error < < _ ( " Session: cannot create track/bus from template description " ) < < endmsg ;
goto out ;
}
2009-03-05 12:27:05 -05:00
if ( boost : : dynamic_pointer_cast < Track > ( route ) ) {
/* force input/output change signals so that the new diskstream
picks up the configuration of the route . During session
loading this normally happens in a different way .
*/
2011-06-01 12:50:12 -04:00
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( AudioEngine : : instance ( ) - > process_lock ( ) ) ;
2011-06-01 12:50:12 -04:00
2010-08-30 18:34:21 -04:00
IOChange change ( IOChange : : Type ( IOChange : : ConfigurationChanged | IOChange : : ConnectionsChanged ) ) ;
change . after = route - > input ( ) - > n_ports ( ) ;
route - > input ( ) - > changed ( change , this ) ;
change . after = route - > output ( ) - > n_ports ( ) ;
route - > output ( ) - > changed ( change , this ) ;
2009-03-05 12:27:05 -05:00
}
2009-10-14 12:10:01 -04:00
2009-03-02 11:52:40 -05:00
route - > set_remote_control_id ( control_id ) ;
+ + control_id ;
2009-10-14 12:10:01 -04:00
2009-03-02 11:52:40 -05:00
ret . push_back ( route ) ;
}
2009-10-14 12:10:01 -04:00
2009-03-02 11:52:40 -05:00
catch ( failed_constructor & err ) {
error < < _ ( " Session: could not create new route from template " ) < < endmsg ;
goto out ;
}
2009-10-14 12:10:01 -04:00
2009-03-02 11:52:40 -05:00
catch ( AudioEngine : : PortRegistrationFailure & pfe ) {
2009-04-15 14:04:23 -04:00
error < < pfe . what ( ) < < endmsg ;
2009-03-02 11:52:40 -05:00
goto out ;
}
2009-10-14 12:10:01 -04:00
2009-03-02 11:52:40 -05:00
- - how_many ;
}
out :
if ( ! ret . empty ( ) ) {
2014-06-28 15:36:13 -04:00
StateProtector sp ( this ) ;
2012-03-07 08:24:20 -05:00
add_routes ( ret , true , true , true ) ;
2012-01-24 08:43:48 -05:00
IO : : enable_connecting ( ) ;
2009-03-02 11:52:40 -05:00
}
return ret ;
}
2008-06-02 17:41:35 -04:00
void
2012-03-07 08:24:20 -05:00
Session : : add_routes ( RouteList & new_routes , bool input_auto_connect , bool output_auto_connect , bool save )
2012-12-04 09:32:28 -05:00
{
try {
PBD : : Unwinder < bool > aip ( _adding_routes_in_progress , true ) ;
add_routes_inner ( new_routes , input_auto_connect , output_auto_connect ) ;
} catch ( . . . ) {
error < < _ ( " Adding new tracks/busses failed " ) < < endmsg ;
}
graph_reordered ( ) ;
update_latency ( true ) ;
update_latency ( false ) ;
set_dirty ( ) ;
if ( save ) {
save_state ( _current_snapshot_name ) ;
}
2014-06-25 15:16:09 -04:00
reassign_track_numbers ( ) ;
2012-12-04 09:32:28 -05:00
RouteAdded ( new_routes ) ; /* EMIT SIGNAL */
}
void
Session : : add_routes_inner ( RouteList & new_routes , bool input_auto_connect , bool output_auto_connect )
2008-06-02 17:41:35 -04:00
{
2011-03-15 15:32:21 -04:00
ChanCount existing_inputs ;
ChanCount existing_outputs ;
2012-06-27 18:57:06 -04:00
uint32_t order = next_control_id ( ) ;
2011-06-01 12:50:12 -04:00
2013-10-23 10:27:13 -04:00
if ( _order_hint ! = 0 ) {
order = _order_hint ;
_order_hint = 0 ;
}
2011-03-15 15:32:21 -04:00
count_existing_track_channels ( existing_inputs , existing_outputs ) ;
2008-08-04 18:37:24 -04:00
{
2008-06-02 17:41:35 -04:00
RCUWriter < RouteList > writer ( routes ) ;
2011-03-14 17:53:10 -04:00
boost : : shared_ptr < RouteList > r = writer . get_copy ( ) ;
2008-06-02 17:41:35 -04:00
r - > insert ( r - > end ( ) , new_routes . begin ( ) , new_routes . end ( ) ) ;
2009-06-16 10:58:33 -04:00
2009-06-25 16:46:39 -04:00
/* if there is no control out and we're not in the middle of loading,
resort the graph here . if there is a control out , we will resort
2009-10-14 12:10:01 -04:00
toward the end of this method . if we are in the middle of loading ,
2009-06-25 16:46:39 -04:00
we will resort when done .
*/
2010-03-22 17:35:35 -04:00
if ( ! _monitor_out & & IO : : connecting_legal ) {
2009-06-16 10:58:33 -04:00
resort_routes_using ( r ) ;
}
2008-06-02 17:41:35 -04:00
}
for ( RouteList : : iterator x = new_routes . begin ( ) ; x ! = new_routes . end ( ) ; + + x ) {
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
boost : : weak_ptr < Route > wpr ( * x ) ;
2009-12-26 11:15:11 -05:00
boost : : shared_ptr < Route > r ( * x ) ;
2008-06-02 17:41:35 -04:00
2009-12-26 11:15:11 -05:00
r - > listen_changed . connect_same_thread ( * this , boost : : bind ( & Session : : route_listen_changed , this , _1 , wpr ) ) ;
2010-04-26 23:10:53 -04:00
r - > solo_changed . connect_same_thread ( * this , boost : : bind ( & Session : : route_solo_changed , this , _1 , _2 , wpr ) ) ;
2010-05-06 14:40:37 -04:00
r - > solo_isolated_changed . connect_same_thread ( * this , boost : : bind ( & Session : : route_solo_isolated_changed , this , _1 , wpr ) ) ;
2009-12-26 11:15:11 -05:00
r - > mute_changed . connect_same_thread ( * this , boost : : bind ( & Session : : route_mute_changed , this , _1 ) ) ;
r - > output ( ) - > changed . connect_same_thread ( * this , boost : : bind ( & Session : : set_worst_io_latencies_x , this , _1 , _2 ) ) ;
r - > processors_changed . connect_same_thread ( * this , boost : : bind ( & Session : : route_processors_changed , this , _1 ) ) ;
2008-08-04 18:37:24 -04:00
2009-12-26 11:15:11 -05:00
if ( r - > is_master ( ) ) {
_master_out = r ;
2008-06-02 17:41:35 -04:00
}
2008-08-04 18:37:24 -04:00
2010-03-22 17:35:35 -04:00
if ( r - > is_monitor ( ) ) {
_monitor_out = r ;
2008-06-02 17:41:35 -04:00
}
2010-04-21 16:42:22 -04:00
boost : : shared_ptr < Track > tr = boost : : dynamic_pointer_cast < Track > ( r ) ;
if ( tr ) {
tr - > PlaylistChanged . connect_same_thread ( * this , boost : : bind ( & Session : : track_playlist_changed , this , boost : : weak_ptr < Track > ( tr ) ) ) ;
track_playlist_changed ( boost : : weak_ptr < Track > ( tr ) ) ;
tr - > RecordEnableChanged . connect_same_thread ( * this , boost : : bind ( & Session : : update_have_rec_enabled_track , this ) ) ;
2010-07-24 12:40:56 -04:00
2010-11-26 14:57:03 -05:00
boost : : shared_ptr < MidiTrack > mt = boost : : dynamic_pointer_cast < MidiTrack > ( tr ) ;
if ( mt ) {
mt - > StepEditStatusChange . connect_same_thread ( * this , boost : : bind ( & Session : : step_edit_status_change , this , _1 ) ) ;
2011-03-20 18:09:46 -04:00
mt - > output ( ) - > changed . connect_same_thread ( * this , boost : : bind ( & Session : : midi_output_change_handler , this , _1 , _2 , boost : : weak_ptr < Route > ( mt ) ) ) ;
2010-11-26 14:57:03 -05:00
}
2010-04-21 16:42:22 -04:00
}
2011-06-01 12:50:12 -04:00
2012-12-04 09:32:28 -05:00
2012-03-07 08:24:20 -05:00
if ( input_auto_connect | | output_auto_connect ) {
auto_connect_route ( r , existing_inputs , existing_outputs , true , input_auto_connect ) ;
2011-03-14 17:53:10 -04:00
}
2012-06-27 18:57:06 -04:00
/* order keys are a GUI responsibility but we need to set up
reasonable defaults because they also affect the remote control
ID in most situations .
*/
2012-12-04 09:32:28 -05:00
2013-10-20 09:19:43 -04:00
if ( ! r - > has_order_key ( ) ) {
2013-04-06 16:04:02 -04:00
if ( r - > is_auditioner ( ) ) {
2012-06-27 18:57:06 -04:00
/* use an arbitrarily high value */
2013-10-20 09:19:43 -04:00
r - > set_order_key ( UINT_MAX ) ;
2012-06-27 18:57:06 -04:00
} else {
DEBUG_TRACE ( DEBUG : : OrderKeys , string_compose ( " while adding, set %1 to order key %2 \n " , r - > name ( ) , order ) ) ;
2013-10-20 09:19:43 -04:00
r - > set_order_key ( order ) ;
2012-06-27 18:57:06 -04:00
order + + ;
}
}
2012-12-13 08:44:11 -05:00
ARDOUR : : GUIIdle ( ) ;
2011-03-14 17:53:10 -04:00
}
2008-06-02 17:41:35 -04:00
2010-03-22 17:35:35 -04:00
if ( _monitor_out & & IO : : connecting_legal ) {
2012-12-04 09:32:28 -05:00
Glib : : Threads : : Mutex : : Lock lm ( _engine . process_lock ( ) ) ;
for ( RouteList : : iterator x = new_routes . begin ( ) ; x ! = new_routes . end ( ) ; + + x ) {
if ( ( * x ) - > is_monitor ( ) ) {
/* relax */
} else if ( ( * x ) - > is_master ( ) ) {
2012-01-18 12:51:57 -05:00
/* relax */
2012-12-04 09:32:28 -05:00
} else {
( * x ) - > enable_monitor_send ( ) ;
2010-11-26 14:57:03 -05:00
}
2008-06-02 17:41:35 -04:00
}
}
}
2009-07-21 08:05:44 -04:00
void
Session : : globally_set_send_gains_to_zero ( boost : : shared_ptr < Route > dest )
{
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
boost : : shared_ptr < Send > s ;
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2010-12-29 16:07:22 -05:00
if ( ( s = ( * i ) - > internal_send_for ( dest ) ) ! = 0 ) {
s - > amp ( ) - > gain_control ( ) - > set_value ( 0.0 ) ;
2009-07-21 08:05:44 -04:00
}
}
}
void
Session : : globally_set_send_gains_to_unity ( boost : : shared_ptr < Route > dest )
{
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
boost : : shared_ptr < Send > s ;
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2010-12-29 16:07:22 -05:00
if ( ( s = ( * i ) - > internal_send_for ( dest ) ) ! = 0 ) {
s - > amp ( ) - > gain_control ( ) - > set_value ( 1.0 ) ;
2009-07-21 08:05:44 -04:00
}
}
}
void
Session : : globally_set_send_gains_from_track ( boost : : shared_ptr < Route > dest )
{
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
boost : : shared_ptr < Send > s ;
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2010-12-29 16:07:22 -05:00
if ( ( s = ( * i ) - > internal_send_for ( dest ) ) ! = 0 ) {
s - > amp ( ) - > gain_control ( ) - > set_value ( ( * i ) - > gain_control ( ) - > get_value ( ) ) ;
2009-07-21 08:05:44 -04:00
}
}
}
2010-12-29 17:07:34 -05:00
/** @param include_buses true to add sends to buses and tracks, false for just tracks */
2009-06-25 16:46:39 -04:00
void
2010-12-29 17:07:34 -05:00
Session : : globally_add_internal_sends ( boost : : shared_ptr < Route > dest , Placement p , bool include_buses )
2009-06-25 16:46:39 -04:00
{
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
boost : : shared_ptr < RouteList > t ( new RouteList ) ;
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2011-08-10 16:21:18 -04:00
/* no MIDI sends because there are no MIDI busses yet */
if ( include_buses | | boost : : dynamic_pointer_cast < AudioTrack > ( * i ) ) {
2009-06-25 16:46:39 -04:00
t - > push_back ( * i ) ;
}
}
2009-07-14 20:47:34 -04:00
add_internal_sends ( dest , p , t ) ;
2009-06-25 16:46:39 -04:00
}
void
2009-07-14 20:47:34 -04:00
Session : : add_internal_sends ( boost : : shared_ptr < Route > dest , Placement p , boost : : shared_ptr < RouteList > senders )
2009-06-25 16:46:39 -04:00
{
2012-01-30 13:09:54 -05:00
for ( RouteList : : iterator i = senders - > begin ( ) ; i ! = senders - > end ( ) ; + + i ) {
add_internal_send ( dest , ( * i ) - > before_processor_for_placement ( p ) , * i ) ;
}
}
void
Session : : add_internal_send ( boost : : shared_ptr < Route > dest , int index , boost : : shared_ptr < Route > sender )
{
add_internal_send ( dest , sender - > before_processor_for_index ( index ) , sender ) ;
}
void
Session : : add_internal_send ( boost : : shared_ptr < Route > dest , boost : : shared_ptr < Processor > before , boost : : shared_ptr < Route > sender )
{
if ( sender - > is_monitor ( ) | | sender - > is_master ( ) | | sender = = dest | | dest - > is_monitor ( ) | | dest - > is_master ( ) ) {
2009-06-25 16:46:39 -04:00
return ;
}
if ( ! dest - > internal_return ( ) ) {
2012-01-30 13:09:54 -05:00
dest - > add_internal_return ( ) ;
2009-06-25 16:46:39 -04:00
}
2009-11-19 12:06:00 -05:00
2012-01-30 13:09:54 -05:00
sender - > add_aux_send ( dest , before ) ;
2009-11-19 12:06:00 -05:00
graph_reordered ( ) ;
2009-06-25 16:46:39 -04:00
}
2008-06-02 17:41:35 -04:00
void
2010-11-29 17:07:42 -05:00
Session : : remove_route ( boost : : shared_ptr < Route > route )
2008-06-02 17:41:35 -04:00
{
2012-01-17 20:30:44 -05:00
if ( route = = _master_out ) {
2010-11-26 14:57:03 -05:00
return ;
}
2010-06-16 12:59:20 -04:00
2010-11-26 14:57:03 -05:00
route - > set_solo ( false , this ) ;
2010-08-16 20:28:20 -04:00
2008-08-04 18:37:24 -04:00
{
2008-06-02 17:41:35 -04:00
RCUWriter < RouteList > writer ( routes ) ;
2011-03-14 17:53:10 -04:00
boost : : shared_ptr < RouteList > rs = writer . get_copy ( ) ;
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
rs - > remove ( route ) ;
/* deleting the master out seems like a dumb
idea , but its more of a UI policy issue
than our concern .
*/
if ( route = = _master_out ) {
2010-11-29 17:07:42 -05:00
_master_out = boost : : shared_ptr < Route > ( ) ;
2008-06-02 17:41:35 -04:00
}
2010-03-22 17:35:35 -04:00
if ( route = = _monitor_out ) {
_monitor_out . reset ( ) ;
2008-06-02 17:41:35 -04:00
}
/* writer goes out of scope, forces route list update */
}
2010-06-24 12:20:32 -04:00
2010-11-26 14:57:03 -05:00
update_route_solo_state ( ) ;
2008-08-04 18:37:24 -04:00
2010-05-06 14:40:37 -04:00
// We need to disconnect the route's inputs and outputs
2008-06-02 17:41:35 -04:00
2009-06-09 16:21:19 -04:00
route - > input ( ) - > disconnect ( 0 ) ;
route - > output ( ) - > disconnect ( 0 ) ;
2008-08-04 18:37:24 -04:00
2009-11-30 18:34:48 -05:00
/* if the route had internal sends sending to it, remove them */
if ( route - > internal_return ( ) ) {
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
boost : : shared_ptr < Send > s = ( * i ) - > internal_send_for ( route ) ;
if ( s ) {
( * i ) - > remove_processor ( s ) ;
}
}
2011-06-01 12:50:12 -04:00
}
2009-11-30 18:34:48 -05:00
2014-06-29 21:31:58 -04:00
/* if the monitoring section had a pointer to this route, remove it */
if ( _monitor_out & & ! route - > is_master ( ) & & ! route - > is_monitor ( ) ) {
Glib : : Threads : : Mutex : : Lock lm ( AudioEngine : : instance ( ) - > process_lock ( ) ) ;
PBD : : Unwinder < bool > uw ( ignore_route_processor_changes , true ) ;
route - > remove_aux_or_listen ( _monitor_out ) ;
}
2010-11-26 14:57:03 -05:00
boost : : shared_ptr < MidiTrack > mt = boost : : dynamic_pointer_cast < MidiTrack > ( route ) ;
if ( mt & & mt - > step_editing ( ) ) {
if ( _step_editors > 0 ) {
_step_editors - - ;
}
}
2010-07-24 12:40:56 -04:00
2011-03-14 16:33:47 -04:00
update_latency_compensation ( ) ;
2008-06-02 17:41:35 -04:00
set_dirty ( ) ;
2010-11-26 14:57:03 -05:00
/* Re-sort routes to remove the graph's current references to the one that is
2010-07-13 22:23:37 -04:00
* going away , then flush old references out of the graph .
2010-11-26 14:57:03 -05:00
*/
2010-06-24 12:20:32 -04:00
2010-07-13 22:23:37 -04:00
resort_routes ( ) ;
2012-01-22 07:28:49 -05:00
if ( _process_graph ) {
_process_graph - > clear_other_chain ( ) ;
}
2010-06-24 12:20:32 -04:00
2008-06-02 17:41:35 -04:00
/* get rid of it from the dead wood collection in the route list manager */
/* XXX i think this is unsafe as it currently stands, but i am not sure. (pd, october 2nd, 2006) */
routes . flush ( ) ;
/* try to cause everyone to drop their references */
route - > drop_references ( ) ;
2009-12-30 11:48:58 -05:00
Route : : RemoteControlIDChange ( ) ; /* EMIT SIGNAL */
2008-06-02 17:41:35 -04:00
/* save the new state of the world */
if ( save_state ( _current_snapshot_name ) ) {
save_history ( _current_snapshot_name ) ;
}
2014-06-25 15:16:09 -04:00
reassign_track_numbers ( ) ;
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
void
2009-07-21 11:55:17 -04:00
Session : : route_mute_changed ( void * /*src*/ )
2008-06-02 17:41:35 -04:00
{
set_dirty ( ) ;
}
2009-07-01 09:36:50 -04:00
void
2009-07-21 11:55:17 -04:00
Session : : route_listen_changed ( void * /*src*/ , boost : : weak_ptr < Route > wpr )
2009-07-01 09:36:50 -04:00
{
boost : : shared_ptr < Route > route = wpr . lock ( ) ;
if ( ! route ) {
error < < string_compose ( _ ( " programming error: %1 " ) , X_ ( " invalid route weak ptr passed to route_solo_changed " ) ) < < endmsg ;
return ;
}
2011-02-19 19:55:32 -05:00
if ( route - > listening_via_monitor ( ) ) {
2010-05-05 11:47:51 -04:00
2010-11-26 14:57:03 -05:00
if ( Config - > get_exclusive_solo ( ) ) {
/* new listen: disable all other listen */
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2010-11-26 14:57:03 -05:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2013-04-06 16:04:02 -04:00
if ( ( * i ) = = route | | ( * i ) - > solo_isolated ( ) | | ( * i ) - > is_master ( ) | | ( * i ) - > is_monitor ( ) | | ( * i ) - > is_auditioner ( ) ) {
2010-11-26 14:57:03 -05:00
continue ;
2011-06-01 12:50:12 -04:00
}
2010-11-26 14:57:03 -05:00
( * i ) - > set_listen ( false , this ) ;
}
}
2010-05-05 11:47:51 -04:00
2009-07-01 09:36:50 -04:00
_listen_cnt + + ;
2010-05-05 11:47:51 -04:00
2009-07-01 09:36:50 -04:00
} else if ( _listen_cnt > 0 ) {
2010-05-05 11:47:51 -04:00
2009-07-01 09:36:50 -04:00
_listen_cnt - - ;
}
2011-02-22 16:15:42 -05:00
update_route_solo_state ( ) ;
2009-07-01 09:36:50 -04:00
}
2010-05-06 14:40:37 -04:00
void
Session : : route_solo_isolated_changed ( void * /*src*/ , boost : : weak_ptr < Route > wpr )
{
boost : : shared_ptr < Route > route = wpr . lock ( ) ;
if ( ! route ) {
/* should not happen */
error < < string_compose ( _ ( " programming error: %1 " ) , X_ ( " invalid route weak ptr passed to route_solo_changed " ) ) < < endmsg ;
return ;
}
2011-06-01 12:50:12 -04:00
2011-03-14 17:53:10 -04:00
bool send_changed = false ;
if ( route - > solo_isolated ( ) ) {
if ( _solo_isolated_cnt = = 0 ) {
send_changed = true ;
}
_solo_isolated_cnt + + ;
} else if ( _solo_isolated_cnt > 0 ) {
_solo_isolated_cnt - - ;
if ( _solo_isolated_cnt = = 0 ) {
send_changed = true ;
}
}
if ( send_changed ) {
IsolatedChanged ( ) ; /* EMIT SIGNAL */
}
2010-05-06 14:40:37 -04:00
}
2011-06-01 12:50:12 -04:00
2008-06-02 17:41:35 -04:00
void
2010-04-26 23:10:53 -04:00
Session : : route_solo_changed ( bool self_solo_change , void * /*src*/ , boost : : weak_ptr < Route > wpr )
2008-08-04 18:37:24 -04:00
{
2011-08-10 11:13:15 -04:00
DEBUG_TRACE ( DEBUG : : Solo , string_compose ( " route solo change, self = %1 \n " , self_solo_change ) ) ;
2010-11-26 14:57:03 -05:00
if ( ! self_solo_change ) {
// session doesn't care about changes to soloed-by-others
return ;
}
2010-04-26 23:10:53 -04:00
2008-06-02 17:41:35 -04:00
if ( solo_update_disabled ) {
// We know already
2011-08-10 11:13:15 -04:00
DEBUG_TRACE ( DEBUG : : Solo , " solo update disabled - changed ignored \n " ) ;
2008-06-02 17:41:35 -04:00
return ;
}
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
boost : : shared_ptr < Route > route = wpr . lock ( ) ;
2011-08-10 11:13:15 -04:00
assert ( route ) ;
2011-06-01 12:50:12 -04:00
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2009-06-09 16:21:19 -04:00
int32_t delta ;
2008-06-02 17:41:35 -04:00
2009-11-21 12:20:57 -05:00
if ( route - > self_soloed ( ) ) {
2009-06-09 16:21:19 -04:00
delta = 1 ;
} else {
delta = - 1 ;
}
2011-06-01 12:50:12 -04:00
2011-07-25 12:10:11 -04:00
RouteGroup * rg = route - > route_group ( ) ;
bool leave_group_alone = ( rg & & rg - > is_active ( ) & & rg - > is_solo ( ) ) ;
2010-11-26 14:57:03 -05:00
if ( delta = = 1 & & Config - > get_exclusive_solo ( ) ) {
2011-07-25 12:10:11 -04:00
/* new solo: disable all other solos, but not the group if its solo-enabled */
2010-11-26 14:57:03 -05:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2013-04-06 16:04:02 -04:00
if ( ( * i ) = = route | | ( * i ) - > solo_isolated ( ) | | ( * i ) - > is_master ( ) | | ( * i ) - > is_monitor ( ) | | ( * i ) - > is_auditioner ( ) | |
2011-07-25 12:10:11 -04:00
( leave_group_alone & & ( ( * i ) - > route_group ( ) = = rg ) ) ) {
2010-11-26 14:57:03 -05:00
continue ;
2011-06-01 12:50:12 -04:00
}
2010-11-26 14:57:03 -05:00
( * i ) - > set_solo ( false , this ) ;
}
}
2008-08-04 18:37:24 -04:00
2011-08-10 11:13:15 -04:00
DEBUG_TRACE ( DEBUG : : Solo , string_compose ( " propagate solo change, delta = %1 \n " , delta ) ) ;
2009-06-10 14:10:07 -04:00
solo_update_disabled = true ;
2011-06-01 12:50:12 -04:00
2010-11-26 14:57:03 -05:00
RouteList uninvolved ;
2011-06-01 12:50:12 -04:00
2011-08-10 11:13:15 -04:00
DEBUG_TRACE ( DEBUG : : Solo , string_compose ( " %1 \n " , route - > name ( ) ) ) ;
2009-06-09 16:21:19 -04:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2009-11-17 17:29:43 -05:00
bool via_sends_only ;
2010-11-26 14:57:03 -05:00
bool in_signal_flow ;
2009-06-10 09:59:06 -04:00
2013-04-06 16:04:02 -04:00
if ( ( * i ) = = route | | ( * i ) - > solo_isolated ( ) | | ( * i ) - > is_master ( ) | | ( * i ) - > is_monitor ( ) | | ( * i ) - > is_auditioner ( ) | |
2011-07-25 12:10:11 -04:00
( leave_group_alone & & ( ( * i ) - > route_group ( ) = = rg ) ) ) {
2009-11-21 12:20:57 -05:00
continue ;
2011-06-01 12:50:12 -04:00
}
2010-04-26 23:10:53 -04:00
2010-11-26 14:57:03 -05:00
in_signal_flow = false ;
2010-04-27 13:10:04 -04:00
2011-08-10 11:13:15 -04:00
DEBUG_TRACE ( DEBUG : : Solo , string_compose ( " check feed from %1 \n " , ( * i ) - > name ( ) ) ) ;
2010-11-26 14:57:03 -05:00
if ( ( * i ) - > feeds ( route , & via_sends_only ) ) {
2012-11-21 14:56:55 -05:00
DEBUG_TRACE ( DEBUG : : Solo , string_compose ( " \t there is a feed from %1 \n " , ( * i ) - > name ( ) ) ) ;
2009-11-17 18:11:42 -05:00
if ( ! via_sends_only ) {
2010-11-26 14:57:03 -05:00
if ( ! route - > soloed_by_others_upstream ( ) ) {
( * i ) - > mod_solo_by_others_downstream ( delta ) ;
}
2012-11-21 14:56:55 -05:00
} else {
DEBUG_TRACE ( DEBUG : : Solo , string_compose ( " \t there is a send-only feed from %1 \n " , ( * i ) - > name ( ) ) ) ;
2009-11-21 12:20:57 -05:00
}
2011-08-10 11:13:15 -04:00
in_signal_flow = true ;
} else {
2012-11-21 14:56:55 -05:00
DEBUG_TRACE ( DEBUG : : Solo , string_compose ( " \t no feed from %1 \n " , ( * i ) - > name ( ) ) ) ;
2011-06-01 12:50:12 -04:00
}
2011-08-10 11:13:15 -04:00
DEBUG_TRACE ( DEBUG : : Solo , string_compose ( " check feed to %1 \n " , ( * i ) - > name ( ) ) ) ;
2011-06-01 12:50:12 -04:00
2010-11-26 14:57:03 -05:00
if ( route - > feeds ( * i , & via_sends_only ) ) {
2011-08-10 11:13:15 -04:00
/* propagate solo upstream only if routing other than
sends is involved , but do consider the other route
( * i ) to be part of the signal flow even if only
sends are involved .
*/
DEBUG_TRACE ( DEBUG : : Solo , string_compose ( " %1 feeds %2 via sends only %3 sboD %4 sboU %5 \n " ,
route - > name ( ) ,
( * i ) - > name ( ) ,
via_sends_only ,
route - > soloed_by_others_downstream ( ) ,
route - > soloed_by_others_upstream ( ) ) ) ;
if ( ! via_sends_only ) {
if ( ! route - > soloed_by_others_downstream ( ) ) {
DEBUG_TRACE ( DEBUG : : Solo , string_compose ( " \t mod %1 by %2 \n " , ( * i ) - > name ( ) , delta ) ) ;
( * i ) - > mod_solo_by_others_upstream ( delta ) ;
2012-11-21 14:56:55 -05:00
} else {
DEBUG_TRACE ( DEBUG : : Solo , " \t already soloed by others downstream \n " ) ;
2011-08-10 11:13:15 -04:00
}
2012-11-21 14:56:55 -05:00
} else {
DEBUG_TRACE ( DEBUG : : Solo , string_compose ( " \t feed to %1 ignored, sends-only \n " , ( * i ) - > name ( ) ) ) ;
2011-08-10 11:13:15 -04:00
}
2010-11-26 14:57:03 -05:00
in_signal_flow = true ;
2011-08-10 11:13:15 -04:00
} else {
DEBUG_TRACE ( DEBUG : : Solo , " \t no feed to \n " ) ;
2010-11-26 14:57:03 -05:00
}
2010-05-03 18:07:47 -04:00
2010-11-26 14:57:03 -05:00
if ( ! in_signal_flow ) {
uninvolved . push_back ( * i ) ;
}
2008-06-02 17:41:35 -04:00
}
2008-08-04 18:37:24 -04:00
2009-06-10 14:10:07 -04:00
solo_update_disabled = false ;
2011-08-10 11:13:15 -04:00
DEBUG_TRACE ( DEBUG : : Solo , " propagation complete \n " ) ;
2009-06-10 14:10:07 -04:00
update_route_solo_state ( r ) ;
2010-05-03 18:07:47 -04:00
2010-11-26 14:57:03 -05:00
/* now notify that the mute state of the routes not involved in the signal
pathway of the just - solo - changed route may have altered .
*/
2010-05-03 18:07:47 -04:00
2010-11-26 14:57:03 -05:00
for ( RouteList : : iterator i = uninvolved . begin ( ) ; i ! = uninvolved . end ( ) ; + + i ) {
2012-11-21 14:56:55 -05:00
DEBUG_TRACE ( DEBUG : : Solo , string_compose ( " mute change for %1, which neither feeds or is fed by %2 \n " , ( * i ) - > name ( ) , route - > name ( ) ) ) ;
2010-11-26 14:57:03 -05:00
( * i ) - > mute_changed ( this ) ;
}
2010-05-03 18:07:47 -04:00
2008-06-02 17:41:35 -04:00
SoloChanged ( ) ; /* EMIT SIGNAL */
set_dirty ( ) ;
}
void
2009-06-10 14:10:07 -04:00
Session : : update_route_solo_state ( boost : : shared_ptr < RouteList > r )
2008-06-02 17:41:35 -04:00
{
2010-03-10 12:31:16 -05:00
/* now figure out if anything that matters is soloed (or is "listening")*/
2008-06-02 17:41:35 -04:00
2009-06-10 14:10:07 -04:00
bool something_soloed = false ;
2010-11-26 14:57:03 -05:00
uint32_t listeners = 0 ;
uint32_t isolated = 0 ;
2008-08-04 18:37:24 -04:00
2009-06-10 14:10:07 -04:00
if ( ! r ) {
r = routes . reader ( ) ;
}
2008-06-02 17:41:35 -04:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2013-04-06 16:04:02 -04:00
if ( ! ( * i ) - > is_master ( ) & & ! ( * i ) - > is_monitor ( ) & & ! ( * i ) - > is_auditioner ( ) & & ( * i ) - > self_soloed ( ) ) {
2009-06-10 14:10:07 -04:00
something_soloed = true ;
2008-06-02 17:41:35 -04:00
}
2010-03-10 12:31:16 -05:00
2013-04-06 16:04:02 -04:00
if ( ! ( * i ) - > is_auditioner ( ) & & ( * i ) - > listening_via_monitor ( ) ) {
2010-11-26 14:57:03 -05:00
if ( Config - > get_solo_control_is_listen_control ( ) ) {
listeners + + ;
} else {
( * i ) - > set_listen ( false , this ) ;
}
}
2010-05-06 14:40:37 -04:00
2010-11-26 14:57:03 -05:00
if ( ( * i ) - > solo_isolated ( ) ) {
isolated + + ;
}
2008-06-02 17:41:35 -04:00
}
2010-11-26 14:57:03 -05:00
if ( something_soloed ! = _non_soloed_outs_muted ) {
_non_soloed_outs_muted = something_soloed ;
SoloActive ( _non_soloed_outs_muted ) ; /* EMIT SIGNAL */
}
2010-03-06 14:47:34 -05:00
2010-11-26 14:57:03 -05:00
_listen_cnt = listeners ;
2010-05-06 14:40:37 -04:00
2010-11-26 14:57:03 -05:00
if ( isolated ! = _solo_isolated_cnt ) {
_solo_isolated_cnt = isolated ;
IsolatedChanged ( ) ; /* EMIT SIGNAL */
}
2012-11-21 14:56:55 -05:00
DEBUG_TRACE ( DEBUG : : Solo , string_compose ( " solo state updated by session, soloed? %1 listeners %2 isolated %3 \n " ,
something_soloed , listeners , isolated ) ) ;
2008-06-02 17:41:35 -04:00
}
2011-06-01 12:50:12 -04:00
boost : : shared_ptr < RouteList >
2009-11-18 23:25:46 -05:00
Session : : get_routes_with_internal_returns ( ) const
{
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2009-11-18 23:25:46 -05:00
boost : : shared_ptr < RouteList > rl ( new RouteList ) ;
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
if ( ( * i ) - > internal_return ( ) ) {
rl - > push_back ( * i ) ;
}
}
return rl ;
}
2010-04-20 22:24:38 -04:00
bool
Session : : io_name_is_legal ( const std : : string & name )
{
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2011-06-01 12:50:12 -04:00
2010-11-26 14:57:03 -05:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
if ( ( * i ) - > name ( ) = = name ) {
return false ;
}
2011-06-01 12:50:12 -04:00
2010-11-26 14:57:03 -05:00
if ( ( * i ) - > has_io_processor_named ( name ) ) {
return false ;
}
}
2011-06-01 12:50:12 -04:00
2010-11-26 14:57:03 -05:00
return true ;
2010-04-20 22:24:38 -04:00
}
2011-07-03 11:01:21 -04:00
void
2012-11-12 21:19:04 -05:00
Session : : set_exclusive_input_active ( boost : : shared_ptr < RouteList > rl , bool onoff , bool flip_others )
2011-07-03 11:01:21 -04:00
{
2012-11-12 21:19:04 -05:00
RouteList rl2 ;
2011-07-03 11:01:21 -04:00
vector < string > connections ;
2012-11-12 21:19:04 -05:00
/* if we are passed only a single route and we're not told to turn
* others off , then just do the simple thing .
*/
2011-07-03 11:01:21 -04:00
2012-11-12 21:19:04 -05:00
if ( flip_others = = false & & rl - > size ( ) = = 1 ) {
boost : : shared_ptr < MidiTrack > mt = boost : : dynamic_pointer_cast < MidiTrack > ( rl - > front ( ) ) ;
if ( mt ) {
mt - > set_input_active ( onoff ) ;
return ;
}
2011-07-03 11:01:21 -04:00
}
2012-11-12 21:19:04 -05:00
for ( RouteList : : iterator rt = rl - > begin ( ) ; rt ! = rl - > end ( ) ; + + rt ) {
2011-07-03 11:01:21 -04:00
2012-11-12 21:19:04 -05:00
PortSet & ps ( ( * rt ) - > input ( ) - > ports ( ) ) ;
for ( PortSet : : iterator p = ps . begin ( ) ; p ! = ps . end ( ) ; + + p ) {
p - > get_connections ( connections ) ;
}
for ( vector < string > : : iterator s = connections . begin ( ) ; s ! = connections . end ( ) ; + + s ) {
routes_using_input_from ( * s , rl2 ) ;
}
/* scan all relevant routes to see if others are on or off */
bool others_are_already_on = false ;
for ( RouteList : : iterator r = rl2 . begin ( ) ; r ! = rl2 . end ( ) ; + + r ) {
2011-07-03 11:01:21 -04:00
boost : : shared_ptr < MidiTrack > mt = boost : : dynamic_pointer_cast < MidiTrack > ( * r ) ;
2012-11-12 21:19:04 -05:00
if ( ! mt ) {
continue ;
}
if ( ( * r ) ! = ( * rt ) ) {
2011-07-03 11:01:21 -04:00
if ( mt - > input_active ( ) ) {
others_are_already_on = true ;
}
2012-11-12 21:19:04 -05:00
} else {
/* this one needs changing */
mt - > set_input_active ( onoff ) ;
2011-07-03 11:01:21 -04:00
}
}
2012-11-12 21:19:04 -05:00
if ( flip_others ) {
2011-07-03 11:01:21 -04:00
2012-11-12 21:19:04 -05:00
/* globally reverse other routes */
for ( RouteList : : iterator r = rl2 . begin ( ) ; r ! = rl2 . end ( ) ; + + r ) {
if ( ( * r ) ! = ( * rt ) ) {
boost : : shared_ptr < MidiTrack > mt = boost : : dynamic_pointer_cast < MidiTrack > ( * r ) ;
if ( mt ) {
mt - > set_input_active ( ! others_are_already_on ) ;
}
}
2011-07-03 11:01:21 -04:00
}
}
}
}
void
Session : : routes_using_input_from ( const string & str , RouteList & rl )
{
2012-11-12 21:19:04 -05:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2011-07-03 11:01:21 -04:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
if ( ( * i ) - > input ( ) - > connected_to ( str ) ) {
rl . push_back ( * i ) ;
}
}
}
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < Route >
2008-06-02 17:41:35 -04:00
Session : : route_by_name ( string name )
{
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2008-06-02 17:41:35 -04:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
if ( ( * i ) - > name ( ) = = name ) {
return * i ;
}
}
2010-11-29 17:07:42 -05:00
return boost : : shared_ptr < Route > ( ( Route * ) 0 ) ;
2008-06-02 17:41:35 -04:00
}
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < Route >
2008-06-02 17:41:35 -04:00
Session : : route_by_id ( PBD : : ID id )
{
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2008-06-02 17:41:35 -04:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
if ( ( * i ) - > id ( ) = = id ) {
return * i ;
}
}
2010-11-29 17:07:42 -05:00
return boost : : shared_ptr < Route > ( ( Route * ) 0 ) ;
2008-06-02 17:41:35 -04:00
}
2011-12-10 14:20:15 -05:00
boost : : shared_ptr < Track >
Session : : track_by_diskstream_id ( PBD : : ID id )
{
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
boost : : shared_ptr < Track > t = boost : : dynamic_pointer_cast < Track > ( * i ) ;
if ( t & & t - > using_diskstream_id ( id ) ) {
return t ;
}
}
return boost : : shared_ptr < Track > ( ) ;
}
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < Route >
2008-06-02 17:41:35 -04:00
Session : : route_by_remote_id ( uint32_t id )
{
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2008-06-02 17:41:35 -04:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
if ( ( * i ) - > remote_control_id ( ) = = id ) {
return * i ;
}
}
2010-11-29 17:07:42 -05:00
return boost : : shared_ptr < Route > ( ( Route * ) 0 ) ;
2008-06-02 17:41:35 -04:00
}
2014-06-25 15:16:09 -04:00
void
Session : : reassign_track_numbers ( )
{
int64_t tn = 0 ;
int64_t bn = 0 ;
RouteList r ( * ( routes . reader ( ) ) ) ;
SignalOrderRouteSorter sorter ;
r . sort ( sorter ) ;
2014-06-28 15:36:13 -04:00
StateProtector sp ( this ) ;
2014-06-25 15:16:09 -04:00
for ( RouteList : : iterator i = r . begin ( ) ; i ! = r . end ( ) ; + + i ) {
if ( boost : : dynamic_pointer_cast < Track > ( * i ) ) {
( * i ) - > set_track_number ( + + tn ) ;
}
else if ( ! ( * i ) - > is_master ( ) & & ! ( * i ) - > is_monitor ( ) & & ! ( * i ) - > is_auditioner ( ) ) {
( * i ) - > set_track_number ( - - bn ) ;
}
}
const uint32_t decimals = ceilf ( log10f ( tn + 1 ) ) ;
const bool decimals_changed = _track_number_decimals ! = decimals ;
_track_number_decimals = decimals ;
if ( decimals_changed & & config . get_track_name_number ( ) ) {
for ( RouteList : : iterator i = r . begin ( ) ; i ! = r . end ( ) ; + + i ) {
boost : : shared_ptr < Track > t = boost : : dynamic_pointer_cast < Track > ( * i ) ;
if ( t ) {
t - > resync_track_name ( ) ;
}
}
// trigger GUI re-layout
config . ParameterChanged ( " track-name-number " ) ;
}
}
2011-01-19 12:38:56 -05:00
void
Session : : playlist_region_added ( boost : : weak_ptr < Region > w )
{
boost : : shared_ptr < Region > r = w . lock ( ) ;
if ( ! r ) {
return ;
}
/* These are the operations that are currently in progress... */
list < GQuark > curr = _current_trans_quarks ;
curr . sort ( ) ;
/* ...and these are the operations during which we want to update
the session range location markers .
*/
list < GQuark > ops ;
ops . push_back ( Operations : : capture ) ;
ops . push_back ( Operations : : paste ) ;
ops . push_back ( Operations : : duplicate_region ) ;
ops . push_back ( Operations : : insert_file ) ;
ops . push_back ( Operations : : insert_region ) ;
ops . push_back ( Operations : : drag_region_brush ) ;
ops . push_back ( Operations : : region_drag ) ;
ops . push_back ( Operations : : selection_grab ) ;
ops . push_back ( Operations : : region_fill ) ;
ops . push_back ( Operations : : fill_selection ) ;
ops . push_back ( Operations : : create_region ) ;
2011-05-12 17:29:27 -04:00
ops . push_back ( Operations : : region_copy ) ;
ops . push_back ( Operations : : fixed_time_region_copy ) ;
2011-01-19 12:38:56 -05:00
ops . sort ( ) ;
/* See if any of the current operations match the ones that we want */
list < GQuark > in ;
set_intersection ( _current_trans_quarks . begin ( ) , _current_trans_quarks . end ( ) , ops . begin ( ) , ops . end ( ) , back_inserter ( in ) ) ;
/* If so, update the session range markers */
if ( ! in . empty ( ) ) {
maybe_update_session_range ( r - > position ( ) , r - > last_frame ( ) ) ;
}
}
/** Update the session range markers if a is before the current start or
* b is after the current end .
2010-05-09 16:48:21 -04:00
*/
2008-06-02 17:41:35 -04:00
void
2011-01-19 12:38:56 -05:00
Session : : maybe_update_session_range ( framepos_t a , framepos_t b )
2008-06-02 17:41:35 -04:00
{
if ( _state_of_the_state & Loading ) {
return ;
}
2010-05-09 16:48:21 -04:00
if ( _session_range_location = = 0 ) {
2011-06-01 12:50:12 -04:00
2011-01-19 12:38:56 -05:00
add_session_range_location ( a , b ) ;
2011-06-01 12:50:12 -04:00
2010-05-09 16:48:21 -04:00
} else {
2011-06-01 12:50:12 -04:00
2011-01-19 12:38:56 -05:00
if ( a < _session_range_location - > start ( ) ) {
_session_range_location - > set_start ( a ) ;
2010-05-09 16:48:21 -04:00
}
2011-06-01 12:50:12 -04:00
2011-01-19 12:38:56 -05:00
if ( b > _session_range_location - > end ( ) ) {
_session_range_location - > set_end ( b ) ;
}
2008-06-02 17:41:35 -04:00
}
}
2011-01-19 12:38:56 -05:00
void
Session : : playlist_ranges_moved ( list < Evoral : : RangeMove < framepos_t > > const & ranges )
2008-06-02 17:41:35 -04:00
{
2011-01-19 12:38:56 -05:00
for ( list < Evoral : : RangeMove < framepos_t > > : : const_iterator i = ranges . begin ( ) ; i ! = ranges . end ( ) ; + + i ) {
maybe_update_session_range ( i - > to , i - > to + i - > length ) ;
2008-06-02 17:41:35 -04:00
}
}
2011-03-01 11:23:31 -05:00
void
Session : : playlist_regions_extended ( list < Evoral : : Range < framepos_t > > const & ranges )
{
for ( list < Evoral : : Range < framepos_t > > : : const_iterator i = ranges . begin ( ) ; i ! = ranges . end ( ) ; + + i ) {
maybe_update_session_range ( i - > from , i - > to ) ;
}
}
2008-06-02 17:41:35 -04:00
/* Region management */
boost : : shared_ptr < Region >
2010-03-01 19:00:00 -05:00
Session : : find_whole_file_parent ( boost : : shared_ptr < Region const > child ) const
2008-06-02 17:41:35 -04:00
{
2010-11-26 14:57:03 -05:00
const RegionFactory : : RegionMap & regions ( RegionFactory : : regions ( ) ) ;
2010-03-06 10:40:42 -05:00
RegionFactory : : RegionMap : : const_iterator i ;
2008-06-02 17:41:35 -04:00
boost : : shared_ptr < Region > region ;
2008-08-04 18:37:24 -04:00
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( region_lock ) ;
2008-06-02 17:41:35 -04:00
for ( i = regions . begin ( ) ; i ! = regions . end ( ) ; + + i ) {
region = i - > second ;
if ( region - > whole_file ( ) ) {
if ( child - > source_equivalent ( region ) ) {
return region ;
}
}
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
return boost : : shared_ptr < Region > ( ) ;
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
int
2010-06-23 16:14:07 -04:00
Session : : destroy_sources ( list < boost : : shared_ptr < Source > > srcs )
2008-06-02 17:41:35 -04:00
{
2010-11-26 14:57:03 -05:00
set < boost : : shared_ptr < Region > > relevant_regions ;
2008-08-04 18:37:24 -04:00
2010-06-23 16:14:07 -04:00
for ( list < boost : : shared_ptr < Source > > : : iterator s = srcs . begin ( ) ; s ! = srcs . end ( ) ; + + s ) {
2010-11-26 14:57:03 -05:00
RegionFactory : : get_regions_using_source ( * s , relevant_regions ) ;
2008-06-02 17:41:35 -04:00
}
2010-11-26 14:57:03 -05:00
for ( set < boost : : shared_ptr < Region > > : : iterator r = relevant_regions . begin ( ) ; r ! = relevant_regions . end ( ) ; ) {
set < boost : : shared_ptr < Region > > : : iterator tmp ;
2010-06-23 16:14:07 -04:00
2010-11-26 14:57:03 -05:00
tmp = r ;
+ + tmp ;
2010-06-23 16:14:07 -04:00
2010-11-26 14:57:03 -05:00
playlists - > destroy_region ( * r ) ;
RegionFactory : : map_remove ( * r ) ;
2008-06-02 17:41:35 -04:00
2010-11-26 14:57:03 -05:00
( * r ) - > drop_sources ( ) ;
( * r ) - > drop_references ( ) ;
2010-06-23 16:14:07 -04:00
2010-11-26 14:57:03 -05:00
relevant_regions . erase ( r ) ;
2010-06-23 16:14:07 -04:00
2010-11-26 14:57:03 -05:00
r = tmp ;
}
2010-06-23 16:14:07 -04:00
for ( list < boost : : shared_ptr < Source > > : : iterator s = srcs . begin ( ) ; s ! = srcs . end ( ) ; ) {
2011-06-01 12:50:12 -04:00
2010-11-26 14:57:03 -05:00
{
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock ls ( source_lock ) ;
2010-11-26 14:57:03 -05:00
/* remove from the main source list */
sources . erase ( ( * s ) - > id ( ) ) ;
}
2008-06-02 17:41:35 -04:00
2010-11-26 14:57:03 -05:00
( * s ) - > mark_for_remove ( ) ;
( * s ) - > drop_references ( ) ;
2010-06-23 16:14:07 -04:00
2010-11-26 14:57:03 -05:00
s = srcs . erase ( s ) ;
}
2008-06-02 17:41:35 -04:00
return 0 ;
}
int
Session : : remove_last_capture ( )
{
2010-06-23 16:14:07 -04:00
list < boost : : shared_ptr < Source > > srcs ;
2008-08-04 18:37:24 -04:00
2010-04-21 16:42:22 -04:00
boost : : shared_ptr < RouteList > rl = routes . reader ( ) ;
for ( RouteList : : iterator i = rl - > begin ( ) ; i ! = rl - > end ( ) ; + + i ) {
boost : : shared_ptr < Track > tr = boost : : dynamic_pointer_cast < Track > ( * i ) ;
if ( ! tr ) {
continue ;
}
2011-06-01 12:50:12 -04:00
2010-06-23 16:14:07 -04:00
list < boost : : shared_ptr < Source > > & l = tr - > last_capture_sources ( ) ;
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
if ( ! l . empty ( ) ) {
2010-06-23 16:14:07 -04:00
srcs . insert ( srcs . end ( ) , l . begin ( ) , l . end ( ) ) ;
2008-06-02 17:41:35 -04:00
l . clear ( ) ;
}
}
2010-06-23 16:14:07 -04:00
destroy_sources ( srcs ) ;
2008-06-02 17:41:35 -04:00
save_state ( _current_snapshot_name ) ;
return 0 ;
}
/* Source Management */
2009-02-16 21:11:49 -05:00
2008-06-02 17:41:35 -04:00
void
Session : : add_source ( boost : : shared_ptr < Source > source )
{
pair < SourceMap : : key_type , SourceMap : : mapped_type > entry ;
pair < SourceMap : : iterator , bool > result ;
entry . first = source - > id ( ) ;
entry . second = source ;
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
{
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( source_lock ) ;
2008-06-02 17:41:35 -04:00
result = sources . insert ( entry ) ;
}
if ( result . second ) {
2008-08-04 18:37:24 -04:00
2010-11-26 14:57:03 -05:00
/* yay, new source */
2008-06-02 17:41:35 -04:00
2012-05-27 14:07:30 -04:00
boost : : shared_ptr < FileSource > fs = boost : : dynamic_pointer_cast < FileSource > ( source ) ;
if ( fs ) {
if ( ! fs - > within_session ( ) ) {
ensure_search_path_includes ( Glib : : path_get_dirname ( fs - > path ( ) ) , fs - > type ( ) ) ;
}
}
2010-06-23 16:14:07 -04:00
set_dirty ( ) ;
2010-11-26 14:57:03 -05:00
boost : : shared_ptr < AudioFileSource > afs ;
2011-06-01 12:50:12 -04:00
2010-11-26 14:57:03 -05:00
if ( ( afs = boost : : dynamic_pointer_cast < AudioFileSource > ( source ) ) ! = 0 ) {
if ( Config - > get_auto_analyse_audio ( ) ) {
Analyser : : queue_source_for_analysis ( source , false ) ;
}
}
2011-02-28 21:04:50 -05:00
source - > DropReferences . connect_same_thread ( * this , boost : : bind ( & Session : : remove_source , this , boost : : weak_ptr < Source > ( source ) ) ) ;
2011-03-14 17:53:10 -04:00
}
2008-06-02 17:41:35 -04:00
}
void
Session : : remove_source ( boost : : weak_ptr < Source > src )
{
2011-03-02 06:30:37 -05:00
if ( _state_of_the_state & Deletion ) {
return ;
}
2011-06-01 12:50:12 -04:00
2008-06-02 17:41:35 -04:00
SourceMap : : iterator i ;
boost : : shared_ptr < Source > source = src . lock ( ) ;
if ( ! source ) {
return ;
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
2008-08-04 18:37:24 -04:00
{
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( source_lock ) ;
2008-06-02 17:41:35 -04:00
if ( ( i = sources . find ( source - > id ( ) ) ) ! = sources . end ( ) ) {
sources . erase ( i ) ;
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
}
2008-08-04 18:37:24 -04:00
2014-07-09 10:09:49 -04:00
if ( ! ( _state_of_the_state & StateOfTheState ( InCleanup | Loading ) ) ) {
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
/* save state so we don't end up with a session file
referring to non - existent sources .
*/
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
save_state ( _current_snapshot_name ) ;
}
}
boost : : shared_ptr < Source >
Session : : source_by_id ( const PBD : : ID & id )
{
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( source_lock ) ;
2008-06-02 17:41:35 -04:00
SourceMap : : iterator i ;
boost : : shared_ptr < Source > source ;
if ( ( i = sources . find ( id ) ) ! = sources . end ( ) ) {
source = i - > second ;
}
return source ;
}
2014-04-13 10:29:07 -04:00
boost : : shared_ptr < AudioFileSource >
2014-05-29 16:27:33 -04:00
Session : : audio_source_by_path_and_channel ( const string & path , uint16_t chn ) const
2008-06-02 17:41:35 -04:00
{
2014-04-13 10:29:07 -04:00
/* Restricted to audio files because only audio sources have channel
as a property .
*/
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( source_lock ) ;
2008-06-02 17:41:35 -04:00
2014-04-13 10:29:07 -04:00
for ( SourceMap : : const_iterator i = sources . begin ( ) ; i ! = sources . end ( ) ; + + i ) {
2009-02-16 21:11:49 -05:00
boost : : shared_ptr < AudioFileSource > afs
= boost : : dynamic_pointer_cast < AudioFileSource > ( i - > second ) ;
2008-06-02 17:41:35 -04:00
if ( afs & & afs - > path ( ) = = path & & chn = = afs - > channel ( ) ) {
return afs ;
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
}
2014-04-13 10:29:07 -04:00
return boost : : shared_ptr < AudioFileSource > ( ) ;
}
boost : : shared_ptr < MidiSource >
2014-05-29 16:27:33 -04:00
Session : : midi_source_by_path ( const std : : string & path ) const
2014-04-13 10:29:07 -04:00
{
/* Restricted to MIDI files because audio sources require a channel
for unique identification , in addition to a path .
*/
Glib : : Threads : : Mutex : : Lock lm ( source_lock ) ;
for ( SourceMap : : const_iterator s = sources . begin ( ) ; s ! = sources . end ( ) ; + + s ) {
boost : : shared_ptr < MidiSource > ms
= boost : : dynamic_pointer_cast < MidiSource > ( s - > second ) ;
boost : : shared_ptr < FileSource > fs
= boost : : dynamic_pointer_cast < FileSource > ( s - > second ) ;
if ( ms & & fs & & fs - > path ( ) = = path ) {
return ms ;
}
}
return boost : : shared_ptr < MidiSource > ( ) ;
2008-06-02 17:41:35 -04:00
}
2010-11-09 17:18:52 -05:00
uint32_t
Session : : count_sources_by_origin ( const string & path )
{
2010-11-26 14:57:03 -05:00
uint32_t cnt = 0 ;
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( source_lock ) ;
2010-11-09 17:18:52 -05:00
for ( SourceMap : : iterator i = sources . begin ( ) ; i ! = sources . end ( ) ; + + i ) {
boost : : shared_ptr < FileSource > fs
= boost : : dynamic_pointer_cast < FileSource > ( i - > second ) ;
2010-11-26 14:57:03 -05:00
if ( fs & & fs - > origin ( ) = = path ) {
+ + cnt ;
}
2010-11-09 17:18:52 -05:00
}
return cnt ;
}
2010-09-14 11:45:21 -04:00
string
Session : : peak_path ( string base ) const
2009-02-16 21:11:49 -05:00
{
2012-06-23 01:06:54 -04:00
return Glib : : build_filename ( _session_dir - > peak_path ( ) , base + peakfile_suffix ) ;
2009-02-16 21:11:49 -05:00
}
string
2014-07-08 00:53:06 -04:00
Session : : new_audio_source_path_for_embedded ( const std : : string & path )
2008-06-02 17:41:35 -04:00
{
2014-07-08 00:53:06 -04:00
/* embedded source:
*
* we know that the filename is already unique because it exists
* out in the filesystem .
*
* However , when we bring it into the session , we could get a
* collision .
*
* Eg . two embedded files :
*
* / foo / bar / baz . wav
* / frob / nic / baz . wav
*
* When merged into session , these collide .
*
* There will not be a conflict with in - memory sources
* because when the source was created we already picked
* a unique name for it .
*
* This collision is not likely to be common , but we have to guard
* against it . So , if there is a collision , take the md5 hash of the
* the path , and use that as the filename instead .
*/
2008-06-02 17:41:35 -04:00
2014-07-08 00:53:06 -04:00
SessionDirectory sdir ( get_best_session_directory_for_new_audio ( ) ) ;
string base = Glib : : path_get_basename ( path ) ;
string newpath = Glib : : build_filename ( sdir . sound_path ( ) , base ) ;
if ( Glib : : file_test ( newpath , Glib : : FILE_TEST_EXISTS ) ) {
2008-06-02 17:41:35 -04:00
2014-07-08 00:53:06 -04:00
MD5 md5 ;
2014-07-02 17:35:48 -04:00
2014-07-08 00:53:06 -04:00
md5 . digestString ( path . c_str ( ) ) ;
md5 . writeToString ( ) ;
base = md5 . digestChars ;
2014-07-08 12:25:36 -04:00
string ext = get_suffix ( path ) ;
2014-06-02 11:20:37 -04:00
2014-07-08 12:25:36 -04:00
if ( ! ext . empty ( ) ) {
base + = ' . ' ;
base + = ext ;
}
2014-07-08 00:53:06 -04:00
newpath = Glib : : build_filename ( sdir . sound_path ( ) , base ) ;
2008-06-02 17:41:35 -04:00
2014-07-08 00:53:06 -04:00
/* if this collides, we're screwed */
2008-06-02 17:41:35 -04:00
2014-07-08 00:53:06 -04:00
if ( Glib : : file_test ( newpath , Glib : : FILE_TEST_EXISTS ) ) {
error < < string_compose ( _ ( " Merging embedded file %1: name collision AND md5 hash collision! " ) , path ) < < endmsg ;
return string ( ) ;
}
2008-06-02 17:41:35 -04:00
2014-07-08 00:53:06 -04:00
}
2008-06-02 17:41:35 -04:00
2014-07-08 00:53:06 -04:00
return newpath ;
}
2008-06-02 17:41:35 -04:00
2014-07-08 00:53:06 -04:00
bool
Session : : audio_source_name_is_unique ( const string & name , uint32_t chan )
{
std : : vector < string > sdirs = source_search_path ( DataType : : AUDIO ) ;
vector < space_and_path > : : iterator i ;
uint32_t existing = 0 ;
2010-07-22 10:52:05 -04:00
2014-07-08 00:53:06 -04:00
for ( vector < string > : : const_iterator i = sdirs . begin ( ) ; i ! = sdirs . end ( ) ; + + i ) {
/* note that we search *without* the extension so that
we don ' t end up both " Audio 1-1.wav " and " Audio 1-1.caf "
in the event that this new name is required for
a file format change .
*/
2008-06-02 17:41:35 -04:00
2014-07-08 00:53:06 -04:00
const string spath = * i ;
2014-07-10 08:16:27 -04:00
if ( matching_unsuffixed_filename_exists_in ( spath , name ) ) {
2014-07-08 00:53:06 -04:00
existing + + ;
break ;
}
/* it is possible that we have the path already
* assigned to a source that has not yet been written
* ( ie . the write source for a diskstream ) . we have to
* check this in order to make sure that our candidate
* path isn ' t used again , because that can lead to
* two Sources point to the same file with different
* notions of their removability .
*/
string possible_path = Glib : : build_filename ( spath , name ) ;
2010-07-22 10:52:05 -04:00
2014-07-08 00:53:06 -04:00
if ( audio_source_by_path_and_channel ( possible_path , chan ) ) {
existing + + ;
break ;
}
}
2014-07-10 08:16:27 -04:00
2014-07-08 00:53:06 -04:00
return ( existing = = 0 ) ;
}
2014-04-13 11:35:49 -04:00
2014-07-08 00:53:06 -04:00
string
Session : : format_audio_source_name ( const string & legalized_base , uint32_t nchan , uint32_t chan , bool destructive , bool take_required , uint32_t cnt , bool related_exists )
{
ostringstream sstr ;
const string ext = native_header_format_extension ( config . get_native_file_header_format ( ) , DataType : : AUDIO ) ;
if ( destructive ) {
sstr < < ' T ' ;
sstr < < setfill ( ' 0 ' ) < < setw ( 4 ) < < cnt ;
sstr < < legalized_base ;
} else {
sstr < < legalized_base ;
if ( take_required | | related_exists ) {
sstr < < ' - ' ;
sstr < < cnt ;
}
}
if ( nchan = = 2 ) {
if ( chan = = 0 ) {
sstr < < " %L " ;
} else {
sstr < < " %R " ;
}
} else if ( nchan > 2 ) {
if ( nchan < 26 ) {
sstr < < ' % ' ;
sstr < < ' a ' + chan ;
} else {
/* XXX what? more than 26 channels! */
sstr < < ' % ' ;
sstr < < chan + 1 ;
}
}
sstr < < ext ;
2014-04-14 03:03:35 -04:00
2014-07-08 00:53:06 -04:00
return sstr . str ( ) ;
}
2014-04-13 11:35:49 -04:00
2014-07-08 00:53:06 -04:00
/** Return a unique name based on \a base for a new internal audio source */
string
Session : : new_audio_source_path ( const string & base , uint32_t nchan , uint32_t chan , bool destructive , bool take_required )
{
uint32_t cnt ;
string possible_name ;
const uint32_t limit = 9999 ; // arbitrary limit on number of files with the same basic name
string legalized ;
bool some_related_source_name_exists = false ;
2008-06-02 17:41:35 -04:00
2014-07-08 00:53:06 -04:00
legalized = legalize_for_path ( base ) ;
// Find a "version" of the base name that doesn't exist in any of the possible directories.
for ( cnt = ( destructive ? + + destructive_index : 1 ) ; cnt < = limit ; + + cnt ) {
possible_name = format_audio_source_name ( legalized , nchan , chan , destructive , take_required , cnt , some_related_source_name_exists ) ;
if ( audio_source_name_is_unique ( possible_name , chan ) ) {
2008-06-02 17:41:35 -04:00
break ;
}
2014-07-08 00:53:06 -04:00
2014-06-02 11:20:37 -04:00
some_related_source_name_exists = true ;
2008-06-02 17:41:35 -04:00
if ( cnt > limit ) {
2009-02-16 21:11:49 -05:00
error < < string_compose (
_ ( " There are already %1 recordings for %2, which I consider too many. " ) ,
limit , base ) < < endmsg ;
2008-06-02 17:41:35 -04:00
destroy ( ) ;
throw failed_constructor ( ) ;
}
}
2011-06-01 12:50:12 -04:00
2014-06-02 11:20:37 -04:00
/* We've established that the new name does not exist in any session
* directory , so now find out which one we should use for this new
* audio source .
*/
2008-06-02 17:41:35 -04:00
2014-06-02 11:20:37 -04:00
SessionDirectory sdir ( get_best_session_directory_for_new_audio ( ) ) ;
std : : string s = Glib : : build_filename ( sdir . sound_path ( ) , possible_name ) ;
2009-11-25 09:37:20 -05:00
2014-06-02 11:20:37 -04:00
return s ;
2008-06-02 17:41:35 -04:00
}
2014-04-13 10:29:07 -04:00
/** Return a unique name based on \a owner_name for a new internal MIDI source */
2008-06-02 17:41:35 -04:00
string
2014-06-02 11:20:37 -04:00
Session : : new_midi_source_path ( const string & base )
2008-06-02 17:41:35 -04:00
{
uint32_t cnt ;
char buf [ PATH_MAX + 1 ] ;
const uint32_t limit = 10000 ;
string legalized ;
2014-06-02 11:20:37 -04:00
string possible_path ;
2014-04-13 10:29:07 -04:00
string possible_name ;
2008-06-02 17:41:35 -04:00
buf [ 0 ] = ' \0 ' ;
2014-06-02 11:20:37 -04:00
legalized = legalize_for_path ( base ) ;
2008-06-02 17:41:35 -04:00
2009-02-16 21:11:49 -05:00
// Find a "version" of the file name that doesn't exist in any of the possible directories.
2014-07-02 17:35:48 -04:00
std : : vector < string > sdirs = source_search_path ( DataType : : MIDI ) ;
/* - the main session folder is the first in the vector.
* - after checking all locations for file - name uniqueness ,
* we keep the one from the last iteration as new file name
* - midi files are small and should just be kept in the main session - folder
*
* - > reverse the array , check main session folder last and use that as location
* for MIDI files .
*/
std : : reverse ( sdirs . begin ( ) , sdirs . end ( ) ) ;
2014-04-10 08:58:04 -04:00
2008-06-02 17:41:35 -04:00
for ( cnt = 1 ; cnt < = limit ; + + cnt ) {
vector < space_and_path > : : iterator i ;
uint32_t existing = 0 ;
2014-06-02 11:20:37 -04:00
2014-07-02 17:35:48 -04:00
for ( vector < string > : : const_iterator i = sdirs . begin ( ) ; i ! = sdirs . end ( ) ; + + i ) {
2008-06-02 17:41:35 -04:00
2014-04-13 10:29:07 -04:00
snprintf ( buf , sizeof ( buf ) , " %s-%u.mid " , legalized . c_str ( ) , cnt ) ;
possible_name = buf ;
2008-08-04 18:37:24 -04:00
2014-07-02 17:35:48 -04:00
possible_path = Glib : : build_filename ( * i , possible_name ) ;
2014-04-13 10:29:07 -04:00
if ( Glib : : file_test ( possible_path , Glib : : FILE_TEST_EXISTS ) ) {
existing + + ;
}
2008-06-02 17:41:35 -04:00
2014-05-29 16:27:33 -04:00
if ( midi_source_by_path ( possible_path ) ) {
2008-06-02 17:41:35 -04:00
existing + + ;
2008-08-04 18:37:24 -04:00
}
2008-06-02 17:41:35 -04:00
}
if ( existing = = 0 ) {
break ;
}
if ( cnt > limit ) {
2009-02-16 21:11:49 -05:00
error < < string_compose (
_ ( " There are already %1 recordings for %2, which I consider too many. " ) ,
2014-06-02 11:20:37 -04:00
limit , base ) < < endmsg ;
2009-02-16 21:11:49 -05:00
destroy ( ) ;
2014-06-02 11:20:37 -04:00
return 0 ;
2008-06-02 17:41:35 -04:00
}
}
2014-06-02 11:20:37 -04:00
/* No need to "find best location" for software/app-based RAID, because
MIDI is so small that we always put it in the same place .
*/
return possible_path ;
2008-06-02 17:41:35 -04:00
}
2008-08-04 18:37:24 -04:00
2009-02-16 21:11:49 -05:00
2014-06-02 11:20:37 -04:00
/** Create a new within-session audio source */
boost : : shared_ptr < AudioFileSource >
Session : : create_audio_source_for_session ( size_t n_chans , string const & base , uint32_t chan , bool destructive )
{
const string path = new_audio_source_path ( base , n_chans , chan , destructive , true ) ;
if ( ! path . empty ( ) ) {
return boost : : dynamic_pointer_cast < AudioFileSource > (
SourceFactory : : createWritable ( DataType : : AUDIO , * this , path , destructive , frame_rate ( ) ) ) ;
} else {
throw failed_constructor ( ) ;
}
}
2009-11-30 08:16:38 -05:00
/** Create a new within-session MIDI source */
2008-06-02 17:41:35 -04:00
boost : : shared_ptr < MidiSource >
2014-04-13 10:29:07 -04:00
Session : : create_midi_source_for_session ( string const & basic_name )
2008-06-02 17:41:35 -04:00
{
2014-06-02 11:20:37 -04:00
const string path = new_midi_source_path ( basic_name ) ;
if ( ! path . empty ( ) ) {
return boost : : dynamic_pointer_cast < SMFSource > (
SourceFactory : : createWritable (
DataType : : MIDI , * this , path , false , frame_rate ( ) ) ) ;
} else {
throw failed_constructor ( ) ;
2014-04-13 10:29:07 -04:00
}
}
2010-06-23 21:37:24 -04:00
2014-04-13 10:29:07 -04:00
/** Create a new within-session MIDI source */
boost : : shared_ptr < MidiSource >
Session : : create_midi_source_by_stealing_name ( boost : : shared_ptr < Track > track )
{
/* the caller passes in the track the source will be used in,
so that we can keep the numbering sane .
Rationale : a track with the name " Foo " that has had N
captures carried out so far will ALREADY have a write source
named " Foo-N+1.mid " waiting to be used for the next capture .
If we call new_midi_source_name ( ) we will get " Foo-N+2 " . But
there is no region corresponding to " Foo-N+1 " , so when
" Foo-N+2 " appears in the track , the gap presents the user
with odd behaviour - why did it skip past Foo - N + 1 ?
We could explain this to the user in some odd way , but
instead we rename " Foo-N+1.mid " as " Foo-N+2.mid " , and then
use " Foo-N+1 " here .
If that attempted rename fails , we get " Foo-N+2.mid " anyway .
*/
boost : : shared_ptr < MidiTrack > mt = boost : : dynamic_pointer_cast < MidiTrack > ( track ) ;
assert ( mt ) ;
std : : string name = track - > steal_write_source_name ( ) ;
2011-06-01 12:50:12 -04:00
2014-04-10 08:58:04 -04:00
if ( name . empty ( ) ) {
2014-04-13 10:29:07 -04:00
return boost : : shared_ptr < MidiSource > ( ) ;
2010-11-26 14:57:03 -05:00
}
2010-06-23 21:37:24 -04:00
2014-06-02 11:20:37 -04:00
const string path = new_midi_source_path ( name ) ;
2008-08-04 18:37:24 -04:00
2009-02-16 21:11:49 -05:00
return boost : : dynamic_pointer_cast < SMFSource > (
2010-11-26 14:57:03 -05:00
SourceFactory : : createWritable (
2013-03-30 14:02:26 -04:00
DataType : : MIDI , * this , path , false , frame_rate ( ) ) ) ;
2008-06-02 17:41:35 -04:00
}
2008-09-26 04:29:30 -04:00
void
Session : : add_playlist ( boost : : shared_ptr < Playlist > playlist , bool unused )
2008-06-02 17:41:35 -04:00
{
if ( playlist - > hidden ( ) ) {
return ;
}
2009-12-22 15:21:43 -05:00
playlists - > add ( playlist ) ;
2008-06-02 17:41:35 -04:00
2008-09-26 04:29:30 -04:00
if ( unused ) {
playlist - > release ( ) ;
}
2008-06-02 17:41:35 -04:00
set_dirty ( ) ;
}
void
Session : : remove_playlist ( boost : : weak_ptr < Playlist > weak_playlist )
{
if ( _state_of_the_state & Deletion ) {
return ;
}
boost : : shared_ptr < Playlist > playlist ( weak_playlist . lock ( ) ) ;
if ( ! playlist ) {
return ;
}
2009-12-04 14:09:08 -05:00
playlists - > remove ( playlist ) ;
2008-06-02 17:41:35 -04:00
set_dirty ( ) ;
}
2008-08-04 18:37:24 -04:00
void
2008-06-02 17:41:35 -04:00
Session : : set_audition ( boost : : shared_ptr < Region > r )
{
pending_audition_region = r ;
2009-11-08 11:28:21 -05:00
add_post_transport_work ( PostTransportAudition ) ;
2009-10-23 20:39:28 -04:00
_butler - > schedule_transport_work ( ) ;
2008-06-02 17:41:35 -04:00
}
void
Session : : audition_playlist ( )
{
2009-12-03 21:15:12 -05:00
SessionEvent * ev = new SessionEvent ( SessionEvent : : Audition , SessionEvent : : Add , SessionEvent : : Immediate , 0 , 0.0 ) ;
2008-06-02 17:41:35 -04:00
ev - > region . reset ( ) ;
queue_event ( ev ) ;
}
void
Session : : non_realtime_set_audition ( )
{
2012-04-11 11:10:12 -04:00
assert ( pending_audition_region ) ;
auditioner - > audition_region ( pending_audition_region ) ;
pending_audition_region . reset ( ) ;
2008-06-02 17:41:35 -04:00
AuditionActive ( true ) ; /* EMIT SIGNAL */
}
void
Session : : audition_region ( boost : : shared_ptr < Region > r )
{
2009-12-03 21:15:12 -05:00
SessionEvent * ev = new SessionEvent ( SessionEvent : : Audition , SessionEvent : : Add , SessionEvent : : Immediate , 0 , 0.0 ) ;
2008-06-02 17:41:35 -04:00
ev - > region = r ;
queue_event ( ev ) ;
}
void
Session : : cancel_audition ( )
{
2014-06-29 22:04:35 -04:00
if ( ! auditioner ) {
return ;
}
2010-03-24 23:40:07 -04:00
if ( auditioner - > auditioning ( ) ) {
2008-06-02 17:41:35 -04:00
auditioner - > cancel_audition ( ) ;
AuditionActive ( false ) ; /* EMIT SIGNAL */
}
}
bool
Session : : RoutePublicOrderSorter : : operator ( ) ( boost : : shared_ptr < Route > a , boost : : shared_ptr < Route > b )
{
2011-06-01 12:50:12 -04:00
if ( a - > is_monitor ( ) ) {
2010-11-26 14:57:03 -05:00
return true ;
}
if ( b - > is_monitor ( ) ) {
return false ;
}
2013-10-20 09:19:43 -04:00
return a - > order_key ( ) < b - > order_key ( ) ;
2008-06-02 17:41:35 -04:00
}
bool
Session : : is_auditioning ( ) const
{
/* can be called before we have an auditioner object */
if ( auditioner ) {
2010-03-24 23:40:07 -04:00
return auditioner - > auditioning ( ) ;
2008-06-02 17:41:35 -04:00
} else {
return false ;
}
}
void
Session : : graph_reordered ( )
{
/* don't do this stuff if we are setting up connections
2009-11-27 19:49:04 -05:00
from a set_state ( ) call or creating new tracks . Ditto for deletion .
2008-06-02 17:41:35 -04:00
*/
2012-12-04 09:32:28 -05:00
if ( ( _state_of_the_state & ( InitialConnecting | Deletion ) ) | | _adding_routes_in_progress ) {
2008-06-02 17:41:35 -04:00
return ;
}
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
/* every track/bus asked for this to be handled but it was deferred because
we were connecting . do it now .
*/
request_input_change_handling ( ) ;
resort_routes ( ) ;
2008-08-04 18:37:24 -04:00
/* force all diskstreams to update their capture offset values to
2008-06-02 17:41:35 -04:00
reflect any changes in latencies within the graph .
*/
2008-08-04 18:37:24 -04:00
2010-04-21 16:42:22 -04:00
boost : : shared_ptr < RouteList > rl = routes . reader ( ) ;
for ( RouteList : : iterator i = rl - > begin ( ) ; i ! = rl - > end ( ) ; + + i ) {
boost : : shared_ptr < Track > tr = boost : : dynamic_pointer_cast < Track > ( * i ) ;
if ( tr ) {
tr - > set_capture_offset ( ) ;
}
2008-06-02 17:41:35 -04:00
}
}
2012-06-12 12:41:29 -04:00
/** @return Number of frames that there is disk space available to write,
* if known .
*/
boost : : optional < framecnt_t >
2008-06-02 17:41:35 -04:00
Session : : available_capture_duration ( )
{
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( space_lock ) ;
2012-06-28 12:08:48 -04:00
2012-06-12 12:41:29 -04:00
if ( _total_free_4k_blocks_uncertain ) {
return boost : : optional < framecnt_t > ( ) ;
}
2008-06-02 17:41:35 -04:00
float sample_bytes_on_disk = 4.0 ; // keep gcc happy
2009-05-13 20:13:27 -04:00
switch ( config . get_native_file_data_format ( ) ) {
2008-06-02 17:41:35 -04:00
case FormatFloat :
sample_bytes_on_disk = 4.0 ;
break ;
case FormatInt24 :
sample_bytes_on_disk = 3.0 ;
break ;
case FormatInt16 :
sample_bytes_on_disk = 2.0 ;
break ;
2008-08-04 18:37:24 -04:00
default :
2008-06-02 17:41:35 -04:00
/* impossible, but keep some gcc versions happy */
fatal < < string_compose ( _ ( " programming error: %1 " ) ,
X_ ( " illegal native file data format " ) )
< < endmsg ;
/*NOTREACHED*/
}
double scale = 4096.0 / sample_bytes_on_disk ;
2010-09-17 12:24:22 -04:00
if ( _total_free_4k_blocks * scale > ( double ) max_framecnt ) {
return max_framecnt ;
2008-06-02 17:41:35 -04:00
}
2011-06-01 12:50:12 -04:00
2010-09-17 12:24:22 -04:00
return ( framecnt_t ) floor ( _total_free_4k_blocks * scale ) ;
2008-06-02 17:41:35 -04:00
}
void
2010-11-29 17:07:42 -05:00
Session : : add_bundle ( boost : : shared_ptr < Bundle > bundle )
2008-06-02 17:41:35 -04:00
{
{
2009-01-25 01:47:11 -05:00
RCUWriter < BundleList > writer ( _bundles ) ;
boost : : shared_ptr < BundleList > b = writer . get_copy ( ) ;
b - > push_back ( bundle ) ;
2008-06-02 17:41:35 -04:00
}
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
BundleAdded ( bundle ) ; /* EMIT SIGNAL */
set_dirty ( ) ;
}
void
2010-11-29 17:07:42 -05:00
Session : : remove_bundle ( boost : : shared_ptr < Bundle > bundle )
2008-06-02 17:41:35 -04:00
{
bool removed = false ;
{
2009-01-25 01:47:11 -05:00
RCUWriter < BundleList > writer ( _bundles ) ;
boost : : shared_ptr < BundleList > b = writer . get_copy ( ) ;
BundleList : : iterator i = find ( b - > begin ( ) , b - > end ( ) , bundle ) ;
2008-08-04 18:37:24 -04:00
2009-01-25 01:47:11 -05:00
if ( i ! = b - > end ( ) ) {
b - > erase ( i ) ;
2008-06-02 17:41:35 -04:00
removed = true ;
}
}
if ( removed ) {
BundleRemoved ( bundle ) ; /* EMIT SIGNAL */
}
set_dirty ( ) ;
}
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < Bundle >
2008-06-02 17:41:35 -04:00
Session : : bundle_by_name ( string name ) const
{
2009-01-25 01:47:11 -05:00
boost : : shared_ptr < BundleList > b = _bundles . reader ( ) ;
2009-10-14 12:10:01 -04:00
2009-01-25 01:47:11 -05:00
for ( BundleList : : const_iterator i = b - > begin ( ) ; i ! = b - > end ( ) ; + + i ) {
2008-06-02 17:41:35 -04:00
if ( ( * i ) - > name ( ) = = name ) {
return * i ;
}
}
return boost : : shared_ptr < Bundle > ( ) ;
}
void
2010-02-19 13:09:08 -05:00
Session : : tempo_map_changed ( const PropertyChange & )
2008-06-02 17:41:35 -04:00
{
clear_clicks ( ) ;
2008-08-04 18:37:24 -04:00
2009-12-04 14:09:08 -05:00
playlists - > update_after_tempo_map_change ( ) ;
2008-06-02 17:41:35 -04:00
2010-08-09 12:40:31 -04:00
_locations - > apply ( * this , & Session : : update_locations_after_tempo_map_change ) ;
2011-06-01 12:50:12 -04:00
2008-06-02 17:41:35 -04:00
set_dirty ( ) ;
}
2010-08-09 12:40:31 -04:00
void
Session : : update_locations_after_tempo_map_change ( Locations : : LocationList & loc )
{
for ( Locations : : LocationList : : iterator i = loc . begin ( ) ; i ! = loc . end ( ) ; + + i ) {
( * i ) - > recompute_frames_from_bbt ( ) ;
}
}
2008-06-02 17:41:35 -04:00
/** Ensures that all buffers (scratch, send, silent, etc) are allocated for
* the given count with the current block size .
*/
void
Session : : ensure_buffers ( ChanCount howmany )
{
2014-05-26 00:58:44 -04:00
BufferManager : : ensure_buffers ( howmany , bounce_processing ( ) ? bounce_chunk_size : 0 ) ;
2008-06-02 17:41:35 -04:00
}
2009-05-04 11:50:51 -04:00
void
Session : : ensure_buffer_set ( BufferSet & buffers , const ChanCount & count )
{
for ( DataType : : iterator t = DataType : : begin ( ) ; t ! = DataType : : end ( ) ; + + t ) {
buffers . ensure_buffers ( * t , count . get ( * t ) , _engine . raw_buffer_size ( * t ) ) ;
}
}
2008-06-02 17:41:35 -04:00
uint32_t
Session : : next_insert_id ( )
{
/* this doesn't really loop forever. just think about it */
while ( true ) {
for ( boost : : dynamic_bitset < uint32_t > : : size_type n = 0 ; n < insert_bitset . size ( ) ; + + n ) {
if ( ! insert_bitset [ n ] ) {
insert_bitset [ n ] = true ;
return n ;
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
}
}
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
/* none available, so resize and try again */
insert_bitset . resize ( insert_bitset . size ( ) + 16 , false ) ;
}
}
uint32_t
Session : : next_send_id ( )
{
/* this doesn't really loop forever. just think about it */
while ( true ) {
for ( boost : : dynamic_bitset < uint32_t > : : size_type n = 0 ; n < send_bitset . size ( ) ; + + n ) {
if ( ! send_bitset [ n ] ) {
send_bitset [ n ] = true ;
return n ;
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
}
}
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
/* none available, so resize and try again */
send_bitset . resize ( send_bitset . size ( ) + 16 , false ) ;
}
}
2012-01-18 12:51:57 -05:00
uint32_t
Session : : next_aux_send_id ( )
{
/* this doesn't really loop forever. just think about it */
while ( true ) {
for ( boost : : dynamic_bitset < uint32_t > : : size_type n = 0 ; n < aux_send_bitset . size ( ) ; + + n ) {
if ( ! aux_send_bitset [ n ] ) {
aux_send_bitset [ n ] = true ;
return n ;
}
}
/* none available, so resize and try again */
aux_send_bitset . resize ( aux_send_bitset . size ( ) + 16 , false ) ;
}
}
2009-05-07 13:31:18 -04:00
uint32_t
Session : : next_return_id ( )
{
/* this doesn't really loop forever. just think about it */
while ( true ) {
for ( boost : : dynamic_bitset < uint32_t > : : size_type n = 0 ; n < return_bitset . size ( ) ; + + n ) {
if ( ! return_bitset [ n ] ) {
return_bitset [ n ] = true ;
return n ;
}
}
/* none available, so resize and try again */
return_bitset . resize ( return_bitset . size ( ) + 16 , false ) ;
}
}
2008-06-02 17:41:35 -04:00
void
Session : : mark_send_id ( uint32_t id )
{
if ( id > = send_bitset . size ( ) ) {
send_bitset . resize ( id + 16 , false ) ;
}
if ( send_bitset [ id ] ) {
warning < < string_compose ( _ ( " send ID %1 appears to be in use already " ) , id ) < < endmsg ;
}
send_bitset [ id ] = true ;
}
2012-01-18 12:51:57 -05:00
void
Session : : mark_aux_send_id ( uint32_t id )
{
if ( id > = aux_send_bitset . size ( ) ) {
aux_send_bitset . resize ( id + 16 , false ) ;
}
if ( aux_send_bitset [ id ] ) {
warning < < string_compose ( _ ( " aux send ID %1 appears to be in use already " ) , id ) < < endmsg ;
}
aux_send_bitset [ id ] = true ;
}
2009-05-07 13:31:18 -04:00
void
Session : : mark_return_id ( uint32_t id )
{
if ( id > = return_bitset . size ( ) ) {
return_bitset . resize ( id + 16 , false ) ;
}
if ( return_bitset [ id ] ) {
warning < < string_compose ( _ ( " return ID %1 appears to be in use already " ) , id ) < < endmsg ;
}
return_bitset [ id ] = true ;
}
2008-06-02 17:41:35 -04:00
void
Session : : mark_insert_id ( uint32_t id )
{
if ( id > = insert_bitset . size ( ) ) {
insert_bitset . resize ( id + 16 , false ) ;
}
if ( insert_bitset [ id ] ) {
warning < < string_compose ( _ ( " insert ID %1 appears to be in use already " ) , id ) < < endmsg ;
}
insert_bitset [ id ] = true ;
}
2010-03-31 21:24:13 -04:00
void
Session : : unmark_send_id ( uint32_t id )
{
if ( id < send_bitset . size ( ) ) {
2010-11-26 14:57:03 -05:00
send_bitset [ id ] = false ;
}
2010-03-31 21:24:13 -04:00
}
2012-01-18 12:51:57 -05:00
void
Session : : unmark_aux_send_id ( uint32_t id )
{
if ( id < aux_send_bitset . size ( ) ) {
aux_send_bitset [ id ] = false ;
}
}
2010-03-31 21:24:13 -04:00
void
Session : : unmark_return_id ( uint32_t id )
{
if ( id < return_bitset . size ( ) ) {
2010-11-26 14:57:03 -05:00
return_bitset [ id ] = false ;
}
2010-03-31 21:24:13 -04:00
}
void
Session : : unmark_insert_id ( uint32_t id )
{
if ( id < insert_bitset . size ( ) ) {
2010-11-26 14:57:03 -05:00
insert_bitset [ id ] = false ;
}
2010-03-31 21:24:13 -04:00
}
2008-06-02 17:41:35 -04:00
void
Session : : reset_native_file_format ( )
{
2010-04-21 16:42:22 -04:00
boost : : shared_ptr < RouteList > rl = routes . reader ( ) ;
for ( RouteList : : iterator i = rl - > begin ( ) ; i ! = rl - > end ( ) ; + + i ) {
boost : : shared_ptr < Track > tr = boost : : dynamic_pointer_cast < Track > ( * i ) ;
if ( tr ) {
2010-11-26 14:57:03 -05:00
/* don't save state as we do this, there's no point
*/
2010-07-22 10:52:05 -04:00
2010-11-26 14:57:03 -05:00
_state_of_the_state = StateOfTheState ( _state_of_the_state | InCleanup ) ;
2010-04-21 16:42:22 -04:00
tr - > reset_write_sources ( false ) ;
2010-11-26 14:57:03 -05:00
_state_of_the_state = StateOfTheState ( _state_of_the_state & ~ InCleanup ) ;
2010-04-21 16:42:22 -04:00
}
2008-06-02 17:41:35 -04:00
}
}
bool
Session : : route_name_unique ( string n ) const
{
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
for ( RouteList : : const_iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
if ( ( * i ) - > name ( ) = = n ) {
return false ;
}
}
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
return true ;
}
2009-04-29 12:15:33 -04:00
bool
Session : : route_name_internal ( string n ) const
{
if ( auditioner & & auditioner - > name ( ) = = n ) {
return true ;
}
if ( _click_io & & _click_io - > name ( ) = = n ) {
return true ;
}
return false ;
}
2008-06-02 17:41:35 -04:00
int
2010-03-02 13:05:26 -05:00
Session : : freeze_all ( InterThreadInfo & itt )
2008-06-02 17:41:35 -04:00
{
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2008-06-02 17:41:35 -04:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2009-04-15 14:04:23 -04:00
boost : : shared_ptr < Track > t ;
2008-06-02 17:41:35 -04:00
2009-04-15 14:04:23 -04:00
if ( ( t = boost : : dynamic_pointer_cast < Track > ( * i ) ) ! = 0 ) {
2008-06-02 17:41:35 -04:00
/* XXX this is wrong because itt.progress will keep returning to zero at the start
of every track .
*/
2010-03-02 13:05:26 -05:00
t - > freeze_me ( itt ) ;
2008-06-02 17:41:35 -04:00
}
}
return 0 ;
}
2008-09-10 11:03:30 -04:00
boost : : shared_ptr < Region >
2010-08-16 15:58:34 -04:00
Session : : write_one_track ( AudioTrack & track , framepos_t start , framepos_t end ,
2009-10-14 12:10:01 -04:00
bool /*overwrite*/ , vector < boost : : shared_ptr < Source > > & srcs ,
2012-03-15 17:40:17 -04:00
InterThreadInfo & itt ,
boost : : shared_ptr < Processor > endpoint , bool include_endpoint ,
2014-06-03 15:08:45 -04:00
bool for_export , bool for_freeze )
2008-06-02 17:41:35 -04:00
{
2008-09-10 11:03:30 -04:00
boost : : shared_ptr < Region > result ;
2008-06-02 17:41:35 -04:00
boost : : shared_ptr < Playlist > playlist ;
boost : : shared_ptr < AudioFileSource > fsource ;
2010-12-10 17:28:29 -05:00
ChanCount diskstream_channels ( track . n_channels ( ) ) ;
2010-08-16 15:58:34 -04:00
framepos_t position ;
framecnt_t this_chunk ;
framepos_t to_do ;
2014-05-25 13:43:37 -04:00
framepos_t latency_skip ;
2008-06-02 17:41:35 -04:00
BufferSet buffers ;
2010-08-16 15:58:34 -04:00
framepos_t len = end - start ;
2010-11-26 14:57:03 -05:00
bool need_block_size_reset = false ;
2010-12-10 17:28:29 -05:00
ChanCount const max_proc = track . max_processor_streams ( ) ;
2014-06-22 21:58:07 -04:00
string legal_playlist_name ;
string possible_path ;
2008-09-10 11:03:30 -04:00
if ( end < = start ) {
error < < string_compose ( _ ( " Cannot write a range where end <= start (e.g. %1 <= %2) " ) ,
end , start ) < < endmsg ;
return result ;
}
2008-06-02 17:41:35 -04:00
2014-06-03 15:08:45 -04:00
diskstream_channels = track . bounce_get_output_streams ( diskstream_channels , endpoint ,
include_endpoint , for_export , for_freeze ) ;
2014-05-25 12:10:01 -04:00
if ( diskstream_channels . n_audio ( ) < 1 ) {
error < < _ ( " Cannot write a range with no audio. " ) < < endmsg ;
return result ;
}
2009-04-16 12:02:25 -04:00
// block all process callback handling
block_processing ( ) ;
2008-08-04 18:37:24 -04:00
2014-05-25 02:23:36 -04:00
{
// synchronize with AudioEngine::process_callback()
// make sure processing is not currently running
// and processing_blocked() is honored before
// acquiring thread buffers
Glib : : Threads : : Mutex : : Lock lm ( _engine . process_lock ( ) ) ;
}
2014-05-26 00:17:49 -04:00
_bounce_processing_active = true ;
2008-06-02 17:41:35 -04:00
/* call tree *MUST* hold route_lock */
2008-08-04 18:37:24 -04:00
2010-04-21 16:42:22 -04:00
if ( ( playlist = track . playlist ( ) ) = = 0 ) {
2008-06-02 17:41:35 -04:00
goto out ;
}
2014-06-22 21:58:07 -04:00
legal_playlist_name = legalize_for_path ( playlist - > name ( ) ) ;
2010-12-10 17:28:29 -05:00
for ( uint32_t chan_n = 0 ; chan_n < diskstream_channels . n_audio ( ) ; + + chan_n ) {
2008-06-02 17:41:35 -04:00
2014-06-02 11:20:37 -04:00
string base_name = string_compose ( " %1-%2-bounce " , playlist - > name ( ) , chan_n ) ;
2014-07-01 09:46:18 -04:00
string path = new_audio_source_path ( legal_playlist_name , diskstream_channels . n_audio ( ) , chan_n , false , true ) ;
2014-06-02 11:20:37 -04:00
if ( path . empty ( ) ) {
2008-06-02 17:41:35 -04:00
goto out ;
}
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
try {
fsource = boost : : dynamic_pointer_cast < AudioFileSource > (
2014-06-02 11:20:37 -04:00
SourceFactory : : createWritable ( DataType : : AUDIO , * this , path , false , frame_rate ( ) ) ) ;
2008-06-02 17:41:35 -04:00
}
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
catch ( failed_constructor & err ) {
2014-06-02 11:20:37 -04:00
error < < string_compose ( _ ( " cannot create new audio file \" %1 \" for %2 " ) , path , track . name ( ) ) < < endmsg ;
2008-06-02 17:41:35 -04:00
goto out ;
}
srcs . push_back ( fsource ) ;
}
2012-03-16 12:51:54 -04:00
/* tell redirects that care that we are about to use a much larger
* blocksize . this will flush all plugins too , so that they are ready
* to be used for this process .
*/
2011-06-01 12:50:12 -04:00
2010-11-26 14:57:03 -05:00
need_block_size_reset = true ;
2014-05-26 00:58:44 -04:00
track . set_block_size ( bounce_chunk_size ) ;
_engine . main_thread ( ) - > get_buffers ( ) ;
2010-08-16 15:58:34 -04:00
2008-06-02 17:41:35 -04:00
position = start ;
to_do = len ;
2014-06-03 15:08:45 -04:00
latency_skip = track . bounce_get_latency ( endpoint , include_endpoint , for_export , for_freeze ) ;
2008-06-02 17:41:35 -04:00
/* create a set of reasonably-sized buffers */
2014-05-25 13:43:37 -04:00
for ( DataType : : iterator t = DataType : : begin ( ) ; t ! = DataType : : end ( ) ; + + t ) {
2014-05-26 00:58:44 -04:00
buffers . ensure_buffers ( * t , max_proc . get ( * t ) , bounce_chunk_size ) ;
2014-05-25 13:43:37 -04:00
}
2010-12-10 17:28:29 -05:00
buffers . set_count ( max_proc ) ;
2008-06-02 17:41:35 -04:00
2010-12-10 17:28:29 -05:00
for ( vector < boost : : shared_ptr < Source > > : : iterator src = srcs . begin ( ) ; src ! = srcs . end ( ) ; + + src ) {
2008-06-02 17:41:35 -04:00
boost : : shared_ptr < AudioFileSource > afs = boost : : dynamic_pointer_cast < AudioFileSource > ( * src ) ;
if ( afs )
afs - > prepare_for_peakfile_writes ( ) ;
}
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
while ( to_do & & ! itt . cancel ) {
2008-08-04 18:37:24 -04:00
2014-05-26 00:58:44 -04:00
this_chunk = min ( to_do , bounce_chunk_size ) ;
2008-08-04 18:37:24 -04:00
2014-06-03 15:08:45 -04:00
if ( track . export_stuff ( buffers , start , this_chunk , endpoint , include_endpoint , for_export , for_freeze ) ) {
2008-06-02 17:41:35 -04:00
goto out ;
}
2014-05-25 13:43:37 -04:00
start + = this_chunk ;
to_do - = this_chunk ;
itt . progress = ( float ) ( 1.0 - ( ( double ) to_do / len ) ) ;
2014-05-26 00:58:44 -04:00
if ( latency_skip > = bounce_chunk_size ) {
latency_skip - = bounce_chunk_size ;
2014-05-25 13:43:37 -04:00
continue ;
}
const framecnt_t current_chunk = this_chunk - latency_skip ;
2008-06-02 17:41:35 -04:00
uint32_t n = 0 ;
for ( vector < boost : : shared_ptr < Source > > : : iterator src = srcs . begin ( ) ; src ! = srcs . end ( ) ; + + src , + + n ) {
boost : : shared_ptr < AudioFileSource > afs = boost : : dynamic_pointer_cast < AudioFileSource > ( * src ) ;
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
if ( afs ) {
2014-05-25 13:43:37 -04:00
if ( afs - > write ( buffers . get_audio ( n ) . data ( latency_skip ) , current_chunk ) ! = current_chunk ) {
2008-06-02 17:41:35 -04:00
goto out ;
}
}
}
2014-05-25 13:43:37 -04:00
latency_skip = 0 ;
}
2008-08-04 18:37:24 -04:00
2014-05-25 13:43:37 -04:00
/* post-roll, pick up delayed processor output */
2014-06-03 15:08:45 -04:00
latency_skip = track . bounce_get_latency ( endpoint , include_endpoint , for_export , for_freeze ) ;
2008-08-04 18:37:24 -04:00
2014-05-25 13:43:37 -04:00
while ( latency_skip & & ! itt . cancel ) {
2014-05-26 00:58:44 -04:00
this_chunk = min ( latency_skip , bounce_chunk_size ) ;
2014-05-25 13:43:37 -04:00
latency_skip - = this_chunk ;
buffers . silence ( this_chunk , 0 ) ;
2014-06-03 15:08:45 -04:00
track . bounce_process ( buffers , start , this_chunk , endpoint , include_endpoint , for_export , for_freeze ) ;
2014-05-25 13:43:37 -04:00
uint32_t n = 0 ;
for ( vector < boost : : shared_ptr < Source > > : : iterator src = srcs . begin ( ) ; src ! = srcs . end ( ) ; + + src , + + n ) {
boost : : shared_ptr < AudioFileSource > afs = boost : : dynamic_pointer_cast < AudioFileSource > ( * src ) ;
2008-06-02 17:41:35 -04:00
2014-05-25 13:43:37 -04:00
if ( afs ) {
if ( afs - > write ( buffers . get_audio ( n ) . data ( ) , this_chunk ) ! = this_chunk ) {
goto out ;
}
}
}
2008-06-02 17:41:35 -04:00
}
if ( ! itt . cancel ) {
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
time_t now ;
struct tm * xnow ;
time ( & now ) ;
xnow = localtime ( & now ) ;
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
for ( vector < boost : : shared_ptr < Source > > : : iterator src = srcs . begin ( ) ; src ! = srcs . end ( ) ; + + src ) {
boost : : shared_ptr < AudioFileSource > afs = boost : : dynamic_pointer_cast < AudioFileSource > ( * src ) ;
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
if ( afs ) {
afs - > update_header ( position , * xnow , now ) ;
afs - > flush_header ( ) ;
}
}
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
/* construct a region to represent the bounced material */
2010-02-18 08:59:49 -05:00
PropertyList plist ;
2011-06-01 12:50:12 -04:00
2010-02-18 08:59:49 -05:00
plist . add ( Properties : : start , 0 ) ;
plist . add ( Properties : : length , srcs . front ( ) - > length ( srcs . front ( ) - > timeline_position ( ) ) ) ;
plist . add ( Properties : : name , region_name_from_path ( srcs . front ( ) - > name ( ) , true ) ) ;
2011-06-01 12:50:12 -04:00
2010-02-18 08:59:49 -05:00
result = RegionFactory : : create ( srcs , plist ) ;
2011-06-01 12:50:12 -04:00
2008-06-02 17:41:35 -04:00
}
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
out :
2008-09-10 11:03:30 -04:00
if ( ! result ) {
2008-06-02 17:41:35 -04:00
for ( vector < boost : : shared_ptr < Source > > : : iterator src = srcs . begin ( ) ; src ! = srcs . end ( ) ; + + src ) {
boost : : shared_ptr < AudioFileSource > afs = boost : : dynamic_pointer_cast < AudioFileSource > ( * src ) ;
if ( afs ) {
afs - > mark_for_remove ( ) ;
}
2009-10-14 12:10:01 -04:00
2008-06-02 17:41:35 -04:00
( * src ) - > drop_references ( ) ;
}
} else {
for ( vector < boost : : shared_ptr < Source > > : : iterator src = srcs . begin ( ) ; src ! = srcs . end ( ) ; + + src ) {
boost : : shared_ptr < AudioFileSource > afs = boost : : dynamic_pointer_cast < AudioFileSource > ( * src ) ;
2008-08-04 18:37:24 -04:00
2008-06-02 17:41:35 -04:00
if ( afs )
afs - > done_with_peakfile_writes ( ) ;
}
}
2014-05-26 00:17:49 -04:00
_bounce_processing_active = false ;
2010-08-16 15:58:34 -04:00
2010-11-26 14:57:03 -05:00
if ( need_block_size_reset ) {
2014-05-26 00:58:44 -04:00
_engine . main_thread ( ) - > drop_buffers ( ) ;
2010-11-26 14:57:03 -05:00
track . set_block_size ( get_block_size ( ) ) ;
}
2011-06-01 12:50:12 -04:00
2009-04-16 12:02:25 -04:00
unblock_processing ( ) ;
2008-06-02 17:41:35 -04:00
2008-09-10 11:03:30 -04:00
return result ;
2008-06-02 17:41:35 -04:00
}
2010-04-13 16:48:33 -04:00
gain_t *
Session : : gain_automation_buffer ( ) const
{
2010-11-26 14:57:03 -05:00
return ProcessThread : : gain_automation_buffer ( ) ;
2010-04-13 16:48:33 -04:00
}
2012-06-11 06:42:30 -04:00
gain_t *
Session : : send_gain_automation_buffer ( ) const
{
return ProcessThread : : send_gain_automation_buffer ( ) ;
}
2010-04-13 16:48:33 -04:00
pan_t * *
Session : : pan_automation_buffer ( ) const
{
2010-11-26 14:57:03 -05:00
return ProcessThread : : pan_automation_buffer ( ) ;
2010-04-13 16:48:33 -04:00
}
2008-06-02 17:41:35 -04:00
BufferSet &
Session : : get_silent_buffers ( ChanCount count )
{
2010-11-26 14:57:03 -05:00
return ProcessThread : : get_silent_buffers ( count ) ;
2008-06-02 17:41:35 -04:00
}
BufferSet &
2013-07-31 18:35:24 -04:00
Session : : get_scratch_buffers ( ChanCount count , bool silence )
2008-06-02 17:41:35 -04:00
{
2013-07-31 18:35:24 -04:00
return ProcessThread : : get_scratch_buffers ( count , silence ) ;
2008-06-02 17:41:35 -04:00
}
2013-07-30 10:55:33 -04:00
BufferSet &
Session : : get_route_buffers ( ChanCount count , bool silence )
{
return ProcessThread : : get_route_buffers ( count , silence ) ;
}
2008-06-02 17:41:35 -04:00
BufferSet &
Session : : get_mix_buffers ( ChanCount count )
{
2010-11-26 14:57:03 -05:00
return ProcessThread : : get_mix_buffers ( count ) ;
2008-06-02 17:41:35 -04:00
}
2008-08-04 18:37:24 -04:00
uint32_t
2008-06-02 17:41:35 -04:00
Session : : ntracks ( ) const
{
uint32_t n = 0 ;
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2008-06-02 17:41:35 -04:00
for ( RouteList : : const_iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2009-04-15 14:04:23 -04:00
if ( boost : : dynamic_pointer_cast < Track > ( * i ) ) {
2008-06-02 17:41:35 -04:00
+ + n ;
}
}
return n ;
}
2008-08-04 18:37:24 -04:00
uint32_t
2008-06-02 17:41:35 -04:00
Session : : nbusses ( ) const
{
uint32_t n = 0 ;
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2008-06-02 17:41:35 -04:00
for ( RouteList : : const_iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2009-04-15 14:04:23 -04:00
if ( boost : : dynamic_pointer_cast < Track > ( * i ) = = 0 ) {
2008-06-02 17:41:35 -04:00
+ + n ;
}
}
return n ;
}
void
Session : : add_automation_list ( AutomationList * al )
{
automation_lists [ al - > id ( ) ] = al ;
}
2010-04-21 16:42:22 -04:00
/** @return true if there is at least one record-enabled track, otherwise false */
2009-04-29 13:30:35 -04:00
bool
2010-04-21 16:42:22 -04:00
Session : : have_rec_enabled_track ( ) const
2009-04-29 13:30:35 -04:00
{
2013-01-21 14:42:34 -05:00
return g_atomic_int_get ( const_cast < gint * > ( & _have_rec_enabled_track ) ) = = 1 ;
2009-04-29 13:30:35 -04:00
}
2010-04-21 16:42:22 -04:00
/** Update the state of our rec-enabled tracks flag */
2009-04-29 13:30:35 -04:00
void
2010-04-21 16:42:22 -04:00
Session : : update_have_rec_enabled_track ( )
2009-04-29 13:30:35 -04:00
{
2010-04-21 16:42:22 -04:00
boost : : shared_ptr < RouteList > rl = routes . reader ( ) ;
RouteList : : iterator i = rl - > begin ( ) ;
while ( i ! = rl - > end ( ) ) {
boost : : shared_ptr < Track > tr = boost : : dynamic_pointer_cast < Track > ( * i ) ;
if ( tr & & tr - > record_enabled ( ) ) {
break ;
}
2011-06-01 12:50:12 -04:00
2009-04-29 13:30:35 -04:00
+ + i ;
}
2010-04-21 16:42:22 -04:00
int const old = g_atomic_int_get ( & _have_rec_enabled_track ) ;
2009-04-29 13:30:35 -04:00
2010-04-21 16:42:22 -04:00
g_atomic_int_set ( & _have_rec_enabled_track , i ! = rl - > end ( ) ? 1 : 0 ) ;
2009-04-29 13:30:35 -04:00
2010-04-21 16:42:22 -04:00
if ( g_atomic_int_get ( & _have_rec_enabled_track ) ! = old ) {
2009-04-29 13:30:35 -04:00
RecordStateChanged ( ) ; /* EMIT SIGNAL */
}
}
2009-06-17 15:30:54 -04:00
void
2009-07-01 09:36:50 -04:00
Session : : listen_position_changed ( )
2009-06-17 15:30:54 -04:00
{
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2011-02-19 19:55:32 -05:00
( * i ) - > listen_position_changed ( ) ;
2009-06-17 15:30:54 -04:00
}
}
2009-06-20 09:41:55 -04:00
2009-07-01 09:36:50 -04:00
void
Session : : solo_control_mode_changed ( )
{
/* cancel all solo or all listen when solo control mode changes */
2010-11-26 14:57:03 -05:00
if ( soloing ( ) ) {
set_solo ( get_routes ( ) , false ) ;
} else if ( listening ( ) ) {
set_listen ( get_routes ( ) , false ) ;
}
2009-07-01 09:36:50 -04:00
}
2011-09-07 07:56:23 -04:00
/** Called when a property of one of our route groups changes */
2009-06-20 09:41:55 -04:00
void
2011-09-07 07:56:23 -04:00
Session : : route_group_property_changed ( RouteGroup * rg )
2009-06-20 13:15:33 -04:00
{
2011-09-07 07:56:23 -04:00
RouteGroupPropertyChanged ( rg ) ; /* EMIT SIGNAL */
}
/** Called when a route is added to one of our route groups */
void
Session : : route_added_to_route_group ( RouteGroup * rg , boost : : weak_ptr < Route > r )
{
RouteAddedToRouteGroup ( rg , r ) ;
}
/** Called when a route is removed from one of our route groups */
void
Session : : route_removed_from_route_group ( RouteGroup * rg , boost : : weak_ptr < Route > r )
{
RouteRemovedFromRouteGroup ( rg , r ) ;
2009-06-20 13:15:33 -04:00
}
2009-11-09 15:05:18 -05:00
2014-07-09 11:29:26 -04:00
boost : : shared_ptr < RouteList >
Session : : get_tracks ( ) const
{
boost : : shared_ptr < RouteList > rl = routes . reader ( ) ;
boost : : shared_ptr < RouteList > tl ( new RouteList ) ;
for ( RouteList : : const_iterator r = rl - > begin ( ) ; r ! = rl - > end ( ) ; + + r ) {
if ( boost : : dynamic_pointer_cast < Track > ( * r ) ) {
2014-07-09 12:02:22 -04:00
if ( ! ( * r ) - > is_auditioner ( ) ) {
tl - > push_back ( * r ) ;
}
2014-07-09 11:29:26 -04:00
}
}
return tl ;
}
2009-11-29 07:47:59 -05:00
boost : : shared_ptr < RouteList >
2010-09-17 14:20:37 -04:00
Session : : get_routes_with_regions_at ( framepos_t const p ) const
2009-11-29 07:47:59 -05:00
{
2010-11-29 17:07:42 -05:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
boost : : shared_ptr < RouteList > rl ( new RouteList ) ;
2009-11-29 07:47:59 -05:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
boost : : shared_ptr < Track > tr = boost : : dynamic_pointer_cast < Track > ( * i ) ;
if ( ! tr ) {
continue ;
}
2011-06-01 12:50:12 -04:00
2010-04-21 16:42:22 -04:00
boost : : shared_ptr < Playlist > pl = tr - > playlist ( ) ;
2009-11-29 07:47:59 -05:00
if ( ! pl ) {
continue ;
}
2011-06-01 12:50:12 -04:00
2009-11-29 07:47:59 -05:00
if ( pl - > has_region_at ( p ) ) {
rl - > push_back ( * i ) ;
}
}
return rl ;
}
2010-05-09 16:48:21 -04:00
void
Session : : goto_end ( )
{
if ( _session_range_location ) {
request_locate ( _session_range_location - > end ( ) , false ) ;
} else {
request_locate ( 0 , false ) ;
}
}
void
Session : : goto_start ( )
{
if ( _session_range_location ) {
request_locate ( _session_range_location - > start ( ) , false ) ;
} else {
request_locate ( 0 , false ) ;
}
}
2010-09-17 12:24:22 -04:00
framepos_t
2010-05-09 16:48:21 -04:00
Session : : current_start_frame ( ) const
{
return _session_range_location ? _session_range_location - > start ( ) : 0 ;
}
2010-09-17 12:24:22 -04:00
framepos_t
2010-05-09 16:48:21 -04:00
Session : : current_end_frame ( ) const
{
return _session_range_location ? _session_range_location - > end ( ) : 0 ;
}
void
2010-12-03 17:26:29 -05:00
Session : : add_session_range_location ( framepos_t start , framepos_t end )
2010-05-09 16:48:21 -04:00
{
2010-08-09 12:40:31 -04:00
_session_range_location = new Location ( * this , start , end , _ ( " session " ) , Location : : IsSessionRange ) ;
_locations - > add ( _session_range_location ) ;
2010-05-09 16:48:21 -04:00
}
2010-07-20 22:17:57 -04:00
2010-07-24 12:40:56 -04:00
void
Session : : step_edit_status_change ( bool yn )
{
2010-11-26 14:57:03 -05:00
bool send = false ;
2010-07-24 12:40:56 -04:00
2010-11-26 14:57:03 -05:00
bool val = false ;
if ( yn ) {
send = ( _step_editors = = 0 ) ;
val = true ;
2010-07-24 12:40:56 -04:00
2010-11-26 14:57:03 -05:00
_step_editors + + ;
} else {
send = ( _step_editors = = 1 ) ;
val = false ;
2010-07-24 12:40:56 -04:00
2010-11-26 14:57:03 -05:00
if ( _step_editors > 0 ) {
_step_editors - - ;
}
}
2010-07-24 12:40:56 -04:00
2010-11-26 14:57:03 -05:00
if ( send ) {
StepEditStatusChange ( val ) ;
}
2010-07-24 12:40:56 -04:00
}
2010-08-01 21:59:34 -04:00
2011-06-01 12:50:12 -04:00
2010-10-07 14:33:20 -04:00
void
Session : : start_time_changed ( framepos_t old )
{
/* Update the auto loop range to match the session range
( unless the auto loop range has been changed by the user )
*/
2010-12-29 17:36:03 -05:00
2010-10-07 14:33:20 -04:00
Location * s = _locations - > session_range_location ( ) ;
2010-12-29 17:36:03 -05:00
if ( s = = 0 ) {
return ;
}
2011-06-01 12:50:12 -04:00
2010-10-07 14:33:20 -04:00
Location * l = _locations - > auto_loop_location ( ) ;
2012-04-07 06:05:17 -04:00
if ( l & & l - > start ( ) = = old ) {
2010-10-07 14:33:20 -04:00
l - > set_start ( s - > start ( ) , true ) ;
}
}
void
Session : : end_time_changed ( framepos_t old )
{
/* Update the auto loop range to match the session range
( unless the auto loop range has been changed by the user )
*/
Location * s = _locations - > session_range_location ( ) ;
2010-12-29 17:36:03 -05:00
if ( s = = 0 ) {
return ;
}
2011-06-01 12:50:12 -04:00
2010-10-07 14:33:20 -04:00
Location * l = _locations - > auto_loop_location ( ) ;
2011-10-07 15:49:21 -04:00
if ( l & & l - > end ( ) = = old ) {
2010-10-07 14:33:20 -04:00
l - > set_end ( s - > end ( ) , true ) ;
}
}
2010-11-09 01:03:51 -05:00
2013-07-15 08:05:37 -04:00
std : : vector < std : : string >
2010-11-09 01:03:51 -05:00
Session : : source_search_path ( DataType type ) const
{
2013-08-15 06:04:08 -04:00
Searchpath sp ;
2011-12-07 13:52:14 -05:00
if ( session_dirs . size ( ) = = 1 ) {
switch ( type ) {
case DataType : : AUDIO :
2013-07-15 08:05:37 -04:00
sp . push_back ( _session_dir - > sound_path ( ) ) ;
2011-12-07 13:52:14 -05:00
break ;
case DataType : : MIDI :
2013-07-15 08:05:37 -04:00
sp . push_back ( _session_dir - > midi_path ( ) ) ;
2011-12-07 13:52:14 -05:00
break ;
}
} else {
for ( vector < space_and_path > : : const_iterator i = session_dirs . begin ( ) ; i ! = session_dirs . end ( ) ; + + i ) {
SessionDirectory sdir ( i - > path ) ;
switch ( type ) {
case DataType : : AUDIO :
2013-07-15 08:05:37 -04:00
sp . push_back ( sdir . sound_path ( ) ) ;
2011-12-07 13:52:14 -05:00
break ;
case DataType : : MIDI :
2013-07-15 08:05:37 -04:00
sp . push_back ( sdir . midi_path ( ) ) ;
2011-12-07 13:52:14 -05:00
break ;
}
}
}
2010-11-09 01:03:51 -05:00
2012-10-23 10:52:26 -04:00
if ( type = = DataType : : AUDIO ) {
const string sound_path_2X = _session_dir - > sound_path_2X ( ) ;
if ( Glib : : file_test ( sound_path_2X , Glib : : FILE_TEST_EXISTS | Glib : : FILE_TEST_IS_DIR ) ) {
2013-07-15 08:05:37 -04:00
if ( find ( sp . begin ( ) , sp . end ( ) , sound_path_2X ) = = sp . end ( ) ) {
sp . push_back ( sound_path_2X ) ;
2012-11-14 16:54:04 -05:00
}
2012-10-23 10:52:26 -04:00
}
}
2013-07-15 08:05:37 -04:00
// now check the explicit (possibly user-specified) search path
2011-12-07 12:45:18 -05:00
switch ( type ) {
case DataType : : AUDIO :
2013-08-15 06:04:08 -04:00
sp + = Searchpath ( config . get_audio_search_path ( ) ) ;
2011-12-07 12:45:18 -05:00
break ;
case DataType : : MIDI :
2013-08-15 06:04:08 -04:00
sp + = Searchpath ( config . get_midi_search_path ( ) ) ;
2011-12-07 12:45:18 -05:00
break ;
}
2013-07-15 08:05:37 -04:00
return sp ;
2010-11-09 01:03:51 -05:00
}
2010-11-09 12:24:17 -05:00
void
Session : : ensure_search_path_includes ( const string & path , DataType type )
{
2013-08-15 06:04:08 -04:00
Searchpath sp ;
2010-11-09 12:24:17 -05:00
2010-11-26 14:57:03 -05:00
if ( path = = " . " ) {
return ;
}
2010-11-09 18:50:20 -05:00
2011-12-07 13:52:14 -05:00
switch ( type ) {
case DataType : : AUDIO :
2013-08-15 06:04:08 -04:00
sp + = Searchpath ( config . get_audio_search_path ( ) ) ;
2011-12-07 13:52:14 -05:00
break ;
case DataType : : MIDI :
2013-08-15 06:04:08 -04:00
sp + = Searchpath ( config . get_midi_search_path ( ) ) ;
2011-12-07 13:52:14 -05:00
break ;
}
2012-05-28 12:32:41 -04:00
2013-07-15 08:05:37 -04:00
for ( vector < std : : string > : : iterator i = sp . begin ( ) ; i ! = sp . end ( ) ; + + i ) {
2012-03-04 19:34:45 -05:00
/* No need to add this new directory if it has the same inode as
an existing one ; checking inode rather than name prevents duplicated
directories when we are using symlinks .
On Windows , I think we could just do if ( * i = = path ) here .
*/
2012-06-23 01:08:14 -04:00
if ( PBD : : equivalent_paths ( * i , path ) ) {
2010-11-26 14:57:03 -05:00
return ;
}
}
2010-11-09 12:24:17 -05:00
2013-07-15 08:05:37 -04:00
sp + = path ;
2011-06-01 12:50:12 -04:00
2010-11-26 14:57:03 -05:00
switch ( type ) {
case DataType : : AUDIO :
2013-07-15 08:05:37 -04:00
config . set_audio_search_path ( sp . to_string ( ) ) ;
2010-11-26 14:57:03 -05:00
break ;
case DataType : : MIDI :
2013-07-15 08:05:37 -04:00
config . set_midi_search_path ( sp . to_string ( ) ) ;
2010-11-26 14:57:03 -05:00
break ;
}
2010-11-09 12:24:17 -05:00
}
2010-11-18 19:58:57 -05:00
2014-07-08 00:53:06 -04:00
void
Session : : remove_dir_from_search_path ( const string & dir , DataType type )
{
Searchpath sp ;
switch ( type ) {
case DataType : : AUDIO :
sp = Searchpath ( config . get_audio_search_path ( ) ) ;
break ;
case DataType : : MIDI :
sp = Searchpath ( config . get_midi_search_path ( ) ) ;
break ;
}
sp - = dir ;
switch ( type ) {
case DataType : : AUDIO :
config . set_audio_search_path ( sp . to_string ( ) ) ;
break ;
case DataType : : MIDI :
config . set_midi_search_path ( sp . to_string ( ) ) ;
break ;
}
}
2011-02-17 11:43:55 -05:00
boost : : shared_ptr < Speakers >
2011-06-01 12:50:12 -04:00
Session : : get_speakers ( )
2010-11-18 19:58:57 -05:00
{
2011-03-14 17:53:10 -04:00
return _speakers ;
2010-11-18 19:58:57 -05:00
}
2010-11-26 18:30:48 -05:00
list < string >
Session : : unknown_processors ( ) const
{
list < string > p ;
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
list < string > t = ( * i ) - > unknown_processors ( ) ;
copy ( t . begin ( ) , t . end ( ) , back_inserter ( p ) ) ;
}
p . sort ( ) ;
p . unique ( ) ;
return p ;
}
2011-02-11 11:14:54 -05:00
2011-02-15 14:55:14 -05:00
void
Session : : update_latency ( bool playback )
{
2011-03-14 17:53:10 -04:00
DEBUG_TRACE ( DEBUG : : Latency , string_compose ( " JACK latency callback: %1 \n " , ( playback ? " PLAYBACK " : " CAPTURE " ) ) ) ;
2011-02-15 22:25:23 -05:00
2012-12-04 09:32:28 -05:00
if ( ( _state_of_the_state & ( InitialConnecting | Deletion ) ) | | _adding_routes_in_progress ) {
2011-03-14 17:53:10 -04:00
return ;
}
2011-03-14 16:33:47 -04:00
2011-02-15 22:25:23 -05:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2011-03-14 17:53:10 -04:00
framecnt_t max_latency = 0 ;
2011-02-15 22:25:23 -05:00
2011-03-14 17:53:10 -04:00
if ( playback ) {
/* reverse the list so that we work backwards from the last route to run to the first */
2011-09-21 13:28:13 -04:00
RouteList * rl = routes . reader ( ) . get ( ) ;
r . reset ( new RouteList ( * rl ) ) ;
2011-03-14 17:53:10 -04:00
reverse ( r - > begin ( ) , r - > end ( ) ) ;
}
2011-02-15 22:25:23 -05:00
2011-03-14 17:53:10 -04:00
/* compute actual latency values for the given direction and store them all in per-port
structures . this will also publish the same values ( to JACK ) so that computation of latency
for routes can consistently use public latency values .
*/
2011-03-14 16:33:47 -04:00
2011-02-15 22:25:23 -05:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2011-03-14 17:53:10 -04:00
max_latency = max ( max_latency , ( * i ) - > set_private_port_latencies ( playback ) ) ;
}
2011-03-10 21:55:52 -05:00
2011-03-15 15:32:21 -04:00
/* because we latency compensate playback, our published playback latencies should
be the same for all output ports - all material played back by ardour has
the same latency , whether its caused by plugins or by latency compensation . since
these may differ from the values computed above , reset all playback port latencies
to the same value .
*/
DEBUG_TRACE ( DEBUG : : Latency , string_compose ( " Set public port latencies to %1 \n " , max_latency ) ) ;
2011-06-01 12:50:12 -04:00
2011-03-15 15:32:21 -04:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
( * i ) - > set_public_port_latencies ( max_latency , playback ) ;
}
2011-06-01 12:50:12 -04:00
2011-03-14 17:53:10 -04:00
if ( playback ) {
2011-03-10 21:55:52 -05:00
2011-03-14 17:53:10 -04:00
post_playback_latency ( ) ;
2011-06-01 12:50:12 -04:00
2011-03-14 17:53:10 -04:00
} else {
2011-03-14 16:33:47 -04:00
2011-03-14 17:53:10 -04:00
post_capture_latency ( ) ;
}
2011-03-12 15:25:09 -05:00
2011-03-14 17:53:10 -04:00
DEBUG_TRACE ( DEBUG : : Latency , " JACK latency callback: DONE \n " ) ;
2011-03-10 21:55:52 -05:00
}
2011-03-14 16:33:47 -04:00
void
Session : : post_playback_latency ( )
{
2011-03-14 17:53:10 -04:00
set_worst_playback_latency ( ) ;
2011-03-14 16:33:47 -04:00
2011-06-01 12:50:12 -04:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2011-09-20 16:29:47 -04:00
2011-03-14 17:53:10 -04:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2013-04-06 16:04:02 -04:00
if ( ! ( * i ) - > is_auditioner ( ) & & ( ( * i ) - > active ( ) ) ) {
2011-03-14 17:53:10 -04:00
_worst_track_latency = max ( _worst_track_latency , ( * i ) - > update_signal_latency ( ) ) ;
}
2011-09-20 16:29:47 -04:00
}
2011-06-01 12:50:12 -04:00
2011-09-20 16:29:47 -04:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
( * i ) - > set_latency_compensation ( _worst_track_latency ) ;
2011-03-14 17:53:10 -04:00
}
2011-03-14 16:33:47 -04:00
}
void
Session : : post_capture_latency ( )
{
2011-03-14 17:53:10 -04:00
set_worst_capture_latency ( ) ;
2011-06-01 12:50:12 -04:00
2011-03-14 17:53:10 -04:00
/* reflect any changes in capture latencies into capture offsets
*/
2011-06-01 12:50:12 -04:00
2011-03-14 17:53:10 -04:00
boost : : shared_ptr < RouteList > rl = routes . reader ( ) ;
for ( RouteList : : iterator i = rl - > begin ( ) ; i ! = rl - > end ( ) ; + + i ) {
boost : : shared_ptr < Track > tr = boost : : dynamic_pointer_cast < Track > ( * i ) ;
if ( tr ) {
tr - > set_capture_offset ( ) ;
}
}
2011-03-14 16:33:47 -04:00
}
2011-09-21 13:28:13 -04:00
void
Session : : initialize_latencies ( )
{
{
2012-07-25 13:48:55 -04:00
Glib : : Threads : : Mutex : : Lock lm ( _engine . process_lock ( ) ) ;
2011-09-21 13:28:13 -04:00
update_latency ( false ) ;
update_latency ( true ) ;
}
set_worst_io_latencies ( ) ;
}
2011-03-14 16:33:47 -04:00
void
Session : : set_worst_io_latencies ( )
{
2011-03-14 17:53:10 -04:00
set_worst_playback_latency ( ) ;
set_worst_capture_latency ( ) ;
2011-03-14 16:33:47 -04:00
}
void
Session : : set_worst_playback_latency ( )
{
2011-03-14 17:53:10 -04:00
if ( _state_of_the_state & ( InitialConnecting | Deletion ) ) {
return ;
}
2011-03-14 16:33:47 -04:00
2011-03-14 17:53:10 -04:00
_worst_output_latency = 0 ;
2011-03-14 16:33:47 -04:00
2013-08-01 14:43:12 -04:00
if ( ! _engine . connected ( ) ) {
2011-03-14 16:33:47 -04:00
return ;
}
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2011-03-14 17:53:10 -04:00
_worst_output_latency = max ( _worst_output_latency , ( * i ) - > output ( ) - > latency ( ) ) ;
2011-03-14 16:33:47 -04:00
}
2011-03-14 17:53:10 -04:00
DEBUG_TRACE ( DEBUG : : Latency , string_compose ( " Worst output latency: %1 \n " , _worst_output_latency ) ) ;
2011-03-14 16:33:47 -04:00
}
void
Session : : set_worst_capture_latency ( )
{
2011-03-14 17:53:10 -04:00
if ( _state_of_the_state & ( InitialConnecting | Deletion ) ) {
return ;
}
2011-03-14 16:33:47 -04:00
2011-03-14 17:53:10 -04:00
_worst_input_latency = 0 ;
2011-03-14 16:33:47 -04:00
2013-08-01 14:43:12 -04:00
if ( ! _engine . connected ( ) ) {
2011-03-14 16:33:47 -04:00
return ;
}
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2011-03-14 17:53:10 -04:00
_worst_input_latency = max ( _worst_input_latency , ( * i ) - > input ( ) - > latency ( ) ) ;
2011-03-14 16:33:47 -04:00
}
DEBUG_TRACE ( DEBUG : : Latency , string_compose ( " Worst input latency: %1 \n " , _worst_input_latency ) ) ;
}
void
Session : : update_latency_compensation ( bool force_whole_graph )
{
2011-03-15 15:32:21 -04:00
bool some_track_latency_changed = false ;
2011-03-14 16:33:47 -04:00
2011-03-15 15:32:21 -04:00
if ( _state_of_the_state & ( InitialConnecting | Deletion ) ) {
2011-03-14 16:33:47 -04:00
return ;
}
DEBUG_TRACE ( DEBUG : : Latency , " ---------------------------- update latency compensation \n \n " ) ;
2011-03-14 17:53:10 -04:00
_worst_track_latency = 0 ;
2011-03-14 16:33:47 -04:00
boost : : shared_ptr < RouteList > r = routes . reader ( ) ;
2011-06-01 12:50:12 -04:00
2011-03-14 16:33:47 -04:00
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
2013-04-06 16:04:02 -04:00
if ( ! ( * i ) - > is_auditioner ( ) & & ( ( * i ) - > active ( ) ) ) {
2011-03-14 17:53:10 -04:00
framecnt_t tl ;
if ( ( * i ) - > signal_latency ( ) ! = ( tl = ( * i ) - > update_signal_latency ( ) ) ) {
2011-03-15 15:32:21 -04:00
some_track_latency_changed = true ;
2011-03-14 17:53:10 -04:00
}
2011-06-01 12:50:12 -04:00
_worst_track_latency = max ( tl , _worst_track_latency ) ;
2011-03-14 17:53:10 -04:00
}
}
2011-03-14 16:33:47 -04:00
2011-03-14 17:53:10 -04:00
DEBUG_TRACE ( DEBUG : : Latency , string_compose ( " worst signal processing latency: %1 (changed ? %2) \n " , _worst_track_latency ,
2011-03-15 15:32:21 -04:00
( some_track_latency_changed ? " yes " : " no " ) ) ) ;
2011-03-14 16:33:47 -04:00
2011-09-21 13:28:13 -04:00
DEBUG_TRACE ( DEBUG : : Latency , " ---------------------------- DONE update latency compensation \n \n " ) ;
if ( some_track_latency_changed | | force_whole_graph ) {
_engine . update_latencies ( ) ;
}
for ( RouteList : : iterator i = r - > begin ( ) ; i ! = r - > end ( ) ; + + i ) {
boost : : shared_ptr < Track > tr = boost : : dynamic_pointer_cast < Track > ( * i ) ;
if ( ! tr ) {
continue ;
}
tr - > set_capture_offset ( ) ;
}
2011-03-14 16:33:47 -04:00
}
2011-12-08 22:06:58 -05:00
char
Session : : session_name_is_legal ( const string & path )
{
char illegal_chars [ ] = { ' / ' , ' \\ ' , ' : ' , ' ; ' , ' \0 ' } ;
for ( int i = 0 ; illegal_chars [ i ] ; + + i ) {
if ( path . find ( illegal_chars [ i ] ) ! = string : : npos ) {
return illegal_chars [ i ] ;
}
}
return 0 ;
}
2012-01-17 20:30:44 -05:00
uint32_t
Session : : next_control_id ( ) const
{
2012-06-25 08:46:13 -04:00
int subtract = 0 ;
2012-06-27 18:57:06 -04:00
/* the monitor bus remote ID is in a different
* " namespace " than regular routes . its existence doesn ' t
2012-06-25 08:46:13 -04:00
* affect normal ( low ) numbered routes .
*/
2012-06-27 18:57:06 -04:00
if ( _monitor_out ) {
2012-06-25 08:46:13 -04:00
subtract + + ;
}
2012-06-27 18:57:06 -04:00
return nroutes ( ) - subtract ;
}
void
2012-07-19 18:35:43 -04:00
Session : : notify_remote_id_change ( )
2012-06-27 18:57:06 -04:00
{
if ( deletion_in_progress ( ) ) {
return ;
2012-06-25 08:46:13 -04:00
}
2012-06-27 18:57:06 -04:00
switch ( Config - > get_remote_model ( ) ) {
2013-10-20 09:19:43 -04:00
case MixerOrdered :
2012-06-27 18:57:06 -04:00
Route : : RemoteControlIDChange ( ) ; /* EMIT SIGNAL */
break ;
default :
break ;
}
2012-07-19 18:35:43 -04:00
}
void
2013-10-20 09:19:43 -04:00
Session : : sync_order_keys ( )
2012-07-19 18:35:43 -04:00
{
if ( deletion_in_progress ( ) ) {
return ;
}
2012-06-27 18:57:06 -04:00
/* tell everyone that something has happened to the sort keys
and let them sync up with the change ( s )
2012-06-28 18:27:37 -04:00
this will give objects that manage the sort order keys the
opportunity to keep them in sync if they wish to .
2012-06-25 08:46:13 -04:00
*/
2013-10-20 09:19:43 -04:00
DEBUG_TRACE ( DEBUG : : OrderKeys , " Sync Order Keys. \n " ) ;
2012-06-27 18:57:06 -04:00
2014-06-25 15:16:09 -04:00
reassign_track_numbers ( ) ;
2013-10-20 09:19:43 -04:00
Route : : SyncOrderKeys ( ) ; /* EMIT SIGNAL */
2012-06-28 18:27:37 -04:00
2012-07-19 18:35:43 -04:00
DEBUG_TRACE ( DEBUG : : OrderKeys , " \t sync done \n " ) ;
2012-01-17 20:30:44 -05:00
}
2012-06-13 12:46:59 -04:00
bool
Session : : operation_in_progress ( GQuark op ) const
{
return ( find ( _current_trans_quarks . begin ( ) , _current_trans_quarks . end ( ) , op ) ! = _current_trans_quarks . end ( ) ) ;
}
2012-10-25 15:46:23 -04:00
boost : : shared_ptr < Port >
Session : : ltc_input_port ( ) const
{
return _ltc_input - > nth ( 0 ) ;
}
boost : : shared_ptr < Port >
Session : : ltc_output_port ( ) const
{
return _ltc_output - > nth ( 0 ) ;
}
void
Session : : reconnect_ltc_input ( )
{
if ( _ltc_input ) {
string src = Config - > get_ltc_source_port ( ) ;
_ltc_input - > disconnect ( this ) ;
if ( src ! = _ ( " None " ) & & ! src . empty ( ) ) {
_ltc_input - > nth ( 0 ) - > connect ( src ) ;
}
}
}
void
Session : : reconnect_ltc_output ( )
{
if ( _ltc_output ) {
#if 0
string src = Config - > get_ltc_sink_port ( ) ;
_ltc_output - > disconnect ( this ) ;
if ( src ! = _ ( " None " ) & & ! src . empty ( ) ) {
_ltc_output - > nth ( 0 ) - > connect ( src ) ;
}
# endif
}
}