diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2017-06-22 19:18:57 -0400 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2017-09-18 11:40:53 -0400 |
commit | d4280997fb1764ae0df619fbb34031bebd4b0670 (patch) | |
tree | 43a52031ea6e0eab44bdfab8efc715e15248e2b2 /libs | |
parent | 5ac7d733c2e34e6dfb3ad42d3c9a5d6169120784 (diff) |
the return of MIDI recording, plus refactor to move post-capture playlist manipulations into Track
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/ardour/disk_writer.h | 7 | ||||
-rw-r--r-- | libs/ardour/ardour/route.h | 5 | ||||
-rw-r--r-- | libs/ardour/ardour/track.h | 5 | ||||
-rw-r--r-- | libs/ardour/ardour/types.h | 7 | ||||
-rw-r--r-- | libs/ardour/disk_writer.cc | 395 | ||||
-rw-r--r-- | libs/ardour/track.cc | 244 |
6 files changed, 356 insertions, 307 deletions
diff --git a/libs/ardour/ardour/disk_writer.h b/libs/ardour/ardour/disk_writer.h index f85eb26f11..72882e86fb 100644 --- a/libs/ardour/ardour/disk_writer.h +++ b/libs/ardour/ardour/disk_writer.h @@ -166,13 +166,8 @@ class LIBARDOUR_API DiskWriter : public DiskIOProcessor framecnt_t& rec_nframes, framecnt_t& rec_offset ); - struct CaptureInfo { - framepos_t start; - framecnt_t frames; - }; - - std::vector<CaptureInfo*> capture_info; mutable Glib::Threads::Mutex capture_info_lock; + CaptureInfos capture_info; private: framecnt_t _input_latency; diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index d7f1ebe8a9..489ad0c6f9 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -583,8 +583,9 @@ public: bool slaved_to (boost::shared_ptr<VCA>) const; bool slaved () const; -protected: - friend class Session; + protected: + friend class Session; + virtual void use_captured_sources (SourceList& srcs, CaptureInfos const &) {} void catch_up_on_solo_mute_override (); void set_listen (bool); diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h index 6c8266d63e..77755ab088 100644 --- a/libs/ardour/ardour/track.h +++ b/libs/ardour/ardour/track.h @@ -137,6 +137,8 @@ class LIBARDOUR_API Track : public Route, public Recordable bool can_be_record_enabled (); bool can_be_record_safe (); + void use_captured_sources (SourceList&, CaptureInfos const &); + void set_block_size (pframes_t); boost::shared_ptr<Playlist> playlist (); @@ -245,6 +247,9 @@ class LIBARDOUR_API Track : public Route, public Recordable void set_align_choice_from_io (); void input_changed (); + void use_captured_audio_sources (SourceList&, CaptureInfos const &); + void use_captured_midi_sources (SourceList&, CaptureInfos const &); + private: void parameter_changed (std::string const & p); diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 8358d78e9a..1f523bc8fe 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -705,6 +705,13 @@ namespace ARDOUR { SMFTempoUse, }; + struct CaptureInfo { + framepos_t start; + framecnt_t frames; + }; + + typedef std::vector<CaptureInfo*> CaptureInfos; + } // namespace ARDOUR static inline ARDOUR::framepos_t diff --git a/libs/ardour/disk_writer.cc b/libs/ardour/disk_writer.cc index 3bc8bbff69..4eb4393861 100644 --- a/libs/ardour/disk_writer.cc +++ b/libs/ardour/disk_writer.cc @@ -706,6 +706,8 @@ DiskWriter::finish_capture (boost::shared_ptr<ChannelList> c) ci->start = capture_start_frame; ci->frames = capture_captured; + DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("Finish capture, add new CI, %1 + %2\n", ci->start, ci->frames)); + /* XXX theoretical race condition here. Need atomic exchange ? However, the circumstances when this is called right now (either on record-disable or transport_stopped) @@ -715,8 +717,6 @@ DiskWriter::finish_capture (boost::shared_ptr<ChannelList> c) accessors, so that invalidation will not occur (both non-realtime). */ - DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("Finish capture, add new CI, %1 + %2\n", ci->start, ci->frames)); - capture_info.push_back (ci); capture_captured = 0; @@ -992,6 +992,48 @@ DiskWriter::do_flush (RunContext ctxt, bool force_flush) /* MIDI*/ + if (_midi_write_source) { + + const framecnt_t total = g_atomic_int_get(const_cast<gint*> (&_frames_pending_write)); + + if (total == 0 || + _midi_buf->read_space() == 0 || + (!force_flush && (total < _chunk_frames) && was_recording)) { + goto out; + } + + /* if there are 2+ chunks of disk i/o possible for + this track), let the caller know so that it can arrange + for us to be called again, ASAP. + + if we are forcing a flush, then if there is* any* extra + work, let the caller know. + + if we are no longer recording and there is any extra work, + let the caller know too. + */ + + if (total >= 2 * _chunk_frames || ((force_flush || !was_recording) && total > _chunk_frames)) { + ret = 1; + } + + if (force_flush) { + /* push out everything we have, right now */ + to_write = UINT32_MAX; + } else { + to_write = _chunk_frames; + } + + if (record_enabled() && ((total > _chunk_frames) || force_flush)) { + Source::Lock lm(_midi_write_source->mutex()); + if (_midi_write_source->midi_write (lm, *_midi_buf, get_capture_start_frame (0), to_write) != to_write) { + error << string_compose(_("MidiDiskstream %1: cannot write to disk"), id()) << endmsg; + return -1; + } + g_atomic_int_add(const_cast<gint*> (&_frames_pending_write), -to_write); + } + } + out: return ret; @@ -1127,13 +1169,11 @@ DiskWriter::use_new_write_source (DataType dt, uint32_t n) void DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abort_capture) { - uint32_t buffer_position; bool more_work = true; int err = 0; - boost::shared_ptr<AudioRegion> region; framecnt_t total_capture; - SourceList srcs; - SourceList::iterator src; + SourceList audio_srcs; + SourceList midi_srcs; ChannelList::iterator chan; vector<CaptureInfo*>::iterator ci; boost::shared_ptr<ChannelList> c = channels.reader(); @@ -1142,7 +1182,6 @@ DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abo finish_capture (c); - boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> (_playlists[DataType::AUDIO]); /* butler is already stopped, but there may be work to do to flush remaining data to disk. @@ -1186,6 +1225,12 @@ DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abo /* new source set up in "out" below */ } + if (_midi_write_source) { + _midi_write_source->mark_for_remove (); + _midi_write_source->drop_references (); + _midi_write_source.reset(); + } + goto out; } @@ -1197,117 +1242,76 @@ DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abo for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) { - boost::shared_ptr<AudioFileSource> s = (*chan)->write_source; + boost::shared_ptr<AudioFileSource> as = (*chan)->write_source; - if (s) { - srcs.push_back (s); - s->update_header (capture_info.front()->start, when, twhen); - s->set_captured_for (_name.val()); - s->mark_immutable (); + if (as) { + audio_srcs.push_back (as); + as->update_header (capture_info.front()->start, when, twhen); + as->set_captured_for (_name.val()); + as->mark_immutable (); if (Config->get_auto_analyse_audio()) { - Analyser::queue_source_for_analysis (s, true); + Analyser::queue_source_for_analysis (as, true); } - DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("newly captured source %1 length %2\n", s->path(), s->length (0))); + DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("newly captured source %1 length %2\n", as->path(), as->length (0))); } - } - if (!pl) { - goto midi; + if (_midi_write_source) { + midi_srcs.push_back (_midi_write_source); + } } - /* destructive tracks have a single, never changing region */ - - if (destructive()) { - - /* send a signal that any UI can pick up to do the right thing. there is - a small problem here in that a UI may need the peak data to be ready - for the data that was recorded and this isn't interlocked with that - process. this problem is deferred to the UI. - */ - - pl->LayeringChanged(); // XXX this may not get the UI to do the right thing - - } else { - - string whole_file_region_name; - whole_file_region_name = region_name_from_path (c->front()->write_source->name(), true); - - /* Register a new region with the Session that - describes the entire source. Do this first - so that any sub-regions will obviously be - children of this one (later!) - */ - - try { - PropertyList plist; - plist.add (Properties::start, c->front()->write_source->last_capture_start_frame()); - plist.add (Properties::length, total_capture); - plist.add (Properties::name, whole_file_region_name); - boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist)); - rx->set_automatic (true); - rx->set_whole_file (true); + /* MIDI */ - region = boost::dynamic_pointer_cast<AudioRegion> (rx); - region->special_set_position (capture_info.front()->start); - } + if (_midi_write_source) { + if (_midi_write_source->length (capture_info.front()->start) == 0) { + /* No data was recorded, so this capture will + effectively be aborted; do the same as we + do for an explicit abort. + */ + if (_midi_write_source) { + _midi_write_source->mark_for_remove (); + _midi_write_source->drop_references (); + _midi_write_source.reset(); + } - catch (failed_constructor& err) { - error << string_compose(_("%1: could not create region for complete audio file"), _name) << endmsg; - /* XXX what now? */ + goto out; } - _last_capture_sources.insert (_last_capture_sources.end(), srcs.begin(), srcs.end()); - - pl->clear_changes (); - pl->set_capture_insertion_in_progress (true); - pl->freeze (); - - const framepos_t preroll_off = _session.preroll_record_trim_len (); - for (buffer_position = c->front()->write_source->last_capture_start_frame(), ci = capture_info.begin(); ci != capture_info.end(); ++ci) { + /* phew, we have data */ - string region_name; + Source::Lock source_lock(_midi_write_source->mutex()); - RegionFactory::region_name (region_name, whole_file_region_name, false); + /* figure out the name for this take */ - DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 capture bufpos %5 start @ %2 length %3 add new region %4\n", - _name, (*ci)->start, (*ci)->frames, region_name, buffer_position)); + midi_srcs.push_back (_midi_write_source); - try { + _midi_write_source->set_timeline_position (capture_info.front()->start); + _midi_write_source->set_captured_for (_name); - PropertyList plist; + /* set length in beats to entire capture length */ - plist.add (Properties::start, buffer_position); - plist.add (Properties::length, (*ci)->frames); - plist.add (Properties::name, region_name); + BeatsFramesConverter converter (_session.tempo_map(), capture_info.front()->start); + const Evoral::Beats total_capture_beats = converter.from (total_capture); + _midi_write_source->set_length_beats (total_capture_beats); - boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist)); - region = boost::dynamic_pointer_cast<AudioRegion> (rx); - if (preroll_off > 0) { - region->trim_front (buffer_position + preroll_off); - } - } - - catch (failed_constructor& err) { - error << _("AudioDiskstream: could not create region for captured audio!") << endmsg; - continue; /* XXX is this OK? */ - } + /* flush to disk: this step differs from the audio path, + where all the data is already on disk. + */ - i_am_the_modifier++; + _midi_write_source->mark_midi_streaming_write_completed (source_lock, Evoral::Sequence<Evoral::Beats>::ResolveStuckNotes, total_capture_beats); + } - pl->add_region (region, (*ci)->start + preroll_off, 1, non_layered()); - pl->set_layer (region, DBL_MAX); - i_am_the_modifier--; + _last_capture_sources.insert (_last_capture_sources.end(), audio_srcs.begin(), audio_srcs.end()); + _last_capture_sources.insert (_last_capture_sources.end(), midi_srcs.begin(), midi_srcs.end()); - buffer_position += (*ci)->frames; - } - pl->thaw (); - pl->set_capture_insertion_in_progress (false); - _session.add_command (new StatefulDiffCommand (pl)); + if (_route) { + _route->use_captured_sources (audio_srcs, capture_info); + _route->use_captured_sources (midi_srcs, capture_info); } mark_write_completed = true; @@ -1323,215 +1327,8 @@ DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abo capture_info.clear (); capture_start_frame = 0; - - midi: - return; } -#if 0 // MIDI PART -void -DiskWriter::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen*/, bool abort_capture) -{ - bool more_work = true; - int err = 0; - boost::shared_ptr<MidiRegion> region; - MidiRegion::SourceList srcs; - MidiRegion::SourceList::iterator src; - vector<CaptureInfo*>::iterator ci; - - finish_capture (); - - /* butler is already stopped, but there may be work to do - to flush remaining data to disk. - */ - - while (more_work && !err) { - switch (do_flush (TransportContext, true)) { - case 0: - more_work = false; - break; - case 1: - break; - case -1: - error << string_compose(_("MidiDiskstream \"%1\": cannot flush captured data to disk!"), _name) << endmsg; - err++; - } - } - - /* XXX is there anything we can do if err != 0 ? */ - Glib::Threads::Mutex::Lock lm (capture_info_lock); - - if (capture_info.empty()) { - goto no_capture_stuff_to_do; - } - - if (abort_capture) { - - if (_write_source) { - _write_source->mark_for_remove (); - _write_source->drop_references (); - _write_source.reset(); - } - - /* new source set up in "out" below */ - - } else { - - framecnt_t total_capture = 0; - for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) { - total_capture += (*ci)->frames; - } - - if (_write_source->length (capture_info.front()->start) != 0) { - - /* phew, we have data */ - - Source::Lock source_lock(_write_source->mutex()); - - /* figure out the name for this take */ - - srcs.push_back (_write_source); - - _write_source->set_timeline_position (capture_info.front()->start); - _write_source->set_captured_for (_name); - - /* set length in beats to entire capture length */ - - BeatsFramesConverter converter (_session.tempo_map(), capture_info.front()->start); - const Evoral::Beats total_capture_beats = converter.from (total_capture); - _write_source->set_length_beats (total_capture_beats); - - /* flush to disk: this step differs from the audio path, - where all the data is already on disk. - */ - - _write_source->mark_midi_streaming_write_completed (source_lock, Evoral::Sequence<Evoral::Beats>::ResolveStuckNotes, total_capture_beats); - - /* we will want to be able to keep (over)writing the source - but we don't want it to be removable. this also differs - from the audio situation, where the source at this point - must be considered immutable. luckily, we can rely on - MidiSource::mark_streaming_write_completed() to have - already done the necessary work for that. - */ - - string whole_file_region_name; - whole_file_region_name = region_name_from_path (_write_source->name(), true); - - /* Register a new region with the Session that - describes the entire source. Do this first - so that any sub-regions will obviously be - children of this one (later!) - */ - - try { - PropertyList plist; - - plist.add (Properties::name, whole_file_region_name); - plist.add (Properties::whole_file, true); - plist.add (Properties::automatic, true); - plist.add (Properties::start, 0); - plist.add (Properties::length, total_capture); - plist.add (Properties::layer, 0); - - boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist)); - - region = boost::dynamic_pointer_cast<MidiRegion> (rx); - region->special_set_position (capture_info.front()->start); - } - - - catch (failed_constructor& err) { - error << string_compose(_("%1: could not create region for complete midi file"), _name) << endmsg; - /* XXX what now? */ - } - - _last_capture_sources.insert (_last_capture_sources.end(), srcs.begin(), srcs.end()); - - _playlist->clear_changes (); - _playlist->freeze (); - - /* Session frame time of the initial capture in this pass, which is where the source starts */ - framepos_t initial_capture = 0; - if (!capture_info.empty()) { - initial_capture = capture_info.front()->start; - } - - const framepos_t preroll_off = _session.preroll_record_trim_len (); - for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) { - - string region_name; - - RegionFactory::region_name (region_name, _write_source->name(), false); - - DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 capture start @ %2 length %3 add new region %4\n", - _name, (*ci)->start, (*ci)->frames, region_name)); - - - // cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add a region\n"; - - try { - PropertyList plist; - - /* start of this region is the offset between the start of its capture and the start of the whole pass */ - plist.add (Properties::start, (*ci)->start - initial_capture); - plist.add (Properties::length, (*ci)->frames); - plist.add (Properties::length_beats, converter.from((*ci)->frames).to_double()); - plist.add (Properties::name, region_name); - - boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist)); - region = boost::dynamic_pointer_cast<MidiRegion> (rx); - if (preroll_off > 0) { - region->trim_front ((*ci)->start - initial_capture + preroll_off); - } - } - - catch (failed_constructor& err) { - error << _("MidiDiskstream: could not create region for captured midi!") << endmsg; - continue; /* XXX is this OK? */ - } - - // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl; - - i_am_the_modifier++; - _playlist->add_region (region, (*ci)->start + preroll_off); - i_am_the_modifier--; - } - - _playlist->thaw (); - _session.add_command (new StatefulDiffCommand(_playlist)); - - } else { - - /* No data was recorded, so this capture will - effectively be aborted; do the same as we - do for an explicit abort. - */ - - if (_write_source) { - _write_source->mark_for_remove (); - _write_source->drop_references (); - _write_source.reset(); - } - } - - } - - reset_write_sources (); - - for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) { - delete *ci; - } - - capture_info.clear (); - capture_start_frame = 0; - - no_capture_stuff_to_do: - - reset_tracker (); -} -#endif - void DiskWriter::transport_looped (framepos_t transport_frame) { diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index 589d1f2672..d1f49fab63 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -19,6 +19,8 @@ #include "ardour/amp.h" #include "ardour/audioengine.h" +#include "ardour/audiofilesource.h" +#include "ardour/audioregion.h" #include "ardour/debug.h" #include "ardour/delivery.h" #include "ardour/disk_reader.h" @@ -26,17 +28,20 @@ #include "ardour/event_type_map.h" #include "ardour/io_processor.h" #include "ardour/meter.h" +#include "ardour/midi_region.h" #include "ardour/monitor_control.h" #include "ardour/playlist.h" #include "ardour/playlist_factory.h" #include "ardour/port.h" #include "ardour/processor.h" #include "ardour/profile.h" +#include "ardour/region_factory.h" #include "ardour/record_enable_control.h" #include "ardour/record_safe_control.h" #include "ardour/route_group_specialized.h" #include "ardour/session.h" #include "ardour/session_playlists.h" +#include "ardour/smf_source.h" #include "ardour/track.h" #include "ardour/types_convert.h" #include "ardour/utils.h" @@ -1262,3 +1267,242 @@ Track::set_processor_state (XMLNode const & node, XMLProperty const* prop, Proce error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg; return false; } + +void +Track::use_captured_sources (SourceList& srcs, CaptureInfos const & capture_info) +{ + if (srcs.empty()) { + return; + } + + boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (srcs.front()); + boost::shared_ptr<SMFSource> mfs = boost::dynamic_pointer_cast<SMFSource> (srcs.front()); + + if (afs) { + use_captured_audio_sources (srcs, capture_info); + } + + if (mfs) { + use_captured_midi_sources (srcs, capture_info); + } +} + +void +Track::use_captured_midi_sources (SourceList& srcs, CaptureInfos const & capture_info) +{ + if (srcs.empty() || data_type() != DataType::MIDI) { + return; + } + + boost::shared_ptr<SMFSource> mfs = boost::dynamic_pointer_cast<SMFSource> (srcs.front()); + boost::shared_ptr<Playlist> pl = _playlists[DataType::MIDI]; + boost::shared_ptr<MidiRegion> midi_region; + CaptureInfos::const_iterator ci; + + if (!mfs || !pl) { + return; + } + + framecnt_t total_capture = 0; + + for (total_capture = 0, ci = capture_info.begin(); ci != capture_info.end(); ++ci) { + total_capture += (*ci)->frames; + } + + /* we will want to be able to keep (over)writing the source + but we don't want it to be removable. this also differs + from the audio situation, where the source at this point + must be considered immutable. luckily, we can rely on + MidiSource::mark_streaming_write_completed() to have + already done the necessary work for that. + */ + + string whole_file_region_name; + whole_file_region_name = region_name_from_path (mfs->name(), true); + + /* Register a new region with the Session that + describes the entire source. Do this first + so that any sub-regions will obviously be + children of this one (later!) + */ + + try { + PropertyList plist; + + plist.add (Properties::name, whole_file_region_name); + plist.add (Properties::whole_file, true); + plist.add (Properties::automatic, true); + plist.add (Properties::start, 0); + plist.add (Properties::length, total_capture); + plist.add (Properties::layer, 0); + + boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist)); + + midi_region = boost::dynamic_pointer_cast<MidiRegion> (rx); + midi_region->special_set_position (capture_info.front()->start); + } + + catch (failed_constructor& err) { + error << string_compose(_("%1: could not create region for complete midi file"), _name) << endmsg; + /* XXX what now? */ + } + + pl->clear_changes (); + pl->freeze (); + + /* Session frame time of the initial capture in this pass, which is where the source starts */ + framepos_t initial_capture = 0; + if (!capture_info.empty()) { + initial_capture = capture_info.front()->start; + } + + BeatsFramesConverter converter (_session.tempo_map(), capture_info.front()->start); + const framepos_t preroll_off = _session.preroll_record_trim_len (); + + for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) { + + string region_name; + + RegionFactory::region_name (region_name, mfs->name(), false); + + DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 capture start @ %2 length %3 add new region %4\n", + _name, (*ci)->start, (*ci)->frames, region_name)); + + + // cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add a region\n"; + + try { + PropertyList plist; + + /* start of this region is the offset between the start of its capture and the start of the whole pass */ + plist.add (Properties::start, (*ci)->start - initial_capture); + plist.add (Properties::length, (*ci)->frames); + plist.add (Properties::length_beats, converter.from((*ci)->frames).to_double()); + plist.add (Properties::name, region_name); + + boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist)); + midi_region = boost::dynamic_pointer_cast<MidiRegion> (rx); + if (preroll_off > 0) { + midi_region->trim_front ((*ci)->start - initial_capture + preroll_off); + } + } + + catch (failed_constructor& err) { + error << _("MidiDiskstream: could not create region for captured midi!") << endmsg; + continue; /* XXX is this OK? */ + } + + // cerr << "add new region, buffer position = " << buffer_position << " @ " << (*ci)->start << endl; + + pl->add_region (midi_region, (*ci)->start + preroll_off); + } + + pl->thaw (); + _session.add_command (new StatefulDiffCommand (pl)); +} + +void +Track::use_captured_audio_sources (SourceList& srcs, CaptureInfos const & capture_info) +{ + if (srcs.empty() || data_type() != DataType::AUDIO) { + return; + } + + boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (srcs.front()); + boost::shared_ptr<Playlist> pl = _playlists[DataType::AUDIO]; + boost::shared_ptr<AudioRegion> region; + + if (!afs || !pl) { + return; + } + + /* destructive tracks have a single, never changing region */ + + if (destructive()) { + + /* send a signal that any UI can pick up to do the right thing. there is + a small problem here in that a UI may need the peak data to be ready + for the data that was recorded and this isn't interlocked with that + process. this problem is deferred to the UI. + */ + + pl->LayeringChanged(); // XXX this may not get the UI to do the right thing + return; + } + + string whole_file_region_name; + whole_file_region_name = region_name_from_path (afs->name(), true); + + /* Register a new region with the Session that + describes the entire source. Do this first + so that any sub-regions will obviously be + children of this one (later!) + */ + + try { + PropertyList plist; + + plist.add (Properties::start, afs->last_capture_start_frame()); + plist.add (Properties::length, afs->length(0)); + plist.add (Properties::name, whole_file_region_name); + boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist)); + rx->set_automatic (true); + rx->set_whole_file (true); + + region = boost::dynamic_pointer_cast<AudioRegion> (rx); + region->special_set_position (afs->natural_position()); + } + + + catch (failed_constructor& err) { + error << string_compose(_("%1: could not create region for complete audio file"), _name) << endmsg; + /* XXX what now? */ + } + + pl->clear_changes (); + pl->set_capture_insertion_in_progress (true); + pl->freeze (); + + const framepos_t preroll_off = _session.preroll_record_trim_len (); + framecnt_t buffer_position = afs->last_capture_start_frame (); + CaptureInfos::const_iterator ci; + + for (ci = capture_info.begin(); ci != capture_info.end(); ++ci) { + + string region_name; + + RegionFactory::region_name (region_name, whole_file_region_name, false); + + DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 capture bufpos %5 start @ %2 length %3 add new region %4\n", + _name, (*ci)->start, (*ci)->frames, region_name, buffer_position)); + + try { + + PropertyList plist; + + plist.add (Properties::start, buffer_position); + plist.add (Properties::length, (*ci)->frames); + plist.add (Properties::name, region_name); + + boost::shared_ptr<Region> rx (RegionFactory::create (srcs, plist)); + region = boost::dynamic_pointer_cast<AudioRegion> (rx); + if (preroll_off > 0) { + region->trim_front (buffer_position + preroll_off); + } + } + + catch (failed_constructor& err) { + error << _("AudioDiskstream: could not create region for captured audio!") << endmsg; + continue; /* XXX is this OK? */ + } + + pl->add_region (region, (*ci)->start + preroll_off, 1, _disk_writer->non_layered()); + pl->set_layer (region, DBL_MAX); + + buffer_position += (*ci)->frames; + } + + pl->thaw (); + pl->set_capture_insertion_in_progress (false); + _session.add_command (new StatefulDiffCommand (pl)); +} |