#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>
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)
{
string mix_template)
: _engine (eng),
+ mmc (0),
_mmc_port (default_mmc_port),
_mtc_port (default_mtc_port),
_midi_port (default_midi_port),
pending_events (2048),
+ state_tree (0),
+ _send_smpte_update (false),
+ 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),
_click_io ((IO*) 0),
+ click_data (0),
+ click_emphasis_data (0),
main_outs (0)
{
bool new_session;
throw failed_constructor();
}
- cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (1)" << endl;
+ info << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (1)" << endl;
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())) {
destroy ();
nframes_t initial_length)
: _engine (eng),
+ mmc (0),
_mmc_port (default_mmc_port),
_mtc_port (default_mtc_port),
_midi_port (default_midi_port),
pending_events (2048),
+ state_tree (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),
+ _click_io ((IO *) 0),
+ click_data (0),
+ click_emphasis_data (0),
main_outs (0)
{
throw failed_constructor();
}
- cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (2)" << endl;
+ info << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (2)" << endl;
n_physical_audio_outputs = _engine.n_physical_audio_outputs();
n_physical_audio_inputs = _engine.n_physical_audio_inputs();
_history.clear ();
/* 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;
}
tmp = i;
++tmp;
-
+
i->second->drop_references ();
-
+
i = tmp;
}
-
audio_sources.clear ();
-
+
#ifdef TRACK_DESTRUCTION
cerr << "delete mix groups\n";
#endif /* TRACK_DESTRUCTION */
i = tmp;
}
- if (butler_mixdown_buffer) {
- delete [] butler_mixdown_buffer;
- }
-
- if (butler_gain_buffer) {
- delete [] butler_gain_buffer;
- }
-
Crossfade::set_buffer_size (0);
- if (mmc) {
- delete mmc;
- }
+ delete mmc;
}
void
void
Session::when_engine_running ()
{
- string first_physical_output;
-
/* 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 */
} else {
- /* default state for Click */
-
- first_physical_output = _engine.get_nth_physical_audio_output (0);
+ /* default state for Click: dual-mono to first 2 physical outputs */
- if (first_physical_output.length()) {
- if (_click_io->add_output_port (first_physical_output, this)) {
- // relax, even though its an error
- } else {
- _clicking = Config->get_clicking ();
+ for (int physport = 0; physport < 2; ++physport) {
+ string physical_output = _engine.get_nth_physical_audio_output (physport);
+
+ if (physical_output.length()) {
+ if (_click_io->add_output_port (physical_output, this)) {
+ // relax, even though its an error
+ }
}
}
+
+ if (_click_io->n_outputs() > 0) {
+ _clicking = Config->get_clicking ();
+ }
}
}
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_audio_outputs; ++np) {
}
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) {
_state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
-
/* 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
if (transport_rolling() && play_loop) {
- //if (_transport_frame < location->start() || _transport_frame > location->end()) {
+ // if (_transport_frame > location->end()) {
- if (_transport_frame > location->end()) {
+ if (_transport_frame < location->start() || _transport_frame > location->end()) {
// relocate to beginning of loop
clear_events (Event::LocateRoll);
}
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);
}
set_loop = true;
}
+ if (location->is_start()) {
+ start_location = location;
+ }
+ if (location->is_end()) {
+ end_location = location;
+ }
}
if (!set_loop) {
if (g_atomic_int_get (&_record_status) == Recording) {
g_atomic_int_set (&_record_status, Enabled);
- if (Config->get_monitoring_model() == HardwareMonitoring) {
+ 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 (Config->get_auto_input() && (*i)->record_enabled ()) {
+ if ((*i)->record_enabled ()) {
//cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
(*i)->monitor_input (false);
}
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 */
-
- ret -= offset;
+ /* check to see if we have passed the first guaranteed
+ audible frame past our last stopping position. if not,
+ the return that last stopping 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_stop_frame + offset) {
+ return last_stop_frame;
+
+ }
+ }
+
+
+ /* forwards */
+ ret -= offset;
+
+ } else if (_transport_speed < 0.0f) {
+
+ /* XXX wot? no backward looping? */
+
+ if (tf > last_stop_frame - offset) {
+ return last_stop_frame;
+ } else {
+ /* backwards */
+ ret += offset;
+ }
+ }
}
return ret;
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;
+ error << pfe.what() << endmsg;
if (track) {
/* we need to get rid of this, since the track failed to be created */
<< endmsg;
goto failure;
}
-
+ /*
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_audio_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_audio_outputs && x < bus->n_outputs(); ++x) {
port = "";
}
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;
+ error << pfe.what() << endmsg;
goto failure;
}
}
+Session::RouteList
+Session::new_route_from_template (uint32_t how_many, const std::string& template_path)
+{
+ char name[32];
+ RouteList ret;
+ uint32_t control_id;
+ XMLTree tree;
+ uint32_t number = 1;
+
+ if (!tree.read (template_path.c_str())) {
+ return ret;
+ }
+
+ XMLNode* node = tree.root();
+
+ control_id = ntracks() + nbusses() + 1;
+
+ while (how_many) {
+
+ XMLNode node_copy (*node); // make a copy so we can change the name if we need to
+
+ std::string node_name = IO::name_from_state (*node_copy.children().front());
+
+ /* generate a new name by adding a number to the end of the template name */
+
+ do {
+ snprintf (name, sizeof (name), "%s %" PRIu32, node_name.c_str(), number);
+
+ number++;
+
+ if (route_by_name (name) == 0) {
+ break;
+ }
+
+ } while (number < UINT_MAX);
+
+ if (number == UINT_MAX) {
+ fatal << _("Session: UINT_MAX routes? impossible!") << endmsg;
+ /*NOTREACHED*/
+ }
+
+ IO::set_name_in_state (*node_copy.children().front(), name);
+
+ Track::zero_diskstream_id_in_xml (node_copy);
+
+ try {
+ shared_ptr<Route> route (XMLRouteFactory (node_copy));
+
+ if (route == 0) {
+ error << _("Session: cannot create track/bus from template description") << endmsg;
+ goto out;
+ }
+
+ 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.
+ */
+ route->input_changed (IOChange (ConfigurationChanged|ConnectionsChanged), this);
+ route->output_changed (IOChange (ConfigurationChanged|ConnectionsChanged), this);
+ }
+
+ route->set_remote_control_id (control_id);
+ ++control_id;
+
+ ret.push_back (route);
+ }
+
+ catch (failed_constructor &err) {
+ error << _("Session: could not create new route from template") << endmsg;
+ goto out;
+ }
+
+ catch (AudioEngine::PortRegistrationFailure& pfe) {
+ error << pfe.what() << endmsg;
+ goto out;
+ }
+
+ --how_many;
+ }
+
+ out:
+ if (!ret.empty()) {
+ add_routes (ret, true);
+ }
+
+ return ret;
+}
+
+boost::shared_ptr<Route>
+Session::new_video_track (string name)
+{
+ uint32_t control_id = ntracks() + nbusses() + 1;
+ shared_ptr<Route> new_route (
+ new Route ( *this, name, -1, -1, -1, -1, Route::Flag(0), ARDOUR::DataType::NIL));
+ new_route->set_remote_control_id (control_id);
+
+ RouteList rl;
+ rl.push_back (new_route);
+ {
+ RCUWriter<RouteList> writer (routes);
+ shared_ptr<RouteList> r = writer.get_copy ();
+ r->insert (r->end(), rl.begin(), rl.end());
+ resort_routes_using (r);
+ }
+ return new_route;
+}
+
void
Session::add_routes (RouteList& new_routes, bool save)
{
route->drop_references ();
+ sync_order_keys (N_("session"));
+
/* save the new state of the world */
if (save_state (_current_snapshot_name)) {
/* don't mess with busses */
- if (dynamic_cast<AudioTrack*>((*i).get()) == 0) {
+ if (boost::dynamic_pointer_cast<AudioTrack>(*i) == 0) {
continue;
}
/* don't mess with tracks */
- if (dynamic_cast<AudioTrack*>((*i).get()) != 0) {
+ if (boost::dynamic_pointer_cast<AudioTrack>(*i) != 0) {
continue;
}
}
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.
*/
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if ((*i)->soloed()) {
mute = true;
- if (dynamic_cast<AudioTrack*>((*i).get())) {
+ if (boost::dynamic_pointer_cast<AudioTrack>(*i)) {
is_track = true;
}
break;
/* only alter track solo mute */
- if (dynamic_cast<AudioTrack*>((*i).get())) {
+ if (boost::dynamic_pointer_cast<AudioTrack>(*i)) {
if ((*i)->soloed()) {
(*i)->set_solo_mute (!mute);
} else {
} else {
/* only alter bus solo mute */
-
- if (!dynamic_cast<AudioTrack*>((*i).get())) {
+
+ if (!boost::dynamic_pointer_cast<AudioTrack>(*i)) {
if ((*i)->soloed()) {
*/
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)
{
boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
for (DiskstreamList::const_iterator i = dsl->begin(); i != dsl->end(); ++i) {
+ if ((*i)->destructive()) //ignore tape tracks when getting max extents
+ continue;
boost::shared_ptr<Playlist> pl = (*i)->playlist();
if ((me = pl->get_maximum_extent()) > max) {
max = me;
}
int
-Session::region_name (string& result, string base, bool newlevel) const
+Session::region_name (string& result, string base, bool newlevel)
{
char buf[16];
string subbase;
Glib::Mutex::Lock lm (region_lock);
snprintf (buf, sizeof (buf), "%d", (int)audio_regions.size() + 1);
-
-
result = "region.";
result += buf;
} else {
- /* XXX this is going to be slow. optimize me later */
-
if (newlevel) {
subbase = base;
} else {
subbase = base.substr (0, pos);
}
-
- bool name_taken = true;
{
Glib::Mutex::Lock lm (region_lock);
-
- for (int n = 1; n < 5000; ++n) {
-
- result = subbase;
- snprintf (buf, sizeof (buf), ".%d", n);
+
+ map<string,uint32_t>::iterator x;
+
+ result = subbase;
+
+ if ((x = region_name_map.find (subbase)) == region_name_map.end()) {
+ result += ".1";
+ region_name_map[subbase] = 1;
+ } else {
+ x->second++;
+ snprintf (buf, sizeof (buf), ".%d", x->second);
result += buf;
-
- name_taken = false;
-
- for (AudioRegionList::const_iterator i = audio_regions.begin(); i != audio_regions.end(); ++i) {
- if (i->second->name() == result) {
- name_taken = true;
- break;
- }
- }
-
- if (!name_taken) {
- break;
- }
}
}
-
- if (name_taken) {
- fatal << string_compose(_("too many regions with names like %1"), base) << endmsg;
- /*NOTREACHED*/
- }
}
+
return 0;
}
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 (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) {
-
- AudioRegionList::iterator x;
-
- for (x = audio_regions.begin(); x != audio_regions.end(); ++x) {
+ 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) {
- oar = boost::dynamic_pointer_cast<AudioRegion> (x->second);
+ error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg;
- if (ar->region_list_equivalent (oar)) {
- break;
+ } else 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;
+
+ pair<AudioRegionList::iterator,bool> x = audio_regions.insert (entry);
+
+ if (!x.second) {
+ return;
+ }
+
+ added = true;
+ }
+
+ } else {
+
+ fatal << _("programming error: ")
+ << X_("unknown region type passed to Session::add_region()")
+ << endmsg;
+ /*NOTREACHED*/
+
}
+ }
+ }
+
+ /* mark dirty because something has changed even if we didn't
+ add the region to the region list.
+ */
+
+ set_dirty ();
+
+ if (added) {
- if (x == audio_regions.end()) {
+ vector<boost::weak_ptr<AudioRegion> > v;
+ boost::shared_ptr<AudioRegion> first_ar;
- pair<AudioRegionList::key_type,AudioRegionList::mapped_type> entry;
+ for (vector<boost::shared_ptr<Region> >::iterator ii = new_regions.begin(); ii != new_regions.end(); ++ii) {
- entry.first = region->id();
- entry.second = ar;
+ boost::shared_ptr<Region> region = *ii;
+ boost::shared_ptr<AudioRegion> ar;
- pair<AudioRegionList::iterator,bool> x = audio_regions.insert (entry);
+ if (region == 0) {
-
- if (!x.second) {
- return;
- }
+ error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg;
- added = true;
- }
+ } else if ((ar = boost::dynamic_pointer_cast<AudioRegion> (region)) != 0) {
+ v.push_back (ar);
- } else {
+ if (!first_ar) {
+ first_ar = ar;
+ }
+ }
- fatal << _("programming error: ")
- << X_("unknown region type passed to Session::add_region()")
- << endmsg;
- /*NOTREACHED*/
+ 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)));
+
+ update_region_name_map (region);
+ }
+ if (!v.empty()) {
+ AudioRegionsAdded (v); /* EMIT SIGNAL */
}
}
+}
- /* mark dirty because something has changed even if we didn't
- add the region to the region list.
- */
-
- set_dirty();
+void
+Session::update_region_name_map (boost::shared_ptr<Region> region)
+{
+ string::size_type last_period = region->name().find_last_of ('.');
- 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 */
+ if (last_period != string::npos && last_period < region->name().length() - 1) {
+
+ string base = region->name().substr (0, last_period);
+ string number = region->name().substr (last_period+1);
+ map<string,uint32_t>::iterator x;
+
+ /* note that if there is no number, we get zero from atoi,
+ which is just fine
+ */
+
+ region_name_map[base] = atoi (number);
}
}
/* relay hidden changes */
RegionHiddenChange (region);
}
+
+ if (what_changed & NameChanged) {
+ update_region_name_map (region);
+ }
}
void
set_dirty();
}
+ if (Config->get_auto_analyse_audio()) {
+ Analyser::queue_source_for_analysis (source, false);
+ }
}
}
Glib::ustring
Session::peak_path (Glib::ustring base) const
{
- Glib::ustring res;
-
- res = peak_dir ();
- res += base;
- res += ".peak";
-
- return res;
+ return Glib::build_filename(peak_dir (), base + ".peak");
}
string
Session::set_all_solo (bool yn)
{
shared_ptr<RouteList> r = routes.reader ();
-
+
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (!(*i)->hidden()) {
(*i)->set_solo (yn, this);
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,CPU_CACHE_ALIGN,current_block_size * sizeof(Sample));
+ 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,CPU_CACHE_ALIGN,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
memset (p, 0, sizeof (Sample) * current_block_size);
_silent_buffers.push_back (p);
return 0;
}
-int
-Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t len,
- bool overwrite, vector<boost::shared_ptr<AudioSource> >& srcs, InterThreadInfo& itt)
+boost::shared_ptr<Region>
+Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t end,
+ bool overwrite, vector<boost::shared_ptr<AudioSource> >& srcs, InterThreadInfo& itt, bool enable_processing)
{
- int ret = -1;
+ boost::shared_ptr<Region> result;
boost::shared_ptr<Playlist> playlist;
boost::shared_ptr<AudioFileSource> fsource;
uint32_t x;
nframes_t position;
nframes_t this_chunk;
nframes_t to_do;
+ nframes_t len = end - start;
vector<Sample*> buffers;
+ if (end <= start) {
+ error << string_compose (_("Cannot write a range where end <= start (e.g. %1 <= %2)"),
+ end, start) << endmsg;
+ return result;
+ }
+
// any bigger than this seems to cause stack overflows in called functions
const nframes_t chunk_size = (128 * 1024)/4;
- g_atomic_int_set (&processing_prohibited, 1);
+ // block all process callback handling
+
+ block_processing ();
/* call tree *MUST* hold route_lock */
this_chunk = min (to_do, chunk_size);
- if (track.export_stuff (buffers, nchans, start, this_chunk)) {
+ if (track.export_stuff (buffers, nchans, start, this_chunk, enable_processing)) {
goto out;
}
/* construct a region to represent the bounced material */
- boost::shared_ptr<Region> aregion = RegionFactory::create (srcs, 0, srcs.front()->length(),
- region_name_from_path (srcs.front()->name(), true));
-
- ret = 0;
+ result = RegionFactory::create (srcs, 0, srcs.front()->length(),
+ region_name_from_path (srcs.front()->name(), true));
}
out:
- if (ret) {
+ if (!result) {
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->mark_for_remove ();
}
-
+
(*src)->drop_references ();
}
}
for (vector<Sample*>::iterator i = buffers.begin(); i != buffers.end(); ++i) {
- free(*i);
+ free (*i);
}
- g_atomic_int_set (&processing_prohibited, 0);
+ unblock_processing ();
itt.done = true;
- return ret;
+ return result;
}
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 * 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
+ _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;
}
}
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
}