#include <pbd/stacktrace.h>
#include <pbd/file_utils.h>
-#include <ardour/audioengine.h>
-#include <ardour/configuration.h>
-#include <ardour/session.h>
-#include <ardour/session_directory.h>
-#include <ardour/utils.h>
+#include <ardour/analyser.h>
+#include <ardour/audio_buffer.h>
#include <ardour/audio_diskstream.h>
+#include <ardour/audio_track.h>
+#include <ardour/audioengine.h>
+#include <ardour/audiofilesource.h>
#include <ardour/audioplaylist.h>
#include <ardour/audioregion.h>
-#include <ardour/audiofilesource.h>
+#include <ardour/auditioner.h>
+#include <ardour/buffer_set.h>
+#include <ardour/bundle.h>
+#include <ardour/click.h>
+#include <ardour/configuration.h>
+#include <ardour/crossfade.h>
+#include <ardour/cycle_timer.h>
+#include <ardour/data_type.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/smf_source.h>
-#include <ardour/auditioner.h>
-#include <ardour/recent_sessions.h>
-#include <ardour/io_processor.h>
-#include <ardour/send.h>
-#include <ardour/processor.h>
-#include <ardour/plugin_insert.h>
-#include <ardour/port_insert.h>
-#include <ardour/auto_bundle.h>
-#include <ardour/slave.h>
-#include <ardour/tempo.h>
-#include <ardour/audio_track.h>
#include <ardour/midi_track.h>
-#include <ardour/cycle_timer.h>
#include <ardour/named_selection.h>
-#include <ardour/crossfade.h>
#include <ardour/playlist.h>
-#include <ardour/click.h>
-#include <ardour/data_type.h>
-#include <ardour/buffer_set.h>
-#include <ardour/source_factory.h>
+#include <ardour/plugin_insert.h>
+#include <ardour/port_insert.h>
+#include <ardour/processor.h>
+#include <ardour/recent_sessions.h>
#include <ardour/region_factory.h>
-#include <ardour/filename_extensions.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/slave.h>
+#include <ardour/smf_source.h>
+#include <ardour/source_factory.h>
#include <ardour/tape_file_matcher.h>
-#include <ardour/analyser.h>
-
-#ifdef HAVE_LIBLO
-#include <ardour/osc.h>
-#endif
+#include <ardour/tempo.h>
+#include <ardour/utils.h>
#include "i18n.h"
bool Session::_disable_all_loaded_plugins = false;
-Session::compute_peak_t Session::compute_peak = 0;
-Session::find_peaks_t Session::find_peaks = 0;
-Session::apply_gain_to_buffer_t Session::apply_gain_to_buffer = 0;
-Session::mix_buffers_with_gain_t Session::mix_buffers_with_gain = 0;
-Session::mix_buffers_no_gain_t Session::mix_buffers_no_gain = 0;
-
sigc::signal<void,std::string> Session::Dialog;
sigc::signal<int> Session::AskAboutPendingState;
sigc::signal<int,nframes_t,nframes_t> Session::AskAboutSampleRateMismatch;
string mix_template)
: _engine (eng),
+ _requested_return_frame (-1),
_scratch_buffers(new BufferSet()),
_silent_buffers(new BufferSet()),
_mix_buffers(new BufferSet()),
+ mmc (0),
_mmc_port (default_mmc_port),
_mtc_port (default_mtc_port),
_midi_port (default_midi_port),
_midi_clock_port (default_midi_clock_port),
_session_dir (new SessionDirectory(fullpath)),
pending_events (2048),
+ state_tree (0),
+ butler_mixdown_buffer (0),
+ butler_gain_buffer (0),
post_transport_work((PostTransportWork)0),
_send_smpte_update (false),
- midi_requests (128),
+ midi_thread (pthread_t (0)),
+ midi_requests (128), // the size of this should match the midi request pool size
diskstreams (new DiskstreamList),
routes (new RouteList),
auditioner ((Auditioner*) 0),
_total_free_4k_blocks (0),
+ _bundles (new BundleList),
_bundle_xml_node (0),
_click_io ((IO*) 0),
- main_outs (0)
+ click_data (0),
+ click_emphasis_data (0),
+ main_outs (0),
+ _metadata (new SessionMetadata())
+
{
bool new_session;
nframes_t initial_length)
: _engine (eng),
+ _requested_return_frame (-1),
_scratch_buffers(new BufferSet()),
_silent_buffers(new BufferSet()),
_mix_buffers(new BufferSet()),
+ mmc (0),
_mmc_port (default_mmc_port),
_mtc_port (default_mtc_port),
_midi_port (default_midi_port),
_midi_clock_port (default_midi_clock_port),
_session_dir ( new SessionDirectory(fullpath)),
pending_events (2048),
+ state_tree (0),
+ butler_mixdown_buffer (0),
+ butler_gain_buffer (0),
post_transport_work((PostTransportWork)0),
_send_smpte_update (false),
+ midi_thread (pthread_t (0)),
midi_requests (16),
diskstreams (new DiskstreamList),
routes (new RouteList),
+ auditioner ((Auditioner *) 0),
_total_free_4k_blocks (0),
+ _bundles (new BundleList),
_bundle_xml_node (0),
- main_outs (0)
-
+ _click_io ((IO *) 0),
+ click_data (0),
+ click_emphasis_data (0),
+ main_outs (0),
+ _metadata (new SessionMetadata())
{
bool new_session;
/* clear state tree so that no references to objects are held any more */
- if (state_tree) {
- delete state_tree;
- }
+ delete state_tree;
terminate_butler_thread ();
//terminate_midi_thread ();
- if (click_data && click_data != default_click) {
+ if (click_data != default_click) {
delete [] click_data;
}
- if (click_emphasis_data && click_emphasis_data != default_click_emphasis) {
+ if (click_emphasis_data != default_click_emphasis) {
delete [] click_emphasis_data;
}
i = tmp;
}
- if (butler_mixdown_buffer) {
- delete [] butler_mixdown_buffer;
- }
-
- if (butler_gain_buffer) {
- delete [] butler_gain_buffer;
- }
+ delete [] butler_mixdown_buffer;
+ delete [] butler_gain_buffer;
Crossfade::set_buffer_size (0);
- if (mmc) {
- delete mmc;
- }
+ delete mmc;
}
void
// XXX HOW TO ALERT UI TO THIS ? DO WE NEED TO?
}
- /* Create a set of Bundle objects that map
- to the physical outputs currently available
- */
-
BootMessage (_("Set up standard connections"));
- /* ONE: MONO */
+ /* Create a set of Bundle objects that map
+ 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;
+ it doesn't really scale that well to higher channel counts */
for (uint32_t np = 0; np < n_physical_outputs; ++np) {
char buf[32];
snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1);
- shared_ptr<AutoBundle> c (new AutoBundle (buf, true));
- c->set_channels (1);
+ shared_ptr<Bundle> c (new Bundle (buf, true));
+ c->add_channel (_("mono"));
c->set_port (0, _engine.get_nth_physical_output (DataType::AUDIO, np));
add_bundle (c);
}
- for (uint32_t np = 0; np < n_physical_inputs; ++np) {
- char buf[32];
- snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
-
- shared_ptr<AutoBundle> c (new AutoBundle (buf, false));
- c->set_channels (1);
- c->set_port (0, _engine.get_nth_physical_input (DataType::AUDIO, np));
+ for (uint32_t np = 0; np < n_physical_outputs; np += 2) {
+ if (np + 1 < n_physical_outputs) {
+ char buf[32];
+ snprintf (buf, sizeof(buf), _("out %" PRIu32 "+%" PRIu32), np + 1, np + 2);
+ shared_ptr<Bundle> c (new Bundle (buf, true));
+ c->add_channel (_("L"));
+ c->set_port (0, _engine.get_nth_physical_output (DataType::AUDIO, np));
+ c->add_channel (_("R"));
+ c->set_port (1, _engine.get_nth_physical_output (DataType::AUDIO, np + 1));
- add_bundle (c);
+ add_bundle (c);
+ }
}
- /* TWO: STEREO */
-
- for (uint32_t np = 0; np < n_physical_outputs; np +=2) {
+ for (uint32_t np = 0; np < n_physical_inputs; ++np) {
char buf[32];
- snprintf (buf, sizeof (buf), _("out %" PRIu32 "+%" PRIu32), np+1, np+2);
+ snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
- shared_ptr<AutoBundle> c (new AutoBundle (buf, true));
- c->set_channels (2);
- c->set_port (0, _engine.get_nth_physical_output (DataType::AUDIO, np));
- c->set_port (1, _engine.get_nth_physical_output (DataType::AUDIO, np + 1));
+ shared_ptr<Bundle> c (new Bundle (buf, false));
+ c->add_channel (_("mono"));
+ c->set_port (0, _engine.get_nth_physical_input (DataType::AUDIO, np));
add_bundle (c);
}
- for (uint32_t np = 0; np < n_physical_inputs; np +=2) {
- char buf[32];
- snprintf (buf, sizeof (buf), _("in %" PRIu32 "+%" PRIu32), np+1, np+2);
+ for (uint32_t np = 0; np < n_physical_inputs; np += 2) {
+ if (np + 1 < n_physical_inputs) {
+ char buf[32];
+ snprintf (buf, sizeof(buf), _("in %" PRIu32 "+%" PRIu32), np + 1, np + 2);
- shared_ptr<AutoBundle> c (new AutoBundle (buf, false));
- c->set_channels (2);
- c->set_port (0, _engine.get_nth_physical_input (DataType::AUDIO, np));
- c->set_port (1, _engine.get_nth_physical_input (DataType::AUDIO, np + 1));
+ shared_ptr<Bundle> c (new Bundle (buf, false));
+ c->add_channel (_("L"));
+ c->set_port (0, _engine.get_nth_physical_input (DataType::AUDIO, np));
+ c->add_channel (_("R"));
+ c->set_port (1, _engine.get_nth_physical_input (DataType::AUDIO, np + 1));
- add_bundle (c);
+ add_bundle (c);
+ }
}
- /* THREE MASTER */
-
if (_master_out) {
/* create master/control ports */
_master_out->allow_pan_reset ();
}
-
- shared_ptr<AutoBundle> c (new AutoBundle (_("Master Out"), true));
-
- c->set_channels (_master_out->n_inputs().n_total());
- for (uint32_t n = 0; n < _master_out->n_inputs ().n_total(); ++n) {
- c->set_port (n, _master_out->input(n)->name());
- }
- add_bundle (c);
}
BootMessage (_("Setup signal flow and plugins"));
BootMessage (_("Connect to engine"));
_engine.set_session (this);
-
-#ifdef HAVE_LIBLO
- /* and to OSC */
-
- BootMessage (_("OSC startup"));
-
- osc->set_session (*this);
-#endif
-
}
void
nframes_t offset;
nframes_t tf;
+ if (_transport_speed == 0.0f && non_realtime_work_pending()) {
+ return last_stop_frame;
+ }
+
/* the first of these two possible settings for "offset"
mean that the audible frame is stationary until
audio emerges from the latency compensation
} else {
tf = _transport_frame;
}
-
- if (_transport_speed == 0) {
- return tf;
- }
-
- if (tf < offset) {
- return 0;
- }
-
+
ret = tf;
if (!non_realtime_work_pending()) {
/* MOVING */
- /* take latency into account */
+ /* check to see if we have passed the first guaranteed
+ audible frame past our last start position. if not,
+ return that last start point because in terms
+ of audible frames, we have not moved yet.
+ */
+
+ if (_transport_speed > 0.0f) {
+
+ if (!play_loop || !have_looped) {
+ if (tf < _last_roll_location + offset) {
+ return _last_roll_location;
+
+ }
+ }
+
+
+ /* forwards */
+ ret -= offset;
+
+ } else if (_transport_speed < 0.0f) {
+
+ /* XXX wot? no backward looping? */
- ret -= offset;
+ if (tf > _last_roll_location - offset) {
+ return _last_roll_location;
+ } else {
+ /* backwards */
+ ret += offset;
+ }
+ }
}
return ret;
ensure_buffers(_scratch_buffers->available());
- if (_gain_automation_buffer) {
- delete [] _gain_automation_buffer;
- }
+ delete [] _gain_automation_buffer;
_gain_automation_buffer = new gain_t[nframes];
allocate_pan_automation_buffers (nframes, _npan_buffers, true);
}
}
-#if 0
vector<string> physinputs;
vector<string> physoutputs;
_engine.get_physical_outputs (DataType::MIDI, physoutputs);
_engine.get_physical_inputs (DataType::MIDI, physinputs);
- uint32_t nphysical_in;
- uint32_t nphysical_out;
- control_id = ntracks() + nbusses();
-#endif
+
+ // control_id = ntracks() + nbusses();
while (how_many) {
} while (track_id < (UINT_MAX-1));
- /*
- if (Config->get_input_auto_connect() & AutoConnectPhysical) {
- nphysical_in = min (n_physical_inputs, (uint32_t) physinputs.size());
- } else {
- nphysical_in = 0;
- }
-
- if (Config->get_output_auto_connect() & AutoConnectPhysical) {
- nphysical_out = min (n_physical_outputs, (uint32_t) physinputs.size());
- } else {
- nphysical_out = 0;
- }
- */
-
shared_ptr<MidiTrack> track;
try {
vector<string> physinputs;
vector<string> physoutputs;
- uint32_t nphysical_in;
- uint32_t nphysical_out;
_engine.get_physical_outputs (DataType::AUDIO, physoutputs);
_engine.get_physical_inputs (DataType::AUDIO, physinputs);
+
control_id = ntracks() + nbusses() + 1;
while (how_many) {
} while (track_id < (UINT_MAX-1));
- if (Config->get_input_auto_connect() & AutoConnectPhysical) {
- nphysical_in = min (n_physical_inputs, (uint32_t) physinputs.size());
- } else {
- nphysical_in = 0;
- }
-
- if (Config->get_output_auto_connect() & AutoConnectPhysical) {
- nphysical_out = min (n_physical_outputs, (uint32_t) physinputs.size());
- } else {
- nphysical_out = 0;
- }
-
shared_ptr<AudioTrack> track;
try {
goto failed;
}
- if (nphysical_in) {
+ if (!physinputs.empty()) {
+ uint32_t nphysical_in = physinputs.size();
+
for (uint32_t x = 0; x < track->n_inputs().n_audio() && x < nphysical_in; ++x) {
port = "";
}
}
- for (uint32_t x = 0; x < track->n_outputs().n_midi(); ++x) {
-
- port = "";
+ if (!physoutputs.empty()) {
+ uint32_t nphysical_out = physoutputs.size();
- if (nphysical_out && (Config->get_output_auto_connect() & AutoConnectPhysical)) {
- port = physoutputs[(channels_used+x)%nphysical_out];
- } else if (Config->get_output_auto_connect() & AutoConnectMaster) {
- if (_master_out) {
- port = _master_out->input (x%_master_out->n_inputs().n_audio())->name();
+ for (uint32_t x = 0; x < track->n_outputs().n_audio(); ++x) {
+
+ port = "";
+
+ if (Config->get_output_auto_connect() & AutoConnectPhysical) {
+ port = physoutputs[(channels_used+x)%nphysical_out];
+ } else if (Config->get_output_auto_connect() & AutoConnectMaster) {
+ if (_master_out) {
+ port = _master_out->input (x%_master_out->n_inputs().n_audio())->name();
+ }
+ }
+
+ if (port.length() && track->connect_output (track->output (x), port, this)) {
+ break;
}
- }
-
- if (port.length() && track->connect_output (track->output (x), port, this)) {
- break;
}
}
}
-Session::RouteList
+RouteList
Session::new_audio_route (int input_channels, int output_channels, uint32_t how_many)
{
char bus_name[32];
uint32_t bus_id = 1;
uint32_t n = 0;
+ uint32_t channels_used = 0;
string port;
RouteList ret;
uint32_t control_id;
shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if (dynamic_cast<AudioTrack*>((*i).get()) == 0) {
+ if (boost::dynamic_pointer_cast<Track>(*i) == 0) {
+ /* its a bus ? */
if (!(*i)->is_hidden() && (*i)->name() != _("master")) {
bus_id++;
+ n++;
+ channels_used += (*i)->n_inputs().n_audio();
}
}
}
_engine.get_physical_outputs (DataType::AUDIO, physoutputs);
_engine.get_physical_inputs (DataType::AUDIO, physinputs);
+
+ n_physical_audio_outputs = physoutputs.size();
+ n_physical_audio_inputs = physinputs.size();
+
control_id = ntracks() + nbusses() + 1;
while (how_many) {
goto failure;
}
- for (uint32_t x = 0; n_physical_inputs && x < bus->n_inputs().n_audio(); ++x) {
- port = "";
+ /*
+ for (uint32_t x = 0; n_physical_audio_inputs && x < bus->n_inputs(); ++x) {
+
+ port = "";
+
if (Config->get_input_auto_connect() & AutoConnectPhysical) {
- port = physinputs[((n+x)%n_physical_inputs)];
- }
-
+ port = physinputs[((n+x)%n_physical_audio_inputs)];
+ }
+
if (port.length() && bus->connect_input (bus->input (x), port, this)) {
break;
}
}
+ */
- for (uint32_t x = 0; n_physical_outputs && x < bus->n_outputs().n_audio(); ++x) {
-
+ for (uint32_t x = 0; n_physical_audio_outputs && x < bus->n_outputs().n_audio(); ++x) {
port = "";
if (Config->get_output_auto_connect() & AutoConnectPhysical) {
}
}
+ channels_used += bus->n_inputs ().n_audio();
+
bus->set_remote_control_id (control_id);
++control_id;
if ((*x)->is_control()) {
_control_out = (*x);
}
-
- add_bundle ((*x)->bundle_for_inputs());
- add_bundle ((*x)->bundle_for_outputs());
}
if (_control_out && IO::connecting_legal) {
route->drop_references ();
+ sync_order_keys (N_("session"));
+
/* save the new state of the world */
if (save_state (_current_snapshot_name)) {
bool is_track = false;
bool signal = false;
- /* caller must hold RouteLock */
-
/* this is where we actually implement solo by changing
the solo mute setting of each track.
*/
has.
*/
update_route_solo_state();
-}
+}
+
+void
+Session::catch_up_on_solo_mute_override ()
+{
+ if (Config->get_solo_model() != InverseMute) {
+ return;
+ }
+
+ /* this is called whenever the param solo-mute-override is
+ changed.
+ */
+ shared_ptr<RouteList> r = routes.reader ();
+
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ (*i)->catch_up_on_solo_mute_override ();
+ }
+}
shared_ptr<Route>
Session::route_by_name (string name)
}
void
-Session::add_playlist (boost::shared_ptr<Playlist> playlist)
+Session::unassigned_playlists (std::list<boost::shared_ptr<Playlist> > & list)
+{
+ Glib::Mutex::Lock lm (playlist_lock);
+ for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
+ if (!(*i)->get_orig_diskstream_id().to_s().compare ("0")) {
+ list.push_back (*i);
+ }
+ }
+ for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
+ if (!(*i)->get_orig_diskstream_id().to_s().compare ("0")) {
+ list.push_back (*i);
+ }
+ }
+}
+
+void
+Session::add_playlist (boost::shared_ptr<Playlist> playlist, bool unused)
{
if (playlist->hidden()) {
return;
}
}
+ if (unused) {
+ playlist->release();
+ }
+
set_dirty();
PlaylistAdded (playlist); /* EMIT SIGNAL */
_plugin_inserts.insert (_plugin_inserts.begin(), plugin_insert);
} else if ((send = dynamic_cast<Send *> (processor)) != 0) {
_sends.insert (_sends.begin(), send);
+ } else if (dynamic_cast<InternalSend *> (processor) != 0) {
+ /* relax */
} else {
fatal << _("programming error: unknown type of Insert created!") << endmsg;
/*NOTREACHED*/
}
} else if ((plugin_insert = dynamic_cast<PluginInsert *> (processor)) != 0) {
_plugin_inserts.remove (plugin_insert);
+ } else if (dynamic_cast<InternalSend *> (processor) != 0) {
+ /* relax */
} else if ((send = dynamic_cast<Send *> (processor)) != 0) {
list<Send*>::iterator x = find (_sends.begin(), _sends.end(), send);
if (x != _sends.end()) {
Session::add_bundle (shared_ptr<Bundle> bundle)
{
{
- Glib::Mutex::Lock guard (bundle_lock);
- _bundles.push_back (bundle);
+ RCUWriter<BundleList> writer (_bundles);
+ boost::shared_ptr<BundleList> b = writer.get_copy ();
+ b->push_back (bundle);
}
BundleAdded (bundle); /* EMIT SIGNAL */
bool removed = false;
{
- Glib::Mutex::Lock guard (bundle_lock);
- BundleList::iterator i = find (_bundles.begin(), _bundles.end(), bundle);
+ RCUWriter<BundleList> writer (_bundles);
+ boost::shared_ptr<BundleList> b = writer.get_copy ();
+ BundleList::iterator i = find (b->begin(), b->end(), bundle);
- if (i != _bundles.end()) {
- _bundles.erase (i);
+ if (i != b->end()) {
+ b->erase (i);
removed = true;
}
}
shared_ptr<Bundle>
Session::bundle_by_name (string name) const
{
- Glib::Mutex::Lock lm (bundle_lock);
-
- for (BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) {
+ boost::shared_ptr<BundleList> b = _bundles.reader ();
+
+ for (BundleList::const_iterator i = b->begin(); i != b->end(); ++i) {
if ((*i)->name() == name) {
return* i;
}
BufferSet&
Session::get_scratch_buffers (ChanCount count)
{
- assert(_scratch_buffers->available() >= count);
- _scratch_buffers->set_count(count);
+ if (count != ChanCount::ZERO) {
+ assert(_scratch_buffers->available() >= count);
+ _scratch_buffers->set_count(count);
+ } else {
+ _scratch_buffers->set_count (_scratch_buffers->available());
+ }
+
return *_scratch_buffers;
}
}
void
-Session::sync_order_keys ()
+Session::sync_order_keys (const char* base)
{
if (!Config->get_sync_all_route_ordering()) {
/* leave order keys as they are */
boost::shared_ptr<RouteList> r = routes.reader ();
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- (*i)->sync_order_keys ();
+ (*i)->sync_order_keys (base);
}
- Route::SyncOrderKeys (); // EMIT SIGNAL
+ Route::SyncOrderKeys (base); // EMIT SIGNAL
}
-void
-Session::foreach_bundle (sigc::slot<void, boost::shared_ptr<Bundle> > sl)
-{
- Glib::Mutex::Lock lm (bundle_lock);
- for (BundleList::iterator i = _bundles.begin(); i != _bundles.end(); ++i) {
- sl (*i);
- }
-}