+ boost::shared_ptr<Region> region (wregion.lock());
+
+ if (!region) {
+ return;
+ }
+
+ _last_capture_regions.remove (region);
+}
+
+void
+Diskstream::playlist_ranges_moved (list< Evoral::RangeMove<framepos_t> > const & movements_frames)
+{
+ if (!_track || Config->get_automation_follows_regions () == false) {
+ return;
+ }
+
+ list< Evoral::RangeMove<double> > movements;
+
+ for (list< Evoral::RangeMove<framepos_t> >::const_iterator i = movements_frames.begin();
+ i != movements_frames.end();
+ ++i) {
+
+ movements.push_back(Evoral::RangeMove<double>(i->from, i->length, i->to));
+ }
+
+ /* move panner automation */
+ boost::shared_ptr<Panner> p = _track->main_outs()->panner ();
+ if (p) {
+ for (uint32_t i = 0; i < p->npanners (); ++i) {
+ boost::shared_ptr<AutomationList> pan_alist = p->streampanner(i).pan_control()->alist();
+ XMLNode & before = pan_alist->get_state ();
+ pan_alist->move_ranges (movements);
+ _session.add_command (new MementoCommand<AutomationList> (
+ *pan_alist.get(), &before, &pan_alist->get_state ()));
+ }
+ }
+
+ /* move processor automation */
+ _track->foreach_processor (boost::bind (&Diskstream::move_processor_automation, this, _1, movements_frames));
+}
+
+void
+Diskstream::move_processor_automation (boost::weak_ptr<Processor> p, list< Evoral::RangeMove<framepos_t> > const & movements_frames)
+{
+ boost::shared_ptr<Processor> processor (p.lock ());
+ if (!processor) {
+ return;
+ }
+
+ list< Evoral::RangeMove<double> > movements;
+ for (list< Evoral::RangeMove<framepos_t> >::const_iterator i = movements_frames.begin();
+ i != movements_frames.end(); ++i) {
+ movements.push_back(Evoral::RangeMove<double>(i->from, i->length, i->to));
+ }
+
+ set<Evoral::Parameter> const a = processor->what_can_be_automated ();
+
+ for (set<Evoral::Parameter>::iterator i = a.begin (); i != a.end (); ++i) {
+ boost::shared_ptr<AutomationList> al = processor->automation_control(*i)->alist();
+ XMLNode & before = al->get_state ();
+ al->move_ranges (movements);
+ _session.add_command (
+ new MementoCommand<AutomationList> (
+ *al.get(), &before, &al->get_state ()
+ )
+ );
+ }
+}
+
+void
+Diskstream::check_record_status (nframes_t transport_frame, nframes_t /*nframes*/, bool can_record)
+{
+ int possibly_recording;
+ int rolling;
+ int change;
+ const int transport_rolling = 0x4;
+ const int track_rec_enabled = 0x2;
+ const int global_rec_enabled = 0x1;
+ const int fully_rec_enabled = (transport_rolling|track_rec_enabled|global_rec_enabled);
+
+ /* merge together the 3 factors that affect record status, and compute
+ what has changed.
+ */
+
+ rolling = _session.transport_speed() != 0.0f;
+ possibly_recording = (rolling << 2) | (record_enabled() << 1) | can_record;
+ change = possibly_recording ^ last_possibly_recording;
+
+ if (possibly_recording == last_possibly_recording) {
+ return;
+ }
+ if (possibly_recording == fully_rec_enabled) {
+
+ if (last_possibly_recording == fully_rec_enabled) {
+ return;
+ }
+
+ /* we transitioned to recording. lets see if its transport based or a punch */
+
+ first_recordable_frame = transport_frame + _capture_offset;
+ last_recordable_frame = max_frames;
+ capture_start_frame = transport_frame;
+
+ if (change & transport_rolling) {
+
+ /* transport-change (started rolling) */
+
+ if (_alignment_style == ExistingMaterial) {
+
+ /* there are two delays happening:
+
+ 1) inbound, represented by _capture_offset
+ 2) outbound, represented by _session.worst_output_latency()
+
+ the first sample to record occurs when the larger of these
+ two has elapsed, since they occur in parallel.
+
+ since we've already added _capture_offset, just add the
+ difference if _session.worst_output_latency() is larger.
+ */
+
+ if (_capture_offset < _session.worst_output_latency()) {
+ first_recordable_frame += (_session.worst_output_latency() - _capture_offset);
+ }
+ } else {
+ first_recordable_frame += _roll_delay;
+ }
+
+ } else {
+
+ /* punch in */
+
+ if (_alignment_style == ExistingMaterial) {
+
+ /* There are two kinds of punch:
+
+ manual punch in happens at the correct transport frame
+ because the user hit a button. but to get alignment correct
+ we have to back up the position of the new region to the
+ appropriate spot given the roll delay.
+
+ autopunch toggles recording at the precise
+ transport frame, and then the DS waits
+ to start recording for a time that depends
+ on the output latency.
+
+ XXX: BUT THIS CODE DOESN'T DIFFERENTIATE !!!
+
+ */
+
+ if (_capture_offset < _session.worst_output_latency()) {
+ /* see comment in ExistingMaterial block above */
+ first_recordable_frame += (_session.worst_output_latency() - _capture_offset);
+ }
+
+ } else {
+ capture_start_frame -= _roll_delay;
+ }
+ }
+
+ prepare_record_status (capture_start_frame);
+
+ } else {
+
+ if (last_possibly_recording == fully_rec_enabled) {
+
+ /* we were recording last time */
+
+ if (change & transport_rolling) {
+ /* transport-change (stopped rolling): last_recordable_frame was set in ::prepare_to_stop() */
+
+ } else {
+ /* punch out */
+
+ last_recordable_frame = transport_frame + _capture_offset;
+
+ if (_alignment_style == ExistingMaterial) {
+ if (_session.worst_output_latency() > _capture_offset) {
+ last_recordable_frame += (_session.worst_output_latency() - _capture_offset);
+ }
+ } else {
+ last_recordable_frame += _roll_delay;
+ }
+ }
+ }
+ }
+
+ last_possibly_recording = possibly_recording;
+}
+
+void
+Diskstream::route_going_away ()
+{
+ _io.reset ();
+}
+
+void
+Diskstream::calculate_record_range(OverlapType ot, sframes_t transport_frame, nframes_t nframes,
+ nframes_t& rec_nframes, nframes_t& rec_offset)
+{
+ switch (ot) {
+ case OverlapNone:
+ rec_nframes = 0;
+ break;
+
+ case OverlapInternal:
+ /* ---------- recrange
+ |---| transrange
+ */
+ rec_nframes = nframes;
+ rec_offset = 0;
+ break;
+
+ case OverlapStart:
+ /* |--------| recrange
+ -----| transrange
+ */
+ rec_nframes = transport_frame + nframes - first_recordable_frame;
+ if (rec_nframes) {
+ rec_offset = first_recordable_frame - transport_frame;