along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <algorithm>
#include <cerrno>
#include <unistd.h>
#include <limits.h>
+#include <sys/time.h>
#include <sigc++/bind.h>
#include <sigc++/retype.h>
#include <glibmm/thread.h>
#include <glibmm/miscutils.h>
+#include <glibmm/fileutils.h>
#include <pbd/error.h>
#include <glibmm/thread.h>
#include <ardour/audioengine.h>
#include <ardour/configuration.h>
#include <ardour/session.h>
+#include <ardour/analyser.h>
#include <ardour/audio_diskstream.h>
#include <ardour/utils.h>
#include <ardour/audioplaylist.h>
#include <ardour/audioregion.h>
#include <ardour/audiofilesource.h>
-#include <ardour/destructive_filesource.h>
#include <ardour/auditioner.h>
#include <ardour/recent_sessions.h>
#include <ardour/redirect.h>
using namespace PBD;
using boost::shared_ptr;
+#ifdef __x86_64__
+static const int CPU_CACHE_ALIGN = 64;
+#else
+static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it matters less */
+#endif
+
const char* Session::_template_suffix = X_(".template");
const char* Session::_statefile_suffix = X_(".ardour");
const char* Session::_pending_suffix = X_(".pending");
const char* Session::interchange_dir_name = X_("interchange");
const char* Session::export_dir_name = X_("export");
-Session::compute_peak_t Session::compute_peak = 0;
+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;
sigc::signal<void> Session::SendFeedback;
sigc::signal<void> Session::SMPTEOffsetChanged;
sigc::signal<void> Session::StartTimeChanged;
sigc::signal<void> Session::EndTimeChanged;
+sigc::signal<void> Session::AutoBindingOn;
+sigc::signal<void> Session::AutoBindingOff;
+
+
+sigc::signal<void, std::string, std::string> Session::Exported;
+
int
Session::find_session (string str, string& path, string& snapshot, bool& isnew)
{
}
Session::Session (AudioEngine &eng,
- string fullpath,
- string snapshot_name,
- string* mix_template)
+ const string& fullpath,
+ const string& snapshot_name,
+ string mix_template)
: _engine (eng),
_mmc_port (default_mmc_port),
{
bool new_session;
+ if (!eng.connected()) {
+ throw failed_constructor();
+ }
+
cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (1)" << endl;
- n_physical_outputs = _engine.n_physical_outputs();
- n_physical_inputs = _engine.n_physical_inputs();
+ n_physical_audio_outputs = _engine.n_physical_audio_outputs();
+ n_physical_audio_inputs = _engine.n_physical_audio_inputs();
first_stage_init (fullpath, snapshot_name);
- new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
+ new_session = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
+
if (new_session) {
if (create (new_session, mix_template, compute_initial_length())) {
- cerr << "create failed\n";
destroy ();
throw failed_constructor ();
}
{
bool new_session;
+ if (!eng.connected()) {
+ throw failed_constructor();
+ }
+
cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (2)" << endl;
- n_physical_outputs = _engine.n_physical_outputs();
- n_physical_inputs = _engine.n_physical_inputs();
+ n_physical_audio_outputs = _engine.n_physical_audio_outputs();
+ n_physical_audio_inputs = _engine.n_physical_audio_inputs();
- if (n_physical_inputs) {
- n_physical_inputs = max (requested_physical_in, n_physical_inputs);
+ if (n_physical_audio_inputs) {
+ n_physical_audio_inputs = max (requested_physical_in, n_physical_audio_inputs);
}
- if (n_physical_outputs) {
- n_physical_outputs = max (requested_physical_out, n_physical_outputs);
+ if (n_physical_audio_outputs) {
+ n_physical_audio_outputs = max (requested_physical_out, n_physical_audio_outputs);
}
first_stage_init (fullpath, snapshot_name);
new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
if (new_session) {
- if (create (new_session, 0, initial_length)) {
+ if (create (new_session, string(), initial_length)) {
destroy ();
throw failed_constructor ();
}
}
if (!rl.empty()) {
- add_routes (rl);
+ add_routes (rl, false);
}
}
throw failed_constructor ();
}
- store_recent_sessions(_name, _path);
+ store_recent_sessions (_name, _path);
- bool was_dirty = dirty ();
-
_state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
- Config->ParameterChanged.connect (mem_fun (*this, &Session::config_changed));
- if (was_dirty) {
- DirtyChanged (); /* EMIT SIGNAL */
- }
+ Config->ParameterChanged.connect (mem_fun (*this, &Session::config_changed));
}
Session::~Session ()
remove_pending_capture_state ();
_state_of_the_state = StateOfTheState (CannotSave|Deletion);
+
_engine.remove_session ();
GoingAway (); /* EMIT SIGNAL */
tmp = i;
++tmp;
-
+
i->second->drop_references ();
-
+
i = tmp;
}
-
audio_sources.clear ();
-
+
#ifdef TRACK_DESTRUCTION
cerr << "delete mix groups\n";
#endif /* TRACK_DESTRUCTION */
/* we don't want to run execute this again */
+ BootMessage (_("Set block size and sample rate"));
+
set_block_size (_engine.frames_per_cycle());
set_frame_rate (_engine.frame_rate());
+ BootMessage (_("Using configuration"));
+
Config->map_parameters (mem_fun (*this, &Session::config_changed));
/* every time we reconnect, recompute worst case output latencies */
/* default state for Click */
- first_physical_output = _engine.get_nth_physical_output (0);
+ first_physical_output = _engine.get_nth_physical_audio_output (0);
if (first_physical_output.length()) {
if (_click_io->add_output_port (first_physical_output, this)) {
error << _("cannot setup Click I/O") << endmsg;
}
+ BootMessage (_("Compute I/O Latencies"));
+
set_worst_io_latencies ();
if (_clicking) {
to the physical outputs currently available
*/
+ BootMessage (_("Set up standard connections"));
+
/* ONE: MONO */
- for (uint32_t np = 0; np < n_physical_outputs; ++np) {
+ for (uint32_t np = 0; np < n_physical_audio_outputs; ++np) {
char buf[32];
snprintf (buf, sizeof (buf), _("out %" PRIu32), np+1);
Connection* c = new OutputConnection (buf, true);
c->add_port ();
- c->add_connection (0, _engine.get_nth_physical_output (np));
+ c->add_connection (0, _engine.get_nth_physical_audio_output (np));
add_connection (c);
}
- for (uint32_t np = 0; np < n_physical_inputs; ++np) {
+ for (uint32_t np = 0; np < n_physical_audio_inputs; ++np) {
char buf[32];
snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
Connection* c = new InputConnection (buf, true);
c->add_port ();
- c->add_connection (0, _engine.get_nth_physical_input (np));
+ c->add_connection (0, _engine.get_nth_physical_audio_input (np));
add_connection (c);
}
/* TWO: STEREO */
- for (uint32_t np = 0; np < n_physical_outputs; np +=2) {
+ for (uint32_t np = 0; np < n_physical_audio_outputs; np +=2) {
char buf[32];
snprintf (buf, sizeof (buf), _("out %" PRIu32 "+%" PRIu32), np+1, np+2);
c->add_port ();
c->add_port ();
- c->add_connection (0, _engine.get_nth_physical_output (np));
- c->add_connection (1, _engine.get_nth_physical_output (np+1));
+ c->add_connection (0, _engine.get_nth_physical_audio_output (np));
+ c->add_connection (1, _engine.get_nth_physical_audio_output (np+1));
add_connection (c);
}
- for (uint32_t np = 0; np < n_physical_inputs; np +=2) {
+ for (uint32_t np = 0; np < n_physical_audio_inputs; np +=2) {
char buf[32];
snprintf (buf, sizeof (buf), _("in %" PRIu32 "+%" PRIu32), np+1, np+2);
c->add_port ();
c->add_port ();
- c->add_connection (0, _engine.get_nth_physical_input (np));
- c->add_connection (1, _engine.get_nth_physical_input (np+1));
+ c->add_connection (0, _engine.get_nth_physical_audio_input (np));
+ c->add_connection (1, _engine.get_nth_physical_audio_input (np+1));
add_connection (c);
}
}
n = 0;
while ((int) _master_out->n_outputs() < _master_out->output_maximum()) {
- if (_master_out->add_output_port (_engine.get_nth_physical_output (n), this)) {
+ if (_master_out->add_output_port (_engine.get_nth_physical_audio_output (n), this)) {
error << _("cannot setup master outputs")
<< endmsg;
break;
}
add_connection (c);
}
+
+ BootMessage (_("Setup signal flow and plugins"));
hookup_io ();
/* catch up on send+insert cnts */
+ BootMessage (_("Catch up with send/insert state"));
+
insert_cnt = 0;
for (list<PortInsert*>::iterator i = _port_inserts.begin(); i != _port_inserts.end(); ++i) {
/* hook us up to the engine */
+ BootMessage (_("Connect to engine"));
+
_engine.set_session (this);
#ifdef HAVE_LIBLO
/* and to OSC */
+ BootMessage (_("OSC startup"));
+
osc->set_session (*this);
#endif
- _state_of_the_state = Clean;
-
- DirtyChanged (); /* EMIT SIGNAL */
}
void
_state_of_the_state = StateOfTheState (_state_of_the_state | InitialConnecting);
+
if (auditioner == 0) {
/* we delay creating the auditioner till now because
if (_control_out) {
uint32_t n;
+ vector<string> cports;
while ((int) _control_out->n_inputs() < _control_out->input_maximum()) {
if (_control_out->add_input_port ("", this)) {
}
n = 0;
while ((int) _control_out->n_outputs() < _control_out->output_maximum()) {
- if (_control_out->add_output_port (_engine.get_nth_physical_output (n), this)) {
+ if (_control_out->add_output_port (_engine.get_nth_physical_audio_output (n), this)) {
error << _("cannot set up master outputs")
<< endmsg;
break;
}
n++;
}
- }
+
+
+ uint32_t ni = _control_out->n_inputs();
+
+ for (n = 0; n < ni; ++n) {
+ cports.push_back (_control_out->input(n)->name());
+ }
+
+ boost::shared_ptr<RouteList> r = routes.reader ();
+
+ for (RouteList::iterator x = r->begin(); x != r->end(); ++x) {
+ (*x)->set_control_outs (cports);
+ }
+ }
/* Tell all IO objects to connect themselves together */
_state_of_the_state = StateOfTheState (_state_of_the_state & ~InitialConnecting);
+
/* now handle the whole enchilada as if it was one
graph reorder event.
*/
}
void
-Session::diskstream_playlist_changed (boost::shared_ptr<Diskstream> dstream)
+Session::diskstream_playlist_changed (boost::weak_ptr<Diskstream> wptr)
{
+ boost::shared_ptr<Diskstream> dstream = wptr.lock();
+
+ if (!dstream) {
+ return;
+
+ }
+
boost::shared_ptr<Playlist> playlist;
if ((playlist = dstream->playlist()) != 0) {
}
last_loopend = location->end();
-
}
void
auto_punch_changed_connection = location->changed.connect (mem_fun (this, &Session::auto_punch_changed));
location->set_auto_punch (true, this);
+
+
+ auto_punch_changed (location);
+
auto_punch_location_changed (location);
}
auto_loop_changed_connection = location->changed.connect (mem_fun (this, &Session::auto_loop_changed));
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);
}
if ((rs = (RecordState) g_atomic_int_get (&_record_status)) != Disabled) {
- if (!Config->get_latched_record_enable () || force) {
+ if ((!Config->get_latched_record_enable () && !play_loop) || force) {
g_atomic_int_set (&_record_status, Disabled);
} else {
if (rs == Recording) {
void
Session::step_back_from_record ()
{
- g_atomic_int_set (&_record_status, Enabled);
+ /* XXX really atomic compare+swap here */
+ if (g_atomic_int_get (&_record_status) == Recording) {
+ g_atomic_int_set (&_record_status, Enabled);
- if (Config->get_monitoring_model() == HardwareMonitoring) {
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if (Config->get_auto_input() && (*i)->record_enabled ()) {
- //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
- (*i)->monitor_input (false);
+ if (Config->get_monitoring_model() == HardwareMonitoring && Config->get_auto_input()) {
+ boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
+
+ for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
+ if ((*i)->record_enabled ()) {
+ //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
+ (*i)->monitor_input (false);
+ }
}
}
}
sync_time_vars();
- Route::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * 0.25));
+ IO::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * (0.001 * Config->get_automation_interval())));
+
+ clear_clicks ();
// XXX we need some equivalent to this, somehow
// SndFileSource::setup_standard_crossfades (frames_per_second);
uint32_t np;
current_block_size = nframes;
-
+
for (np = 0, i = _passthru_buffers.begin(); i != _passthru_buffers.end(); ++i, ++np) {
free (*i);
}
#ifdef NO_POSIX_MEMALIGN
buf = (Sample *) malloc(current_block_size * sizeof(Sample));
#else
- posix_memalign((void **)&buf,16,current_block_size * 4);
+ posix_memalign((void **)&buf,CPU_CACHE_ALIGN,current_block_size * sizeof(Sample));
#endif
*i = buf;
uint32_t nphysical_in;
uint32_t nphysical_out;
- _engine.get_physical_outputs (physoutputs);
- _engine.get_physical_inputs (physinputs);
+ _engine.get_physical_audio_outputs (physoutputs);
+ _engine.get_physical_audio_inputs (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());
+ nphysical_in = min (n_physical_audio_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());
+ nphysical_out = min (n_physical_audio_outputs, (uint32_t) physinputs.size());
} else {
nphysical_out = 0;
}
+
+ shared_ptr<AudioTrack> track;
try {
- shared_ptr<AudioTrack> track (new AudioTrack (*this, track_name, Route::Flag (0), mode));
+ track = boost::shared_ptr<AudioTrack>((new AudioTrack (*this, track_name, Route::Flag (0), mode)));
if (track->ensure_io (input_channels, 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;
}
-
+
if (nphysical_in) {
for (uint32_t x = 0; x < track->n_inputs() && x < nphysical_in; ++x) {
channels_used += track->n_inputs ();
- if (_control_out) {
- vector<string> cports;
- uint32_t ni = _control_out->n_inputs();
-
- for (n = 0; n < ni; ++n) {
- cports.push_back (_control_out->input(n)->name());
- }
-
- track->set_control_outs (cports);
- }
-
- // assert (current_thread != RT_thread)
-
track->audio_diskstream()->non_realtime_input_change();
track->DiskstreamChanged.connect (mem_fun (this, &Session::resort_routes));
new_routes.push_back (track);
ret.push_back (track);
+
}
catch (failed_constructor &err) {
error << _("Session: could not create new audio track.") << endmsg;
- // XXX should we delete the tracks already created?
- ret.clear ();
- return ret;
+
+ if (track) {
+ /* we need to get rid of this, since the track failed to be created */
+ /* XXX arguably, AudioTrack::AudioTrack should not do the Session::add_diskstream() */
+
+ {
+ RCUWriter<DiskstreamList> writer (diskstreams);
+ boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
+ ds->remove (track->audio_diskstream());
+ }
+ }
+
+ goto failed;
}
-
+
+ catch (AudioEngine::PortRegistrationFailure& pfe) {
+
+ error << _("No more JACK ports are available. You will need to stop Ardour and restart JACK with ports if you need this many tracks.") << endmsg;
+
+ if (track) {
+ /* we need to get rid of this, since the track failed to be created */
+ /* XXX arguably, AudioTrack::AudioTrack should not do the Session::add_diskstream() */
+
+ {
+ RCUWriter<DiskstreamList> writer (diskstreams);
+ boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
+ ds->remove (track->audio_diskstream());
+ }
+ }
+
+ goto failed;
+ }
+
--how_many;
}
+ failed:
if (!new_routes.empty()) {
- add_routes (new_routes, false);
- save_state (_current_snapshot_name);
+ add_routes (new_routes, true);
}
return ret;
}
+void
+Session::set_remote_control_ids ()
+{
+ RemoteModel m = Config->get_remote_model();
+
+ shared_ptr<RouteList> r = routes.reader ();
+
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ if ( MixerOrdered == m) {
+ long order = (*i)->order_key(N_("signal"));
+ (*i)->set_remote_control_id( order+1 );
+ } else if ( EditorOrdered == m) {
+ long order = (*i)->order_key(N_("editor"));
+ (*i)->set_remote_control_id( order+1 );
+ } else if ( UserOrdered == m) {
+ //do nothing ... only changes to remote id's are initiated by user
+ }
+ }
+}
+
+
Session::RouteList
Session::new_audio_route (int input_channels, int output_channels, uint32_t how_many)
{
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (dynamic_cast<AudioTrack*>((*i).get()) == 0) {
- if (!(*i)->hidden()) {
+ if (!(*i)->hidden() && (*i)->name() != _("master")) {
bus_id++;
}
}
vector<string> physinputs;
vector<string> physoutputs;
- _engine.get_physical_outputs (physoutputs);
- _engine.get_physical_inputs (physinputs);
+ _engine.get_physical_audio_outputs (physoutputs);
+ _engine.get_physical_audio_inputs (physinputs);
control_id = ntracks() + nbusses() + 1;
while (how_many) {
do {
- ++bus_id;
-
snprintf (bus_name, sizeof(bus_name), "Bus %" PRIu32, bus_id);
+ bus_id++;
+
if (route_by_name (bus_name) == 0) {
break;
}
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
+ goto failure;
}
- for (uint32_t x = 0; n_physical_inputs && x < bus->n_inputs(); ++x) {
+ 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)) {
}
}
- for (uint32_t x = 0; n_physical_outputs && x < bus->n_outputs(); ++x) {
+ for (uint32_t x = 0; n_physical_audio_outputs && x < bus->n_outputs(); ++x) {
port = "";
if (Config->get_output_auto_connect() & AutoConnectPhysical) {
- port = physoutputs[((n+x)%n_physical_outputs)];
+ port = physoutputs[((n+x)%n_physical_audio_outputs)];
} else if (Config->get_output_auto_connect() & AutoConnectMaster) {
if (_master_out) {
port = _master_out->input (x%_master_out->n_inputs())->name();
}
}
- if (_control_out) {
- vector<string> cports;
- uint32_t ni = _control_out->n_inputs();
-
- for (uint32_t n = 0; n < ni; ++n) {
- cports.push_back (_control_out->input(n)->name());
- }
- bus->set_control_outs (cports);
- }
-
bus->set_remote_control_id (control_id);
++control_id;
catch (failed_constructor &err) {
error << _("Session: could not create new audio route.") << endmsg;
- ret.clear ();
- return ret;
+ goto failure;
}
+ catch (AudioEngine::PortRegistrationFailure& pfe) {
+ error << _("No more JACK ports are available. You will need to stop Ardour and restart JACK with ports if you need this many tracks.") << endmsg;
+ goto failure;
+ }
+
+
--how_many;
}
+ failure:
if (!ret.empty()) {
- add_routes (ret, false);
- save_state (_current_snapshot_name);
+ add_routes (ret, true);
}
return ret;
if ((*x)->control()) {
_control_out = (*x);
- }
+ }
}
+ if (_control_out && IO::connecting_legal) {
+
+ vector<string> cports;
+ uint32_t ni = _control_out->n_inputs();
+ uint32_t n;
+
+ for (n = 0; n < ni; ++n) {
+ cports.push_back (_control_out->input(n)->name());
+ }
+
+ for (RouteList::iterator x = new_routes.begin(); x != new_routes.end(); ++x) {
+ (*x)->set_control_outs (cports);
+ }
+ }
+
set_dirty();
if (save) {
Session::add_diskstream (boost::shared_ptr<Diskstream> dstream)
{
/* need to do this in case we're rolling at the time, to prevent false underruns */
- dstream->do_refill_with_alloc();
+ dstream->do_refill_with_alloc ();
- {
+ dstream->set_block_size (current_block_size);
+
+ {
RCUWriter<DiskstreamList> writer (diskstreams);
boost::shared_ptr<DiskstreamList> ds = writer.get_copy();
ds->push_back (dstream);
- }
-
- dstream->set_block_size (current_block_size);
+ /* writer goes out of scope, copies ds back to main */
+ }
- dstream->PlaylistChanged.connect (sigc::bind (mem_fun (*this, &Session::diskstream_playlist_changed), dstream));
+ dstream->PlaylistChanged.connect (sigc::bind (mem_fun (*this, &Session::diskstream_playlist_changed),
+ boost::weak_ptr<Diskstream> (dstream)));
/* this will connect to future changes, and check the current length */
diskstream_playlist_changed (dstream);
boost::shared_ptr<DiskstreamList> d = dsl.get_copy();
d->remove (ds);
}
+
+ diskstreams.flush ();
}
find_current_end ();
+ // We need to disconnect the routes inputs and outputs
+
+ route->disconnect_inputs (0);
+ route->disconnect_outputs (0);
+
update_latency_compensation (false, false);
set_dirty();
- // We need to disconnect the routes inputs and outputs
- route->disconnect_inputs(NULL);
- route->disconnect_outputs(NULL);
-
/* 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) */
void
Session::add_region (boost::shared_ptr<Region> region)
+{
+ vector<boost::shared_ptr<Region> > v;
+ v.push_back (region);
+ add_regions (v);
+}
+
+void
+Session::add_regions (vector<boost::shared_ptr<Region> >& new_regions)
{
boost::shared_ptr<AudioRegion> ar;
boost::shared_ptr<AudioRegion> oar;
{
Glib::Mutex::Lock lm (region_lock);
- if ((ar = boost::dynamic_pointer_cast<AudioRegion> (region)) != 0) {
-
- AudioRegionList::iterator x;
-
- for (x = audio_regions.begin(); x != audio_regions.end(); ++x) {
-
- oar = boost::dynamic_pointer_cast<AudioRegion> (x->second);
-
- if (ar->region_list_equivalent (oar)) {
- break;
- }
- }
-
- if (x == audio_regions.end()) {
-
- pair<AudioRegionList::key_type,AudioRegionList::mapped_type> entry;
-
- entry.first = region->id();
- entry.second = ar;
+ for (vector<boost::shared_ptr<Region> >::iterator ii = new_regions.begin(); ii != new_regions.end(); ++ii) {
+
+ boost::shared_ptr<Region> region = *ii;
+
+ if (region == 0) {
- pair<AudioRegionList::iterator,bool> x = audio_regions.insert (entry);
+ error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg;
+ } else if ((ar = boost::dynamic_pointer_cast<AudioRegion> (region)) != 0) {
- if (!x.second) {
- return;
+ AudioRegionList::iterator x;
+
+ for (x = audio_regions.begin(); x != audio_regions.end(); ++x) {
+
+ oar = boost::dynamic_pointer_cast<AudioRegion> (x->second);
+
+ if (ar->region_list_equivalent (oar)) {
+ break;
+ }
}
+
+ if (x == audio_regions.end()) {
+
+ pair<AudioRegionList::key_type,AudioRegionList::mapped_type> entry;
+
+ entry.first = region->id();
+ entry.second = ar;
+
+ pair<AudioRegionList::iterator,bool> x = audio_regions.insert (entry);
+
+
+ if (!x.second) {
+ return;
+ }
+
+ added = true;
+ }
- added = true;
- }
-
- } else {
-
- fatal << _("programming error: ")
- << X_("unknown region type passed to Session::add_region()")
- << endmsg;
- /*NOTREACHED*/
-
+ } else {
+
+ fatal << _("programming error: ")
+ << X_("unknown region type passed to Session::add_region()")
+ << endmsg;
+ /*NOTREACHED*/
+
+ }
}
}
set_dirty();
if (added) {
- region->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_region), boost::weak_ptr<Region>(region)));
- region->StateChanged.connect (sigc::bind (mem_fun (*this, &Session::region_changed), boost::weak_ptr<Region>(region)));
- AudioRegionAdded (ar); /* EMIT SIGNAL */
+
+ vector<boost::weak_ptr<AudioRegion> > v;
+ boost::shared_ptr<AudioRegion> first_ar;
+
+ for (vector<boost::shared_ptr<Region> >::iterator ii = new_regions.begin(); ii != new_regions.end(); ++ii) {
+
+ boost::shared_ptr<Region> region = *ii;
+ boost::shared_ptr<AudioRegion> ar;
+
+ if (region == 0) {
+
+ error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg;
+
+ } else if ((ar = boost::dynamic_pointer_cast<AudioRegion> (region)) != 0) {
+ v.push_back (ar);
+
+ if (!first_ar) {
+ first_ar = ar;
+ }
+ }
+
+ region->StateChanged.connect (sigc::bind (mem_fun (*this, &Session::region_changed), boost::weak_ptr<Region>(region)));
+ region->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_region), boost::weak_ptr<Region>(region)));
+ }
+
+ if (!v.empty()) {
+ AudioRegionsAdded (v); /* EMIT SIGNAL */
+ }
}
}
}
destroy_regions (r);
+
+ save_state (_current_snapshot_name);
+
return 0;
}
set_dirty();
}
+ if (Config->get_auto_analyse_audio()) {
+ Analyser::queue_source_for_analysis (source, false);
+ }
}
}
return source;
}
-string
-Session::peak_path_from_audio_path (string audio_path) const
+
+boost::shared_ptr<Source>
+Session::source_by_path_and_channel (const Glib::ustring& path, uint16_t chn)
{
- string res;
+ Glib::Mutex::Lock lm (audio_source_lock);
+
+ for (AudioSourceList::iterator i = audio_sources.begin(); i != audio_sources.end(); ++i) {
+ boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(i->second);
+
+ if (afs && afs->path() == path && chn == afs->channel()) {
+ return afs;
+ }
+
+ }
+ return boost::shared_ptr<Source>();
+}
+Glib::ustring
+Session::peak_path (Glib::ustring base) const
+{
+ Glib::ustring res;
+
res = peak_dir ();
- res += PBD::basename_nosuffix (audio_path);
+ res += base;
res += ".peak";
return res;
{
PathScanner scanner;
- vector<string *>* possible_audiofiles = scanner (sound_dir(), "\\.(wav|aiff|caf|w64)$", false, true);
+ vector<string *>* possible_audiofiles = scanner (sound_dir(), "\\.(wav|aiff|caf|w64|L|R)$", false, true);
Glib::Mutex::Lock lm (audio_source_lock);
continue;
}
- if (AudioFileSource::is_empty (*this, *(*i))) {
+ if (AudioFileSource::is_empty (*this, **i)) {
unlink ((*i)->c_str());
- string peak_path = peak_path_from_audio_path (**i);
- unlink (peak_path.c_str());
+ Glib::ustring peakpath = peak_path (PBD::basename_nosuffix (**i));
+ unlink (peakpath.c_str());
}
delete* i;
Session::graph_reordered ()
{
/* don't do this stuff if we are setting up connections
- from a set_state() call.
+ from a set_state() call or creating new tracks.
*/
if (_state_of_the_state & InitialConnecting) {
sample_bytes_on_disk = 3.0;
break;
+ case FormatInt16:
+ sample_bytes_on_disk = 2.0;
+ break;
+
default:
/* impossible, but keep some gcc versions happy */
fatal << string_compose (_("programming error: %1"),
Session::tempo_map_changed (Change ignored)
{
clear_clicks ();
+
+ for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
+ (*i)->update_after_tempo_map_change ();
+ }
+
+ for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
+ (*i)->update_after_tempo_map_change ();
+ }
+
set_dirty ();
}
void
Session::ensure_passthru_buffers (uint32_t howmany)
{
+ if (current_block_size == 0) {
+ return;
+ }
+
while (howmany > _passthru_buffers.size()) {
Sample *p;
#ifdef NO_POSIX_MEMALIGN
p = (Sample *) malloc(current_block_size * sizeof(Sample));
#else
- posix_memalign((void **)&p,16,current_block_size * 4);
+ if (posix_memalign((void **)&p,CPU_CACHE_ALIGN,current_block_size * sizeof(Sample)) != 0) {
+ fatal << string_compose (_("Memory allocation error: posix_memalign (%1 * %2) failed (%3)"),
+ current_block_size, sizeof (Sample), strerror (errno))
+ << endmsg;
+ /*NOTREACHED*/
+ }
#endif
_passthru_buffers.push_back (p);
#ifdef NO_POSIX_MEMALIGN
p = (Sample *) malloc(current_block_size * sizeof(Sample));
#else
- posix_memalign((void **)&p,16,current_block_size * 4);
+ if (posix_memalign((void **)&p,CPU_CACHE_ALIGN,current_block_size * 4) != 0) {
+ fatal << string_compose (_("Memory allocation error: posix_memalign (%1 * %2) failed (%3)"),
+ current_block_size, sizeof (Sample), strerror (errno))
+ << endmsg;
+ /*NOTREACHED*/
+ }
#endif
memset (p, 0, sizeof (Sample) * current_block_size);
_silent_buffers.push_back (p);
#ifdef NO_POSIX_MEMALIGN
p = (Sample *) malloc(current_block_size * sizeof(Sample));
#else
- posix_memalign((void **)&p,16,current_block_size * 4);
+ posix_memalign((void **)&p,CPU_CACHE_ALIGN,current_block_size * sizeof(Sample));
#endif
memset (p, 0, sizeof (Sample) * current_block_size);
_send_buffers.push_back (p);
for (boost::dynamic_bitset<uint32_t>::size_type n = 0; n < insert_bitset.size(); ++n) {
if (!insert_bitset[n]) {
insert_bitset[n] = true;
- cerr << "Returning " << n << " as insert ID\n";
return n;
}
for (boost::dynamic_bitset<uint32_t>::size_type n = 0; n < send_bitset.size(); ++n) {
if (!send_bitset[n]) {
send_bitset[n] = true;
- cerr << "Returning " << n << " as send ID\n";
return n;
}
#ifdef NO_POSIX_MEMALIGN
b = (Sample *) malloc(chunk_size * sizeof(Sample));
#else
- posix_memalign((void **)&b,16,chunk_size * 4);
+ posix_memalign((void **)&b,4096,chunk_size * sizeof(Sample));
#endif
buffers.push_back (b);
}
+ for (vector<boost::shared_ptr<AudioSource> >::iterator src=srcs.begin(); src != srcs.end(); ++src) {
+ (*src)->prepare_for_peakfile_writes ();
+ }
+
while (to_do && !itt.cancel) {
this_chunk = min (to_do, chunk_size);
if (afs) {
afs->update_header (position, *xnow, now);
+ afs->flush_header ();
}
}
- /* build peakfile for new source */
-
- for (vector<boost::shared_ptr<AudioSource> >::iterator src=srcs.begin(); src != srcs.end(); ++src) {
- boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
- if (afs) {
- afs->build_peaks ();
- }
- }
-
/* construct a region to represent the bounced material */
boost::shared_ptr<Region> aregion = RegionFactory::create (srcs, 0, srcs.front()->length(),
(*src)->drop_references ();
}
+
+ } else {
+ for (vector<boost::shared_ptr<AudioSource> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
+ (*src)->done_with_peakfile_writes ();
+ }
}
for (vector<Sample*>::iterator i = buffers.begin(); i != buffers.end(); ++i) {
vector<Sample*>&
Session::get_silent_buffers (uint32_t howmany)
{
+ if (howmany > _silent_buffers.size()) {
+
+ error << string_compose (_("Programming error: get_silent_buffers() called for %1 buffers but only %2 exist"),
+ howmany, _silent_buffers.size()) << endmsg;
+
+ if (howmany > 1000) {
+ cerr << "ABSURD: more than 1000 silent buffers requested!\n";
+ abort ();
+ }
+
+ while (howmany > _silent_buffers.size()) {
+ Sample *p = 0;
+
+#ifdef NO_POSIX_MEMALIGN
+ p = (Sample *) malloc(current_block_size * sizeof(Sample));
+#else
+ if (posix_memalign((void **)&p,CPU_CACHE_ALIGN,current_block_size * 4) != 0) {
+ fatal << string_compose (_("Memory allocation error: posix_memalign (%1 * %2) failed (%3)"),
+ current_block_size, sizeof (Sample), strerror (errno))
+ << endmsg;
+ /*NOTREACHED*/
+ }
+#endif
+ _silent_buffers.push_back (p);
+ }
+ }
+
for (uint32_t i = 0; i < howmany; ++i) {
memset (_silent_buffers[i], 0, sizeof (Sample) * current_block_size);
}
+
return _silent_buffers;
}
return _engine.frame_rate() * 60 * 5;
}
+void
+Session::sync_order_keys ()
+{
+ if (!Config->get_sync_all_route_ordering()) {
+ /* leave order keys as they are */
+ return;
+ }
+
+ boost::shared_ptr<RouteList> r = routes.reader ();
+
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ (*i)->sync_order_keys ();
+ }
+
+ Route::SyncOrderKeys (); // EMIT SIGNAL
+}