#include "pbd/file_utils.h"
#include "pbd/convert.h"
#include "pbd/strsplit.h"
+#include "pbd/strsplit.h"
+#include "pbd/unwind.h"
#include "ardour/amp.h"
#include "ardour/analyser.h"
#include "ardour/audio_track.h"
#include "ardour/audioengine.h"
#include "ardour/audiofilesource.h"
-#include "ardour/audioplaylist.h"
-#include "ardour/audioregion.h"
#include "ardour/auditioner.h"
#include "ardour/buffer_manager.h"
#include "ardour/buffer_set.h"
#include "ardour/bundle.h"
#include "ardour/butler.h"
#include "ardour/click.h"
-#include "ardour/configuration.h"
#include "ardour/control_protocol_manager.h"
-#include "ardour/crossfade.h"
-#include "ardour/cycle_timer.h"
#include "ardour/data_type.h"
#include "ardour/debug.h"
#include "ardour/filename_extensions.h"
-#include "ardour/internal_send.h"
-#include "ardour/io_processor.h"
-#include "ardour/midi_diskstream.h"
-#include "ardour/midi_playlist.h"
-#include "ardour/midi_region.h"
+#include "ardour/graph.h"
#include "ardour/midi_track.h"
#include "ardour/midi_ui.h"
#include "ardour/named_selection.h"
-#include "ardour/process_thread.h"
+#include "ardour/operations.h"
#include "ardour/playlist.h"
+#include "ardour/plugin.h"
#include "ardour/plugin_insert.h"
-#include "ardour/port_insert.h"
-#include "ardour/processor.h"
+#include "ardour/process_thread.h"
#include "ardour/rc_configuration.h"
#include "ardour/recent_sessions.h"
+#include "ardour/region.h"
#include "ardour/region_factory.h"
-#include "ardour/return.h"
#include "ardour/route_graph.h"
#include "ardour/route_group.h"
#include "ardour/send.h"
#include "ardour/session.h"
#include "ardour/session_directory.h"
-#include "ardour/session_directory.h"
-#include "ardour/session_metadata.h"
#include "ardour/session_playlists.h"
-#include "ardour/slave.h"
#include "ardour/smf_source.h"
#include "ardour/source_factory.h"
-#include "ardour/tape_file_matcher.h"
-#include "ardour/tempo.h"
#include "ardour/utils.h"
-#include "ardour/graph.h"
-#include "ardour/speakers.h"
-#include "ardour/operations.h"
#include "midi++/port.h"
+#include "midi++/jack_midi_port.h"
#include "midi++/mmc.h"
#include "midi++/manager.h"
#include "i18n.h"
+namespace ARDOUR {
+class MidiSource;
+class Processor;
+class Speakers;
+}
+
using namespace std;
using namespace ARDOUR;
using namespace PBD;
PBD::Signal1<void, framepos_t> Session::StartTimeChanged;
PBD::Signal1<void, framepos_t> Session::EndTimeChanged;
-PBD::Signal0<void> Session::AutoBindingOn;
-PBD::Signal0<void> Session::AutoBindingOff;
PBD::Signal2<void,std::string, std::string> Session::Exported;
PBD::Signal1<int,boost::shared_ptr<Playlist> > Session::AskAboutPlaylistDeletion;
PBD::Signal0<void> Session::Quit;
, _post_transport_work (0)
, _send_timecode_update (false)
, _all_route_group (new RouteGroup (*this, "all"))
- , _process_graph (new Graph (*this))
, routes (new RouteList)
, _total_free_4k_blocks (0)
, _bundles (new BundleList)
, click_data (0)
, click_emphasis_data (0)
, main_outs (0)
- , _metadata (new SessionMetadata())
, _have_rec_enabled_track (false)
, _suspend_timecode_transmission (0)
{
_locations = new Locations (*this);
+ 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));
+ }
+
playlists.reset (new SessionPlaylists);
_all_route_group->set_active (true, this);
Session::~Session ()
{
+#ifdef PT_TIMING
+ ST.dump ("ST.dump");
+#endif
destroy ();
}
delete *i;
}
- Crossfade::set_buffer_size (0);
-
/* not strictly necessary, but doing it here allows the shared_ptr debugging to work */
playlists.reset ();
XMLNode* child = 0;
_click_io.reset (new ClickIO (*this, "click"));
+ _click_gain.reset (new Amp (*this));
+ _click_gain->activate ();
if (state_tree && (child = find_named_node (*state_tree->root(), "Click")) != 0) {
/* existing state for Click */
- int c;
+ int c = 0;
if (Stateful::loading_state_version < 3000) {
c = _click_io->set_state_2X (*child->children().front(), Stateful::loading_state_version, false);
} else {
- c = _click_io->set_state (*child->children().front(), Stateful::loading_state_version);
+ 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);
+ }
+ }
}
-
-
+
if (c == 0) {
_clicking = Config->get_clicking ();
BootMessage (_("Setup signal flow and plugins"));
+ /* Reset all panners */
+
+ Delivery::reset_panners ();
+
+ /* this will cause the CPM to instantiate any protocols that are in use
+ * (or mandatory), which will pass it this Session, and then call
+ * set_state() on each instantiated protocol to match stored state.
+ */
+
ControlProtocolManager::instance().set_session (this);
/* This must be done after the ControlProtocolManager set_session above,
as it will set states for ports which the ControlProtocolManager creates.
*/
+
MIDI::Manager::instance()->set_port_states (Config->midi_port_states ());
/* And this must be done after the MIDI::Manager::set_port_states as
hookup_io ();
- if (_is_new && !no_auto_connect()) {
+ /* Let control protocols know that we are now all connected, so they
+ * could start talking to surfaces if they want to.
+ */
+ ControlProtocolManager::instance().midi_connectivity_established ();
+
+ if (_is_new && !no_auto_connect()) {
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock());
+ auto_connect_master_bus ();
+ }
- /* don't connect the master bus outputs if there is a monitor bus */
+ _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
- if (_master_out && Config->get_auto_connect_standard_busses() && !_monitor_out) {
+ /* update latencies */
- /* if requested auto-connect the outputs to the first N physical ports.
- */
+ initialize_latencies ();
- uint32_t limit = _master_out->n_outputs().n_total();
+ /* hook us up to the engine */
- 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];
- }
+ BootMessage (_("Connect to engine"));
+ _engine.set_session (this);
+}
- 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;
- }
- }
+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;
}
}
+ }
+}
- if (_monitor_out) {
+void
+Session::remove_monitor_section ()
+{
+ if (!_monitor_out) {
+ return;
+ }
- /* AUDIO ONLY as of june 29th 2009, because listen semantics for anything else
- are undefined, at best.
- */
+ /* force reversion to Solo-In-Place */
+ Config->set_solo_control_is_listen_control (false);
- /* control out listens to master bus (but ignores it
- under some conditions)
- */
+ {
+ /* Hold process lock while doing this so that we don't hear bits and
+ * pieces of audio as we work on each route.
+ */
+
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+
+ /* 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 {
+ (*x)->remove_aux_or_listen (_monitor_out);
+ }
+ }
+ }
- uint32_t limit = _monitor_out->n_inputs().n_audio();
+ remove_route (_monitor_out);
+ auto_connect_master_bus ();
+}
- if (_master_out) {
- 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);
+void
+Session::add_monitor_section ()
+{
+ RouteList rl;
- 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_out || !_master_out) {
+ return;
+ }
- /* if control out is not connected, connect control out to physical outs
- */
+ boost::shared_ptr<Route> r (new Route (*this, _("monitor"), Route::MonitorOut, DataType::AUDIO));
- if (!_monitor_out->output()->connected ()) {
+ if (r->init ()) {
+ return;
+ }
- if (!Config->get_monitor_bus_preferred_bundle().empty()) {
+#ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
+ // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
+#endif
+ {
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+ r->input()->ensure_io (_master_out->output()->n_ports(), false, this);
+ r->output()->ensure_io (_master_out->output()->n_ports(), false, this);
+ }
- boost::shared_ptr<Bundle> b = bundle_by_name (Config->get_monitor_bus_preferred_bundle());
+ rl.push_back (r);
+ add_routes (rl, false, false, false);
+
+ assert (_monitor_out);
- if (b) {
- _monitor_out->output()->connect_ports_to_bundle (b, this);
- } else {
- warning << string_compose (_("The preferred I/O for the monitor bus (%1) cannot be found"),
- Config->get_monitor_bus_preferred_bundle())
- << endmsg;
- }
+ /* 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) {
+ _monitor_out->output()->connect_ports_to_bundle (b, this);
+ } 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 */
- } else {
+ uint32_t mod = n_physical_outputs.get (DataType::AUDIO);
+ uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO);
+ vector<string> outputs[DataType::num_types];
- /* Monitor bus is audio only */
- uint32_t mod = n_physical_outputs.get (DataType::AUDIO);
- uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO);
-
- 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;
- }
- }
+ for (uint32_t i = 0; i < DataType::num_types; ++i) {
+ _engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]);
+ }
+
+
+ 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;
}
}
}
}
}
- _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
+ /* Hold process lock while doing this so that we don't hear bits and
+ * pieces of audio as we work on each route.
+ */
+
+ Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
- /* update latencies */
+ /* 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.
+ */
- initialize_latencies ();
- /* hook us up to the engine */
+ boost::shared_ptr<RouteList> rls = routes.reader ();
- BootMessage (_("Connect to engine"));
- _engine.set_session (this);
+ 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 ();
+ }
+ }
}
void
/* Tell all IO objects to connect themselves together */
IO::enable_connecting ();
- MIDI::Port::MakeConnections ();
-
- /* Now reset all panners */
-
- Delivery::reset_panners ();
-
- /* Connect tracks to monitor/listen bus if there is one. 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.
- */
-
- if (_monitor_out) {
- boost::shared_ptr<RouteList> r = routes.reader ();
- for (RouteList::iterator x = r->begin(); x != r->end(); ++x) {
-
- if ((*x)->is_monitor()) {
-
- /* relax */
-
- } else if ((*x)->is_master()) {
-
- /* relax */
-
- } else {
-
- (*x)->listen_via_monitor ();
- }
- }
- }
+ MIDI::JackMIDIPort::MakeConnections ();
/* Anyone who cares about input state, wake up and do something */
}
}
-void
-Session::reset_input_monitor_state ()
-{
- if (transport_rolling()) {
- set_track_monitor_input_status (Config->get_monitoring_model() == HardwareMonitoring && !config.get_auto_input());
- } else {
- set_track_monitor_input_status (Config->get_monitoring_model() == HardwareMonitoring);
- }
-}
-
void
Session::auto_punch_start_changed (Location* location)
{
/* writer goes out of scope and forces update */
}
- //_process_graph->dump(1);
-
#ifndef NDEBUG
boost::shared_ptr<RouteList> rl = routes.reader ();
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
Note: the process graph rechain does not require a
topologically-sorted list, but hey ho.
*/
- _process_graph->rechain (sorted_routes, edges);
+ if (_process_graph) {
+ _process_graph->rechain (sorted_routes, edges);
+ }
+
_current_route_graph = edges;
/* Complete the building of the routes' lists of what directly
/** Caller must not hold process lock
* @param name_template string to use for the start of the name, or "" to use "MIDI".
+ * @param instrument plugin info for the instrument to insert pre-fader, if any
*/
list<boost::shared_ptr<MidiTrack> >
-Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_many, string name_template)
+Session::new_midi_track (boost::shared_ptr<PluginInfo> instrument, TrackMode mode, RouteGroup* route_group, uint32_t how_many, string name_template)
{
char track_name[32];
uint32_t track_id = 0;
list<boost::shared_ptr<MidiTrack> > ret;
uint32_t control_id;
- control_id = ntracks() + nbusses();
+ control_id = next_control_id ();
bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("MIDI");
failed:
if (!new_routes.empty()) {
- add_routes (new_routes, true, true);
+ add_routes (new_routes, true, true, true);
+
+ 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);
+
+ }
+ }
}
return ret;
* @param name_template string to use for the start of the name, or "" to use "Audio".
*/
list< boost::shared_ptr<AudioTrack> >
-Session::new_audio_track (
- int input_channels, int output_channels, TrackMode mode, RouteGroup* route_group, uint32_t how_many, string name_template
- )
+Session::new_audio_track (int input_channels, int output_channels, TrackMode mode, RouteGroup* route_group,
+ uint32_t how_many, string name_template)
{
char track_name[32];
uint32_t track_id = 0;
list<boost::shared_ptr<AudioTrack> > ret;
uint32_t control_id;
- control_id = ntracks() + nbusses() + 1;
+ control_id = next_control_id ();
bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Audio");
failed:
if (!new_routes.empty()) {
- add_routes (new_routes, true, true);
+ add_routes (new_routes, true, true, true);
}
return ret;
RouteList ret;
uint32_t control_id;
- control_id = ntracks() + nbusses() + 1;
+ control_id = next_control_id ();
bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Bus");
failure:
if (!ret.empty()) {
- add_routes (ret, false, true);
+ add_routes (ret, false, true, true); // autoconnect outputs only
}
return ret;
XMLNode* node = tree.root();
- control_id = ntracks() + nbusses() + 1;
+ IO::disable_connecting ();
+
+ control_id = next_control_id ();
while (how_many) {
out:
if (!ret.empty()) {
- add_routes (ret, true, true);
+ add_routes (ret, true, true, true);
+ IO::enable_connecting ();
}
return ret;
}
void
-Session::add_routes (RouteList& new_routes, bool auto_connect, bool save)
+Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output_auto_connect, bool save)
{
ChanCount existing_inputs;
ChanCount existing_outputs;
}
}
- if (auto_connect) {
- auto_connect_route (r, existing_inputs, existing_outputs, true);
+ if (input_auto_connect || output_auto_connect) {
+ auto_connect_route (r, existing_inputs, existing_outputs, true, input_auto_connect);
}
}
if (_monitor_out && IO::connecting_legal) {
- for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
- if ((*x)->is_monitor()) {
- /* relax */
- } else if ((*x)->is_master()) {
- /* relax */
- } else {
- (*x)->listen_via_monitor ();
+ {
+ Glib::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()) {
+ /* relax */
+ } else {
+ (*x)->enable_monitor_send ();
+ }
}
}
void
Session::add_internal_sends (boost::shared_ptr<Route> dest, Placement p, boost::shared_ptr<RouteList> senders)
{
- if (dest->is_monitor() || dest->is_master()) {
+ 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()) {
return;
}
if (!dest->internal_return()) {
- dest->add_internal_return();
+ dest->add_internal_return ();
}
- for (RouteList::iterator i = senders->begin(); i != senders->end(); ++i) {
-
- if ((*i)->is_monitor() || (*i)->is_master() || (*i) == dest) {
- continue;
- }
-
- (*i)->listen_via (dest, p);
- }
+ sender->add_aux_send (dest, before);
graph_reordered ();
}
void
Session::remove_route (boost::shared_ptr<Route> route)
{
- if (((route == _master_out) || (route == _monitor_out)) && !Config->get_allow_special_bus_removal()) {
+ if (route == _master_out) {
return;
}
}
if (route == _monitor_out) {
-
- /* cancel control outs for all routes */
-
- for (RouteList::iterator r = rs->begin(); r != rs->end(); ++r) {
- (*r)->drop_listen (_monitor_out);
- }
-
_monitor_out.reset ();
}
*/
resort_routes ();
- _process_graph->clear_other_chain ();
+ if (_process_graph) {
+ _process_graph->clear_other_chain ();
+ }
/* get rid of it from the dead wood collection in the route list manager */
/* yay, new source */
+ 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());
+ }
+ }
+
set_dirty();
boost::shared_ptr<AudioFileSource> afs;
}
}
- if (!_state_of_the_state & InCleanup) {
+ if (!(_state_of_the_state & InCleanup)) {
/* save state so we don't end up with a session file
referring to non-existent sources.
void
Session::non_realtime_set_audition ()
{
- if (!pending_audition_region) {
- auditioner->audition_current_playlist ();
- } else {
- auditioner->audition_region (pending_audition_region);
- pending_audition_region.reset ();
- }
+ assert (pending_audition_region);
+ auditioner->audition_region (pending_audition_region);
+ pending_audition_region.reset ();
AuditionActive (true); /* EMIT SIGNAL */
}
}
}
+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);
+ }
+}
+
uint32_t
Session::next_return_id ()
{
send_bitset[id] = true;
}
+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;
+}
+
void
Session::mark_return_id (uint32_t id)
{
}
}
+void
+Session::unmark_aux_send_id (uint32_t id)
+{
+ if (id < aux_send_bitset.size()) {
+ aux_send_bitset[id] = false;
+ }
+}
+
void
Session::unmark_return_id (uint32_t id)
{
boost::shared_ptr<Region>
Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
bool /*overwrite*/, vector<boost::shared_ptr<Source> >& srcs,
- InterThreadInfo& itt, bool enable_processing)
+ InterThreadInfo& itt,
+ boost::shared_ptr<Processor> endpoint, bool include_endpoint,
+ bool for_export)
{
boost::shared_ptr<Region> result;
boost::shared_ptr<Playlist> playlist;
goto out;
}
- /* external redirects will be a problem */
-
- if (track.has_external_redirects()) {
- goto out;
- }
-
ext = native_header_format_extension (config.get_native_file_header_format(), DataType::AUDIO);
for (uint32_t chan_n = 0; chan_n < diskstream_channels.n_audio(); ++chan_n) {
srcs.push_back (fsource);
}
- /* tell redirects that care that we are about to use a much larger blocksize */
+ /* 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.
+ */
need_block_size_reset = true;
track.set_block_size (chunk_size);
- /* XXX need to flush all redirects */
-
position = start;
to_do = len;
this_chunk = min (to_do, chunk_size);
- if (track.export_stuff (buffers, start, this_chunk, enable_processing)) {
+ if (track.export_stuff (buffers, start, this_chunk, endpoint, include_endpoint, for_export)) {
goto out;
}
Location* l = _locations->auto_loop_location ();
- if (l->start() == old) {
+ if (l && l->start() == old) {
l->set_start (s->start(), true);
}
}
search_path = config.get_midi_search_path ();
break;
}
-
+
split (search_path, dirs, ':');
for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
- if (*i == path) {
+ /* 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.
+ */
+ if (PBD::sys::inodes_same (*i, path)) {
return;
}
}
return 0;
}
+
+uint32_t
+Session::next_control_id () const
+{
+ return ntracks() + nbusses() + 1;
+}